12.1 了解认证机制

12.1 了解认证机制

在前面的章节中,我们讲到API服务器可以配置一到多个认证的插件(授权插件同样也可以)。API服务器接收到的请求会经过一个认证插件的列表,列表中的每个插件都可以检查这个请求和尝试确定谁在发送这个请求。列表中的第一个插件可以提取请求中客户端的用户名、用户ID和组信息,并返回给API服务器。API服务器会停止调用剩余的认证插件并继续进入授权阶段。

目前有几个认证插件是直接可用的。它们使用下列方法获取客户端的身份认证:

  • 客户端证书
  • 传入在HTTP头中的认证token
  • 基础的HTTP认证
  • 其他

启动API服务器时,通过命令行选项可以开启认证插件。

12.1.1 用户和组

认证插件会返回已经认证过用户的用户名和组(多个组)。Kubernetes不会在任何地方存储这些信息,这些信息被用来验证用户是否被授权执行某个操作。

了解用户

Kubernetes区分了两种连接到API服务器的客户端。

  • 真实的人(用户)
  • pod(更准确地说是运行在pod中的应用)

这两种类型的客户端都使用了上述的认证插件进行认证。用户应该被管理在外部系统中,例如单点登录系统(SSO),但是pod使用一种称为service accounts的机制,该机制被创建和存储在集群中作为ServiceAccount资源。相反,没有资源代表用户账户,这也就意味着不能通过API服务器来创建、更新或删除用户。

我们不会详细讨论如何管理用户,但是会具体地探讨ServiceAccount,因为它们对于运行中的pod很重要。关于如何配置集群来供用户身份认证的更多信息,集群管理员应该参考集群管理 中的Kubernetes集群管理员指南。

了解组

正常用户和ServiceAccount都可以属于一个或多个组。我们已经讲过认证插件会连同用户名和用户ID返回组。组可以一次给多个用户赋予权限,而不是必须单独给用户赋予权限。

由插件返回的组仅仅是表示组名称的字符串,但是系统内置的组会有一些特殊的含义。

  • system:unauthenticated 组用于所有认证插件都不会认证客户端身份的请求。
  • system:authenticated 组会自动分配给一个成功通过认证的用户。
  • system:serviceaccounts 组包含所有在系统中的ServiceAccount。
  • system:serviceaccounts: 组包含了所有在特定命名空间中的ServiceAccount。

12.1.2 ServiceAccount介绍

接下来我们更详细地探讨ServiceAccount。你已经了解API服务器要求客户端在服务器上执行操作之前对自己进行身份认证,并且你已经了解了pod是怎么通过发送 /var/run/secrets/kubernetes.io/serviceaccount/token 文件内容来进行身份认证的。这个文件通过加密卷挂载进每个容器的文件系统中。

但是那个文件具体表示了什么呢?每个pod都与一个ServiceAccount相关联,它代表了运行在pod中应用程序的身份证明。token文件持有ServiceAccount的认证token。应用程序使用这个token连接API服务器时,身份认证插件会对ServiceAccount进行身份认证,并将ServiceAccount的用户名传回API服务器内部。ServiceAccount用户名的格式像下面这样:

system.serviceaccount:<namespace>:<service account name>

API服务器将这个用户名传给已配置好的授权插件,这决定该应用程序所尝试执行的操作是否被ServiceAccount允许执行。

ServiceAccount只不过是一种运行在pod中的应用程序和API服务器身份认证的一种方式。如前所述,应用程序通过在请求中传递ServiceAccount token来实现这一点。

了解ServiceAccount资源

ServiceAccount就像Pod、Secret、ConfigMap等一样都是资源,它们作用在单独的命名空间,为每个命名空间自动创建一个默认的ServiceAccount(你的pod会一直使用)。

可以像其他资源那样查看ServiceAccount列表:

$ kubectl get sa

注意 serviceaccount 的缩写是sa。

如你所见,当前命名空间只包含default ServiceAccount,其他额外的ServiceAccount可以在需要时添加。每个pod都与一个ServiceAccount相关联,但是多个pod可以使用同一个ServiceAccount。通过图12.1我们可以了解,pod只能使用同一个命名空间中的ServiceAccount。

img

image

图12.1 每个pod会分配一个在这个pod命名空间中的单一ServiceAccount

ServiceAccount如何和授权进行绑定

在pod的manifest文件中,可以用指定账户名称的方式将一个ServiceAccount赋值给一个pod。如果不显式地指定ServiceAccount的账户名称,pod会使用在这个命名空间中的默认ServiceAccount。

可以通过将不同的ServiceAccount赋值给pod来控制每个pod可以访问的资源。当API服务器接收到一个带有认证token的请求时,服务器会用这个token来验证发送请求的客户端所关联的ServiceAccount是否允许执行请求的操作。API服务器通过管理员配置好的系统级别认证插件来获取这些信息。其中一个现成的授权插件是基于角色控制的插件(RBAC),这个插件会在本章后续进行讨论。从Kubernetes 1.6版本开始,RBAC插件是绝大多数集群应该使用的授权插件。

12.1.3 创建ServiceAccount

我们已经讲过每个命名空间都拥有一个默认的ServiceAccount,也可以在需要时创建额外的ServiceAccount。但是为什么应该费力去创建新的ServiceAccount而不是对所有的pod都使用默认的ServiceAccount?

显而易见的原因是集群安全性。不需要读取任何集群元数据的pod应该运行在一个受限制的账户下,这个账户不允许它们检索或修改部署在集群中的任何资源。需要检索资源元数据的pod应该运行在只允许读取这些对象元数据的ServiceAccount下。反之,需要修改这些对象的pod应该在它们自己的ServiceAccount下运行,这些ServiceAccount允许修改API对象。

下面让我们了解一下如何创建其他的ServiceAccount,它们如何与密钥进行关联,以及如何将它们分配给pod。

创建ServiceAccount

得益于 kubectl create serviceaccount 命令,创建ServiceAccount非常容易。让我们新创建一个名为foo的 ServiceAccount:

$ kubectl create serviceaccount foo

然后如下面的代码清单所示的那样,可以使用describe命令来查看ServiceAccount。

代码清单12.1 使用 kubectl describe 命令查看ServiceAccount

$ kubectl describe serviceaccount foo
Name:                foo
Namespace:           custom
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>  #
Mountable secrets:   foo-token-shg6r
Tokens:              foo-token-shg6r #认证tonken
Events:              <none>

可以看到,我们已经创建了自定义的token密钥,并将它和ServiceAccount相关联。如果通过 kubectl describe secret foo-token-qzq7j 查看密钥里面的数据,如下面的代码清单所示,你会发现它包含了和默认的ServiceAccount相同的条目(CA证书、命名空间和token),当然这两个token本身显然是不相同的。

代码清单12.2 查看自定义的ServiceAccount密钥

$ kubectl describe secret foo-token-shg6r

注意 你可能已经了解过JSON Web Token(JWT)。ServiceAccount中使用的身份认证token就是JWT token。

了解ServiceAccount上的可挂载密钥

通过使用 kubectl describe 命令查看ServiceAccount时,token会显示在可挂载密钥列表中。下面让我们来解释一下这个列表代表什么。在第7章中,你学会了如何创建密钥并且把它们挂载进一个pod里。在默认情况下,pod可以挂载任何它需要的密钥。但是我们可以通过对ServiceAccount进行配置,让pod只允许挂载ServiceAccount中列出的可挂载密钥。为了开启这个功能,ServiceAccount必须包含以下注解:kubernetes.io/enforce-mountable-secrets=″true″

如果ServiceAccount被加上了这个注解,任何使用这个ServiceAccount的pod只能挂载进ServiceAccount的可挂载密钥——这些pod不能使用其他的密钥。

了解ServiceAccount的镜像拉取密钥

ServiceAccount也可以包含镜像拉取密钥的list。这个list曾经在第7章中查看过;如果你已经不记得了,镜像拉取密钥持有从私有镜像仓库拉取容器镜像的凭证。

下面的代码清单中显示了ServiceAccount定义的一个例子,它包含了我们在第7章中创建的镜像拉取密钥。

代码清单12.3 带有镜像拉取密钥的ServiceAccount:sa-image-pull-secrets.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-service-account
imagePullSecrets:
- name: my-dockerhub-secret

ServiceAccount的镜像拉取密钥和它的可挂载密钥表现有些轻微不同。和可挂载密钥不同的是,ServiceAccount中的镜像拉取密钥不是用来确定一个pod可以使用哪些镜像拉取密钥的。添加到ServiceAccount中的镜像拉取密钥会自动添加到所有使用这个ServiceAccount的pod中。向ServiceAccount中添加镜像拉取密钥可以不必对每个pod都单独进行镜像拉取密钥的添加操作。

12.1.4 将ServiceAccount分配给pod

在创建另外的ServiceAccount之后,需要将它们赋值给pod。通过在pod定义文件中的 spec.serviceAccountName 字段上设置ServiceAccount的名称来进行分配。

注意 pod的ServiceAccount必须在pod创建时进行设置,后续不能被修改。

创建使用自定义ServiceAccount的pod

在第8章中部署了一个运行在基于 tutum/curl 镜像的容器上的pad,并在其旁边放置了一个ambassador容器。我们使用它来查看API服务器的REST接口。这个ambassador容器会运行 kubectl proxy 进程,这个进程会使用pod的ServiceAccount 的token和API服务器进行身份认证。

现在可以修改pod,让pod使用我们几分钟前创建的foo ServiceAccount。接下来的代码清单展示了这个pod的定义。

代码清单12.4 使用一个非默认ServiceAccount的pod:curl-custom-sa.yaml

无法找到了tutum/curl 镜像

apiVersion: v1
kind: Pod
metadata:
  name: curl-custom-sa
spec:
  serviceAccountName: foo  # 这个pod使用的ServiceAccount是foo
  containers:
  - name: main
    image: curlimages/curl
    command: ["sleep", "9999999"]
  - name: ambassador
    image: luksa/kubectl-proxy:latest 

为了确认自定义的ServiceAccount token已经挂载进这两个容器中,如下面的代码清单所示的那样,可以打印出这个token的内容。

代码清单12.5 查看挂载进pod容器内的token

$ kubectl exec -it curl-custom-sa -c main -- cat /var/run/secrets/kubernetes.io/serviceaccount/token

通过对比代码清单12.5和 12.2中token的字符串,你会发现这个token来自foo ServiceAccount的token。

使用自定义的ServiceAccount token和API服务器进行通信

让我们看看是否可以使用这个token和API服务器进行通信。前面提到过,ambassador容器在使用这个token和服务器进行通信,因此可以通过ambassador来测试这个token,这个ambassador监听在 localhost:8001 上,如下面的代码清单所示。

**代码清单12.6 使用自定义的ServiceAccount和API服务器进行通信 **

新版这里也有变化: 访问之后是403

$ kubectl exec -it curl-custom-sa -c main -- curl localhost:8001/api/v1/pods{    "kind": "PodList", "apiVersion": "v1", "metadata": {       "selfLink": "/api/v1/pods",     "resourceVersion": "433895" },  "item": [   ......

好的,我们从服务器得到了正确的响应,也就意味着自定义的ServiceAccount可以允许列出pod。这可能是因为集群没有使用RBAC授权插件,或者按照第8章所讲的那样,你给了所有的ServiceAccount全部的权限。

如果集群没有使用合适的授权,创建和使用额外的ServiceAccount并没有多大意义,因为即使默认的ServiceAccount也允许执行任何操作。在这种情况下,使用ServiceAccount的唯一原因就是前面讲过的加强可挂载密钥,或者通过ServiceAccount提供镜像拉取密钥。

如果使用RBAC授权插件,创建额外的ServiceAccount实际上是必要的,我们会在后面讨论RBAC授权插件的使用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,367评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,959评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,750评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,226评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,252评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,975评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,592评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,497评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,027评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,147评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,274评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,953评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,623评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,143评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,260评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,607评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,271评论 2 358