ServiceAccount 和 rbac
一、简单感受一下:
可以通过将不同的sa赋值给pod来控制每个pod可以访问的资源。当api服务器收到一个带有认证token的请求时,服务器会用这个token来验证发送请求的客户端所关联的sa是否运行执行请求的操作。
几个注意点:
1、向sa中添加镜像拉取秘钥可以不必对每个pod都单独进行镜像拉取秘钥的添加操作。
2、pod的sa必须在pod创建时进行设置,后续不能被修改。
3、让pod只允许挂载sa中列出的可挂载秘钥,sa在创建的时候就必须指定注解,kubernetes.io/enforce-mountable-secrets="true"
二、token
1、创建个pod
apiVersion: v1 kind: Pod metadata: name: curl-custom-sa spec: serviceAccountName: foo containers: - name: main image: tutum/curl command: ["sleep", "9999999"] - name: ambassador image: luksa/kubectl-proxy:1.6.2
2、查看挂载进pod容器内的token
kubectl exec -it curl-custom-sa -c main cat /var/run/secrets/kubernetes.io/serviceaccount/token kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. eyJhbGciOiJSUzI1NiIsImtpZCI6ImduV1VxbVFYdkh6eWVjSER3SHdsUXE3b3Jpd1NfazB0OGNxaUIzaVdnUVUifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNjkyNjAwNTMxLCJpYXQiOjE2NjEwNjQ1MzEsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJjdXJsLWN1c3RvbS1zYSIsInVpZCI6IjE0ZDhjNjg3LWE0YzQtNDU0ZS1hODY3LThkNmEzYzU3YWE1OCJ9LCJzZXJ2aWNlYWNjb3VudCI6eyJuYW1lIjoiZm9vIiwidWlkIjoiZGEzYmEyODYtMjZkYi00MjIzLWFmNmQtNzVmYTdhYmNiMWNhIn0sIndhcm5hZnRlciI6MTY2MTA2ODEzOH0sIm5iZiI6MTY2MTA2NDUzMSwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6Zm9vIn0.H5Xw6qHWeML9Sfxh7PKjUx2yiSx2LHun84t4twZcpcDkc0aCfDSu1m8AAQWKh68QF6JM-HpczSa_ZHnxzqIUOpnGPkh7hH8xftRX6fdkKFfzXfO9ojkGF9ptrhA8JKuf3bGP5lRfQ3dFEIqMMqgvDOmN1iq0knaFjHXnvh6WJBiNN4eezAyILo-zUKsUOnJrO8mJq2PG3V3NCPiYaWG2pyvBrZqJXdlcWKmYJsIm-UyTVsHGbnwEYgUKKXc7HkL3MebxfYpqUKz38LZde61mKxNkzZVyRn1cwoqqE_vz99wgN8mc-FthMV14k_F93bCFqCUt4xO5oY73r4LRsUE5x
3、我自己尝试的创建的sa是没有操作权限的。
三、rbac,除了rbac还有其他的授权插件,授权插件检查是否允许用户请求的动作执行。
1、认证动词和http方法之间的映射关系
http方法 | 单一资源的动词 | 集合的动词 |
GET,HEAD | get(以及watch用户监听) | list(以及watch) |
POST | create | n/a |
PUT | update | n/a |
PATCH | patch | n/a |
DELETE | delete | deletecollection |
2、role和rolebinding
角色定义了可以做什么操作,绑定定义了谁可以做这些操作。
角色和集群角色,区别在于角色和角色绑定是命名空间资源,而集群角色和集群角色绑定是集群级别的资源。
角色和角色绑定:
2.1)创建sa
apiVersion: v1 kind: ServiceAccount metadata: creationTimestamp: "2022-08-14T08:26:34Z" name: foo namespace: default resourceVersion: "4311847" uid: da3ba286-26db-4223-af6d-75fa7abcb1ca secrets: - name: foo-token-rjkxw
2.2)创建role,在指定资源时,必须使用复数的形式。
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: default name: service-reader rules: - apiGroups: [""] verbs: ["get", "list"] resources: ["services"]
2.3)rolebinding,如果要绑定一个user(用户)而不是sa上,使用--user作为参数来指定用户名。如果要绑定角色到组,可以使用--group参数。
kubectl create rolebinding test --role=service-reader --serviceaccount=default:foo -n default
2.4)测试
kubectl exec -it curl-custom-sa -c main curl localhost:8001/api/v1/namespaces/default/services { "kind": "ServiceList", "apiVersion": "v1", "metadata": { "resourceVersion": "4619791" }, "items": [ . . . .
查看pod时就返回403
kubectl exec -it curl-custom-sa -c main curl localhost:8001/api/v1/namespaces/default/pod kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. { "kind": "Status", "apiVersion": "v1", "metadata": { }, "status": "Failure", "message": "pod is forbidden: User \"system:serviceaccount:default:foo\" cannot list resource \"pod\" in API group \"\" in the namespace \"default\"", "reason": "Forbidden", "details": { "kind": "pod" }, "code": 403 }
2.5)rolebinding将来自不同命名空间的sa绑定到同一个role, rolebinding可以引用来自其他命名空间中的sa。这样就实现了访问其他ns中的资源。
以下发生在ttt这个ns。
kubectl get sa bar -n ttt -o yaml apiVersion: v1 kind: ServiceAccount metadata: creationTimestamp: "2022-08-14T09:48:41Z" name: bar namespace: ttt resourceVersion: "4317975" uid: 801153c4-3d5a-4d31-9395-f18fd693cd52 secrets: - name: bar-token-tclnh --- apiVersion: v1 kind: Pod metadata: name: curl-custom-sa-ttt namespace: ttt spec: serviceAccountName: bar --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: creationTimestamp: "2022-08-14T09:17:30Z" name: test namespace: default resourceVersion: "4318642" uid: 4c3945aa-044e-40c7-8c5f-91c924388ee9 roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: service-reader subjects: - kind: ServiceAccount name: bar namespace: ttt - kind: ServiceAccount name: foo namespace: default containers: - name: main image: tutum/curl command: ["sleep", "9999999"] - name: ambassador image: luksa/kubectl-proxy:1.6.2
在ttt 命名空间中测试是否可以访问default中的service,别的资源是不行的。
kubectl -n ttt exec -it curl-custom-sa-ttt -c main curl localhost:8001/api/v1/namespaces/default/services { "kind": "ServiceList", "apiVersion": "v1", "metadata": { "resourceVersion": "4620600" }, "items": [ { "metadata": { "name": "kubernetes", "namespace": "default", "uid": "bf42983a-5db3-42d7-803d-2d10886c762a", "resourceVersion": "205", "creationTimestamp": "2022-03-29T10:01:42Z", "labels": { "component": "apiserver", "provider": "kubernetes" . . .
3、culster-role和cluster-rolebinding
一个常规的角色只允许访问和角色在同一命名空间中的资源。如果你希望允许跨不同命名空间访问资源,就必须要在每个ns中创建一个role和rolebinding。如果你想将这种行为扩展到所有的ns,需要在每个ns中创建相同的role和rolebinding。
3.1) 试试普通的功能
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: pv-reader rules: - apiGroups: [""] verbs: ["get", "list"] resources: ["persistentvolumes"] --- kubectl create clusterrolebinding pv-test --clusterrole=pv-reader --serviceaccount=default:foo --- kubectl exec -it curl-custom-sa -c main curl localhost:8001/api/v1/persistentvolumes { "kind": "PersistentVolumeList", "apiVersion": "v1", "metadata": { "resourceVersion": "4624017" }, "items": [ { "metadata": { "name": "pv-a", "uid": "8a5ddc4a-b232-4958-a187-cfdfc122aa08", "resourceVersion": "3747274", "creationTimestamp": "2022-07-31T10:15:56Z", "annotations": { "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"PersistentVolume\",\"metadata\":{\"annotations\":{},\"name\":\"pv-a\"},\"spec\":{\"accessModes\":[\"ReadWriteOnce\"],\"capacity\":{\"storage\":\"1Mi\"},\"h ...
测试的接口路径里面没有包含命名空间,因为pv不在命名空间里面,rolebinding虽然可以在你想开启命名空间资源的访问时引用一个clusterrole,但是不能对集群级别(没有命名空间)资源使用相同的方法。必须使用cluster-rolebinding来对集群级别的资源进行授权访问。
一个rolebinding不能授予集群级别的资源访问权限,即使它引用率一个cluster-rolebinding。
4、允许访问非资源型的url
api服务器也会对外暴露非资源型的url。访问这些url也必须要显示地授予权限,否则api服务器会拒绝客户端的请求。
例如:
xxx@localhost serviceaccount % kubectl get clusterrole system:discovery -o yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: annotations: rbac.authorization.kubernetes.io/autoupdate: "true" creationTimestamp: "2022-03-29T10:01:41Z" labels: kubernetes.io/bootstrapping: rbac-defaults name: system:discovery resourceVersion: "84" uid: f7ee554f-8c0a-421f-b88a-be30542989c9 rules: - nonResourceURLs: - /api - /api/* - /apis - /apis/* - /healthz - /livez - /openapi - /openapi/* - /readyz - /version - /version/ verbs: - get xxx@localhost serviceaccount % kubectl get clusterrolebinding system:discovery -o yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: annotations: rbac.authorization.kubernetes.io/autoupdate: "true" creationTimestamp: "2022-03-29T10:01:41Z" labels: kubernetes.io/bootstrapping: rbac-defaults name: system:discovery resourceVersion: "148" uid: cce8a7de-668f-4b7d-bdb0-3075ec71c49d roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: system:discovery subjects: - apiGroup: rbac.authorization.k8s.io kind: Group name: system:authenticated
5、使用clusterRole来授权访问指定命名空间中的资源
cluster不是必须一直和集群级别的clusterRoleBinding捆绑使用。他们也可以和常规的有命名空间的rolebinding进行捆绑。
kubectl get clusterrole view -o yaml aggregationRule: clusterRoleSelectors: - matchLabels: rbac.authorization.k8s.io/aggregate-to-view: "true" apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: annotations: rbac.authorization.kubernetes.io/autoupdate: "true" creationTimestamp: "2022-03-29T10:01:41Z" labels: kubernetes.io/bootstrapping: rbac-defaults rbac.authorization.k8s.io/aggregate-to-edit: "true" name: view resourceVersion: "390" uid: ddd1999c-a8c5-426c-9359-93b5495a99ae rules: - apiGroups: - "" resources: - configmaps - endpoints - persistentvolumeclaims - persistentvolumeclaims/status - pods - replicationcontrollers - replicationcontrollers/scale - serviceaccounts - services - services/status verbs: - get - list - watch - apiGroups: - "" resources: - bindings - events - limitranges - namespaces/status - pods/log - pods/status - replicationcontrollers/status - resourcequotas - resourcequotas/status verbs: - get - list - watch - apiGroups: - "" resources: - namespaces verbs: - get - list - watch - apiGroups: - discovery.k8s.io resources: - endpointslices verbs: - get - list - watch - apiGroups: - apps resources: - controllerrevisions - daemonsets - daemonsets/status - deployments - deployments/scale - deployments/status - replicasets - replicasets/scale - replicasets/status - statefulsets - statefulsets/scale - statefulsets/status verbs: - get - list - watch - apiGroups: - autoscaling resources: - horizontalpodautoscalers - horizontalpodautoscalers/status verbs: - get - list - watch - apiGroups: - batch resources: - cronjobs - cronjobs/status - jobs - jobs/status verbs: - get - list - watch - apiGroups: - extensions resources: - daemonsets - daemonsets/status - deployments - deployments/scale - deployments/status - ingresses - ingresses/status - networkpolicies - replicasets - replicasets/scale - replicasets/status - replicationcontrollers/scale verbs: - get - list - watch - apiGroups: - policy resources: - poddisruptionbudgets - poddisruptionbudgets/status verbs: - get - list - watch - apiGroups: - networking.k8s.io resources: - ingresses - ingresses/status - networkpolicies verbs: - get - list - watch
clusterRole 和 clusterRolebinding捆绑,那在绑定中列出的主体可以在所有命名空间中查看指定资源。
culsterRole 和 rolebinding捆绑,那在绑定中列出的主体只能查看在rolebinding命名空间中的资源。
5.1)绑定试试
kubectl create clusterrolebinding view-test --clusterrole=view --serviceaccount=default:foo kubectl exec -it curl-custom-sa -c main curl localhost:8001/api/v1/pods kubectl exec -it curl-custom-sa -c main curl localhost:8001/api/v1/namespaces/ttt/pods
5.2)缓存rolebinding 就变成只能查询对应ns中的资源
6、何时使用具体的role和 binding组合。
访问的资源 | 使用的角色类型 | 使用的绑定类型 |
集群级别的资源(nodes,pv,...) | clusterRole | clusterRoleBinding |
非资源型url(/api,/healthz,...) | clusterRole | clusterRoleBinding |
在任何ns中的资源 | clusterRole | clusterRoleBinding |
在具体ns中的资源(在多个ns中重用这个相同的clusterrole) | clusterRole | rolebinding |
在具体的ns中的资源 | role | rolebinding |