我对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相关联并启动。如果不了解这一点可能会感到混乱,所以我在开始时进行了补充说明。流程如下。

    1. 如果Pod启动时指定了ServiceAccount,则使用该ServiceAccount;如果未指定,则与default关联。

 

    1. 检查与Pod关联的ServiceAccount是否存在,如果不存在,则拒绝。

 

    1. 如果Pod没有设置ImagePullSecrets,则会添加ServiceAccount的ImagePullSecrets。

 

    1. 会添加一个用于存放用于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”,但有些微妙的地方不太确定。

广告
将在 10 秒后关闭
bannerAds