开发同学用kubectl查看线上Kubernetes集群中的一些情况,如何生成kubeconfig?
对指定的用户赋予合适的权限,首先需要明确这里的授权对象(用户)、该对象的认证方式、授权权限大小及授权方式几个概念。
在k8s集群中,当一个请求到达APIServer时,会经过多个阶段以执行访问验证、控制的行为,阶段顺序依次是:
- 传输安全,一般我们APIServer只开启https端口,建立TLS连接以确保传输安全
- 认证,请求到达APIServer后会依次尝试每个认证模块,有一个认证通过即可
- 鉴权,认证通过后进入到鉴权阶段,即判断特定的用户对特定的对象进行特定的操作是否有相应的权限
- 准入,鉴权通过则进入准入阶段,准入模块可以对请求进行验证和修改,多个准入控制器会被依次调用。有一个准入失败则立即响应拒绝服务
下面概括了认证授权相关的概念
Kubernetes集群中的用户有两类:
- 服务账户serviceaccount,由k8s管理,绑定到指定的名称空间,每个sa与一个secret关联用以保存相关凭据
- 普通用户,集群中没有对应的资源专门管理普通用户,一般是在集群外管理的。这里当然也有用户组的概念
认证策略#
身份认证策略有下面几种:
- 客户端证书:传递给APIServer的
--client-ca-file=SOMEFILE
参数指定了一个或多个证书机构,用此证书机构验证客户端提供的证书,验证通过则表示认证通过 - 持有者令牌
- 静态令牌:给APIServer传递
--token-auth-file=SOMEFILE
选项以启用 - 启动引导令牌:动态管理的令牌,一般用作平滑启动引导新集群
- 服务账户令牌:sa关联的secret中保存APIServer公开的CA证书和一个已签名的JWT令牌。一般在pod内使用,当然也可以在集群外部使用
- OpenID Connect令牌:OAuth2方式
- webhook令牌:用回调机制来验证令牌,Webhook插件用POST请求发送一个JSON序列化的对象到远程服务
- 静态密码
- HTTP基本认证
- 用户伪装
- 身份认证代理
- 匿名
鉴权主要有下面四个模块:
- Node:限制kubelet对APIServer的请求
- ABAC:基于属性的访问控制
- RBAC:基于角色的访问控制
- Webhook:http回调,查询外部的REST服务
生成kubeconfig#
利用ssl工具一步步生成#
一般我们给开发同学的权限是只读的,那如何给单个开发同学或者开发组生成对应的kubeconfig以只读权限访问集群?
在kubeconfig文件中,包含的信息有用户(组)、集群地址、客户端的数字证书(或Bearer token,或basic auth)等信息。由集群CA签名的有合法证书的用户都是通过认证的用户,Kubernetes使用证书中的subject的通用名称(Common Name)字段作为用户名,Organization字段作为用户组信息。
因此可以为指定用户或用户组生成集群CA机构签发的客户端证书,以证书认证的方式访问APIServer。
常用的证书生成工具有easyrsa、cfssl和openssl,这里以openssl为例:
1
2
3
4
5
6
7
8
9
| mkdir developer; cd developer/
# 生成私钥
openssl genrsa -out developer.key
# 生成签名请求文件,CN为developer,可指定organization字段值作为组名
openssl req -new -key developer.key -out developer.csr -subj "/CN=developer"
# 查看csr
openssl req -noout -text -in developer.csr
# 通过签名请求文件、集群CA证书及其私钥生成客户端签名证书
openssl x509 -req -in developer.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out developer.crt -days 3650
|
有了用户(组),且通过了集群身份认证,开始对其授权。集群中内置了一些常用的role和clusterrole,可以作为参考或者直接拿来用。此处将developer用户和内置的view这个clusterrole进行绑定,也可以为生成数字证书的时候指定的Organization组绑定对应的role或clusterrole
1
2
3
4
| # 检查下权限范围
kubectl get clusterrole view -o yaml
# 将developer用户和view这个clusterrole进行绑定,使其具有相应的权限
kubectl create clusterrolebinding developer-viewer --clusterrole=view --user=developer
|
view是集群范围内全局只读权限的clusterrole,对所有资源只有get/list/watch权限,没有delete、patch、create等变更行为权限,kubectl get clusterrole view -o yaml
查看其声明:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| 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"
labels:
kubernetes.io/bootstrapping: rbac-defaults
rbac.authorization.k8s.io/aggregate-to-edit: "true"
name: view
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- persistentvolumeclaims
- persistentvolumeclaims/status
- pods
- replicationcontrollers
- replicationcontrollers/scale
- serviceaccounts
- services
- services/status
verbs:
- get
- list
- watch
......省略部分内容
|
有了上面的用户、认证、授权信息,就可以生成对应权限的kubeconfig文件了
1
2
3
4
5
6
7
8
9
10
11
12
13
| # 设置集群信息
kubectl config --kubeconfig=developer.config set-cluster ${clustername} --server=https://${kubernetes_address}:6443 --certificate-authority=/etc/kubernetes/pki/ca.crt --embed-certs
# 设置凭据信息
kubectl config --kubeconfig=developer.config set-credentials ${username} --client-key=developer.key --client-certificate=developer.crt --embed-certs
# 设置上下文信息
kubectl config --kubeconfig=developer.config set-context developer --cluster=${clustername} --user=${username}
cat developer.config
kubectl --kubeconfig=developer.config config use-context ${username}
# 测试delete操作,响应forbidden
kubectl --kubeconfig=developer.config delete pod -n kube-system kube-proxy-cjvq5
#Error from server (Forbidden): pods "kube-proxy-cjvq5" is forbidden: User "developer" cannot delete resource "pods" in API group "" in the namespace "kube-system"
|
至此,我们对单个用户或用户组赋予了相应的集群操作权限。
利用CertificateSigningRequest资源申请证书签名#
Kubernetes提供了certificates.k8s.io API,可以使用此API请求证书签名。
步骤和上面方法基本一致,首先生成私钥和签名请求文件:
1
2
| openssl genrsa -out baiqi.key 2048
openssl req -new -key baiqi.key -out baiqi.csr
|
创建CertificateSigningRequest资源:
1
2
3
4
5
6
7
8
9
10
11
12
| cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: baiqi_csr
spec:
request: $(cat baiqi.csr | base64 | tr -d "\n")
signerName: kubernetes.io/kube-apiserver-client
expirationSeconds: 31536000
usages:
- client auth
EOF
|
查看创建的csr对象,处于pending状态,等待审批:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| $ kubectl get csr
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
baiqi_csr 4s kubernetes.io/kube-apiserver-client kubernetes-admin 365d Pending
$ kubectl describe csr baiqi_csr
Name: baiqi_csr
Labels: <none>
Annotations: ...
Requesting User: kubernetes-admin
Signer: kubernetes.io/kube-apiserver-client
Requested Duration: 365d
Status: Pending
Subject:
Common Name: baiqi
Serial Number:
Organization: MHC
Organizational Unit: tech
Country: CN
Locality: HangZhou
Province: ZheJiang
Events: <none>
|
批准csr请求后,颁发的证书在csr对象的.status.certificate
字段中:
1
2
3
4
5
6
| $ kubectl certificate approve baiqi_csr
certificatesigningrequest.certificates.k8s.io/baiqi_csr approved
$ kubectl get csr
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
baiqi_csr 73s kubernetes.io/kube-apiserver-client kubernetes-admin 365d Approved,Issued
|
保存证书到本地文件:
1
| kubectl get csr baiqi_csr -o jsonpath='{.status.certificate}'| base64 -d > baiqi.crt
|
有了证书认证,同前面的步骤一样,绑定对应的角色授权,并将其加入到指定的kubeconfig文件中即可:
1
2
3
4
5
6
7
8
9
10
11
12
13
| $ kubectl create clusterrolebinding baiqi-viewer --clusterrole=view --user=baiqi
# 设置baiqi凭据
$ kubectl config --kubeconfig=developer.config set-credentials baiqi --client-key=baiqi.key --client-certificate=baiqi.crt --embed-certs=true
# 新增上下文
$ kubectl config --kubeconfig=developer.config set-context baiqi --cluster=baiqi --user=baiqi
# 查看上下文信息
$ kubectl --kubeconfig=developer.config config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
baiqi baiqi baiqi
* developer baiqi developer
$ kubectl --kubeconfig=developer.config config use baiqi
$ kubectl --kubeconfig=developer.config delete pod -n kube-system kube-proxy-cjvq5
Error from server (Forbidden): pods "kube-proxy-cjvq5" is forbidden: User "baiqi" cannot delete resource "pods" in API group "" in the namespace "kube-system"
|
使用ServiceAccount token生成#
Kubernetes为每个namespace自动生成默认的sa,sa准入控制器会自动挂载到pod的 /var/run/secrets/kubernetes.io/serviceaccount
目录中,当然也可以指定需要挂载到pod的sa。
每个sa与一个secret关联用以保存相关凭据,包括token和ca证书。在认证时,ServiceAccount的用户名格式为 system:serviceaccount:(NAMESPACE):(SERVICEACCOUNT)
,并从属于两个组:system:serviceaccounts
和 system:serviceaccounts:(NAMESPACE)
。
绑定sa和对应的角色,授予其相应的权限。取出与sa对应secret的token,加入到指定的kubeconfig中。操作如下:
1
2
3
4
5
6
7
8
9
10
11
12
| $ kubectl create sa fmk
$ TOKEN=$(kubectl get secrets $(kubectl get sa fmk -o jsonpath='{.secrets[0].name}') -o jsonpath='{.data.token}' | base64 -d)
$ kubectl get secrets $(kubectl get sa fmk -o jsonpath='{.secrets[0].name}') -o jsonpath='{.data.ca\.crt}' | base64 -d > ca.crt
$ kubectl create clusterrolebinding fmk-viewer --clusterrole=view --serviceaccount=default:fmk
$ kubectl config --kubeconfig=fmk.config set-cluster cluster184 --server=https://{kubernetes_address}:6443 --certificate-authority=ca.crt --embed-certs
$ kubectl --kubeconfig=fmk.config config set-credentials ${user} --token=$TOKEN
$ kubectl --kubeconfig=fmk.config config set-context ${user} --cluster=${clustername} --user=${user}
$ kubectl --kubeconfig=fmk.config config use-context ${user}
$ kubectl --kubeconfig=fmk.config delete pod -n kube-system kube-proxy-cjvq5
Error from server (Forbidden): pods "kube-proxy-cjvq5" is forbidden: User "system:serviceaccount:default:fmk" cannot delete resource "pods" in API group "" in the namespace "kube-system"
|