Kubernetes - Gitlab

Secure deployment to Kubernetes with a service account

Secure deployment to Kubernetes with a service account

cover photo: Emma Döbken 2018.

Now that I have a number of pipelines running I would like to deploy these to Kubernetes through a service account. that is quite simple. As an admin user provide resources such as:

  • the namespaces, optionally with limited resources;
  • an isolated service account with restricted access to one namespace;
  • an encoded config file to be used by the Gitlab pipeline.

Service Account with permissions

The following file serviceaccount.yaml creates the service account, a role, and attach that role to that account:

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: mynamespace-dev-user
  namespace: mynamespace-dev
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: mynamespace-dev-user-full-access
  namespace: mynamespace-dev
rules:
- apiGroups: ["", "extensions", "apps"]
  resources: ["*"]
  verbs: ["*"]
- apiGroups: ["batch"]
  resources:
  - jobs
  - cronjobs
  verbs: ["*"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: mynamespace-dev-user-view
  namespace: mynamespace-dev
subjects:
- kind: ServiceAccount
  name: mynamespace-dev-user
  namespace: mynamespace-dev
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: mynamespace-dev-user-full-access

The following bash file helps to deploy both the namespace and the access file and it creates the sa.kubeconfig:

#!/bin/bash
SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"

NAMESPACE=mynamespace-dev
kubectl apply -f $SCRIPTPATH/namespace.yaml
kubectl apply -f $SCRIPTPATH/access.yaml

APISERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
CLUSTERNAME=$(kubectl config view --minify -o jsonpath='{.clusters[0].name}')
SECRETNAME=$(kubectl get sa "$NAMESPACE-user" -n $NAMESPACE -o=jsonpath="{.secrets[0].name}")
USERTOKEN=$(kubectl get secret $SECRETNAME -n $NAMESPACE -o "jsonpath={.data.token}" | base64 -D)
CERTIFICATE=$(kubectl get secret $SECRETNAME -n $NAMESPACE -o "jsonpath={.data['ca\.crt']}")

read -r -d '' KCONFIG << EOM
apiVersion: v1
kind: Config
clusters:
- name: ${CLUSTERNAME}
  cluster:
    certificate-authority-data: ${CERTIFICATE}
    server: ${APISERVER}
contexts:
- name: default-kube
  context:
    cluster: ${CLUSTERNAME}
    namespace: ${NAMESPACE}
    user: ${NAMESPACE}-user
current-context: default-kube
users:
- name: ${NAMESPACE}-user
  user:
    token: ${USERTOKEN}
EOM

echo $(echo -ne "$KCONFIG" | base64) > $SCRIPTPATH/sa.kubeconfig

Copy the content of this kubeconfig file.

Setup Gitlab CI

Go to the Gitlab project settings > CI/CD > Variables; name the variable something e.g. KUBECONFIGENCR and paste the earlier copied content from sa.kubeconfig as value.

In your projects gitlab-ci.yaml you can add the following variable and deployment:

variables:
  KUBECONFIG: /etc/deploy/config

deploy:
  stage: deploy
  image: dtzar/helm-kubectl:3.1.2
  script:
    - mkdir -p /etc/deploy
    - echo $KUBECONFIGENCR | base64 -d > ${KUBECONFIG}
    - kubectl config use-context default-kube
  script:
    - kubectl apply --install -f ./path/to/my/service

Resources