by Anish
Posted on Tuesday February 12, 2019
This sample chapter extracted from the book, Kubernetes for DevOps .
Get this book on Just $9 or Ask Author for Discount
Multiple steps involved to by the Kubernetes API server, before granting/revoking access for the managed kubernetes resources. it's start with
Kubernetes cluster, the API serves on port 443. The API server presents a certificate. This certificate is often self-signed, so $USER/.kube/config
on the user's machine typically contains the root certificate for the API server's certificate, which when specified is used in place of the system default root certificate
As shown in the below example the API server is running on the port 6443
[email protected]:# kubectl cluster-info
Kubernetes master is running at https://172.16.2.13:6443
KubeDNS is running at https://172.16.2.13:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
by default the kubernetes admin X.509 CA certificate, Private Key and Certificate revocation list is present in the in the KUBE_HOME=/etc/kubernetes/
directory
[email protected]:# ls -l /etc/kubernetes/pki/ca.*
-rw-r--r-- 1 root root 1025 Jan 23 11:14 /etc/kubernetes/pki/ca.crt
-rw------- 1 root root 1679 Jan 23 11:14 /etc/kubernetes/pki/ca.key
-rw-r--r-- 1 root root 17 Feb 7 13:15 /etc/kubernetes/pki/ca.srl
Once you have located the API server, next step is to perform the Authentication, there are two kind of resources which access the kubernetes API server
User and serviceAccount can belongs to one or more groups, groups are designed to grant permission to several users at once, there are reserved built-in group in the kube-system namespace
The system:unauthenticated
group is used for requests where none of the authentication plugins could authenticate the client.
The system:authenticated
group is automatically assigned to a user who was authenticated successfully.
The system:serviceaccounts
group encompasses all ServiceAccounts in the system.
The system:serviceaccounts:<namespace>
includes all ServiceAccounts in a specific namespace.
ServiceAccounts
ServiceAccounts are kubernetes managed resources and are scope to individual namespaces. for example let's GET
all the sa
available in the kube-system.
[email protected]:# kubectl get sa -n kube-system
NAME SECRETS AGE
attachdetach-controller 1 20d
bootstrap-signer 1 20d
certificate-controller 1 20d
clusterrole-aggregation-controller 1 20d
coredns 1 20d
cronjob-controller 1 20d
daemon-set-controller 1 20d
default 1 20d
..............
..............
Let's create a sa
under the namespace dev
[email protected]:# kubectl create sa test -n dev
serviceaccount/test created
List out the sa
under the namespace dev
[email protected]:# kubectl get sa -n dev
NAME SECRETS AGE
default 1 4d
test 1 17m
you might notice a default
ServiceAccounts is already exists. Each namespaces have a default servicesccount
kubectl describe the sa
test
under the namespace dev
[email protected]:# kubectl describe sa test -n dev
Name: test
Namespace: dev
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: test-token-hvbtq
Tokens: test-token-hvbtq
Events: <none>
test-token-hvbtq
test-token-hvbtq
3 . Debugging Secrets
View the secrets of the test-token-hvbtq
[email protected]:# kubectl describe secrets test-token-hvbtq -n dev
Name: test-token-hvbtq
Namespace: dev
Labels: <none>
Annotations: kubernetes.io/service-account.name=test
kubernetes.io/service-account.uid=8d0fcb37-2e8a-11e9-8c68-fa163e589bc0
Type: kubernetes.io/service-account-token
Data
====
token: eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZXYiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlY3JldC5uYW1lIjoidGVzdC10b2tlbi1odmJ0cSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJ0ZXN0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiOGQwZmNiMzctMmU4YS0xMWU5LThjNjgtZmExNjNlNTg5YmMwIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRldjp0ZXN0In0.caDSrXwkrIGXboIQ5Ag9G-2lp0Ltli5bb8V9O8a0rbVvDJChukQbAXko1pVqKA7eNlT-qOBRl1K6CKAZHiYvDEfhhCv68GF6YncDlY-1eaUdNNO-CT6d2DHXEWb6gSGK-3P1dxRqqJjVE4FBsMfLDfnky203DMuToz6BsnxgUJY8aQOl-3z8AFJJOV2-c4i5da2wKQfb2meGVQkTI_bDSdp-aq0PP9si5UXKKsCzeOBbpuEO1Xk66ggf9cIoREbJujy9zJN_QMcdYS3o1lOuIThAIRpkDid4y1VH_ulKMnt7JBrTyOxeFK1UobC2kZbP2LFCzoNIBSXvypEVlrR-hw
ca.crt: 1025 bytes
namespace: 3 bytes
The token value is JSON Web Token, the decoded format.
//Header
{
"alg": "RS256",
"kid": ""
}
//Payload
{
"iss": "kubernetes/serviceaccount",
"kubernetes.io/serviceaccount/namespace": "dev",
"kubernetes.io/serviceaccount/secret.name": "test-token-hvbtq",
"kubernetes.io/serviceaccount/service-account.name": "test",
"kubernetes.io/serviceaccount/service-account.uid": "8d0fcb37-2e8a-11e9-8c68-fa163e589bc0",
"sub": "system:serviceaccount:dev:test"
}
The YAML file for assigning serviceAccountName
to test
and launching a alpine pod with curl installed
[email protected]:# cat alpine-curl.yaml
apiVersion: v1
kind: Pod
metadata:
name: alpine
spec:
serviceAccountName: test
containers:
- image: byrnedo/alpine-curl
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
name: busybox
restartPolicy: Always
[email protected]:# kubectl create -f alpine-curl.yaml -n dev
pod/alpine created
[email protected]:# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
alpine 1/1 Running 0 48s
[email protected]:/home/ansible# kubectl exec alpine -it sh -n dev
/ #
/var/run/secrets/kubernetes.io/serviceaccount/token
# cat /var/run/secrets/kubernetes.io/serviceaccount/token
eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZXYiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlY3JldC5uYW1lIjoidGVzdC10b2tlbi1odmJ0cSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJ0ZXN0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiOGQwZmNiMzctMmU4YS0xMWU5LThjNjgtZmExNjNlNTg5YmMwIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRldjp0ZXN0In0.caDSrXwkrIGXboIQ5Ag9G-2lp0Ltli5bb8V9O8a0rbVvDJChukQbAXko1pVqKA7eNlT-qOBRl1K6CKAZHiYvDEfhhCv68GF6YncDlY-1eaUdNNO-CT6d2DHXEWb6gSGK-3P1dxRqqJjVE4FBsMfLDfnky203DMuToz6BsnxgUJY8aQOl-3z8AFJJOV2-c4i5da2wKQfb2meGVQkTI_bDSdp-aq0PP9si5UXKKsCzeOBbpuEO1Xk66ggf9cIoREbJujy9zJN_QMcdYS3o1lOuIThAIRpkDid4y1VH_ulKMnt7JBrTyOxeFK1UobC2kZbP2LFCzoNIBSXvypEVlrR-hw/
--header "Authorization: Bearer $TOKEN"
# export TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
# curl https://172.16.2.13:6443/api --header "Authorization: Bearer $TOKEN" --insecure
{
"kind": "APIVersions",
"versions": [
"v1"
],
"serverAddressByClientCIDRs": [
{
"clientCIDR": "0.0.0.0/0",
"serverAddress": "172.16.2.13:6443"
}
]
}/
kubectl describe pods alpine -n dev
.....
Containers:
busybox:
Container ID: docker://f330b20da3b95211774f53167e1f2e9149cbe144627f6f24608948cce3641767
Image: byrnedo/alpine-curl
Image ID: docker-pullable://byrnedo/[email protected]:e8cf497b3005c2f66c8411f814f3818ecd683dfea45267ebfb4918088a26a18c
Port: <none>
Host Port: <none>
Command:
sleep
3600
State: Running
Started: Tue, 12 Feb 2019 12:00:30 +0530
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from test-token-hvbtq (ro)
Deleting the sa
test
under namespace dev
[email protected]:# kubectl delete sa test -n dev
serviceaccount "test" deleted
Any Authentication performed using the old token will be Unauthorized
# export TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
# curl https://172.16.2.13:6443/api --header "Authorization: Bearer $TOKEN" --insecure
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "Unauthorized",
"reason": "Unauthorized",
"code": 401
}
Some of the practical use case of setting sa
kubectl -n kube-system create sa jenkins
kubectl create clusterrolebinding jenkins --clusterrole cluster-admin --serviceaccount=<namespace>:jenkins
kubectl create serviceaccount --namespace kube-system tiller
kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'
User Accounts
The Next form of Authentication in kubernetes API is with normal user, this is usually done with TLS authentication and typical steps involved
[email protected]
/etc/kubernetes/pki/
We will bet into this Authentication using normal account in detail in the upcoming topic of Setting up Role-Based Access Control
After the request is authenticated as coming from a specific user
or sa
, the request must be authorized.
For example exec to the alpine kubectl exec alpine -it sh -n dev
and list all pods in the dev name space the request will be forbidden
# export TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
# curl https://172.16.2.13:6443/api/v1/namespaces/dev/pods --header "Authorization: Bearer $TOKEN" --insecure
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "pods is forbidden: User \"system:serviceaccount:dev:test\" cannot list pods in the namespace \"dev\"",
"reason": "Forbidden",
"details": {
"kind": "pods"
},
"code": 403
}
In order to grant Authorization proper policy or RBAC control needs to be in placed, for an instance in order to give pod permission to query all pods in the given namespace, a role and corresponding rolebinding needs to be defined.
The below YAML file has setup necessary authorization for role and rolebinding under the namespace dev
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: test-manager
namespace: dev
rules:
- apiGroups: ["", "batch", "extensions", "apps"]
resources: ["pods"]
verbs: ["*"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: test-binding
namespace: dev
subjects:
- kind: ServiceAccount
name: test
namespace: dev
roleRef:
kind: Role
name: test-manager
apiGroup: rbac.authorization.k8s.io
[email protected]:# kubectl delete -f rbac.yaml
role.rbac.authorization.k8s.io "test-manager" deleted
rolebinding.rbac.authorization.k8s.io "test-binding" deleted
The role is set to query the resource pods with all known HTTP verbs
# curl https://172.16.2.13:6443/api/v1/namespaces/dev/pods --header "Authorization: Bearer $TOKEN" --insecure
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"selfLink": "/api/v1/namespaces/dev/pods",
"resourceVersion": "2302485"
},
"items": [
{
"metadata": {
"name": "alpine",
"namespace": "dev",
"selfLink": "/api/v1/namespaces/dev/pods/alpine",
"uid": "0abb388b-2e97-11e9-8c68-fa163e589bc0",
"resourceVersion": "2300673",
"creationTimestamp": "2019-02-12T07:23:06Z"
....
We will cover RBAC in much detail in upcoming topic let's stick with next important concept Admission Control
In Kubernetes, Admission Controllers enforce semantic validation of objects during create, update, and delete operations.
First check if the admission registration API is enabled in your cluster by running:
[email protected]:# kubectl api-versions | grep admission
admissionregistration.k8s.io/v1beta1
Some example of semantic validation can be done through the Admission Controllers
There are two types of Webhook Admission controllers in Kubernetes 1.9.
These webhooks is that they can be dynamically configured after the start of the api-server
, this enables anyone with the correct Role-based access control (RBAC) to extend the concept of Admission Control.
Next Reading RBAC
Thanku for reading !!! Give a Share for Support
Asking for donation sound bad to me, so i'm raising fund from by offering all my Nine book for just $9