Skip to main content

Creating Isolated Namespaces with RBAC and Tiller

Written on January 26, 2018 by Ron Rivera.

3 min read
––– views

In my previous post, I did a walkthrough on bootstrapping a Kubernetes cluster using kubespray and setting up helm. Since then my team has been busy integrating our existing Kubernetes deployments into Helm Charts.

In this post, I will demostrate how to create a namespace with its own tiller and secured by RBAC to provide isolation of resources between development teams.

Let's get started.

Create namespace

kubectl create ns harbourfront-dev

Create RBAC subject

openssl genrsa -out .certs/devops.key 2048
openssl req -new -key .certs/devops.key -out devops.csr -subj "/CN=devops/O=roncrivera.io"
openssl x509 -req -in devops.csr -CA .certs/ca.crt -CAkey .certs/ca.key \
  -CAcreateserial -out .certs/devops.crt -days 500

Create kubeconfig

  • set the cluster
kubectl config --kubeconfig=devops.kubeconfig set-cluster tools-cluster \
  --server=https://192.168.0.161:6443
  • set the cluster certs for authentication
kubectl config --kubeconfig=devops.kubeconfig set-cluster tools-cluster \
  --certificate-authority=.certs/ca.pem --embed-certs=true

NOTE: To skip ssl cert verification, run:

kubectl config --kubeconfig=devops.kubeconfig set-cluster tools-cluster \
  --insecure-skip-tls-verify=true
  • set credentials for default user
kubectl config --kubeconfig=devops.kubeconfig set-credentials devops \
  --client-certificate=.certs/devops.crt --client-key=.certs/devops.key --embed-certs=true
  • set context for default user
kubectl config --kubeconfig=devops.kubeconfig set-context devops-context \
  --cluster=tools-cluster --namespace=harbourfront-dev --user=devops
  • set default context
kubectl config --kubeconfig=devops.kubeconfig use-context devops-context

At this point, running kubectl get pods will fail like below as the user has not been granted a role yet.

$ KUBECONFIG=devops.kubeconfig kubectl get pods
Error from server (Forbidden): pods is forbidden: User "devops" cannot list pods in the namespace "harbourfront-dev"

Create Tiller Admin for the Namespace

cat <<EOF | kubectl apply -f -
---
apiVersion: v1
kind: ServiceAccount
metadata:
  namespace: harbourfront-dev
  name: tiller
 
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: clusterrolebinding-cluster-admin-tiller-harbourfront-dev
subjects:
- kind: ServiceAccount
  name: tiller
  namespace: harbourfront-dev
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: ""
EOF

Create Deployment Manager Role

cat <<EOF | kubectl apply -f -
	kind: Role
	apiVersion: rbac.authorization.k8s.io/v1
	metadata:
	  namespace: harbourfront-dev
	  name: deployment-manager
	rules:
	- apiGroups: ["", "extensions", "apps"]
	  resources: ["*"]
	  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
EOF

Grant Deployment Manager Role to RBAC Subject

cat <<EOF | kubectl apply -f -
	kind: RoleBinding
	apiVersion: rbac.authorization.k8s.io/v1
	metadata:
	  name: rolebinding-deployment-manager-devops-harbourfront-dev
	  namespace: harbourfront-dev
	subjects:
	- kind: User
	  name: devops
	  apiGroup: ""
	roleRef:
	  kind: Role
	  name: deployment-manager
	  apiGroup: ""
EOF

Install Tiller into Desired Namespace

KUBECONFIG=devops.kubeconfig helm init --upgrade --history-max 10 \
  --service-account tiller --tiller-namespace harbourfront-dev

Deploy to the Namespace using Helm

$ KUBECONFIG=devops.kubeconfig helm install --name ghost --set ghostUrl=blog.roncrivera.io \
  --tiller-namespace harbourfront-dev stable/ghost
NAME:   ghost
LAST DEPLOYED: Fri Jan 26 01:08:10 2018
NAMESPACE: harbourfront-dev
STATUS: DEPLOYED
 
RESOURCES:
==> v1/Pod(related)
NAME                            READY  STATUS   RESTARTS  AGE
ghost-mariadb-5ff54857dd-67kkp  0/1    Pending  0         1s
ghost-ghost-5dbb456c46-pwpcq    0/1    Pending  0         1s
 
==> v1/Secret
 
NAME           TYPE    DATA  AGE
ghost-mariadb  Opaque  2     3s
ghost-ghost    Opaque  1     3s
 
==> v1/ConfigMap
 
NAME           DATA  AGE
ghost-mariadb  1     3s
 
==> v1/PersistentVolumeClaim
 
NAME           STATUS   VOLUME  CAPACITY  ACCESS MODES  STORAGECLASS  AGE
ghost-mariadb  Pending  3s
ghost-ghost    Pending  3s
 
==> v1/Service
 
NAME           TYPE       CLUSTER-IP     EXTERNAL-IP  PORT(S)       AGE
ghost-mariadb  ClusterIP  10.104.28.214  <none>       3306/TCP      2s
ghost-ghost    NodePort   10.105.124.78  <none>       80:31839/TCP  1s
 
==> v1beta1/Deployment
 
NAME           DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
ghost-mariadb  1        1        1           0          1s
ghost-ghost    1        1        1           0          1s
Tweet this article

Join my newsletter

Get notified whenever I post, 100% no spam.

Subscribe Now