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