May 10, 2020

Create User-Specific Namespace with RBAC in Kubernetes

The are possibly tens of articles on this topic but I decided to summarize my learnings on Role Based Access Control (RBAC) and how to grant a user access to a Kubernetes cluster within their own namespace.

Below I define some nouns to establish a common baseline for our understanding:

  • ally is a user
  • app-developer is a role
  • ally-ns is a namespace
  • kind is a cluster

Prerequisites:

  1. ally-ns namespace
apiVersion: v1
kind: Namespace
metadata:
  name: ally-ns

1. Generate private key and certificate signing request (CSR)

According to this article which references The Concise Guide to SSL/TLS for DevOps, ECC 256 bit is 64,000 harder to crack than standard RSA 2048 bit. In addition, RSA is less taxing in terms of CPU usage compared to ECC, however TLS 1.2 supports latest and fastest ciphers. For the sake of completion both algorithms are provided below.

Option 1. RSA 2048

OpenSSL:

openssl genrsa \
  -out ally.key \
  2048

openssl req -new \
  -key ally.key \
  -out ally.csr \
  -subj "/CN=ally/O=ally-ns"

CFSSL:

cat <<EOF | cfssl genkey - | cfssljson -bare server
{
  "CN": "ally",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [{
      "O": "ally-ns"
  }]
}
EOF

Option 2. ECDSA 256

OpenSSL

openssl ecparam -genkey \
  -name prime256v1 \
  -noout \
  -out ally.key

openssl req -new -sha256 \
  -key ally.key \
  -out ally.csr \
  -subj "/CN=ally/O=ally-ns"

CFSSL:

cat <<EOF | cfssl genkey - | cfssljson -bare server
{
  "CN": "ally",
  "key": {
    "algo": "ecdsa",
    "size": 256
  },
  "names": [{
      "O": "ally-ns"
  }]
}
EOF

2. Sign the CSR Request using Kubernetes CA Certificate

Option 1. Sign the CSR manually using CA Certificate

openssl x509 -req \
  -in ally.csr \
  -ca ca.crt \
  -cakey ca.key \
  -cacreateserial \
  -out ally.crt \
  -days 365

Option 2. Sign and approve using Kubernetes Certificates API

As of Kubernetes 1.18, all signed certificates have a validity of 8760 hours (365 days), this will change according to this Github issue comment. In order to change the duration cluster-wide set the --experimental-cluster-signing-duration option on kube-controller-manager. If you wish to keep this intact, use option 1 above.

export K8SUSERNAME=ally

cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1beta1
kind: CertificateSigningRequest
metadata:
  name: $K8SUSERNAME
spec:
  username: $K8SUSERNAME
  groups:
  - system:authenticated
  request: $(cat ally.csr | base64 | tr -d '\n')
  usages:
  - digital signature
  - key encipherment
  - client auth
EOF

# Approve the Certificate Signing Request
kubectl certificate approve $K8SUSERNAME

# Obtain the signed certificate
kubectl get csr $K8SUSERNAME -o jsonpath={.status.certificate} | base64 --decode > ally.crt

3. Generate KUBECONFIG File

Obtain the cluster CA Certificate ca.pem, the user’s private key ally.key and user’s certificate ally.crt before following below steps.

export API_ENDPOINT=https://kind-server:8443

kubectl config \
  set-cluster kind \
  --server https://$API_ENDPOINT \
  --certificate-authority ca.pem \
  --embed-certs=true

kubectl config \
  set-credentials ally
  --client-certificate ally.crt
  --client-key ally.key
  --embed-certs=true

kubectl config \
  set-context ally-context \
  --cluster kind \
  --namespace ally-ns \
  --user ally

4. Create the Role and Set the Required Permissions

This grants all permission to Pods, Deployments, Services, Ingresses within the user’s namespace ally-ns

kubectl create \
  role app-developer-role \
  --verb "*" \
  --resource pod,deploy,svc,ingress,configmap \
  --namespace ally-ns

Per Kubernetes docs, empty apiGroup indicates the core API group.


5. Create the Role Binding to Attachment of Role to User

The role need to bound with a user before the granted permissions take effect

kubectl create \
  rolebinding app-developer-ally \
  --user ally \
  --role app-developer-role \
  --namespace ally-ns

Conclusion

One thing of note is that, creating certificates is one thing and rotating them is another. Once the user certificate expires, you will have to rotate it by going through steps 1-3 again.

© Mike Hosseini 2019