Kubernetes 理论与实践-3-安全与权限管理
前文回顾
Kubernetes 理论与实践-1-基础-Pods, ReplicaSets, Services, Deployments
Access Kubernetes API as Administrator
kubectl config view \
-o jsonpath='{.clusters[?(@.name=="k3d-mycluster")].cluster.server}'
ls usercode/certs
Access Kubernetes API for users
Understanding the process
每一个 API 请求都会经过三个阶段确认
- Authentication 认证: 确定用户身份
- Authorization 授权: 认证成功后,将向用户发放授权证明/token 等信息 (可选择不同的认证机制: Node, ABAC, Webhooks, RBAC)
- Passing the admission control 通过准入控制: 准入控制器在 API 请求被执行应用为持久化状态前会拦截它们,并且可以修改请求,属于高级主题。
认证机制
- 节点(Node): 节点授权根据 kubelet 被调度运行的 Pod 来授予权限。
- ABAC (Attribute-based access control): 基于属性的访问控制(ABAC)是通过属性结合策略实现的,现已被视为过时,推荐使用 RBAC 替代。
- Webhooks: Webhook 通过 HTTP POST 请求用于事件通知。
- RBAC (Role-based access control): 基于角色的访问控制(RBAC)根据单个用户或组的角色来授予(或拒绝)对资源的访问权限。
实践-用于测试的服务定义
go-demo-2.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: go-demo-2
annotations:
kubernetes.io/ingress.class: "nginx"
ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
rules:
- host: go-demo-2.com
http:
paths:
- path: /demo
pathType: ImplementationSpecific
backend:
service:
name: go-demo-2-api
port:
number: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-demo-2-db
spec:
selector:
matchLabels:
type: db
service: go-demo-2
strategy:
type: Recreate
template:
metadata:
labels:
type: db
service: go-demo-2
vendor: MongoLabs
spec:
containers:
- name: db
image: mongo:3.3
---
apiVersion: v1
kind: Service
metadata:
name: go-demo-2-db
spec:
ports:
- port: 27017
selector:
type: db
service: go-demo-2
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-demo-2-api
spec:
replicas: 3
selector:
matchLabels:
type: api
service: go-demo-2
template:
metadata:
labels:
type: api
service: go-demo-2
language: go
spec:
containers:
- name: api
image: vfarcic/go-demo-2
env:
# - name: DB
# value: go-demo-2-db
- name: DB_ENV
value: GO_DEMO_2_DB_SERVICE_HOST
readinessProbe:
httpGet:
path: /demo/hello
port: 8080
periodSeconds: 1
livenessProbe:
httpGet:
path: /demo/hello
port: 8080
---
apiVersion: v1
kind: Service
metadata:
name: go-demo-2-api
spec:
ports:
- port: 8080
selector:
type: api
service: go-demo-2
kubectl create \
-f go-demo-2.yml \
--record --save-config
实践-创建用户
mkdir keys
# Generate private key
openssl genrsa \
-out keys/jdoe.key 2048
# Generate a certificate by the private key
# CN: username, O: organization
openssl req -new \
-key keys/jdoe.key \
-out keys/jdoe.csr \
-subj "/CN=jdoe/O=devs"
We have keys/jdoe.key
and keys/jdoe.csr
now.
我们将使用集群的证书来生成最后的证书。
ls usercode/certs # 集群证书的位置
# /usercode/certs/client-ca.key: 私匙
# /usercode/certs/client-ca.crt: 证书签名请求
openssl x509 -req \
-in keys/jdoe.csr \
-CA /usercode/certs/client-ca.crt \
-CAkey /usercode/certs/client-ca.key \
-CAcreateserial \
-out keys/jdoe.crt \
-days 365
# /usercode/certs/jdoe.crt: 数字证书
We made the certificate keys/jdoe.crt
valid fro a whole year (365 days).
cp /usercode/certs/server-ca.crt /usercode/certs/keys
ls -1 keys
Jdoe 不需要 jdoe.csr
文件(仅用来生成 jdoe.crt
文件),其他文件他们团队还是需要的。
获得集群地址
SERVER=$(kubectl config view \
-o jsonpath='{.clusters[?(@.name=="k3d-mycluster")].cluster.server}')
echo $SERVER
最终需要的配置与文件
- 新证书(jdoe.crt)
- 密钥(jdoe.key)
- 集群证书颁发机构(ca.crt)
- 服务器地址: Jdoe 可以配置其 kubectl 安装
实践-以用户身份访问集群
# SERVIER=https://172.30.1.2:6443
# 配置集群 create cluster called jdoe
kubectl config set-cluster jdoe \
--certificate-authority \
/usercode/certs/keys/server-ca.crt \
--server $SERVER
# 配置用户凭证 (如客户端证书)
kubectl config set-credentials jdoe \
--client-certificate keys/jdoe.crt \
--client-key keys/jdoe.key
# 创建上下文(绑定用户和集群)
kubectl config set-context jdoe \
--cluster jdoe \
--user jdoe
kubectl config use-context jdoe
kubectl config view
未授权访问 kubernetes 对象
kubectl get pods
kubectl get all
可以看到所有对象却无法访问,说明 jdoe 已经有访问集群的权限,但是没有获取相关对象的能力。
访问控制-RBAC 基于角色的访问控制
Rules 规则
- A Rule is a set of operations (verbs), resources, and API groups.
- Verbs:
get
,list
,create
,update
,patch
,watch
,proxy
,redirect
,delete
,deletecollection
,*
. - RBAC uses the
rbac.authorization.k8s.io
group.
Roles 角色
- A Role is a collection of Rules.
- 角色绑定到某个 Namespace 上,我们也可以用 ClusterRole 创建在整个集群可用的角色。
Subjects 主体
- 主体定义了执行操作的实体。主体可以是用户、组或服务账户。
- 用户 user 是位于集群外部的人员或进程。服务账户 service account 用于在 Pod 内部运行的进程,这些进程需要使用 API。
- 组是用户或服务账户的集合。某些组是默认创建的(例如,cluster-admin)。
RoleBindings 角色绑定
- RoleBindings 将 Subjects 绑定到 Roles。
- 由于 Subject 定义了用户,RoleBinding 实际上就是将用户(或用户组或服务账户)绑定到 Role,并授予他们在特定命名空间内对某些对象执行操作的权限。
- 与 Role 类似,RoleBinding 也有一个集群范围的替代品叫做 ClusterRoleBinding。唯一的区别在于它们的范围不受限于命名空间,而是应用于整个集群。
实践-查看预定义的 ClusterRole
以 admin 的用户查看集群
kubectl config use-context k3d-mycluster
kubectl get all
使用指令确认用户权限
kubectl auth can-i get pods --as jdoe
# no
kubectl get roles
# No resources found: kubernete cluster doesn't have default predefined roles.
kubectl get clusterroles
我们会看到一些内容,对于 system:
开头的角色,不要去更改它,会造成集群正常运行。
kubectl get clusterroles | grep -v system
kubectl describe clusterrole view
kubectl describe clusterrole edit
kubectl describe clusterrole admin
kubectl describe clusterrole cluster-admin
view
edit
admin
cluster-admin
kubectl auth can-i "*" "*"
实践-创建 RoleBinding
创建对默认 Namespace 中所有对象有查看访问权利的 RoleBInding。
kubectl create rolebinding jdoe \
--clusterrole view \
--user jdoe
--namespace default \
--save-config
kubectl get rolebindings
- 创建一个 jdoe rolebinding,绑定 jdoe user 与 view clusterrole,namespace 为 default。
- clusterrole 对象也可以用于在某些特定的 namespace, 权利的范围是时使用绑定类型 rolebinding 定义的,而不是 role 类型。
kubectl describe rolebinding jdoe
- 这里没有看到 Namespace,可能会误以为适用于所有命名空间,这个假设是错误的。
- 请记住,RoleBinding 始终与特定的命名空间相关联。(?当前的运行环境是 default namespace ?)
检查命名空间范围: 相同的 RoleBinding 不应在其他任何位置可用:
kubectl --namespace kube-system \
describe rolebinding jdoe
使用 kubectl auth can-i
kubectl auth can-i get pods \
--as jdoe
# Yes
kubectl auth can-i get pods \
--as jdoe --all-namespaces
# No
删除 rolebinding
kubectl delete rolebinding jdoe
实践-创建 ClusterRoleBinding
crb-vew.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: CLusterRoleBinding
metadata:
name: view
subjects:
- kind: User
name: jdoe
apiGroup: rbac.authorization.k8s.io
- roleRef:
kind: ClusterRole
name: view
apiGroup: rbac.authorization.k8s.io
kubectl create -f crb-view.yml \
--record --save-config
kubectl describe clusterrolebinding \
view
kubectl auth can-i get pods \
--as jdoe --all-namespaces
# Yes
实践-RoleBindings 与命名空间组合使用
团队命名空间
创建 dev
命名空间,允许执行任何操作。
rb-dev.yml
apiVersion: v1
kind: Namespace
metadata:
name: dev
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: dev
namespace: dev
subjects:
- kind: User
name: jdoe
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: admin
apiGroup: rbac.authorization.k8s.io
create
kubectl create -f rb-dev.yml \
--record --save-config
verify
kubectl --namespace dev auth can-i \
create deployments --as jdoe
# Yes
kubectl --namespace dev auth can-i \
delete deployments --as jdoe
# Yes
kubectl --namespace dev auth can-i \
"*" "*" --as jdoe
# No
用户特定的命名空间 User specific namespace
rb-jdoe.yml
apiVersion: v1
kind: Namespace
metadata:
name: jdoe
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: jdoe
namespace: jdoe
subjects:
- kind: User
name: jdoe
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
授予 cluster-admin 让 jdoe 能够授权其他人查看命名空间。
create
kubectl create -f rb-jdoe.yml \
--record --save-config
check
kubectl --namespace jdoe auth can-i \
"*" "*" --as jdoe
# Yes
实践-以发布管理员身份授予访问权限
发布经理职责
发布经理职责: 从团队空间发布到 default 空间,发布新版本。
发布经理所需的最低权限是对 Pod、Deployment 和 ReplicaSet 执行作。具有该角色的人应该能够做几乎所有与 Pod 相关的事情,而 Deployment 和 ReplicaSet 的允许作应该限制为 create
、get
、list
、update
和 watch
。
对比下 ClusterRole admin
kubectl describe clusterrole admin
子资源和 API 组
crb-release-manager.yml
: 创建 ClusterRole
# 1. 先定义 ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: release-manager-role
rules:
- apiGroups: [""] # 核心组
resources: ["pods", "pods/attach", "pods/exec", "pods/log", "pods/status"]
verbs: ["*"]
- apiGroups: ["", "apps", "extensions"] # deployments 属于 apps/v1
resources: ["deployments", "replicasets"]
verbs: ["create", "get", "list", "watch"]
---
# 2. 再绑定 ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: jdoe
subjects:
- kind: User
name: jdoe
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: release-manager-role
apiGroup: rbac.authorization.k8s.io
- 第一组规则指定
Pod
资源以及一些子资源(attach
、exec
、log
和status
)。由于我们没有创建 Pod 代理 proxy 或端口转发,因此它们不包括在内。 - 第二组规则是为
deployments
和replicasets
资源设置的。考虑到我们决定对它们进行更严格的限制,我们指定了更具体的动词
,只允许发布经理create
、get
、list
和watch
。由于我们没有指定delete
、deletecollection
、patch
和update
动词,因此发布经理将无法执行相关作。
创建发布经理 RoleBinding
kubectl create \
-f crb-release-manager.yml \
--record --save-config
kubectl describe \
clusterrole release-manager
分配给该角色的用户(几乎)可以使用 Pod 执行任何作,而他们对 Deployment 和 ReplicaSet 的权限仅限于创建和查看。他们将无法更新或删除它们。禁止访问任何其他资源。
kubectl --namespace default auth \
can-i "*" pods --as jdoe
# Yes
kubectl --namespace default auth \
can-i create deployments --as jdoe
# Yes
kubectl --namespace default auth can-i \
delete deployments --as jdoe
# No
# Switch to jdoe in default namespace
kubectl config use-context jdoe
kubectl --namespace default \
create deployment db \
--image mongo:3.3
kubectl --namespace default \
delete deployment db
# jdoe in his own namespace
kubectl config set-context jdoe \
--cluster jdoe \
--user jdoe \
--namespace jdoe
kubectl config use-context jdoe
kubectl create deployment db --image mongo:3.3
kubectl delete deployment db
# 将新用户添加到他的命名空间
kubectl create rolebinding mgandhi \
--clusterrole=view \
--user=mgandhi \
--namespace=jdoe
实践-将用户替换为用户组
回去查看下之前在 jdoe.csr
中写入的信息
openssl req -in /usercode/certs/keys/jdoe.csr \
-noout -subject
我们除了看到用户名 CN,之外,我们还注意到了 devs organisation,我们可以利用这一属性。
groups.yml
: 将 subjects 中的 User
换成 Group
,实现向组织devs
中的所有用户授予权限。
apiVersion: v1
kind: Namespace
metadata:
name: dev
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: dev
namespace: dev
subjects:
- kind: Group
name: devs
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: admin
apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: view
subjects:
- kind: Group
name: devs
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: view
apiGroup: rbac.authorization.k8s.io
首先切换回 default k3d-mycluster 上下文
kubectl config use-context k3d-mycluster
kubectl apply -f groups.yml \
--record
verify
kubectl --namespace dev auth \
can-i create deployments --as jdoe
# No
此处回复 No 是正常,目前使用的证书是 defualt k3d-mycluster 上下文里面的证书,它并没有 jdoe 用户的 organiazation 属性,所以需要先切换到 jdoe 上下文。
kubectl config use-context jdoe
kubectl --namespace dev \
create deployment new-db \
--image mongo:3.3
# OK
任何主题中含有 /O=devs
的证书的用户都将在 dev
命名空间拥有与 Jdoe 相同的权限,并在其他任何地方拥有 view 权限。