前言
Useraccount 作用是在外部访问的时候使用,给人使用所有的namespace都可以使用 。ServiceAccount是给运行在Pod的程序使用的身份认证,Pod容器的进程需要访问API Server时用的就是ServiceAccount账户;ServiceAccount仅局限它所在的namespace,每个namespace创建时都会自动创建一个default service account;创建Pod时,如果没有指定Service Account,Pod则会使用default Service Account。
步骤
ServiceAccount创建
ClusterRole创建
1 由于我们这是学习,所以这里创建一个namespace,而不是在默认的命令空间中创建项目。
[root@master cor0ps-cluster]# kubectl create namespace cor0ps-cluster
namespace/cor0ps-cluster created
2、接下来就是手工创建一个serviceaccount或者直接将serviceaccount绑定到我们前面创建的命令空间。
[root@master cor0ps-cluster]# kubectl create serviceaccount cor0ps-cluster-service-account
serviceaccount/cor0ps-cluster-service-account created
或者
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: cor0ps-cluster-service-account
namespace: cor0ps-cluster
EOF
3、创建一个ClusterRole
如果一个serviceaccount要访问集群的资源,是需要定义一个能访问哪些操作的角色定义。
cat <<EOF | kubectl apply -f -
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cor0ps-cluster-role
namespace: cor0ps-cluster
rules:
- apiGroups:
- ""
- apps
- autoscaling
- batch
- extensions
- policy
- rbac.authorization.k8s.io
resources:
- pods
- componentstatuses
- configmaps
- daemonsets
- deployments
- events
- endpoints
- horizontalpodautoscalers
- ingress
- jobs
- limitranges
- namespaces
- nodes
- pods
- persistentvolumes
- persistentvolumeclaims
- resourcequotas
- replicasets
- replicationcontrollers
- serviceaccounts
- services
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
EOF
当然我们如果知道一个cluster-role,我们可以查询该角色定义了哪些操作
[root@master cor0ps-cluster]# kubectl get clusterrole cor0ps-cluster-role -n cor0ps-cluster -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"rbac.authorization.k8s.io/v1","kind":"ClusterRole","metadata":{"annotations":{},"name":"cor0ps-cluster-role"},"rules":[{"apiGroups":["","apps","autoscaling","batch","extensions","policy","rbac.authorization.k8s.io"],"resources":["pods","componentstatuses","configmaps","daemonsets","deployments","events","endpoints","horizontalpodautoscalers","ingress","jobs","limitranges","namespaces","nodes","pods","persistentvolumes","persistentvolumeclaims","resourcequotas","replicasets","replicationcontrollers","serviceaccounts","services"],"verbs":["get","list","watch","create","update","patch","delete"]}]}
creationTimestamp: "2023-05-16T13:01:41Z"
name: cor0ps-cluster-role
resourceVersion: "55987"
uid: 61b37f23-6431-47b7-972b-cb10b1cbf2c0
rules:
- apiGroups:
- ""
- apps
- autoscaling
- batch
- extensions
- policy
- rbac.authorization.k8s.io
resources:
- pods
- componentstatuses
- configmaps
- daemonsets
- deployments
- events
- endpoints
- horizontalpodautoscalers
- ingress
- jobs
- limitranges
- namespaces
- nodes
- pods
- persistentvolumes
- persistentvolumeclaims
- resourcequotas
- replicasets
- replicationcontrollers
- serviceaccounts
- services
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
4、创建一个CluserRole Binding
现在我们创建好了service account和 clusterRole ,现在需要将它们两个绑定在一起生效。
cat <<EOF | kubectl apply -f -
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cor0ps-cluster-role-binding
subjects:
- namespace: cor0ps-cluster
kind: ServiceAccount
name: cor0ps-cluster-service-account
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cor0ps-cluster-role
EOF
查询刚才创建的clusterrole
[root@master cor0ps-cluster]# kubectl get clusterrolebinding |grep cor0ps
cor0ps-cluster-role-binding ClusterRole/cor0ps-cluster-role 2m13s
查询该角色绑定的信息
[root@master cor0ps-cluster]# kubectl get clusterrolebinding cor0ps-cluster-role-binding -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"rbac.authorization.k8s.io/v1","kind":"ClusterRoleBinding","metadata":{"annotations":{},"name":"cor0ps-cluster-role-binding"},"roleRef":{"apiGroup":"rbac.authorization.k8s.io","kind":"ClusterRole","name":"cor0ps-cluster-role"},"subjects":[{"kind":"ServiceAccount","name":"cor0ps-cluster-service-account","namespace":"cor0ps-cluster"}]}
creationTimestamp: "2023-05-16T13:12:12Z"
name: cor0ps-cluster-role-binding
resourceVersion: "56934"
uid: 7dc0aa0b-5923-432f-bbc5-e1cab5cf332b
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cor0ps-cluster-role
subjects:
- kind: ServiceAccount
name: cor0ps-cluster-service-account
namespace: cor0ps-cluster
5、使用kubectl来验证serviceaccount角色是否生效
为了验证clusterrole 绑定是否生效,我们可以使用kubectl自带的 can-i 命令来验证 API 是否具备权限。
[root@master cor0ps-cluster]# kubectl auth can-i get pods --as=system:serviceaccount:cor0ps-cluster:cor0ps-cluster-service-account
yes
[root@master cor0ps-cluster]# kubectl auth can-i create pods --as=system:serviceaccount:cor0ps-cluster:cor0ps-cluster-service-account
yes
[root@master cor0ps-cluster]# kubectl auth can-i delete deployments --as=system:serviceaccount:cor0ps-cluster:cor0ps-cluster-service-account
yes
yes表示有权限操作,no表示无权限操作。
6、使用API接口来验证
[root@master cor0ps-cluster]# kubectl get serviceaccounts -n cor0ps-cluster
NAME SECRETS AGE
cor0ps-cluster-service-account 0 42m
default 0 45m
[root@master cor0ps-cluster]# kubectl get serviceaccount cor0ps-cluster-service-account -n cor0ps-cluster -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"ServiceAccount","metadata":{"annotations":{},"name":"cor0ps-cluster-service-account","namespace":"cor0ps-cluster"}}
creationTimestamp: "2023-05-16T12:57:53Z"
name: cor0ps-cluster-service-account
namespace: cor0ps-cluster
resourceVersion: "55641"
uid: 2085283b-bec4-4179-be26-71b98ed2664e
由于我这里是新版本v1.27.1,serviceaccount token改用mount挂载到文件。https://www.programmingwithwolfgang.com/use-the-tokenrequest-api-to-create-tokens-in-kubernetes/这里为了对比,寻找一个低版本的测试下:发现低于1.24版本的创建了serviceaccount绑定的时候,会自动生成一个token secret类型。
[root@xdm-f-safe-34266 role]# kubectl get secrets -n cor0ps-cluster
NAME TYPE DATA AGE
cor0ps-cluster-service-account-token-vqgnv kubernetes.io/service-account-token 3 73s
default-secret kubernetes.io/dockerconfigjson 1 70s
default-token-9xxmw kubernetes.io/service-account-token 3 87s
[root@xdm-f-safe-34266 role]# kubectl version --short
Client Version: v1.21.4
Server Version: v1.21.7-r0-daily-build
高于1.24版本是不会自动生成serviceaccount token
[root@icsltaochao-docker cor0ps]# kubectl get secrets -n cor0ps-cluster
NAME TYPE DATA AGE
default-secret kubernetes.io/dockerconfigjson 1 4m21s
paas.elb cfe/secure-opaque 3 4m21s
[root@icsltaochao-docker cor0ps]# kubectl version --short
Client Version: v1.25.3
那么在高版本我们需要给serviceaccount 绑定生成一个token。这里测试使用的namepsace 是cor0ps-cluster。
cat <<EOF | kubectl create -f - -v=6
apiVersion: v1
kind: Secret
metadata:
name: cor0ps-user-token
namespace: cor0ps-cluster //这里一定要指定,默认是default
annotations:
kubernetes.io/service-account.name: cor0ps-cluster-service-account
type: kubernetes.io/service-account-token
EOF
现在我们再来获取下我们创建的token
[xxx cor0ps]# kubectl get secrets
NAME TYPE DATA AGE
cor0ps-user-token kubernetes.io/service-account-token 3 54s
[root@icsltaochao-docker cor0ps]# kubectl get secret cor0ps-user-token -o yaml
apiVersion: v1
data:
ca.crt: xxxx
token: ZXlKa...=
kind: Secret
metadata:
annotations:
kubernetes.io/service-account.name: cor0ps-cluster-service-account
kubernetes.io/service-account.uid: 5c462abc-060d-43b5-a84b-2bc0ecb73675
creationTimestamp: "2023-05-17T03:19:05Z"
name: cor0ps-user-token
namespace: default
resourceVersion: "25076"
uid: 71e36a06-3d4b-4d35-a4c3-81a57dea7bc3
type: kubernetes.io/service-account-token
通过命令解析出token值
SECRET_NAME="cor0ps-user-token"
TOKEN=$(kubectl get secret ${SECRET_NAME} -o jsonpath='{$.data.token}' | base64 -d | sed $'s/$/\n/g')
echo $TOKEN
然后获取apiserver的地址
[xxx cor0ps]# kubectl get endpoints
NAME ENDPOINTS AGE
kubernetes 192.168.0.109:5444,192.168.0.193:5444,192.168.0.7:5444 100m
构造API请求
curl -k https://API-SERVER-IP/api/v1/namespaces?limit=500 -H "Authorization: Bearer $TOKEN"
成功访问。
Role 创建
1、单独创建一个测试role的命令空间
[cor0ps]# kubectl create namespace cor0ps-role
namespace/cor0ps-role created
2、创建serviceaccount和命令空间绑定
apiVersion: v1
kind: ServiceAccount
metadata:
name: cor0ps-role-service-account
namespace: cor0ps-role
3、创建role的定义
cat <<EOF | kubectl apply -f -
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: cor0ps-role
namespace: cor0ps-role
rules:
- apiGroups:
- ""
- apps
- autoscaling
- batch
- extensions
- policy
- rbac.authorization.k8s.io
resources:
- pods
- componentstatuses
- configmaps
- daemonsets
- deployments
- events
- endpoints
- horizontalpodautoscalers
- ingress
- jobs
- limitranges
- namespaces
- nodes
- pods
- persistentvolumes
- persistentvolumeclaims
- resourcequotas
- replicasets
- replicationcontrollers
- serviceaccounts
- services
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
EOF
4、创建role 和 serviceaccount的绑定
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: cor0ps-role-rolebinding
namespace: cor0ps-role
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: cor0ps-role
subjects:
- namespace: cor0ps-role
kind: ServiceAccount
name: cor0ps-role-service-account
5、验证前面配置的role的权限 这里先拉起一个pod。
cat <<EOF | kubectl apply -f -
---
apiVersion: v1
kind: Pod
metadata:
name: role-test
namespace: cor0ps-role
spec:
containers:
- image: bibinwilson/docker-kubectl:latest
name: kubectl
serviceAccountName: cor0ps-role-service-account
EOF
进入容器获取到token 和apiserver的ip,我们访问会出现如下
[root@master cor0ps-role]# API="192.168.133.5:6443"
[root@master cor0ps-role]# curl -k https://$API/api/v1/namespaces?limit=500 -H "Authorization: Bearer $TOKEN"
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "namespaces is forbidden: User "system:serviceaccount:cor0ps-role:cor0ps-role-service-account" cannot list resource "namespaces" in API group "" at the cluster scope",
"reason": "Forbidden",
"details": {
"kind": "namespaces"
},
"code": 403
}
[root@master cor0ps-role]# kubectl auth can-i get pods --as=system:serviceaccount:cor0ps-crolecor0ps-crole-service-account
no
不能遍历所有的namespaces或pods ,那么我们建立的这个role具体有什么作用呢
[root@master cor0ps-role]# curl -k https://192.168.133.5:6443/api/v1/namespaces/cor0ps-role/pods?limit=500 -H "Authorization: Bearer $TOKEN"
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "64210"
},
"items": [
{
"metadata": {
"name": "role-test",
"namespace": "cor0ps-role",
"uid": "08eb9b68-a2a6-4725-9ead-6f8acf9c35de",
"resourceVersion": "61467",
"creationTimestamp": "2023-05-17T12:58:46Z",
"annotations": {
"kubectl.kubernetes.io/last-applied-configuration": "{"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"role-test","namespace":"cor0ps-role"},"spec":{"containers":[{"image":"bibinwilson/docker-kubectl:latest","name":"kubectl"}],"serviceAccountName":"cor0ps-role-service-account"}}n"
},
从这里可以看的出实际role角色只能限定在某个对应绑定的namespace上。那么我们再使用该绑定的token 去访问未绑定的namespace cor0ps-cluster 看下访问结果。
[root@master cor0ps-role]# curl -k https://192.168.133.5:6443/api/v1/namespaces/cor0ps-cluster/pods?limit=500 -H "Authorization: Bearer $TOKEN"
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "pods is forbidden: User "system:serviceaccount:cor0ps-role:cor0ps-role-service-account" cannot list resource "pods" in API group "" in the namespace "cor0ps-cluster"",
"reason": "Forbidden",
"details": {
"kind": "pods"
},
"code": 403
}
结果是不可以的。
如何根据serviceaccount 反推到具体的role 角色定义。
kubectl get serviceaccounts -A -v=6
kubectl get rolebindings,clusterrolebindings --all-namespaces -o custom-columns='KIND:kind,NAMESPACE:metadata.namespace,NAME:metadata.name,SERVICE_ACCOUNTS:subjects[?(@.kind=="ServiceAccount")].name' |grep xxxx
附录
https://devopstales.github.io/kubernetes/k8s-user-accounts/
原文始发于微信公众号(Web安全):攻防矩阵之ServiceAccount创建
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论