Skip to content
Snippets Groups Projects
Commit 6971fd26 authored by Hordur Freyr Yngvason's avatar Hordur Freyr Yngvason Committed by Achilleas Pipinellis
Browse files

Give Knative serving permissions to service account

GitLab uses a kubernetes service account to perform deployments. For
serverless deployments to work as expected with externally created
clusters with their own knative installations (e.g. via Cloud Run), this
account requires additional permissions in the serving.knative.dev API
group.
parent cc3ef635
No related branches found
No related tags found
No related merge requests found
Showing
with 161 additions and 15 deletions
Loading
Loading
@@ -9,6 +9,8 @@ module Clusters
GITLAB_CLUSTER_ROLE_BINDING_NAME = 'gitlab-admin'
GITLAB_CLUSTER_ROLE_NAME = 'cluster-admin'
PROJECT_CLUSTER_ROLE_NAME = 'edit'
GITLAB_KNATIVE_SERVING_ROLE_NAME = 'gitlab-knative-serving-role'
GITLAB_KNATIVE_SERVING_ROLE_BINDING_NAME = 'gitlab-knative-serving-rolebinding'
end
end
end
Loading
Loading
@@ -41,7 +41,15 @@ module Clusters
 
kubeclient.create_or_update_service_account(service_account_resource)
kubeclient.create_or_update_secret(service_account_token_resource)
create_role_or_cluster_role_binding if rbac
return unless rbac
create_role_or_cluster_role_binding
return unless namespace_creator
create_or_update_knative_serving_role
create_or_update_knative_serving_role_binding
end
 
private
Loading
Loading
@@ -63,6 +71,14 @@ module Clusters
end
end
 
def create_or_update_knative_serving_role
kubeclient.update_role(knative_serving_role_resource)
end
def create_or_update_knative_serving_role_binding
kubeclient.update_role_binding(knative_serving_role_binding_resource)
end
def service_account_resource
Gitlab::Kubernetes::ServiceAccount.new(
service_account_name,
Loading
Loading
@@ -92,6 +108,29 @@ module Clusters
Gitlab::Kubernetes::RoleBinding.new(
name: role_binding_name,
role_name: Clusters::Gcp::Kubernetes::PROJECT_CLUSTER_ROLE_NAME,
role_kind: :ClusterRole,
namespace: service_account_namespace,
service_account_name: service_account_name
).generate
end
def knative_serving_role_resource
Gitlab::Kubernetes::Role.new(
name: Clusters::Gcp::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_NAME,
namespace: service_account_namespace,
rules: [{
apiGroups: %w(serving.knative.dev),
resources: %w(configurations configurationgenerations routes revisions revisionuids autoscalers services),
verbs: %w(get list create update delete patch watch)
}]
).generate
end
def knative_serving_role_binding_resource
Gitlab::Kubernetes::RoleBinding.new(
name: Clusters::Gcp::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_BINDING_NAME,
role_name: Clusters::Gcp::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_NAME,
role_kind: :Role,
namespace: service_account_namespace,
service_account_name: service_account_name
).generate
Loading
Loading
---
title: Create Knative role and binding with service account
merge_request: 30235
author:
type: changed
Loading
Loading
@@ -102,12 +102,15 @@ You must do the following:
1. Ensure GitLab can manage Knative:
- For a non-GitLab managed cluster, ensure that the service account for the token
provided can manage resources in the `serving.knative.dev` API group.
- For a GitLab managed cluster,
GitLab uses a service account with the `edit` cluster role. This account needs
the ability to manage resources in the `serving.knative.dev` API group.
We suggest you do this with an [aggregated ClusterRole](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#aggregated-clusterroles)
adding rules to the default `edit` cluster role:
First, save the following YAML as `knative-serving-only-role.yaml`:
- For a GitLab managed cluster, if you added the cluster in [GitLab 12.1 or later](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/30235),
then GitLab will already have the required access and you can proceed to the next step.
Otherwise, you need to manually grant GitLab's service account the ability to manage
resources in the `serving.knative.dev` API group. Since every GitLab service account
has the `edit` cluster role, the simplest way to do this is with an
[aggregated ClusterRole](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#aggregated-clusterroles)
adding rules to the default `edit` cluster role: First, save the following YAML as
`knative-serving-only-role.yaml`:
 
```yaml
apiVersion: rbac.authorization.k8s.io/v1
Loading
Loading
@@ -143,6 +146,9 @@ You must do the following:
kubectl apply -f knative-serving-only-role.yaml
```
 
If you would rather grant permissions on a per service account basis, you can do this
using a `Role` and `RoleBinding` specific to the service account and namespace.
1. Follow the steps to deploy [functions](#deploying-functions)
or [serverless applications](#deploying-serverless-applications) onto your
cluster.
Loading
Loading
@@ -376,13 +382,13 @@ cluster.
By default, a GitLab serverless deployment will be served over `http`. In order to serve over `https` you
must manually obtain and install TLS certificates.
 
The simplest way to accomplish this is to
The simplest way to accomplish this is to
use [Certbot to manually obtain Let's Encrypt certificates](https://knative.dev/docs/serving/using-a-tls-cert/#using-certbot-to-manually-obtain-let-s-encrypt-certificates). Certbot is a free, open source software tool for automatically using Let’s Encrypt certificates on manually-administrated websites to enable HTTPS.
 
NOTE: **Note:**
The instructions below relate to installing and running Certbot on a Linux server and may not work on other operating systems.
 
1. Install Certbot by running the
1. Install Certbot by running the
[`certbot-auto` wrapper script](https://certbot.eff.org/docs/install.html#certbot-auto).
On the command line of your server, run the following commands:
 
Loading
Loading
@@ -594,7 +600,7 @@ The instructions below relate to installing and running Certbot on a Linux serve
Where `cert.pem` and `cert.pk` are your certificate and private key files. Note that the `istio-ingressgateway-certs` secret name is required.
 
1. Configure Knative to use the new secret that you created for HTTPS
connections. Run the
connections. Run the
following command to open the Knative shared `gateway` in edit mode:
 
```sh
Loading
Loading
@@ -641,4 +647,4 @@ The instructions below relate to installing and running Certbot on a Linux serve
 
After your changes are running on your Knative cluster, you can begin using the HTTPS protocol for secure access your deployed Knative services.
In the event a mistake is made during this process and you need to update the cert, you will need to edit the gateway `knative-ingress-gateway`
to switch back to `PASSTHROUGH` mode. Once corrections are made, edit the file again so the gateway will use the new certificates.
\ No newline at end of file
to switch back to `PASSTHROUGH` mode. Once corrections are made, edit the file again so the gateway will use the new certificates.
Loading
Loading
@@ -57,6 +57,13 @@ module Gitlab
:update_cluster_role_binding,
to: :rbac_client
 
# RBAC methods delegates to the apis/rbac.authorization.k8s.io api
# group client
delegate :create_role,
:get_role,
:update_role,
to: :rbac_client
# RBAC methods delegates to the apis/rbac.authorization.k8s.io api
# group client
delegate :create_role_binding,
Loading
Loading
# frozen_string_literal: true
module Gitlab
module Kubernetes
class Role
def initialize(name:, namespace:, rules:)
@name = name
@namespace = namespace
@rules = rules
end
def generate
::Kubeclient::Resource.new(
metadata: { name: name, namespace: namespace },
rules: rules
)
end
private
attr_reader :name, :namespace, :rules
end
end
end
Loading
Loading
@@ -3,9 +3,10 @@
module Gitlab
module Kubernetes
class RoleBinding
def initialize(name:, role_name:, namespace:, service_account_name:)
def initialize(name:, role_name:, role_kind:, namespace:, service_account_name:)
@name = name
@role_name = role_name
@role_kind = role_kind
@namespace = namespace
@service_account_name = service_account_name
end
Loading
Loading
@@ -20,7 +21,7 @@ module Gitlab
 
private
 
attr_reader :name, :role_name, :namespace, :service_account_name
attr_reader :name, :role_name, :role_kind, :namespace, :service_account_name
 
def metadata
{ name: name, namespace: namespace }
Loading
Loading
@@ -29,7 +30,7 @@ module Gitlab
def role_ref
{
apiGroup: 'rbac.authorization.k8s.io',
kind: 'ClusterRole',
kind: role_kind,
name: role_name
}
end
Loading
Loading
Loading
Loading
@@ -176,6 +176,9 @@ describe Gitlab::Kubernetes::KubeClient do
let(:rbac_client) { client.rbac_client }
 
[
:create_role,
:get_role,
:update_role,
:create_cluster_role_binding,
:get_cluster_role_binding,
:update_cluster_role_binding
Loading
Loading
Loading
Loading
@@ -4,6 +4,7 @@ require 'spec_helper'
 
describe Gitlab::Kubernetes::RoleBinding, '#generate' do
let(:role_name) { 'edit' }
let(:role_kind) { 'ClusterRole' }
let(:namespace) { 'my-namespace' }
let(:service_account_name) { 'my-service-account' }
 
Loading
Loading
@@ -20,7 +21,7 @@ describe Gitlab::Kubernetes::RoleBinding, '#generate' do
let(:role_ref) do
{
apiGroup: 'rbac.authorization.k8s.io',
kind: 'ClusterRole',
kind: role_kind,
name: role_name
}
end
Loading
Loading
@@ -37,6 +38,7 @@ describe Gitlab::Kubernetes::RoleBinding, '#generate' do
described_class.new(
name: "gitlab-#{namespace}",
role_name: role_name,
role_kind: role_kind,
namespace: namespace,
service_account_name: service_account_name
).generate
Loading
Loading
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Kubernetes::Role do
let(:role) { described_class.new(name: name, namespace: namespace, rules: rules) }
let(:name) { 'example-name' }
let(:namespace) { 'example-namespace' }
let(:rules) do
[{
apiGroups: %w(hello.world),
resources: %w(oil diamonds coffee),
verbs: %w(say do walk run)
}]
end
describe '#generate' do
subject { role.generate }
let(:resource) do
::Kubeclient::Resource.new(
metadata: { name: name, namespace: namespace },
rules: rules
)
end
it { is_expected.to eq(resource) }
end
end
Loading
Loading
@@ -34,6 +34,8 @@ describe Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService, '#execute' d
stub_kubeclient_create_service_account(api_url, namespace: namespace)
stub_kubeclient_create_secret(api_url, namespace: namespace)
stub_kubeclient_put_secret(api_url, "#{namespace}-token", namespace: namespace)
stub_kubeclient_put_role(api_url, Clusters::Gcp::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_NAME, namespace: namespace)
stub_kubeclient_put_role_binding(api_url, Clusters::Gcp::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_BINDING_NAME, namespace: namespace)
 
stub_kubeclient_get_secret(
api_url,
Loading
Loading
Loading
Loading
@@ -143,6 +143,8 @@ describe Clusters::Gcp::Kubernetes::CreateOrUpdateServiceAccountService do
 
stub_kubeclient_get_role_binding_error(api_url, role_binding_name, namespace: namespace)
stub_kubeclient_create_role_binding(api_url, namespace: namespace)
stub_kubeclient_put_role(api_url, Clusters::Gcp::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_NAME, namespace: namespace)
stub_kubeclient_put_role_binding(api_url, Clusters::Gcp::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_BINDING_NAME, namespace: namespace)
end
 
it_behaves_like 'creates service account and token'
Loading
Loading
@@ -169,6 +171,24 @@ describe Clusters::Gcp::Kubernetes::CreateOrUpdateServiceAccountService do
)
)
end
it 'creates a role and role binding granting knative serving permissions to the service account' do
subject
expect(WebMock).to have_requested(:put, api_url + "/apis/rbac.authorization.k8s.io/v1/namespaces/#{namespace}/roles/#{Clusters::Gcp::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_NAME}").with(
body: hash_including(
metadata: {
name: Clusters::Gcp::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_NAME,
namespace: namespace
},
rules: [{
apiGroups: %w(serving.knative.dev),
resources: %w(configurations configurationgenerations routes revisions revisionuids autoscalers services),
verbs: %w(get list create update delete patch watch)
}]
)
)
end
end
end
end
Loading
Loading
@@ -199,6 +199,11 @@ module KubernetesHelpers
.to_return(kube_response({}))
end
 
def stub_kubeclient_put_role(api_url, name, namespace: 'default')
WebMock.stub_request(:put, api_url + "/apis/rbac.authorization.k8s.io/v1/namespaces/#{namespace}/roles/#{name}")
.to_return(kube_response({}))
end
def kube_v1_secret_body(**options)
{
"kind" => "SecretList",
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment