我对Kubernetes的Service Account进行了调查
简述
如果想使用以下的库,文中提到可以在Pod内使用服务帐户,因此我对此并不十分理解,于是进行了调查。你可以在这里找到相关信息:https://github.com/kubernetes/client-go
我觉得大体上跟文档里写的一样,只要能大致理解其中的氛围,就能在阅读文档时有所帮助。因为我已经简单总结了一下,所以如果你想要更详细的了解,请阅读文档。
请参考
-
- https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/
- https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
版本
-
- Kubernetes
1.10
我觉得如果版本变动多了,这个答案就不会有用了,所以我会注明在我查询时的版本。
用户账户与服务账户
在Kubernetes中,用户账户和服务账户似乎被明确区分开来。
-
- User accountsは人のためのもの、Service accountsはPod内で動くプロセスのためのもの
- User accountsは全てのNamespaceを通して固有である必要があるが、Service accountsはNamespace内で固有であれば良い
因此,尝试使用名称为test创建两个服务账户将导致错误。
$ kubectl create serviceaccount test
serviceaccount "test" created
$ kubectl create serviceaccount test
Error from server (AlreadyExists): serviceaccounts "test" already exists
如果有不同的命名空间,那么就可以创建。
% kubectl create serviceaccount test -n name1
serviceaccount "test" created
服务账号自动化
服务账户由三个组件组成。
-
- A Service account admission controller
-
- A Token controller
- A Service account controller
服务账户控制器
这似乎只是一个用于在所有Namespace中创建名为default的ServiceAccount的控制器。
创建名为”name1″的命名空间后,检查ServiceAccount时发现已经存在一个名为”default”的账号。
$ kubectl create namespace name1
namespace "name1" created
$ kubectl get serviceaccounts -n name1
NAME SECRETS AGE
default 1 24s
我之前误以为这个名为”default”的ServiceAccount与Namespace的”default”有关联,但实际上它只是指最初的默认ServiceAccount,并与Namespace无关。
为什么要什么都加上”default”这个名字呢…
代币控制器
这似乎是一个监视ServiceAccount,并在创建新的ServiceAccount时为其创建用于访问API的凭证的存在。这个凭证中似乎包含了用于API访问的令牌等信息。
当ServiceAccount被删除时,它会帮忙删除相应的凭证。
如果试着创建ServiceAccount,你会发现立即创建了一个名为test-token-wt6nr的Secret。
$ kubectl create serviceaccount test
serviceaccount "test" created
$ kubectl get secret
NAME TYPE DATA AGE
default-token-lg725 kubernetes.io/service-account-token 3 7d
test-token-wt6nr kubernetes.io/service-account-token 3 4s
当查看其中时,里面包含了 token 和 ca.crt。
$ kubectl describe secret test-token-wt6nr
Name: test-token-wt6nr
Namespace: default
Labels: <none>
Annotations: kubernetes.io/service-account.name=test
kubernetes.io/service-account.uid=XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX
Type: kubernetes.io/service-account-token
Data
====
namespace: 7 bytes
token: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
ca.crt: 1042 bytes
如果用户自己创建了与ServiceAccount关联的Secret,Service Account Controller似乎会负责确认ServiceAccount的存在并添加token。这是指需要额外的Secret吗?
{
"kind": "Secret",
"apiVersion": "v1",
"metadata": {
"name": "mysecretname",
"annotations": {
"kubernetes.io/service-account.name": "myserviceaccount"
}
},
"type": "kubernetes.io/service-account-token"
}
只需要一个选项:按照这种方式编写JSON,然后运行 “kubectl create -f secret.json” 就可以了。
服务账户准入控制器
然后最想知道的关键是控制器。 zuì de shì .)
首先,Pod会与ServiceAccount相关联并启动。如果不了解这一点可能会感到混乱,所以我在开始时进行了补充说明。流程如下。
-
- 如果Pod启动时指定了ServiceAccount,则使用该ServiceAccount;如果未指定,则与default关联。
-
- 检查与Pod关联的ServiceAccount是否存在,如果不存在,则拒绝。
-
- 如果Pod没有设置ImagePullSecrets,则会添加ServiceAccount的ImagePullSecrets。
-
- 会添加一个用于存放用于API访问的token的volume。
- 将volumeSource添加到Pod的每个容器中,路径为/var/run/secrets/kubernetes.io/serviceaccount。
简单来说,ServiceAccount持有用于访问API的令牌,而这个令牌会悄悄地挂载到容器中!
我认为最好能够马上看到,所以我们随便部署一个nginx的Pod。
$ kubectl run nginx --image=nginx
deployment.apps "nginx" created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-8586cf59-2ksl7 0/1 ContainerCreating 0 4s
我将在这种状态下尝试进入容器,并且当我查看上面的路径时,确实看到了挂载的token等内容。
% kubectl exec -it nginx-8586cf59-2ksl7 bash
root@nginx-8586cf59-2ksl7:/# ls /var/run/secrets/kubernetes.io/serviceaccount
ca.crt namespace token
只需一种选择,将以下内容以中文母语方式改述:
由于此令牌的内容仅是JWT,因此解码后查看有效载荷,如下所示。
{
"iss": "kubernetes/serviceaccount",
"kubernetes.io/serviceaccount/namespace": "default",
"kubernetes.io/serviceaccount/secret.name": "default-token-lg725",
"kubernetes.io/serviceaccount/service-account.name": "default",
"kubernetes.io/serviceaccount/service-account.uid": "68b1d424-6af0-11e8-84f0-067120183a92",
"sub": "system:serviceaccount:default:default"
}
秘密名称已更改为 default-token-lg725。而且,服务账户名称也被更改为 default。
默认的 ServiceAccount 被自动装入了与其关联的 Secret。
哦,明白了。
但当我查看Pod的定义时,我发现即使我没有在YAML中写任何东西…,但它如下所示(部分省略)。
$ kubectl get pods nginx-8586cf59-2ksl7 -o yaml
apiVersion: v1
kind: Pod
metadata:
...
namespace: default
...
spec:
containers:
- image: nginx
...
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-lg725
readOnly: true
serviceAccount: default
serviceAccountName: default
...
volumes:
- name: default-token-lg725
secret:
defaultMode: 420
secretName: default-token-lg725
...
确实已经挂载了且ServiceAccount:default已经设定了…!!
我认为对于敏锐的人来说,你应该已经知道了,如果想要使用不同的ServiceAccount,只需在YAML文件中写入并执行apply就可以了。
根据上述内容,可以得出结论,Pod会自动挂载ServiceAccount的token和ca.crt。因此,您可以通过访问/var/run/secrets/kubernetes.io/serviceaccount目录来在Pod内运行程序,而无需自己编写~/.kube/config来调用API。
在现实中可用的API取决于ServiceAccount与角色的关联性,但这是另一个讨论话题,现在略过。
总结
我总结了关于ServiceAccount的内容。它的机制与在AWS上将IAM角色附加到EC2上非常类似。
我认为以k8s的对象来表达世界观并实现它非常有趣。
我刚开始学习k8s,之前没有理解它的意义,如果对他人有所帮助,我会感到幸福。
※ “Service accounts”、”Service account”、”ServiceAccount” 这些都混在一起,但是按照文档来写的。当指称资源名称时写成 “ServiceAccount”,我想它可能是指普通账号的解释时写成 “Service accounts”,但有些微妙的地方不太确定。