antony@notes:~/kubernetes$ cat "Kubernetes-Multi-Tenancy.md"
Kubernetes Multi Tenancy
Kubernetes Multi Tenancy
[TOC]
認識 Kubernetes AA
AuthN abbreviates AuthenticatioN: this is the process of verifying the user’s identity and decide whether she is legitimated to access your system.
- 認證你是誰
AuthZ abbreviates AuthoriZation: this is the process of verifying what an authenticated user can do within your system.
- 認證你可以做什麼事情
確認環境乾淨
$ kubectl get all
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.98.0.1 <none> 443/TCP 13d
bigred@m1:~/0613$ kubectl get pvc
No resources found in default namespace.建立使用者憑證
$ mkdir kuser; cd kuser
$ mkdir user01; cd user01
## 產生私鑰
$ openssl genrsa -out private.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
..............................+++++
.......................+++++
e is 65537 (0x010001)
## 檢視 CSR 內容
## 產生請求檔
## CN 使用者帳號
## O 使用者群組
$ openssl req -new -key private.key -out CSR.csr -subj "/CN=user01/O=user01"
$ ls -l
total 8
-rw-r--r-- 1 bigred bigred 911 Jun 13 13:22 CSR.csr
-rw------- 1 bigred bigred 1675 Jun 13 13:22 private.key
$ openssl req -noout -subject -in CSR.csr
subject=CN = user01, O = user01
## Base64 格式的 CSR
$ cat CSR.csr | base64 | tr -d '\n'; echo ""
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1p6Q0NBVThDQVFBd0lqRVBNQTBHQTFVRUF3d0dkWE5sY2pBeE1ROHdEUVlEVlFRS0RBWjFjMlZ5TURFdwpnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFEQ0c2ZEd0RDE2VDNIWGh4d0pqQUcxCkFuUkVjYVNXWm1Zc3kvSStBZmNSVWdFM2hMRzd3SjhjWGhIWURFcWZqcHhGWGw0bFJCaVYvNWJLSUloVVo3RW8KS2dSMEZTVHQ3WWU3cDFSVzhNTVA2QkdUUXR4d0Fub1M3T2dIOGp4WWRmV2tNK3ZHVVgrbjd2Zjg4UTlsZ0Frago2NHJGNTlJSUFRVzdWMHdXTVlpbW1VUHhqK085Z2o5WEVtYTU0U1dHZ0thb0xvWDJrVkl4V2d3b1dzWnBCUUdSCkdieEZhVnFGSUQyNEh2aFVVbFIrL0RBTEFJb1VkN3htNzJ0ejk2cWVseUFKelpYU0RjN0pDSHRMMWN4SndGZFkKYm55V2pubUx4RW5JYUdqL0lDL0E3c3pMazlNUHZVbVVtQkZJdlFuMm9OeXU2WDdNU3ZwZGJOdlhtdkFBaHdaSApBZ01CQUFHZ0FEQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFRTEhqNktQVzNIbjdiQ240Wm9BYmVzdnVWbDR1CkRvMURsNGpWY2Y0OUs2L20zb1p1RU5yZDlBeTFoYmR0eFI5MGpJb2IyWFhjcUFKV25EaFJtenpoQkdsczU5QW0KbStmNjBVN3FKS1I4V2RadnNqWkR3a0RoSGxDQjNJSjRNTVpQS3hVWU5tM1JKL1RoNVg3KzJnMytUQnpoUWI3LwplK3Q5MDhtM1lBeTN0Z2VzZDZFcDg1NVBPT3dFSCt2THZRY3k4djhwdDhwVWxkeXBYVk9hN2lzUHJQdzczT2t2CkhocStNTXFDeGEvaE12MFVFUVdNaWZ4THFJMUNrSnZFZVF3U09iM3gzdDR2Wm1vcDhZUVRSYTQyclJpemJYWTUKczRiWVNWdUh5ZitsYVFNQkdZNEdkVDE5Tml2Q1VOaWFZOGZ4VnlidDdEdER0ODUxY0hmTnVML2pYUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo=
$ export BASE64_CSR=$(base64 < CSR.csr | tr -d "\n")
## 上傳 CSR 至 K8S
$ echo 'apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: user01-csr
spec:
groups:
- system:authenticated
request: ${BASE64_CSR}
signerName: kubernetes.io/kube-apiserver-client
expirationSeconds: 1800 # 30 Min
usages:
- client auth' > csr.yaml
$ cat csr.yaml | envsubst | kubectl apply -f -
certificatesigningrequest.certificates.k8s.io/user01-csr created
## 許可憑證
$ kubectl get csr
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
user01-csr 41s kubernetes.io/kube-apiserver-client kubernetes-admin 30m Pending
$ kubectl certificate approve user01-csr
certificatesigningrequest.certificates.k8s.io/user01-csr approved
$ kubectl get csr
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
user01-csr 55s kubernetes.io/kube-apiserver-client kubernetes-admin 30m Approved,Issued
## 下載許可憑證
$ kubectl get csr user01-csr -o jsonpath='{.status.certificate}' | base64 -d > k8s-signed.crt
$ cat k8s-signed.crt
-----BEGIN CERTIFICATE-----
MIIDCDCCAfCgAwIBAgIRAKEA0ts5MHzGleKU1MOrPAswDQYJKoZIhvcNAQELBQAw
FTETMBEGA1UEAxMKa3ViZXJuZXRlczAeFw0yMjA2MTMwNTIwMTBaFw0yMjA2MTMw
NTU1MTBaMCIxDzANBgNVBAoTBnVzZXIwMTEPMA0GA1UEAxMGdXNlcjAxMIIBIjAN
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwhunRrQ9ek9x14ccCYwBtQJ0RHGk
lmZmLMvyPgH3EVIBN4Sxu8CfHF4R2AxKn46cRV5eJUQYlf+WyiCIVGexKCoEdBUk
7e2Hu6dUVvDDD+gRk0LccAJ6EuzoB/I8WHX1pDPrxlF/p+73/PEPZYAJI+uKxefS
CAEFu1dMFjGIpplD8Y/jvYI/VxJmueElhoCmqC6F9pFSMVoMKFrGaQUBkRm8RWla
hSA9uB74VFJUfvwwCwCKFHe8Zu9rc/eqnpcgCc2V0g3OyQh7S9XMScBXWG58lo55
i8RJyGho/yAvwO7My5PTD71JlJgRSL0J9qDcrul+zEr6XWzb15rwAIcGRwIDAQAB
o0YwRDATBgNVHSUEDDAKBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB8GA1UdIwQY
MBaAFLVzbcvg3zKcW7sqsazkDmMpdrRgMA0GCSqGSIb3DQEBCwUAA4IBAQA/dTMI
xV8K7WmN93nVCrhdhO49PB+E8/IV/Sl0sR8/9ZH/ue1Z8+mYM+lK3eGncNnCBulm
Uj5mFkoGxSgq+HIMlANTLz29wvZptU+GlnjFwqgejVF2srZOX1SZqGTj6GQEFMiG
QWKSixRq8VA9umacx9e/9WJ2pEANO8eqsSnWqS8i6mcW98tuE1MSuSxe0Ld/3GK7
5ijM9AyrLkOMZPs4qTHbIZnkpMKhAGLggwl/cWUQ8iRrAZUI+ywvMatVGch9X41x
60upWoReRY8ofvfE+PbNeaZRY8bDMq6fdw91rZHvniSyRTXOVcFuGMQbzlLDJ54j
JhVHdp7rI37uqYpK
-----END CERTIFICATE-----
$ openssl x509 -noout -subject -in k8s-signed.crt
subject=O = user01, CN = user01注意,不管請求檔狀態如何,過了一定的時間以後, K8s 會自動刪除
產生使用者的 kubeconfig
$ kubectl config view --flatten=true得到的結果與$ cat ~/.kube/config 相同
$ kubectl config view --flatten=true | head -n 6 > config.tmp
$ echo 'contexts:
> - context:
> cluster: kubernetes
> user: user01
> name: user01-context
> current-context: user01-context
> kind: Config
> preferences: {}
> users:
> - name: user01
> user:
> client-certificate-data: ${K8S_CRT}
> client-key-data: ${K8S_KEY}' >> config.tmp
$ export K8S_CRT=$(base64 < k8s-signed.crt | tr -d "\n")
$ export K8S_KEY=$(base64 < private.key | tr -d "\n")
$ cat config.tmp | envsubst > config
$ sudo podman run -it --rm --name k1 -d quay.io/flysangel/image:landlord.kubectl bash
Trying to pull quay.io/flysangel/image:landlord.kubectl...
Getting image source signatures
Copying blob ce67b7059232 done
Copying blob df9b9388f04a skipped: already exists
Copying blob 6a897ff1da73 done
Copying blob 4e828f1a37ea done
Copying config 47ef1553bd done
Writing manifest to image destination
Storing signatures
a153d0c3fcb2b1ccb77ed403661a512d4f6a007c8a8bd57f67c620cdff302674
bigred@m1:~/0613/kuser/user01$ sudo podman cp config k1:/home/bigred/.kube/config
bigred@m1:~/0613/kuser/user01$ sudo podman exec -it k1 bash
## 認證失效,時間超過 30 分鐘
bash-5.1$ kubectl get pod
error: You must be logged in to the server (Unauthorized)
## 如未超過時間限制,錯誤訊息應如下
Bash-5.1$ kubectl get pod
Error from server (Forbidden): pods is forbidden: User "user01" cannot list resource "pods" in API group "" in the namespace "default"練習
請問 K8S etcd 是否存有使用者資訊。 請重新建立 K8S user01 帳號 使用效期為 1 年 將設定檔複製到 podman 測試
[注意] 請確認 csr 是否存留舊資料
$ kubectl get csr
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
user01-csr 48m kubernetes.io/kube-apiserver-client kubernetes-admin 365d Approved,Issued
$ kubectl delete csr user01-csr
certificatesigningrequest.certificates.k8s.io "user01-csr" deleted$ openssl genrsa -out private.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
.......+++++
....+++++
e is 65537 (0x010001)
$ openssl req -new -key private.key -out CSR.csr -subj "/CN=user01/O=user01"
1$ openssl req -noout -subject -in CSR.csr
subject=CN = user01, O = user01
$ export BASE64_CSR=$(base64 < CSR.csr | tr -d "\n")
$ echo 'apiVersion: certificates.k8s.io/v1
> kind: CertificateSigningRequest
> metadata:
> name: user01-csr
> spec:
> groups:
> - system:authenticated
> request: ${BASE64_CSR}
> signerName: kubernetes.io/kube-apiserver-client
> expirationSeconds: 31536000 # 365 day
> usages:
> - client auth' > csr.yaml
$ ls -l
total 12
-rw-r--r-- 1 bigred bigred 911 Jun 13 14:28 CSR.csr
-rw-r--r-- 1 bigred bigred 282 Jun 13 14:29 csr.yaml
-rw------- 1 bigred bigred 1675 Jun 13 14:28 private.key
$ cat csr.yaml | envsubst | kubectl apply -f -
certificatesigningrequest.certificates.k8s.io/user01-csr created
$ kubectl certificate approve user01-csr
certificatesigningrequest.certificates.k8s.io/user01-csr approved
$ kg csr
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
user01-csr 18s kubernetes.io/kube-apiserver-client kubernetes-admin 365d Approved,Issued
$ kubectl get csr user01-csr -o jsonpath='{.status.certificate}' | base64 -d > k8s-signed.crt
$ openssl x509 -noout -subject -in k8s-signed.crt
subject=O = user01, CN = user01
$ kubectl config view --flatten=true | head -n 6 > config.tmp
$ echo 'contexts:
> - context:
> cluster: kubernetes
> user: user01
> name: user01-context
> current-context: user01-context
> kind: Config
> preferences: {}
> users:
> - name: user01
> user:
> client-certificate-data: ${K8S_CRT}
> client-key-data: ${K8S_KEY}' >> config.tmp
$ export K8S_CRT=$(base64 < k8s-signed.crt | tr -d "\n")
$ export K8S_KEY=$(base64 < private.key | tr -d "\n")
$ cat config.tmp | envsubst > config
$ sudo podman ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b18077d221fd localhost/podman-pause:4.1.0-1652313655 12 days ago Exited (0) 4 days ago 0.0.0.0:80->8080/tcp, 0.0.0.0:5432->5432/tcp, 0.0.0.0:6379->6379/tcp 943dc009d7bb-infra
b78deed44826 quay.io/flysangel/quay-rhel8:v3.6.6 registry 12 days ago Exited (137) 4 days ago 0.0.0.0:80->8080/tcp, 0.0.0.0:5432->5432/tcp, 0.0.0.0:6379->6379/tcp quay-quay-app
d45e257168cc quay.io/flysangel/postgres:9.6.24-alpine postgres 12 days ago Exited (0) 4 days ago 0.0.0.0:80->8080/tcp, 0.0.0.0:5432->5432/tcp, 0.0.0.0:6379->6379/tcp quay-postgresql
2992e6a01ba6 quay.io/flysangel/redis-5:1-169 run-redis 12 days ago Exited (0) 4 days ago 0.0.0.0:80->8080/tcp, 0.0.0.0:5432->5432/tcp, 0.0.0.0:6379->6379/tcp quay-redis
a153d0c3fcb2 quay.io/flysangel/image:landlord.kubectl bash 33 minutes ago Up 33 minutes ago k1
$ sudo podman run -it --rm --name k1 -d quay.io/flysangel/image:landlord.kubectl bash
Error: error creating container storage: the container name "k1" is already in use by "a153d0c3fcb2b1ccb77ed403661a512d4f6a007c8a8bd57f67c620cdff302674". You have to remove that container to be able to reuse that name.: that name is already in use
$ sudo podman rm k1
Error: cannot remove container a153d0c3fcb2b1ccb77ed403661a512d4f6a007c8a8bd57f67c620cdff302674 as it is running - running or paused containers cannot be removed without force: container state improper
$ sudo podman rm -f k1
WARN[0010] StopSignal SIGTERM failed to stop container k1 in 10 seconds, resorting to SIGKILL
a153d0c3fcb2b1ccb77ed403661a512d4f6a007c8a8bd57f67c620cdff302674
$ sudo podman run -it --rm --name k1 -d quay.io/flysangel/image:landlord.kubectl bash
f6d7b99e4e39059d62113c4d641ff766a378d1976d9dc1c3b49e90f99db9d494
$ sudo podman cp config k1:/home/bigred/.kube/config
$ sudo podman exec -it k1 bash
bash-5.1$ kubectl get pod
Error from server (Forbidden): pods is forbidden: User "user01" cannot list resource "pods" in API group "" in the namespace "default"檢查憑證指令
$ openssl x509 -noout -text -in k8s-signed.crt認識 Role Based Access Control
Subjects: The set of users and processes that want to access the Kubernetes API.
Resources: The set of Kubernetes API Objects available in the cluster. Examples include Pods, Deployments, Services, Nodes, and PersistentVolumes, among others.
Verbs: The set of operations that can be executed to the resources above. Different verbs are available (examples: get, watch, create, delete, etc.), but ultimately all of them are Create, Read, Update or Delete (CRUD) operations.

Role Based Access Control (RBAC)
$ kubectl create ns user01
$ echo 'apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: user01-role
namespace: user01
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["pods", "services"]
verbs: ["get", "watch", "list"]' > role.yaml
$ kubectl apply -f role.yaml
role.rbac.authorization.k8s.io/user01-role created
$ echo 'apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: user01-rbind
namespace: user01
subjects:
- kind: User
name: user01
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role #this must be Role or ClusterRole
name: user01-role
apiGroup: rbac.authorization.k8s.io' > rolebind.yaml
$ kubectl apply -f rolebind.yaml
rolebinding.rbac.authorization.k8s.io/user01-rbind created
$ kubectl get role -n user01
NAME CREATED AT
user01-role 2022-06-13T06:49:41Z
$ kubectl get rolebinding -n user01
NAME ROLE AGE
user01-rbind Role/user01-role 50s練習
參考投影片 10、14 兩頁。 請重新建立 K8S user02 帳號 使用效期為 1 年 預設使用 user02 namespace 權限具備完全控制 將設定檔複製到 podman 測試
$ mkdir user02
$ cd user02
$ openssl genrsa -out private.key 2048
$ openssl req -new -key private.key -out CSR2.csr -subj "/CN=user02/O=user02"
$ openssl req -noout -subject -in CSR2.csr
$ export BASE64_CSR2=$(base64 < CSR2.csr | tr -d "\n")
$ echo 'apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: user02-csr2
spec:
groups:
- system:authenticated
request: ${BASE64_CSR2}
signerName: kubernetes.io/kube-apiserver-client
expirationSeconds: 31536000 # 365 day
usages:
- client auth' > csr2.yaml
$ cat csr2.yaml | envsubst | kubectl apply -f -
$ kubectl get csr
$ kubectl certificate approve user02-csr2
$ kubectl get csr
$ kubectl get csr user02-csr2 -o jsonpath='{.status.certificate}' | base64 -d > k8s-signed.crt
$ openssl x509 -noout -subject -in k8s-signed.crt
$ kubectl config view --flatten=true | head -n 6 > config.tmp
$ echo 'contexts:
- context:
cluster: kubernetes
namespace: user02
user: user02
name: user02-context
current-context: user02-context
kind: Config
preferences: {}
users:
- name: user02
user:
client-certificate-data: ${K8S_CRT}
client-key-data: ${K8S_KEY}' >> config.tmp
$ cat config.tmp
$ export K8S_CRT=$(base64 < k8s-signed.crt | tr -d "\n")
$ export K8S_KEY=$(base64 < private.key | tr -d "\n")
$ cat config.tmp | envsubst > config
$ sudo podman run -it --rm --name k2 -d quay.io/flysangel/image:landlord.kubectl bash
$ sudo podman cp config k2:/home/bigred/.kube/config
$ sudo podman exec -it k2 bash
kubectl create ns user02
$ echo 'apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: user02-role
namespace: user02
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["*"]
verbs: ["*"]' > role.yaml
$ kubectl apply -f role.yaml
$ echo 'apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: user02-rbind
namespace: user02
subjects:
- kind: User
name: user02
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role #this must be Role or ClusterRole
name: user02-role
apiGroup: rbac.authorization.k8s.io' > rolebind.yaml
$ kubectl apply -f rolebind.yaml
$ kubectl get roles -n user02
$ kubectl get rolebinding -n user01
$ kubectl get rolebinding -n user02
$ sudo podman exec -it k2 bash