Commit 7db78736 authored by Achilleas Pipinellis's avatar Achilleas Pipinellis

Merge branch 'hfy/apply-knative-cluster-role-on-service-account-creation' into 'master'

Create Knative role and binding with service account

See merge request gitlab-org/gitlab-ce!30235
parents cc3ef635 6971fd26
...@@ -9,6 +9,8 @@ module Clusters ...@@ -9,6 +9,8 @@ module Clusters
GITLAB_CLUSTER_ROLE_BINDING_NAME = 'gitlab-admin' GITLAB_CLUSTER_ROLE_BINDING_NAME = 'gitlab-admin'
GITLAB_CLUSTER_ROLE_NAME = 'cluster-admin' GITLAB_CLUSTER_ROLE_NAME = 'cluster-admin'
PROJECT_CLUSTER_ROLE_NAME = 'edit' 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 end
end end
...@@ -41,7 +41,15 @@ module Clusters ...@@ -41,7 +41,15 @@ module Clusters
kubeclient.create_or_update_service_account(service_account_resource) kubeclient.create_or_update_service_account(service_account_resource)
kubeclient.create_or_update_secret(service_account_token_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 end
private private
...@@ -63,6 +71,14 @@ module Clusters ...@@ -63,6 +71,14 @@ module Clusters
end end
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 def service_account_resource
Gitlab::Kubernetes::ServiceAccount.new( Gitlab::Kubernetes::ServiceAccount.new(
service_account_name, service_account_name,
...@@ -92,6 +108,29 @@ module Clusters ...@@ -92,6 +108,29 @@ module Clusters
Gitlab::Kubernetes::RoleBinding.new( Gitlab::Kubernetes::RoleBinding.new(
name: role_binding_name, name: role_binding_name,
role_name: Clusters::Gcp::Kubernetes::PROJECT_CLUSTER_ROLE_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, namespace: service_account_namespace,
service_account_name: service_account_name service_account_name: service_account_name
).generate ).generate
......
---
title: Create Knative role and binding with service account
merge_request: 30235
author:
type: changed
...@@ -102,12 +102,15 @@ You must do the following: ...@@ -102,12 +102,15 @@ You must do the following:
1. Ensure GitLab can manage Knative: 1. Ensure GitLab can manage Knative:
- For a non-GitLab managed cluster, ensure that the service account for the token - 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. provided can manage resources in the `serving.knative.dev` API group.
- For a GitLab managed cluster, - 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),
GitLab uses a service account with the `edit` cluster role. This account needs then GitLab will already have the required access and you can proceed to the next step.
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) Otherwise, you need to manually grant GitLab's service account the ability to manage
adding rules to the default `edit` cluster role: resources in the `serving.knative.dev` API group. Since every GitLab service account
First, save the following YAML as `knative-serving-only-role.yaml`: 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 ```yaml
apiVersion: rbac.authorization.k8s.io/v1 apiVersion: rbac.authorization.k8s.io/v1
...@@ -143,6 +146,9 @@ You must do the following: ...@@ -143,6 +146,9 @@ You must do the following:
kubectl apply -f knative-serving-only-role.yaml 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) 1. Follow the steps to deploy [functions](#deploying-functions)
or [serverless applications](#deploying-serverless-applications) onto your or [serverless applications](#deploying-serverless-applications) onto your
cluster. cluster.
......
...@@ -57,6 +57,13 @@ module Gitlab ...@@ -57,6 +57,13 @@ module Gitlab
:update_cluster_role_binding, :update_cluster_role_binding,
to: :rbac_client 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 # RBAC methods delegates to the apis/rbac.authorization.k8s.io api
# group client # group client
delegate :create_role_binding, delegate :create_role_binding,
......
# 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
...@@ -3,9 +3,10 @@ ...@@ -3,9 +3,10 @@
module Gitlab module Gitlab
module Kubernetes module Kubernetes
class RoleBinding class RoleBinding
def initialize(name:, role_name:, namespace:, service_account_name:) def initialize(name:, role_name:, role_kind:, namespace:, service_account_name:)
@name = name @name = name
@role_name = role_name @role_name = role_name
@role_kind = role_kind
@namespace = namespace @namespace = namespace
@service_account_name = service_account_name @service_account_name = service_account_name
end end
...@@ -20,7 +21,7 @@ module Gitlab ...@@ -20,7 +21,7 @@ module Gitlab
private private
attr_reader :name, :role_name, :namespace, :service_account_name attr_reader :name, :role_name, :role_kind, :namespace, :service_account_name
def metadata def metadata
{ name: name, namespace: namespace } { name: name, namespace: namespace }
...@@ -29,7 +30,7 @@ module Gitlab ...@@ -29,7 +30,7 @@ module Gitlab
def role_ref def role_ref
{ {
apiGroup: 'rbac.authorization.k8s.io', apiGroup: 'rbac.authorization.k8s.io',
kind: 'ClusterRole', kind: role_kind,
name: role_name name: role_name
} }
end end
......
...@@ -176,6 +176,9 @@ describe Gitlab::Kubernetes::KubeClient do ...@@ -176,6 +176,9 @@ describe Gitlab::Kubernetes::KubeClient do
let(:rbac_client) { client.rbac_client } let(:rbac_client) { client.rbac_client }
[ [
:create_role,
:get_role,
:update_role,
:create_cluster_role_binding, :create_cluster_role_binding,
:get_cluster_role_binding, :get_cluster_role_binding,
:update_cluster_role_binding :update_cluster_role_binding
......
...@@ -4,6 +4,7 @@ require 'spec_helper' ...@@ -4,6 +4,7 @@ require 'spec_helper'
describe Gitlab::Kubernetes::RoleBinding, '#generate' do describe Gitlab::Kubernetes::RoleBinding, '#generate' do
let(:role_name) { 'edit' } let(:role_name) { 'edit' }
let(:role_kind) { 'ClusterRole' }
let(:namespace) { 'my-namespace' } let(:namespace) { 'my-namespace' }
let(:service_account_name) { 'my-service-account' } let(:service_account_name) { 'my-service-account' }
...@@ -20,7 +21,7 @@ describe Gitlab::Kubernetes::RoleBinding, '#generate' do ...@@ -20,7 +21,7 @@ describe Gitlab::Kubernetes::RoleBinding, '#generate' do
let(:role_ref) do let(:role_ref) do
{ {
apiGroup: 'rbac.authorization.k8s.io', apiGroup: 'rbac.authorization.k8s.io',
kind: 'ClusterRole', kind: role_kind,
name: role_name name: role_name
} }
end end
...@@ -37,6 +38,7 @@ describe Gitlab::Kubernetes::RoleBinding, '#generate' do ...@@ -37,6 +38,7 @@ describe Gitlab::Kubernetes::RoleBinding, '#generate' do
described_class.new( described_class.new(
name: "gitlab-#{namespace}", name: "gitlab-#{namespace}",
role_name: role_name, role_name: role_name,
role_kind: role_kind,
namespace: namespace, namespace: namespace,
service_account_name: service_account_name service_account_name: service_account_name
).generate ).generate
......
# 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
...@@ -34,6 +34,8 @@ describe Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService, '#execute' d ...@@ -34,6 +34,8 @@ describe Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService, '#execute' d
stub_kubeclient_create_service_account(api_url, namespace: namespace) stub_kubeclient_create_service_account(api_url, namespace: namespace)
stub_kubeclient_create_secret(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_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( stub_kubeclient_get_secret(
api_url, api_url,
......
...@@ -143,6 +143,8 @@ describe Clusters::Gcp::Kubernetes::CreateOrUpdateServiceAccountService do ...@@ -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_get_role_binding_error(api_url, role_binding_name, namespace: namespace)
stub_kubeclient_create_role_binding(api_url, 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 end
it_behaves_like 'creates service account and token' it_behaves_like 'creates service account and token'
...@@ -169,6 +171,24 @@ describe Clusters::Gcp::Kubernetes::CreateOrUpdateServiceAccountService do ...@@ -169,6 +171,24 @@ describe Clusters::Gcp::Kubernetes::CreateOrUpdateServiceAccountService do
) )
) )
end 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 end
end end
...@@ -199,6 +199,11 @@ module KubernetesHelpers ...@@ -199,6 +199,11 @@ module KubernetesHelpers
.to_return(kube_response({})) .to_return(kube_response({}))
end 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) def kube_v1_secret_body(**options)
{ {
"kind" => "SecretList", "kind" => "SecretList",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment