API服务的安全防护
2022-03-05 19:43:11 【

了解认证机制

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


用户和组

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


了解用户

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


真实的人 (用户)


pod (更准确地说是运行在 pod 中的应用)

这两种类型的客户端都使用了上述的认证插件进行认证。用户应该被管理在外部系统中,例如单点登录系统(SSO)。

但是 pod 使用一种称为 service accounts 的机制,该机制被创建和存储在集群中作为 ServiceAccount 资源。 相反,没有资源代表用户账户,这也就意味着不能通过 API 服务器来创建、更新或删除用户。


了解组

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

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


system:unauthenticated 组用于所有认证插件都不会认证客户端身份的请求。


system:authenticated 组会自动分配给一个成功通过认证的用户。


system:serviceaccounts 组包含所有在系统中的 ServiceAccount


system:serviceaccounts:<namespace>: 组包含了所有在特定命名空间中的ServiceAccount。


authenticated 已认证;已验证

Account 账户


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\>:\<serviceaccountname\>

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

ServiceAccount 只不过是一种运行在 pod 中的应用程序和 API 服务器身份认证的一种方式。

应用程序通过在请求中传递 ServiceAccount token 来实现这 一点。


了解 ServiceAccount 资源

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

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



[root@master ~]# kubectl get sa NAME      SECRETS   AGEdefault12d10h

当前命名空间只包含 defaultService Account, 其他额外的 ServiceAccount 可以在需要时添加。每个 pod 都与一个 ServiceAccount 相关联, 但是多个 pod 可以使用同一个 ServiceAccount 。


=600*

如图 pod 只能使用同一个命名空间中的ServiceAccount


ServiceAccount 如何和授权进行绑定

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

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


创建ServiceAccount

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



[root@master~]# kubectl  create serviceaccount foo serviceaccount/foocreated[root@master~]# kubectl  describe sa foo Name:fooNamespace:defaultLabels:<none>Annotations:<none>Image pull secrets:<none># 这些会被自动地添加到使用这个ServiceAccount的所有 pod 中Mountable secrets:foo-token-nvn97# 如果强制使用可挂载的密钥,那么使用这个ServiceAccount 的 pod 只能挂在这些密钥Tokens:foo-token-nvn97# 认证 token , 第一个 token 挂载在容器内 Events:<none>[root@master~]# kubectl  describe secrets foo-token-nvn97 ...ca.crt:1066 bytesnamespace:7bytestoken:eyJhbGciOiJSUzI1NiIsImtpZCI6InhMVzFDN2t4QjFXVXVpLXVBaHFHZjRCVzhYVUtVQW1sOHBfVnMwTnROdkkifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3Nl...

创建了自定义的token密钥,并将它和 ServiceAccount 相关联。


了解ServiceAccount 上的可挂载密钥

通过使用 kubectl describe 命令查看 ServiceAccount 时,token 会显示在可挂载密钥列表中。

在默认情况下,pod 可以挂载任何它需要的密钥。但是我们可以通过对 ServiceAccount 进行配置,让 pod 只允许挂载 ServiceAccount 中列出的可挂载密钥。

为了开启这个功能,ServiceAccount 必须包含以下注解:



kubernetes.io/enforce-mountable-secrets= "true"

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


了解 ServiceAccount 的镜像拉取密钥

ServiceAccount 也可以包含镜像拉取密钥的 list。镜像拉取密钥持有从私有镜像仓库拉取容器镜像的凭证。

下面的代码清单中显示了ServiceAccount 定义的一个例子



kubectlcreate secret docker-registry mydockerhubsecret --docker-username=myusername --docker-password=mypassword --docker-email=my.email@provider.comvimsa-image-pull-secrets.yamlapiVersion: v1kind: ServiceAccountmetadata:name: myserviceaccountimagePullSecrets:-name: mydockerhubsecret

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


ServiceAccount 分配给 pod

通过在 pod 定义文件中的 spec.serviceAccountNarne 字段上设置 ServiceAccount的名称来进行分配。

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


创建使用自定义 ServiceAccount 的 pod



vimcurl-custom-sa.yamlapiVersion:v1kind:Podmetadata:name:curl-custom-saspec:serviceAccountName:foocontainers:-name:mainimage:rancher/curlcommand: ["sleep", "9999999"]  -name:ambassadorimage:luksa/kubectl-proxy

这个ambassador容器会运行 kubectl proxy 进程 ,这个进程会使用 pod 的 ServiceAccount 的token 和API 服务器进行身份认证。



[root@master ]# kubectlexec-itcurl-custom-sa-cmaincat /var/run/secrets/kubernetes.io/serviceaccount/tokenkubectlexec[POD][COMMAND]isDEPRECATEDandwillberemovedinafutureversion. Usekubectlexec[POD]--[COMMAND]instead.eyJhbGciOiJSUzI1NiIsImtpZCI6InhMVzFDN2t4QjFXVXVpLXVBaHFHZjRCVzhYVUtVQW1sOHBfVnMwTnROdkkifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNjcwNjYxODY2LCJpYXQiOj...

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


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



[root@master api]# kubectl exec -it curl-custom-sa -c main curl localhost:8001/api/vl/podskubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [CO{  "kind": "Status",  "apiVersion": "v1",  "metadata": {      },  "status": "Failure",  "message": "pods is forbidden: User \"system:serviceaccount:default:foo\" cannot list resource \"pods\" in API   "reason": "Forbidden",  "details": {    "kind": "pods"  },  "code": 403


】【打印关闭】 【返回顶部
上一篇没有了 下一篇服务器如何防止在线威胁