I'm trying to get access to my kubernetes cluster in my self hosted gitlab instance as it is described in the docs.
deploy:
stage: deployment
script:
- kubectl create secret docker-registry gitlab-registry --docker-server="$CI_REGISTRY" --docker-username="$CI_DEPLOY_USER" --docker-password="$CI_DEPLOY_PASSWORD" --docker-email="$GITLAB_USER_EMAIL" -o yaml --dry-run=client | kubectl apply -f -
But I do get the error
Error from server (Forbidden): error when retrieving current configuration of:
Resource: "/v1, Resource=secrets", GroupVersionKind: "/v1, Kind=Secret"
Name: "gitlab-registry", Namespace: "gitlab"
from server for: "STDIN": secrets "gitlab-registry" is forbidden: User "system:serviceaccount:gitlab:default" cannot get resource "secrets" in API group "" in the namespace "gitlab"
I do not understand the error. Why do I get a forbidden error?
Update
The kubernetes cluster is integrated in gitlab at instance level.
But running kubectl config view
in the CI pipeline gives me
apiVersion: v1
clusters: null
contexts: null
current-context: ""
kind: Config
preferences: {}
users: null
Update2
Thanks to AndD, the secret can be created with this role / service account:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
namespace: gitlab
name: gitlab-deploy
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["secrets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: use-secrets
namespace: gitlab
subjects:
- kind: ServiceAccount
name: default
namespace: gitlab
roleRef:
kind: ClusterRole
name: gitlab-deploy
apiGroup: rbac.authorization.k8s.io
But running a simple apply for this namespace.yaml file
apiVersion: v1
kind: Namespace
metadata:
name: myns
gives me a similar error:
Error from server (Forbidden): error when retrieving current configuration of:
Resource: "/v1, Resource=namespaces", GroupVersionKind: "/v1, Kind=Namespace"
Name: "myns", Namespace: ""
from server for: "namespace.yaml": namespaces "myns" is forbidden: User "system:serviceaccount:gitlab:default" cannot get resource "namespaces" in API group "" in the namespace "myns"
I used ClusterBinding to get this working even for a different namespace. What am I doing wrong?
Kubernetes makes use of a Role-based access control (RBAC) to prevent Pods and Users from being able to interact with resources in the cluster, unless they are not authorized.
From the error, you can see that Gitlab is trying to use the secrets
resource and also that it is using as ServiceAccount
the default
service account in its namespace.
This means that Gitlab is not configured to use a particular ServiceAccount, which means it makes use of the default one (there's a default service account in each namespace of the cluster)
You can attach role auth and permissions to service accounts by using Role
/ ClusterRole
and RoleBinding
/ ClusterRoleBinding
.
Roles or ClusterRoles describe permissions. For example, a Role could be:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: gitlab
name: secret-user
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["secrets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
and this states that "whoever has this role, can do whatever (all the verbs) with secrets but only in the namespace gitlab
"
If you want to give generic permissions in all namespaces, you can use a ClusterRole instead, which is very similar.
Once the Role is created, you then can attach it to a User, a Group or a ServiceAccount, for example:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: use-secrets
namespace: gitlab
subjects:
subjects:
- kind: ServiceAccount
name: default
namespace: gitlab
roleRef:
# "roleRef" specifies the binding to a Role / ClusterRole
kind: Role # this must be Role or ClusterRole
name: secret-user # this must match the name of the Role or ClusterRole you wish to bind to
apiGroup: rbac.authorization.k8s.io
and this bind the role previously created to the ServiceAccount
called default in the namespace gitlab
.
Then, all Pods running in the namespace gitlab
and using the default
service account, will be able to use secrets
(use the verbs listed in the Role) but only in the namespace specified by the Role.
As you can see, this aspect of Kubernetes is pretty complex and powerful, so have a look at the docs because they explain things really well and are also full of examples:
Service Accounts - https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
RBAC - https://kubernetes.io/docs/reference/access-authn-authz/rbac/
A list of RBAC resources - https://stackoverflow.com/questions/57872201/how-to-refer-to-all-subresources-in-a-role-definition
UPDATE
You are doing nothing wrong. It's just that you are trying to use the resource namespace
but Gitlab has no Bind that gives access to that type of resource. With your ClusterRole
you just gave it access to secrets
, but nothing more.
Consider giving the ClusterRole more permissions, changing it to list all resources that you need to access:
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["secrets", "namespaces", "pods"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
For example this will give access to secrets, namespaces and Pods.
As an alternative, you can bind Gitlab's service account to cluster-admin
to directly give it access to everything.
kubectl create clusterrolebinding gitlab-is-now-cluster-admin \
--clusterrole=cluster-admin \
--serviceaccount=gitlab:default
Before doing so tho, consider the following:
Fine-grained role bindings provide greater security, but require more effort to administrate. Broader grants can give unnecessary (and potentially escalating) API access to ServiceAccounts, but are easier to administrate.
So, it is way more secure to first decide which resources can be used by Gitlab and then create a Role / ClusterRole giving access to only those resources (and with the verbs that you need)