Forbidden error to connect to kubernetes cluster in gitlab CI

9/15/2021

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?

-- user3142695
gitlab
gitlab-ci
kubernetes

1 Answer

9/15/2021

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)

-- AndD
Source: StackOverflow