号里很多瓜友问我,Kubernetes中的应用程序是如何访问kubernetes中的资源对象的?
我想了下这个问题,觉得可以先从"SA"谈起。
权限管理是Kubernetes和OpenShift的核心功能之一。Kubenetes本身提供了一系列的安全机制,比如认证(Authentication)、授权(Authorization)、准入控制(Admission Control)认证(Authentication)、授权(Authorization)、准入控制(Admission Control)。但是它本身并不管理用户的信息,用户的身份信息管理是以插件形式存在的,比如管理员可以配置HTpasswd、KeyStone、LDAP、GitHub等登录验证方式。自然人用户可以获取相应的Token来去访问API Server. 那么在系统中运行的程序进程该如何访问API Server呢?
注:在Kubernetes/OpenShift云计算系统中,所有的用户(自然人用户,程序用户)都需要和API Server进行交互,只有认证、授权、准入控制通过后,这些用户才能使用相应的资源(API)。API Server类似门禁一样保证了后端etcd中的数据安全。
为了解决此问题,Kubernetes 引入了ServiceAccount(SA)的概念。我们以OpenShift为例。
注:Pod是Kubernetes/OpenShift系统中最小基本单元,它里面可包含多个容器服务。
SA以Namespace(命名空间)划分,我们新建一个Namespace,叫做test,如下:
代码语言:javascript复制$ oc new-project test
$ oc get sa
NAME SECRETS AGE
builder 2 3m20s
default 2 3m20s
deployer 2 3m20s
注:在OpenShift中,oc = kubectl
可以看到有三个SA被默认创建了,那它们分别起什么作用呢?
先来查看下它们被赋予的权限:
代码语言:javascript复制$ oc get rolebinding
NAME ROLE AGE
admin Cl
usterRole/admin 15m
system:deployers ClusterRole/system:deployer 15m
system:image-builders ClusterRole/system:image-builder 15m
system:image-pullers ClusterRole/system:image-puller 15m
可以看到,SA builder 被赋予了system:image-builder 的权限。我们再去看下system:image-builder可以做什么。
代码语言:javascript复制$ oc describe rolebinding system:image-builders
Name: system:image-builders
Labels: <none>
Annotations: openshift.io/description:
Allows builds in this namespace to push images to this namespace. It is auto-managed by a controller; remove subjects to disable.
Role:
Kind: ClusterRole
Name: system:image-builder
Subjects:
Kind Name Namespace
---- ---- ---------
ServiceAccount builder test
可以看到,system:image-builder 可以做一些imagestream的创建、更新等操作。
代码语言:javascript复制$ oc describe clusterrole system:image-builder
Name: system:image-builder
Labels: rbac.authorization.k8s.io/aggregate-to-admin=true
rbac.authorization.k8s.io/aggregate-to-edit=true
Annotations: openshift.io/description:
Grants the right to build, push and pull images from within a project. Used primarily with service accounts for builds.
rbac.authorization.kubernetes.io/autoupdate: true
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
imagestreams [] [] [create]
imagestreams.image.openshift.io [] [] [create]
imagestreams/layers [] [] [get update]
imagestreams.image.openshift.io/layers [] [] [get update]
builds [] [] [get]
builds.build.openshift.io [] [] [get]
builds/details [] [] [update]
builds.build.openshift.io/details [] [] [update]
类似地,SA deploer 可做一些pod部署的操作。
代码语言:javascript复制$ oc describe rolebinding system:deployers
Name: system:deployers
Labels: <none>
Annotations: openshift.io/description:
Allows deploymentconfigs in this namespace to rollout pods in this namespace. It is auto-managed by a controller; remove subjects to disa...
Role:
Kind: ClusterRole
Name: system:deployer
Subjects:
Kind Name Namespace
---- ---- ---------
ServiceAccount deployer test
$ oc describe clusterrole system:deployer
Name: system:deployer
Labels: <none>
Annotations: openshift.io/description: Grants the right to deploy within a project. Used primarily with service accounts for automated deployments.
rbac.authorization.kubernetes.io/autoupdate: true
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods [] [] [create get list watch]
events [] [] [create list]
imagestreamtags [] [] [create update]
imagetags [] [] [create update]
imagestreamtags.image.openshift.io [] [] [create update]
imagetags.image.openshift.io [] [] [create update]
replicationcontrollers [] [] [delete get list update watch]
replicationcontrollers/scale [] [] [get update]
pods/log [] [] [get]
简单概括如下:
ServiceAccount | 作用 |
---|---|
builder | 构建Pod, 镜像流 |
deployer | 部署Pod |
default | Pod中默认使用该SA |
我们知道要访问API Server,是需要证书、Token的,那SA是如何获取这些证书的呢?
我们看一下这个Pod中默认使用的SA: default.
代码语言:javascript复制$ oc describe sa default
Name: default
Namespace: test
Labels: <none>
Annotations: <none>
Image pull secrets: default-dockercfg-7n87s
Mountable secrets: default-dockercfg-7n87s
default-token-n9f6q
Tokens: default-token-m29km
default-token-n9f6q
Events: <none>
查看下这个default-dockercfg-7n87s 中都有些什么。
代码语言:javascript复制$ oc describe secret default-dockercfg-7n87s
Name: default-dockercfg-7n87s
Namespace: test
Labels: <none>
Annotations: kubernetes.io/service-account.name: default
kubernetes.io/service-account.uid: 6942fa8f-3ddf-4b6a-8bde-5a50e647f7cf
openshift.io/token-secret.name: default-token-m29km
openshift.io/token-secret.value:
eyJhbGciOiJSUzI1NiIsImtpZCI6IkpseHB5c0tySnRtdXZjSFlvckNPTlVUZXMyaFFmM3F1cUtZdFNMQ3Nza2sifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiw...
Type: kubernetes.io/dockercfg
Data
====
.dockercfg: 6723 bytes
使用get 指令获取详细的数据信息:
代码语言:javascript复制$ oc get secret default-dockercfg-7n87s -o yaml
apiVersion: v1
data:
.dockercfg: eyIxNzIuMzAuNTkuMTA1OjUwMDAiOnsidXNlcm5hbWUiOiJzZX...
kind: Secret
metadata:
...
把上面data中的数据用base64 解析出来,得到如下结果:
代码语言:javascript复制{
"172.30.59.105:5000":{
"username":"serviceaccount",
"password":"eyJhbGciOiJSUzI1NiIsImtp...",
"email":"serviceaccount@example.org",
"auth":"c2VydmljZWFjY291bnQ6ZXlKaGJHY2lPaUpTVX..."
},
"image-registry.openshift-image-registry.svc.cluster.local:5000":{
"username":"serviceaccount",
"password":"eyJhbGciOiJSUzI1NiIsImtp...",
"email":"serviceaccount@example.org",
"auth":"c2VydmljZWFjY291bnQ...“
},
"image-registry.openshift-image-registry.svc:5000":{
"username":"serviceaccount",
"password":"eyJhbGciOiJSUzI1...",
"email":"serviceaccount@example.org",
"auth":"c2VydmljZWFjY291bnQ6ZX..."
}
}
可以看到,这个secret(default-dockercfg-7n87s)存储了访问内部镜像仓库的auth 信息。
代码语言:javascript复制$ oc get svc -n openshift-image-registry
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
image-registry ClusterIP 172.30.59.105 <none> 5000/TCP 31h
image-registry-operator ClusterIP None <none> 60000/TCP 31h
既然上面的secret 是用来拉取镜像的,那么另一个应该就是来访问API Server的吧,我们来验证下:
代码语言:javascript复制$ oc get secret default-token-n9f6q -o yaml
apiVersion: v1
data:
ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FU...
namespace: dGVzdA==
service-ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t...
token: ZXlKaGJHY2lPaUpTVXpJMU5...
metadata:
annotations:
...
$ echo -n "dGVzdA=="|base64 -D
test
可以看到该secret中包含了 API Server的CA公钥证书,所在的namespace,访问服务所需的证书,身份验证的Token信息。
我们部署一个pod来看下,它是如何被使用的。
代码语言:javascript复制$ cat pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox
command: ['sh', '-c', 'echo Hello OpenShift! && sleep 3600']
$ oc create -f pod.yaml
pod/myapp-pod created
mac:~ jianzhang$ oc get pods
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 2m32s
可以看到该Pod默认使用了default SA,并挂载default-token-n9f6q 到容器内部的 /var/run/secrets/kubernetes.io/serviceaccount目录下。该Pod中的应用程序可以读取这个挂载的Token 来访问API Server了!
代码语言:javascript复制mac:~ jianzhang$ oc get pods myapp-pod -o yaml
apiVersion: v1
kind: Pod
metadata:
...
name: myapp-pod
namespace: test
...
spec:
containers:
- command:
- sh
- -c
- echo Hello OpenShift! && sleep 3600
image: busybox
imagePullPolicy: Always
name: myapp-container
resources: {}
securityContext:
capabilities:
drop:
- MKNOD
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-n9f6q
readOnly: true
dnsPolicy: ClusterFirst
enableServiceLinks: true
imagePullSecrets:
- name: default-dockercfg-7n87s
nodeName: ...
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 30
tolerations:
...
最后,可以用下面的curl指令去试下看看会返回什么。祝大家5.20快乐!
代码语言:javascript复制$ oc rsh myapp-pod
/ # ls
bin dev etc home proc root run sys tmp usr var
/ # ls /var/run/secrets/kubernetes.io/serviceaccount
ca.crt namespace service-ca.crt token
/ # TOKEN="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"
/ # curl -H "Authorization: Bearer $TOKEN" --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt "https://openshift.default.svc.cluster.local/oapi/v1/users/-"