权限管理RBAC
参考链接:https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/rbac/
1.Role和ClusterRole
Role 作用于namespace内的角色
ClusterRole 作用于整个集群的集群角色
# role default ns的pod读权限
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
# clusterrole 所有ns中secret的读权限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
# "namespace" 被忽略,因为 ClusterRoles 不受名字空间限制
name: secret-reader
rules:
- apiGroups: [""]
# 在 HTTP 层面,用来访问 Secret 资源的名称为 "secrets"
resources: ["secrets"]
verbs: ["get", "watch", "list"]
2.RoleBinding和ClusterRoleBinding
RoleBinding 作用于命名空间,可以绑定role或clusterrole,对象可以是user或group或serviceaccount。
ClusterRoleBinding 作用于集群,可以为整个集群定义一组公用的ClusterRole,然后在多个命名空间中重复使用。
# rolebinding 将pod-reader的role授予default ns下的user jane,即允许jane读取default ns下的pod
apiVersion: rbac.authorization.k8s.io/v1
# 此角色绑定允许 "jane" 读取 "default" 名字空间中的 Pod
# 你需要在该命名空间中有一个名为 “pod-reader” 的 Role
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects:
# 你可以指定不止一个“subject(主体)”
- kind: User
name: jane # "name" 是区分大小写的
apiGroup: rbac.authorization.k8s.io
roleRef:
# "roleRef" 指定与某 Role 或 ClusterRole 的绑定关系
kind: Role # 此字段必须是 Role 或 ClusterRole
name: pod-reader # 此字段必须与你要绑定的 Role 或 ClusterRole 的名称匹配
apiGroup: rbac.authorization.k8s.io
# rolebinding 将secret-reader的clusterrole授予deployment ns 下的user dave,即允许dave读取 deployment ns下的secret
apiVersion: rbac.authorization.k8s.io/v1
# 此角色绑定使得用户 "dave" 能够读取 "development" 名字空间中的 Secrets
# 你需要一个名为 "secret-reader" 的 ClusterRole
kind: RoleBinding
metadata:
name: read-secrets
# RoleBinding 的名字空间决定了访问权限的授予范围。
# 这里隐含授权仅在 "development" 名字空间内的访问权限。
namespace: development
subjects:
- kind: User
name: dave # 'name' 是区分大小写的
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
# ClusterRoleBinding可用于集群级别和所有命名空间授予权限,允许组manager中所有用户读取任何命名空间的secret
apiVersion: rbac.authorization.k8s.io/v1
# 此集群角色绑定允许 “manager” 组中的任何人访问任何名字空间中的 Secret 资源
kind: ClusterRoleBinding
metadata:
name: read-secrets-global
subjects:
- kind: Group
name: manager # 'name' 是区分大小写的
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
K8S多租户权限管理实战
一般这样用:创建ns,创建ns下的sa,创建clusterrole,创建rolebinding将sa和clusterrole绑定
# ns
k create ns kube-users
# sa
k create sa kube-system -n kube-users
# clusterrole 配置pod日志查询和执行命令的权限
cat pod-exec-cr.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pod-exec
rules:
- apiGroups:
- ""
resources:
- pod
- pods/log
verbs:
- get
- list
- apiGroups:
- ""
resources:
- pods/exec
verbs:
- create
# clusterrole 全局ns只读权限
cat ns-readonly.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: namespace-readonly
rules:
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- list
- watch
- apiGroups:
- metrics.k8s.io
resources:
- pods
verbs:
- get
- list
- watch
# 授权 clusterrolebinding
k create clusterrolebinding namespace-readonly --clusterrole=namespace-readonly --serviceaccount=kube-users:kube-system
# 授权 rolebinding
k create rolebinding sa-kube-system-pod-exec --clusterrole=pod-exec --serviceaccount=kube-users:kube-system --namespace=kube-system
# sa对应的secret
k get sa kube-system -n kube-users -o yaml
# 查看secret对于的token
k describe secret kubernetes-dashboard-admin-sa-token -n kubernetes-dashboard
k get secret -n kube-users $(k get secret -n kube-users|grep kube-system-token-name | awk '{print $1}') -o go-template='{{.data.token}}' | base64 -d
Network Policy
在集群中安装支持网络策略的插件,比如Calico、Weave。注意Flannel不支持。
参考链接:https://kubernetes.io/zh-cn/docs/concepts/services-networking/network-policies/
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978
示例1:隔离中间件服务
有一个项目有自己的Mysql和Redis,只希望这个项目的应用能访问该中间件,即中间件只对项目开放,这样可以起到安全的效果。
k create ns nw-demo
# mysql
k create deploy mysql --image=registry.cn-beijing.aliyuncs.com/dotbalo/mysql:5.7.23 -n nw-demo
k set env deploy/mysql MYSQL_ROOT_PASSWORD=mysql -n nw-demo
# redis
k create deploy redis --image=registry.cn-beijing.aliyuncs.com/dotbalo/redis:5.0.9-alpine3.11 -n nw-demo
k get pods -n nw-demo -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysql-857b9b4c94-jwdsh 1/1 Running 0 3m17s 10.244.1.59 k8s-worker-node1 <none> <none>
redis-57bf8685c8-fssxw 1/1 Running 0 74s 10.244.1.60 k8s-worker-node1 <none> <none>
# 测试网络连通性
telnet 10.244.1.59 3306
telnet 10.244.1.60 6379
# 根据pod标签进行隔离
k get pods -n nw-demo --show-labels
NAME READY STATUS RESTARTS AGE LABELS
mysql-857b9b4c94-jwdsh 1/1 Running 0 6m48s app=mysql,pod-template-hash=857b9b4c94
redis-57bf8685c8-fssxw 1/1 Running 0 4m45s app=redis,pod-template-hash=57bf8685c8
# 创建网络策略
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: mysql-np
namespace: nw-demo
spec:
podSelector:
matchLabels:
app: mysql
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
access-nw-mysql-redis: "true"
ports:
- protocol: TCP
port: 3306
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: redis-np
namespace: nw-demo
spec:
podSelector:
matchLabels:
app: redis
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
access-nw-mysql-redis: "true"
ports:
- protocol: TCP
port: 6379
# 创建networkpolicy
k get networkpolicy -n nw-demo
NAME POD-SELECTOR AGE
mysql-np app=mysql 6m46s
redis-np app=redis 6m46s
k get pods -n nw-demo -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysql-857b9b4c94-jwdsh 1/1 Running 0 20m 10.244.1.59 k8s-worker-node1 <none> <none>
redis-57bf8685c8-fssxw 1/1 Running 0 18m 10.244.1.60 k8s-worker-node1 <none> <none>
# 测试
telnet 10.244.1.59 3306
telnet 10.244.1.60 6379
不通
k run -ti debug-tools --image=registry.cn-beijing.aliyuncs.com/dotbalo/debug-tools:latest -n nw-demo
# 添加label
k label namespace nw-demo access-nw-mysql-redis="true"
namespace/nw-demo labeled
k exec -it debug-tools -n nw-demo -- curl 10.244.1.59:3306
k run -ti debug-tools --image=registry.cn-beijing.aliyuncs.com/dotbalo/debug-tools:latest -n default
If you don't see a command prompt, try pressing enter.
(07:32 debug-tools:/)
(07:32 debug-tools:/) curl 10.244.1.60:6379
# 同理如果需要default可以正常访问,即给default namespace添加label就可以。
k get ns nw-demo --show-labels
NAME STATUS AGE LABELS
nw-demo Active 48m access-nw-mysql-redis=true,kubernetes.io/metadata.name=nw-demo
示例2:服务发布限制于Ingress
访问项目是通过域名方式,而非IP+端口,使用Ingress配置域名,然后代理该项目。可以利用网络策略隔离该项目的前端服务,只对Ingress Controller开放。
假设现在创建一个Nginx服务充当前端页面,配置网络策略只让Ingress Controller访问该应用:
# 创建应用
k create deploy nginx --image=registry.cn-beijing.aliyuncs.com/dotbalo/nginx:latest -n nw-demo
# 暴露服务
k expose deploy nginx -n nw-demo --port=80
# 查看
k get svc,pod -n nw-demo -l app=nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/nginx ClusterIP 10.96.36.183 <none> 80/TCP 35s
NAME READY STATUS RESTARTS AGE
pod/nginx-5c9c878b87-d8nqp 1/1 Running 0 92s
# 测试访问
k exec debug-tools -- curl -Is nginx.nw-demo
HTTP/1.1 200 OK
Server: nginx/1.23.3
Date: Mon, 12 Jun 2023 07:45:20 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 13 Dec 2022 15:53:53 GMT
Connection: keep-alive
ETag: "6398a011-267"
Accept-Ranges: bytes
k -n nw-demo exec debug-tools -- curl -Is nginx.nw-demo
HTTP/1.1 200 OK
Server: nginx/1.23.3
Date: Mon, 12 Jun 2023 07:45:36 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 13 Dec 2022 15:53:53 GMT
Connection: keep-alive
ETag: "6398a011-267"
Accept-Ranges: bytes
# network policy只让Ingress Controller访问服务
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: nginx-np
namespace: nw-demo
spec:
podSelector:
matchLabels:
app: nginx
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
podSelector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
- podSelector: {}
ports:
- protocol: TCP
port: 80
对具有app=nginx的pod生效,只让具有app.kubernetes.io/name=ingress-nginx标签的ns下具有app.kubernetes.io/name: ingress-nginx标签的Pod访问(podSelector前面没有-即为且的关系)。同时还有一个允许当前ns下pod访问的策略-podSelector: {}
# 测试连通性
k exec debug-tools -- curl -Is nginx.nw-demo --connect-timeout 2
HTTP/1.1 200 OK
Server: nginx/1.23.3
Date: Mon, 12 Jun 2023 08:17:11 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 13 Dec 2022 15:53:53 GMT
Connection: keep-alive
ETag: "6398a011-267"
Accept-Ranges: bytes
k exec debug-tools -- curl -Is nginx.nw-demo --connect-timeout 2 -n nw-demo
HTTP/1.1 200 OK
Server: nginx/1.23.3
Date: Mon, 12 Jun 2023 08:17:28 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 13 Dec 2022 15:53:53 GMT
Connection: keep-alive
ETag: "6398a011-267"
Accept-Ranges: bytes
command terminated with exit code 6
k get pods -n ingress-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-admission-create-h4tk6 0/1 Completed 0 52d 10.244.1.5 k8s-worker-node1 <none> <none>
ingress-nginx-admission-patch-gl2rc 0/1 Completed 0 52d 10.244.1.6 k8s-worker-node1 <none> <none>
ingress-nginx-controller-797448cb7f-h282r 1/1 Running 0 49d 192.168.73.102 k8s-worker-node1 <none> <none>
k exec ingress-nginx-controller-797448cb7f-h282r -n ingress-nginx -- curl -Is nginx.nw-demo
k create ingress nginx --rule="testnp.com/*=nginx:80" -n nw-demo
curl -H "Host:testnp.com" 192.168.73.102