目前RBAC是k8s授权方式最常用的一种方式。
在k8s上,一个客户端向apiserver发起请求,需要如下信息:
1)username,uid,
2) group,
3) extra(额外信息)
4) API
5) request path,例如:http://127.0.0.1:8080/apis/apps/v1/namespaces/kube-system/d
6)HTTP request action,如get,post,put,delete,
7)Http request action,如 get,list,create,udate,patch,watch,proxy,redirect,delete,deletecollection
8) Rresource
9)Subresource
10)Namespace
11)API group
其实,我们用kubectl向apiserver发起的命令,都是http方式的。 k8s验证分为useraccount和serviceaccount。
[root@s1 kube]# kubectl proxy --port=8080
[root@s1 ~]# kubectl get deploy -n kube-system
NAME READY UP-TO-DATE AVAILABLE AGE
coredns 2/2 2 2 19d
[root@s1 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 19d
[root@s1 ~]# kubectl describe svc kubernetes
Name: kubernetes
Namespace: default
Labels: component=apiserver
provider=kubernetes
Annotations: <none>
Selector: <none>
Type: ClusterIP
IP: 10.96.0.1
Port: https 443/TCP
TargetPort: 6443/TCP
Endpoints: 192.168.100.49:6443
Session Affinity: None
Events: <none>
上面我们看到10.96.0.1是kubernetes apiserver的地址,从而实现了集群外部通过10.96.0.1访问集群内部的pod,同时也实现了集群内部的pod访问集群外部的应用的功能。
只要访问apiserver,就必须实现认证。而认证信息是存储在pod中的。
[root@s1 ~]# kubectl explain pods.spec.serviceAccountName
KIND: Pod
VERSION: v1
FIELD: serviceAccountName <string>
DESCRIPTION:
ServiceAccountName is the name of the ServiceAccount to use to run this
pod. More info:
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
[root@s1 ~]# kubectl create serviceaccount mysa -o yaml --dry-run > mysa.yaml
[root@s1 ~]# cat mysa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: null
name: mysa
上面我们可以看到,只要是kubectl create的,只要加上-o yaml,就可以导出清单文件,这样我们以后就不用从头到尾写清单文件了,而是只要生产一个,然后改改就行了,这个很不错。
另外kubectl get 也可以导出yaml格式的,如下:
[root@s1 kube]# kubectl get pods myapp-798dc9b584-kwngn -o yaml --export
Flag --export has been deprecated, This flag is deprecated and will be removed in future.
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
generateName: myapp-798dc9b584-
labels:
app: myapp
pod-template-hash: 798dc9b584
release: canary
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: myapp-798dc9b584
uid: a361de53-a701-4904-9910-d69667bf1bc8
selfLink: /api/v1/namespaces/default/pods/myapp-798dc9b584-kwngn
spec:
containers:
- image: ikubernetes/myapp:v2
imagePullPolicy: IfNotPresent
name: myapp
ports:
- containerPort: 80
name: http
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-6hhk2
readOnly: true
dnsPolicy: ClusterFirst
enableServiceLinks: true
nodeName: n2
priority: 0
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300
volumes:
- name: default-token-6hhk2
secret:
defaultMode: 420
secretName: default-token-6hhk2
status:
phase: Pending
qosClass: BestEffort
将上面的改改就成为我们新的配置清单了。
创建service account
[root@s1 kube]# kubectl create serviceaccount admin
serviceaccount/admin created
[root@s1 kube]# kubectl get sa
NAME SECRETS AGE
admin 1 5s
default 1 20d
[root@s1 kube]# kubectl describe sa admin
Name: admin
Namespace: default
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: admin-token-96zgz
Tokens: admin-token-96zgz
Events: <none>
[root@s1 kube]# kubectl get secret
NAME TYPE DATA AGE
admin-token-96zgz kubernetes.io/service-account-token 3 5h51m
default-token-6hhk2 kubernetes.io/service-account-token 3 19d
mytomcat-ingress-secret kubernetes.io/tls 2 7d6h
看到自动就会多一个token。
下面我们用配置清单把serviceaccount和pod绑定起来。
[root@s1 kube]# vim pod-sa-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-sa-demo
namespace: default
labels:
app: myapp
tier: frontend
annotations:
lemon.com/created-by: "cluster admin"
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80
serviceAccountName: admin
[root@s1 kube]# kubectl apply -f pod-sa-demo.yaml
pod/pod-sa-demo created
创建useraccount
kubeconfig是客户端连接apiserver时使用的认证格式的配置文件。
[root@s1 kube]# kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://192.168.100.49:6443
name: kubernetes
contexts: #context定义了哪个集群用哪个用户来访问。
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
- context:
cluster: kubernetes
user: zhixin
name: zhixin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
- name: zhixin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
制作证书认证:
1、做一个私钥
[root@s1 kube]# cd /etc/kubernetes/pki/
[root@s1 pki]# (umask 077; openssl genrsa -out lemon.key 2048)
Generating RSA private key, 2048 bit long modulus
...+++
..............................................................+++
e is 65537 (0x10001)
括号是子shell的意思。
2、基于私钥生成一个证书
CN就是用户的账户名字。
[root@s1 pki]# openssl req -new -key lemon.key -out lemon.csr -subj "/CN=lemon"
-subj:替换或指定证书申请者的个人信息
3.设置证书有效时间
[root@s1 pki]# openssl x509 -req -in lemon.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out lemon.crt -days 365 Signature ok
subject=/CN=lemon
Getting CA Private Key
-days:表示证书的过期时间
x509:生成x509格式证书
4、查看证书内容
[root@s1 pki]# openssl x509 -in lemon.crt -text -noout
Certificate:
Data:
Version: 1 (0x0)
Serial Number:
b0:79:6f:46:59:e0:26:6e
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=kubernetes #证书签署人
Validity #有效期限
Not Before: Dec 25 06:28:38 2019 GMT
Not After : Dec 24 06:28:38 2020 GMT
Subject: CN=lemon #一会用这个账户登录k8s
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:cf:4e:ed:86:5c:f4:d0:ab:71:af:f3:61:53:18:
b3:05:1f:74:d2:33:fc:32:86:bd:12:df:13:8f:1c:
63:b0:f6:ad:46:40:e1:44:f0:ed:98:4b:f1:17:ed:
e2:38:85:63:dc:77:1d:e7:76:2b:59:07:2b:ec:0f:
7f:a2:a5:c2:df:7c:dd:32:76:f6:9d:e3:7c:b6:68:
0a:e1:70:d4:a0:51:2b:b6:3d:cd:d4:1e:f8:d5:62:
ce:a0:29:1d:6a:c9:1e:2e:6d:0f:bc:b0:f7:e2:8b:
04:05:ad:98:4f:b5:fb:be:b6:54:c8:15:5c:6a:fd:
73:63:b8:d5:be:27:e6:47:c6:77:82:31:84:c5:df:
06:75:41:a6:64:e7:d9:db:1a:88:1e:c3:9a:06:ce:
85:30:ad:f7:a1:59:c0:ac:bc:8b:94:90:e0:cc:87:
b5:7f:60:39:43:4a:d2:b2:5d:a9:62:5e:93:a8:9e:
b4:0f:72:10:73:65:3a:94:0e:70:1b:e6:72:b6:ef:
e1:15:0b:b5:20:26:f4:7f:d4:0c:5f:3b:48:b5:b5:
32:26:d8:bc:a5:bd:a9:dd:10:9e:1c:80:d4:63:8a:
b2:5b:20:e8:ad:3c:7e:88:ff:26:53:24:15:f7:7e:
ce:2b:73:ee:fe:eb:e5:cf:17:53:4d:5d:a5:49:a8:
9c:d5
Exponent: 65537 (0x10001)
Signature Algorithm: sha256WithRSAEncryption
99:ef:35:64:1b:81:24:2d:0a:b9:b4:90:05:b7:68:b8:67:63:
37:56:74:a0:48:cc:5b:5d:0a:c1:d8:ac:bb:50:d1:bd:d6:06:
70:3e:6d:c6:14:b7:a6:7a:1a:9e:ba:eb:e8:d0:cd:f9:10:b8:
20:40:bb:31:ff:ec:12:6f:30:7b:ef:00:0b:e1:1b:df:58:3f:
b8:0a:86:85:48:4c:9f:5a:4f:a4:76:b2:46:da:ad:9e:cb:b4:
62:65:42:2d:0c:87:eb:5d:8f:21:aa:97:b9:62:d6:9e:8b:2e:
52:53:c4:57:38:1d:e9:64:0c:83:58:11:d6:57:25:f5:cc:ca:
b3:ad:ec:d4:f3:b2:46:3d:40:3a:ec:b4:33:e2:0b:93:9d:05:
ce:fd:91:e5:39:4f:4c:f7:70:a9:24:b4:e2:54:7d:b8:50:37:
6f:e6:3f:17:d9:0f:f2:b5:84:3d:4e:5c:b3:19:0d:5e:e1:b7:
25:ed:c9:99:10:8d:84:7b:a2:bf:6f:2b:d9:b2:13:47:02:84:
a1:08:4e:a0:6f:02:a6:8a:98:e9:4d:a6:06:fa:63:8a:17:e5:
06:28:af:41:09:83:5e:52:c0:b6:43:a9:70:99:52:d6:a8:bf:
e2:29:39:f7:fb:d3:ad:fd:31:4a:35:47:9c:28:8d:16:14:e0:
97:3a:c8:6c
5、把用户账户信息添加到k8s集群中
[root@s1 pki]# kubectl config set-credentials lemon --client-certificate=lemon.crt --client-key=lemon.key --embed-certs=true
User "lemon" set.
embed-certs:表示把用户信息隐藏起来。
5、设置context上下文,指定lemon用户访问k8s的哪个集群
[root@s1 pki]# kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://192.168.100.49:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
- context:
cluster: kubernetes
user: zhixin
name: zhixin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
- name: lemon
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
- name: zhixin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
[root@s1 pki]# kubectl config set-context lemon@kubernetes --cluster=kubernetes --user=lemon
Context "lemon@kubernetes" created.
[root@s1 pki]# kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://192.168.100.49:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
- context:
cluster: kubernetes
user: lemon
name: lemon@kubernetes
- context:
cluster: kubernetes
user: zhixin
name: zhixin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
- name: lemon
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
- name: zhixin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
上面看到contexts里面有lemon的名字了。
6、切换到lemon用户登录k8s
[root@s1 pki]# kubectl config use-context lemon@kubernetes
Switched to context "lemon@kubernetes".
[root@s1 pki]# kubectl get pods
Error from server (Forbidden): pods is forbidden: User "lemon" cannot list resource "pods" in API group "" in the namespace "default"
上面看到get pods时报错了,这是因为用户lemon@kubernetes没有管理器权限,还需要对账户角色进行授权。
7、切回k8s管理员
[root@s1 pki]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".
RBAC(基于角色的访问控制)
在Kubernetes中,授权有ABAC(基于属性的访问控制)、RBAC(基于角色的访问控制)、Webhook、Node、AlwaysDeny(一直拒绝)和AlwaysAllow(一直允许)这6种模式。从1.6版本起,Kubernetes 默认启用RBAC访问控制策略。从1.8开始,RBAC已作为稳定的功能。通过设置–authorization-mode=RBAC,启用RABC。在RABC API中,通过如下的步骤进行授权:1)定义角色:在定义角色时会指定此角色对于资源的访问控制的规则;2)绑定角色:将主体与角色进行绑定,对用户进行访问授权。
在k8s中,一切皆对象。
Object_URL: /apis/<GROUP>/<VERSION>/namespaces/<NAMESPACE_NAME>/<KIND>[OJJECT_ID]
RBAC是通过rolebinding把user绑定到role上的。而role是基于namespace设定的,也就是这说这个user只能访问指定namespace下的pod资源。
而如果把user通过clusterrolebind绑定到clusterrole上后,那么这个user就突破了namespace的限制,而拥有了集群级别的权限,即这个用户可以访问这个集群下所有namespace下的pod了。
但是,我们也可以用rolebinding去把user绑定到clusterrole。在上图中,我们把user1通过rolebinding绑定到clusterrole上,但是我们知道rolebinding只限制在namespace中,所以user1也只限定在namespace中,而不是整个集群中。
[root@s1 pki]# kubectl create role pods-reader --verb=get,list,watch --resource=pods
role.rbac.authorization.k8s.io/pods-reader created
[root@s1 pki]# kubectl create role pods-reader --verb=get,list,watch --resource=pods --dry-run -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
creationTimestamp: null
name: pods-reader
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
[root@s1 pki]# kubectl get role
NAME AGE
pods-reader 115s
[root@s1 pki]# kubectl describe role pods-reader
Name: pods-reader
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods [] [] [get list watch]
注意:想要授予所有权限可以用
*
来表示
[root@s1 pki]# kubectl create rolebinding lemon-read-pods --role=pods-reader --user=lemon
rolebinding.rbac.authorization.k8s.io/lemon-read-pods created
[root@s1 pki]# kubectl create rolebinding lemon-read-pods --role=pods-reader --user=lemon -o yaml --dry-run
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
creationTimestamp: null
name: lemon-read-pods
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: pods-reader
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: lemon
[root@s1 pki]# kubectl describe rolebinding lemon-read-pods
Name: lemon-read-pods
Labels: <none>
Annotations: <none>
Role:
Kind: Role
Name: pods-reader
Subjects:
Kind Name Namespace
---- ---- ---------
User lemon
再切换至lemon集群帐户:
[root@s1 pki]# kubectl config use-context lemon@kubernetes
Switched to context "lemon@kubernetes".
[root@s1 pki]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-798dc9b584-kwngn 1/1 Running 0 146m
myapp-798dc9b584-l4mgr 1/1 Running 0 146m
pod-sa-demo 1/1 Running 0 124m
现在就可以查看默认名称空间中的所有pod,但是没有访问kube-system名称空间中的资源的权限。 rolebinding只对namespace有效
[root@s1 pki]# kubectl get pods -n kube-system
Error from server (Forbidden): pods is forbidden: User "lemon" cannot list resource "pods" in API group "" in the namespace "kube-system"
我们再切换回到管理员。
[root@s1 pki]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".
[root@s1 pki]# kubectl create clusterrole cluster-reader --verb=get,list,watch --resource=pods -o yaml --dry-run > clusterrole-demo.yaml
[root@s1 pki]# cat clusterrole-demo.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
creationTimestamp: null
name: cluster-reader
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
[root@s1 pki]# kubectl apply -f clusterrole-demo.yaml
clusterrole.rbac.authorization.k8s.io/cluster-reader created
创建了lemon-k8s系统帐号,后面可以用这个账户开个终端,切到lemon上,就不用来回在lemon和kubernetes-admin之间切换了.
[root@s1 kube]# useradd lemon-k8s
[root@s1 kube]# cp -rp /root/.kube/ /home/lemon-k8s/
[root@s1 kube]# chown -R lemon-k8s.lemon-k8s /home/lemon-k8s/
[root@s1 kube]# su lemon-k8s
[lemon-k8s@s1 ~]$
[lemon-k8s@s1 ~]$ kubectl config use-context lemon@kubernetes
Switched to context "lemon@kubernetes".
下面开始绑定了,把之前创建的lemon绑定到这个clusterrole上,这样lemon就拥有了读取整个cluster的权限,上面已经验证是无法读取kube-system的
[root@s1 pki]# kubectl create clusterrolebinding lemon-read-all-pods --clusterrole=cluster-reader --user=lemon -o yaml --dry-run > clusterrole-demo.yaml
[root@s1 pki]# cat clusterrole-demo.yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
creationTimestamp: null
name: lemon-read-all-pods
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-reader
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: lemon
[root@s1 pki]# kubectl apply -f clusterrole-demo.yaml
clusterrolebinding.rbac.authorization.k8s.io/lemon-read-all-pods created
[root@s1 pki]# kubectl describe clusterrolebinding lemon-read-all-pods
Name: lemon-read-all-pods
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"rbac.authorization.k8s.io/v1beta1","kind":"ClusterRoleBinding","metadata":{"annotations":{},"creationTimestamp":null,"name"...
Role:
Kind: ClusterRole
Name: cluster-reader
Subjects:
Kind Name Namespace
---- ---- ---------
User lemon
[root@s1 pki]# kubectl get clusterrolebinding |grep read-all-pods
lemon-read-all-pods 10m
[root@s1 pki]# kubectl describe clusterrolebinding lemon-read-all-pods
Name: lemon-read-all-pods
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"rbac.authorization.k8s.io/v1beta1","kind":"ClusterRoleBinding","metadata":{"annotations":{},"creationTimestamp":null,"name"...
Role:
Kind: ClusterRole
Name: cluster-reader
Subjects:
Kind Name Namespace
---- ---- ---------
User lemon
验证,可以读取kube-system的pod了
[lemon-k8s@s1 ~]$ kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-67c766df46-d6qjb 1/1 Running 0 20d
coredns-67c766df46-wdkbt 1/1 Running 0 20d
etcd-s1 1/1 Running 0 20d
kube-apiserver-s1 1/1 Running 0 20d
kube-controller-manager-s1 1/1 Running 0 20d
kube-flannel-ds-amd64-72qgm 1/1 Running 0 20d
kube-flannel-ds-amd64-f2s8n 1/1 Running 0 20d
kube-flannel-ds-amd64-jk22d 1/1 Running 0 20d
kube-proxy-glt2v 1/1 Running 0 20d
kube-proxy-lfpmn 1/1 Running 0 20d
kube-proxy-xxhw6 1/1 Running 0 20d
kube-scheduler-s1 1/1 Running 0 20d
但是无法删除资源。
[lemon-k8s@s1 ~]$ kubectl delete pod myapp-798dc9b584-kwngn
Error from server (Forbidden): pods "myapp-798dc9b584-kwngn" is forbidden: User "lemon" cannot delete resource "pods" in API group "" in the namespace "default"
可见,我们把用户lemon绑定到clusterrole后,这个用户对所有的名称空间都有权限了。因为cluserrolebinding是针对集群的,而rolebinding是只针对namespace的。
[root@s1 pki]# kubectl create rolebinding default-nameespace-admin --clusterrole=admin --user=lemon
rolebinding.rbac.authorization.k8s.io/default-nameespace-admin created
这样,我们就把lemon设置为default名称空间的管理员,而不是其他名称空间的管理员。这就是用rolebinding绑定clusterrole的功能。
[root@s1 pki]# kubectl get clusterrolebinding cluster-admin -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
creationTimestamp: "2019-12-05T06:14:10Z"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: cluster-admin
resourceVersion: "97"
selfLink: /apis/rbac.authorization.k8s.io/v1/clusterrolebindings/cluster-admin
uid: 403f54a7-bc4c-437f-93f2-941c19eff6a0
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:masters
[root@s1 pki]# openssl x509 -in ./apiserver-kubelet-client.crt -text -noout
看到system:masters组具有管理员权限 ,lemon就拥有删除pod的权限。
[lemon-k8s@s1 ~]$ kubectl delete pod myapp-798dc9b584-kwngn
pod "myapp-798dc9b584-kwngn" deleted