服务账号

3.3K
0
0
最后修改于

动机 Motivation#

Pod 中的进程可能需要调用 Kubernetes API。例如:

  • scheduler 调度器
  • replication controller 副本控制器
  • node controller 节点控制器
  • 一个 map-reduce 类的框架,它有一个控制器,会尝试生成动态数量的 worker 并监视它们
  • continuous build and push system 持续构建 / 推送系统
  • monitoring system 监控系统

Processes in Pods may need to call the Kubernetes API.  For example:

  • scheduler
  • replication controller
  • node controller
  • a map-reduce type framework which has a controller that then tries to make a
    dynamically determined number of workers and watch them
  • continuous build and push system
  • monitoring system

它们还可以与 Kubernetes API 以外的服务交互,例如:

  • 镜像仓库,比如 docker —— 当启动容器时需要拉取镜像,在 pod 生成镜像的情况下写入镜像
  • 在大型集成云服务(托管或私有)的环境中访问其他云服务,如 blob 存储。
  • 访问连接到 pod 的 NFS 卷中的文件

They also may interact with services other than the Kubernetes API, such as:

  • an image repository, such as docker -- both when the images are pulled to
    start the containers, and for writing images in the case of pods that generate
    images.
  • accessing other cloud services, such as blob storage, in the context of a
    large, integrated, cloud offering (hosted or private).
  • accessing files in an NFS volume attached to the pod

设计概览 Design Overview#

服务账号绑定了几样东西:

  • 名称,可以被用户理解,
  • 可以进行身份验证和授权的主体
  • 一个安全上下文,定义了 Linux 功能、用户 ID、组 ID 以及其他与文件系统和操作系统交互的功能和控制。
  • 容器可以用来访问各种联网资源的一组 secret

A service account binds together several things:

  • a name, understood by users, and perhaps by peripheral systems, for an
    identity
  • a principal that can be authenticated and authorized
  • a security context, which defines the Linux
    Capabilities, User IDs, Groups IDs, and other capabilities and controls on
    interaction with the file system and OS.
  • a set of secrets, which a container may use to access various
    networked resources.

设计讨论 Design Discussion#

添加一个新 Kind 对象:

A new object Kind is added:

type ServiceAccount struct {
    TypeMeta   `json:",inline" yaml:",inline"`
    ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
    username string
    securityContext ObjectReference // (reference to a securityContext object)
    secrets []ObjectReference // (references to secret objects
}

之所以选择 ServiceAccount 这个名称,是因为它已经被广泛使用(例如 Kerberos 和 LDAP)来指代这种类型的帐户。请注意,它与 Kubernetes 服务对象没有关系。

The name ServiceAccount is chosen because it is widely used already (e.g. by Kerberos and LDAP) to refer to this type of account. Note that it has no relation to Kubernetes Service objects.

ServiceAccount 对象不包含任何无法单独定义的信息:

  • 无论用户如何定义,都可以定义用户名
  • securityContext 和 secrets 仅被引用,并使用 REST API 创建

The ServiceAccount object does not include any information that could not be defined separately:

  • username can be defined however users are defined.
  • securityContext and secrets are only referenced and are created using the
    REST API.

ServiceAccount 对象有两个用途:

  • 用户名到 securityContext 和 secret,以便在显式命名 securityContext 和 secret 不方便的上下文中使用用户名进行简洁引用
  • 提供简单化分配新 securityContext 和 secret 的接口

这些特性稍后解释。

The purpose of the serviceAccount object is twofold:

  • to bind usernames to securityContexts and secrets, so that the username can be used to refer succinctly in contexts where explicitly naming securityContexts and secrets would be inconvenient
  • to provide an interface to simplify allocation of new securityContexts and secrets.

These features are explained later.

名字 Name#

从 Kubernetes API 的视角看,一个user是可以被 Kubernetes API 鉴权的实体。包括人在他电脑上运行的kubectl和一个节点上的一个 Pod 中进行 API 调用的一个容器。

From the standpoint of the Kubernetes API, a user is any principal which can authenticate to Kubernetes API. This includes a human running kubectl on her desktop and a container in a Pod on a Node making API calls.

Kubernetes 中已经有用户名(username)的概念了,它在经过验证的请求上下文中很常见。但是,没有表示一个用户的 API 对象。虽然这可能会发生变化,但可以预计在成熟的安装中,用户标识符的规范存储将由 Kubernetes 外部的系统处理。

There is already a notion of a username in Kubernetes, which is populated into a request context after authentication. However, there is no API object representing a user. While this may evolve, it is expected that in mature installations, the canonical storage of user identifiers will be handled by a system external to Kubernetes.

Kubernetes 没有规定如何划分用户标识符字符串的空间。用户名可以是简单的 Unix 风格的短用户名(例如alice),也可以是允许联合身份的限定名 (alice@example.comvs. alice@example.org)命名约定可以区分服务帐户和用户帐户(例如alice@example.comvs. build-service-account-a3b7f0@foo-namespace.service-accounts.example.com),但 Kubernetes 不需要这个。

Kubernetes does not dictate how to divide up the space of user identifier strings. User names can be simple Unix-style short usernames, (e.g. alice), or may be qualified to allow for federated identity (alice@example.com vs. alice@example.org.) Naming convention may distinguish service accounts from user accounts (e.g. alice@example.com vs. build-service-account-a3b7f0@foo-namespace.service-accounts.example.com), but Kubernetes does not require this.

Kubernetes 也不要求区分人类用户和 Pod 用户。可以设置一个集群,其中 Alice 用为用户名 alice 与 Kubernetes API 对话,并启动 pod,这些 pod 也以用户 alice 的身份与 API 对话,以用户alice的身份向 NFS 写入文件。但是,并不建议这样做。
相反,推荐 Pod 和人类有不同的身份,引用实现来进行区分。

Kubernetes also does not require that there be a distinction between human and Pod users. It will be possible to setup a cluster where Alice the human talks to the Kubernetes API as username alice and starts pods that also talk to the API as user alice and write files to NFS as user alice. But, this is not recommended.
Instead, it is recommended that Pods and Humans have distinct identities, and reference implementations will make this distinction.

这样的区分是有用的:

  • 人类和自动处理的需求是不同的
    • 人需要宽范围能力去完成他们的日常活动。自动处理通常是更狭隘定义的活动。
    • 人可以更好地令牌过期所造成的异常情况。记住,在程序中处理这一点更令人烦恼。因此,需要长期证书或自动轮换证书。
    • 人类通常在不属于集群的机器上保存凭据,因此不受自动管理。具有角色 / 服务帐户的 VM 可以自动管理其凭据。
  • Pod 的身份一般不能被映射为一个人
    • 即使策略运行,它可能被一个人创建,然后一直被其他人修改,直到它的行为不能被归为一个单个人。

TODO: 考虑去掉单独的 serviceAccount 对象,将其放到 SecurityContext 或 Pod 对象中。

The distinction is useful for a number of reasons:

  • the requirements for humans and automated processes are different:
    • Humans need a wide range of capabilities to do their daily activities. Automated processes often have more narrowly-defined activities.
    • Humans may better tolerate the exceptional conditions created by expiration of a token. Remembering to handle this in a program is more annoying. So, either long-lasting credentials or automated rotation of credentials is needed.
    • A Human typically keeps credentials on a machine that is not part of the cluster and so not subject to automatic management. A VM with a role/service-account can have its credentials automatically managed.
  • the identity of a Pod cannot in general be mapped to a single human.
    • If policy allows, it may be created by one human, and then updated by another, and another, until its behavior cannot be attributed to a single human.

TODO: consider getting rid of separate serviceAccount object and just rolling its parts into the SecurityContext or Pod Object.

secrets字段是一个对 /secret 对象的引用列表,作为服务帐户启动的进程应该有权访问这些对象才能断言该角色。

The secrets field is a list of references to /secret objects that a process started as that service account should have access to be able to assert that role.

secret 不与 serviceAccount 对象内联,这样,大部分或是所有用户都对GET /serviceAccounts有权限,他们可以提醒他们自己什么 serviceAccount 是可用的。

The secrets are not inline with the serviceAccount object.  This way, most or all users can have permission to GET /serviceAccounts so they can remind themselves what serviceAccounts are available for use.

不会阻止一个带有两个SecretTypeKubernetesAuth类型 secret 或两个不同类型 secret 的 serviceAccount。
Kubelet 和客户端库有一些事情要完成,以处理一个类型多密钥的情况(选一个或是提供所有的然后按顺序一个个尝试)。

Nothing will prevent creation of a serviceAccount with two secrets of type SecretTypeKubernetesAuth, or secrets of two different types. Kubelet and client libraries will have some behavior, TBD, to handle the case of multiple secrets of a given type (pick first or provide all and try each in order, etc).

当存在和服务账号匹配的 secret,服务账号的 User.Info 和 secret 中的BearerToken就被添加到令牌的 map 中,map 用于 apiserver 的认证处理,并且与其他类型也相似。(我们可能有一些类型可能不在 apiserver 做事,只是被推到 kubelet。)

When a serviceAccount and a matching secret exist, then a User.Info for the serviceAccount and a BearerToken from the secret are added to the map of tokens used by the authentication process in the apiserver, and similarly for other types. (We might have some types that do not do anything on apiserver but just get pushed to the kubelet.)

Pod#

PodSpec被拓展后有一个Pods.Spec.ServiceAccountUsername字段。如果该字段没有设置,会取默认值,如果设置看,Pods.Spec.SecurityContext的对应值会被 Service Account Finalizer(见下文)设置。
TBD:策略如何限制哪个用户用哪个服务账号制造 pod。

The PodSpec is extended to have a Pods.Spec.ServiceAccountUsername field. If this is unset, then a default value is chosen. If it is set, then the corresponding value of Pods.Spec.SecurityContext is set by the Service Account Finalizer (see below).
TBD: how policy limits which users can make pods with which service accounts.

授权 Authorization#

Kubernetes API 授权指的是用户。创建时带有Pods.Spec.ServiceAccountUsername的 Pod 通常得到一个Secret,该 Secret 允许他们作为特定用户向 Kubernetes APIserver 进行身份验证。因此,任何所需的策略都可以应用于它们。

Kubernetes API Authorization Policies refer to users.  Pods created with a Pods.Spec.ServiceAccountUsername typically get a Secret which allows them to authenticate to the Kubernetes APIserver as a particular user. So any policy that is desired can be applied to them.

需要更高级别的工作流来协调服务帐户、secret 和相关策略对象的创建。用户可以自由扩展 Kubernetes,将这种业务逻辑放在他们方便的地方,尽管 Service Account Finalizer 是一个可能发生这种情况的地方(见下文)。

A higher level workflow is needed to coordinate creation of serviceAccounts, secrets and relevant policy objects. Users are free to extend Kubernetes to put this business logic wherever is convenient for them, though the Service Account Finalizer is one place where this can happen (see below).

Kubelet#

kubelet 会将任何具有空 SecurityContext 的 Pod 视为 “未准备好运行”(需要终结器对其进行操作)。
kubele t 将为从非 Apiserver 配置源(http,file)创建的任何 pod 设置默认的、限制性的安全上下文。
Kubelet 监视 apiserver,寻找绑定到它的 pod 所需的 secret。
TODO:如何只让 kubelet 看到它需要知道的 secret。

The kubelet will treat as "not ready to run" (needing a finalizer to act on it) any Pod which has an empty SecurityContext.
The kubelet will set a default, restrictive, security context for any pods created from non-Apiserver config sources (http, file).
Kubelet watches apiserver for secrets which are needed by pods bound to it.
TODO: how to only let kubelet see secrets it needs to know.

服务账号终结器 The service account finalizer#

有几种方式去使用带有 SecurityContext 和 Secret 的 Pod。
一种方式是在 pod 创建时显式指定 securityContext 和 pod 的所有 secret,像这样:
TODO:带显式引用 pod 的例子
另一种方法是使用 Service Account Finalizer,这是一个插件流程,它是可选的,处理围绕服务帐户的业务逻辑。

There are several ways to use Pods with SecurityContexts and Secrets.
One way is to explicitly specify the securityContext and all secrets of a Pod when the pod is initially created, like this:
TODO: example of pod with explicit refs.
Another way is with the Service Account Finalizer, a plugin process which is optional, and which handles business logic around service accounts.

Service Account Finalizer 检测 Pod、命名空间以及服务账号定义。
第一,如果它找到了有Pod.Spec.ServiceAccountUsername但没有设置Pod.Spec.SecurityContext的 pod,那么它会复制引用的 SecurityContext 和对应 serviceAccount 的 secret 引用。
第二如果服务账号定义改变,它可能会采取一些行动。
TODO:当服务账号定义改变时决定它会采取什么行动。
是停止 pod,还是只允许某人列出不合规的 pod ?一般来说,人们可能想自定义?
第三,如果创建新命名空间,可能为该命名空间创建一个新服务账号。可能包括新用户名(例如NAMESPACE-default-service-account@serviceaccounts.$CLUSTERID.kubernetes.io),新 securityContext,用于向 Kubernetes API 验证该服务账号的新生成的 secret 以及该服务帐户的默认策略。
TODO:更具体的例子。默认服务帐户的典型默认权限是什么(例如,对同一命名空间中的服务的只读访问和对该命名空间中的事件的读写访问?)
最后,它可以提供一个界面来自动创建新的服务账号。在这种情况下,用户可能希望 GET 服务账号以查看已创建的内容。

The Service Account Finalizer watches Pods, Namespaces, and ServiceAccount definitions.
First, if it finds pods which have a Pod.Spec.ServiceAccountUsername but no Pod.Spec.SecurityContext set, then it copies in the referenced securityContext and secrets references for the corresponding serviceAccount.
Second, if ServiceAccount definitions change, it may take some actions.
TODO: decide what actions it takes when a serviceAccount definition changes.
Does it stop pods, or just allow someone to list ones that are out of spec? In general, people may want to customize this?
Third, if a new namespace is created, it may create a new serviceAccount for that namespace. This may include a new username (e.g. NAMESPACE-default-service-account@serviceaccounts.$CLUSTERID.kubernetes.io), a new securityContext, a newly generated secret to authenticate that serviceAccount to the Kubernetes API, and default policies for that service account.
TODO: more concrete example. What are typical default permissions for default service account (e.g. readonly access to services in the same namespace and read-write access to events in that namespace?)
Finally, it may provide an interface to automate creation of new serviceAccounts. In that case, the user may want to GET serviceAccounts to see what has been created.