基础
流程介绍
这里是一个认证的一个基本流程:
即: kubectl => 用户认证 => 用户授权 => 入口控制 -> 资源对象
用户认证:检查递交信息包含的证书,用户名。确定是否是正常用户。
用户授权:给用户授权权限策略,授权方式有多种:ABAC mode, RBAC Mode, and Webhook mode。确定是否有权限。
入口控制器:具有特殊功能的过滤器,他们会把请求拦截下来,如果请求违反了过滤器的配置,则请求会被拒绝。确定是否有更精细的粒度控制。
以上三阶段都是通过插件实现的。当某个阶段的某个插件授权通过后,就不会再需要此阶段的其它插件进行校验。
用户认证
令牌认证
kubectl 通过提交令牌给用户认证
TSL认证
kubectl 和 Api server 双向认证
username/password认证
一般不用这种方式
RBAC
https://kubernetes.io/zh/docs/reference/access-authn-authz/rbac/
RBAC授权是目前比较常见的方式。通过角色(规则体),用户(实体),用户绑定角色的方式,赋予用户权限。
通过kubeadm安装的集群,默认就是RBAC授权机制。
涉及到的基本对象:
- 角色:包含权限的对象,分为role和clusterrole。
- role只能用于某个命名空间。clusterrole可以用于整个集群。
- 主题:被授权的对象,可以是 user,group,serviceaccount
- 绑定:用于将角色和主题绑定在一起的对象,分为rolebinding和clusterrolebinding
角色
角色分两种,一种是命名空间级别的 Role,一种是集群级别的 ClusterRole。
用于授权对xxx资源有xxx操作权限。
# role
## https://kubernetes.io/docs/reference/kubernetes-api/authorization-resources/role-v1/
## 拥有 dev 命名空间里 "deployments", "replicasets", "pods" 资源的增删改查权限。
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: developer
namespace: dev
rules:
- apiGroups: ["", "apps"]
resources: ["deployments", "replicasets", "pods"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # 也可以使用['*']
# clusterrole
## https://kubernetes.io/docs/reference/kubernetes-api/authorization-resources/cluster-role-v1/
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: filebeat
labels:
app: filebeat
rules:
- apiGroups: [""] # "" indicates the core API group
resources:
- namespaces
- pods
- nodes
verbs:
- get
- watch
- list
用户
从使用者角度来看的时候,k8s把用户分为普通用户
和服务用户
。普通用户对外(也就是上图里的Human),服务用户对内(也就是上图里的Pod)。
💥请记住,k8s并没有普通用户的实体对象,也就是说通过kubectl get user
是没有这个对象的。因此,只要你递交的用户拥有k8s集群内部CA所签发的证书,那么这个用户就会被rbac子系统认为是有效的。
普通用户
创建普通用户所需的证书
https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/#normal-user
-
创建私钥key,通过私钥发起证书请求,生成请求文件csr
创建私钥会让你填写一些属性,这里有两个属性特别重要,分别是属性CN(填写用户名)和属性O(填写用户组)
例如创建用户
zyh
,群组it
openssl genrsa -out zyh.key 2048 openssl req -new -key zyh.key -out zyh.csr -subj "/CN=zyh/O=it"
-
构建k8s的 CertificateSigningRequest 证书请求对象
- 先将 csr 文件进行base64编码
RequestStr=`cat zyh.csr | base64 | tr -d "\n"`
- 将编码后的内容写入 CertificateSigningRequest 对象的 request 字段
cat <<EOF | kubectl apply -f - apiVersion: certificates.k8s.io/v1 kind: CertificateSigningRequest metadata: name: zyh spec: groups: - system:authenticated request: ${RequestStr} signerName: kubernetes.io/kube-apiserver-client usages: - client auth EOF
⭐️usages字段必须是
client auth
⭐️需要注意的是,证书签发默认只有1年有效期
🌟确保当前 csr 没有重名申请
-
批准证书请求,并获取证书
批准CertificateSigningRequest对象的证书请求:
kubectl get csr kubectl certificate approve zyh
获取批准后的颁发的证书:
kubectl get csr zyh -o jsonpath='{.status.certificate}' | base64 --decode > zyh.crt
⭐️检查证书有效期:
openssl x509 -in zyh.crt -noout -dates
至此,一个普通用户就创建完毕了。但是它没有任何权限,需要随后声明绑定对象,将角色和用户关联。
服务用户
流程
服务用户对象,即ServiceAccount。
-
每一个namespace的时候都会自动创建一个默认ServiceAccount和默认secret,并且默认ServiceAccount关联默认secret。
-
secret中含有sa认证所需的证书和Token。
-
当Pod创建好之后,secret会将证书和Token挂载到
/var/run/secrets/kubernetes.io/serviceaccount/
路径下。Pod通过挂载的认证文件合法化。 -
通过RABC机制对sa进行授权,从而使Pod拥有了获取诸多资源的权限。
-
在没有显式指定sa的时候,Pod会调用默认sa。
例如,下面的SA对象通过imagePullSecrets
附加了额外的secret授权信息myregistrykey
,使得Pod可以拉取镜像。
apiVersion: v1
kind: ServiceAccount
metadata:
name: default
namespace: default
secrets:
- name: default-token-uudge # 这是默认服务账户的Token
imagePullSecrets:
- name: myregistrykey # 这是Secret对象的key,存储着拉取镜像的用户密码
创建服务用户
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin
namespace: kube-system
labels:
app: filebeat
创建完毕后,对应的 secret.namespace 会生成一个新的对象:<sa_name>-token-$RANDOM,用来进行资源对象的认证,请注意这里是认证,不是授权。也就是说通过了认证但没权限访问资源。
用户绑定角色
普通用户绑定
绑定创建。位于 dev 命名空间的 rolebinding 对象
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: developer-rolebinding
namespace: dev
subjects:
- kind: User
name: zyh
apiGroup: ""
roleRef:
kind: Role
name: developer
apiGroup: rbac.authorization.k8s.io # 留空字符串也可以,则使用当前的apiGroup
通过上述创建过程,你可以发现用户创建和用户授权两个阶段是分离的。也就是说,你可以创建多个用户,然后用同一个角色绑定多个用户。
服务用户绑定
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: filebeat
subjects:
- kind: ServiceAccount
name: filebeat
namespace: kube-system
roleRef:
kind: ClusterRole
name: filebeat
apiGroup: rbac.authorization.k8s.io
用户调用
普通用户
-
添加用户证书到kubectl配置
kubectl config set-credentials zyh --client-key=zyh.key --client-certificate=zyh.crt --embed-certs=true
-
设置用户上下文,方便进行用户切换
kubectl config set-context zyh --cluster=kubernetes --user=zyh
–cluster 指定要访问集群的名称
-
通过用户上下文进行用户切换
kubectl config use-context zyh
用户的有效期,取决于你证书的有效期。
-
测试权限
kubectl get pod -n dev === No resources found in developer namespace. kubectl get svc -n dev === Error from server (Forbidden): services is forbidden: User "zyh" cannot list resource "services" in API group "" in the namespace "developer"
服务用户
Pod通过spec.serviceAccountName显式指定一个SA
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: k8s-pod-logs
namespace: kube-system
spec:
selector:
matchLabels:
project: k8s-pod-logs
app: filebeat
template:
metadata:
labels:
project: k8s-pod-logs
app: filebeat
spec:
serviceAccountName: filebeat
对象总结
role 和 rolebinding 是 namespace 级别对象,clusterrole 和 clusterrolebinding 是集群级别对象。
- 授权某个用户单命名空间或者集群权限。
-
通过 rolebinding 将 user 和 role 关联起来,实现对一个 user 添加 namespace 级别的 role 权限。
-
通过 clusterrolebinding 将 user 和 clusterrole 关联起来,实现对一个 user 添加是集群级别的 clusterrole 权限。
- 授权某个用户多个命名空间的权限。
-
通过 rolebinding 将 user 和 clusterrole 关联起来,实现对一个 user 添加 namespace 级别的 clusterrole 权限。
因为 clusterrole 是集群级别,而 rolebinding 是命名空间级别,通过不同namespace下的 rolebinding 将 user 关联到一个 clusterrole 下,可以将 clusterrole 的权限约束到 rolebinding 所在的命名空间。
当你把 user 替换为 group 的时候,将会授权某个组
当你把 user 替换为 serviceaccount 的时候,将会授权调用 spec.serviceAccountName 的 pod