k8s 身份验证

译自官方文档:
https://kubernetes.io/docs/admin/authentication/#users-in-kubernetes

Users in Kubernetes

所有的k8s集群有两类用户:
1. service account (managed by kuberentes)
2. normal user

普通用户一般认为由外部的独立服务管理。管理员分发私钥, 用户将私钥存储到Keystone或者Google Accounts甚至是文件中。由此可见,k8s没有能够代表普通用户账户的对象。因此常规用户无法通过API调用加入到集群。

作为对比, service account 是由k8s api管理的用户。它们会和特定的namespace做绑定,可以通过api server自动创建,或者手动调用API来创建。service accounts 和一系列存储在Secret中的证书相关联,这些证书被安装到集群中,允许集群进程与k8s api对话。

API 请求绑定到普通用户或者service account,或者被视为匿名请求。
这意味着集群内部或外部的每个进程,从在工作站上键入kubectl的人类用户到节点上的kubelet,到控制平面的成员,都必须在向API服务器发出请求时进行身份验证,或者被视为匿名用户。

认证策略

Kubernete 使用客户端证书,承载令牌,认证代理或者http基础认证,通过身份认证常见对API请求进行身份认证。由于是向apiserver发送请求,插件会尝试将一下属性和请求相关联:
- Username: 一个代表了最终用户的字符串。一般是kube-adm或者jane@example.com.
- UID: 一个标识最终用户的字符串,比用户名更加一致和唯一。
- Groups: 将用户与一组常用用户相关联的字符串集合。
- Extra fields: 一个包含了可能有用的额外信息的字符串和列表的映射。

所有值对于认证系统都是不透明的,并且只有授权人验证时才能派上用场。

你可以同时开启多种认证方式。最少要使用两种方式:
1. service account token for service accounts
2. 一种或更多的普通用户认证

当开启了多个认证模块时,第一个模块会验证请求的根路径(对于/aaa/bbb/ccc, 会验证/aaa). apiserver 不保证授权模块的顺序执行。

system:authenticated 包含了所有经过鉴定的用户。

与其他身份验证协议(LDAP,SAML,Kerberos,备用x509方案等)的集成可以使用身份验证代理或身份验证webhook完成。

X509 客户端证书

x509 是一种通用证书格式

启动apiserver时,添加--client-ca-file=SOMEFILE 可以开启客户端证书认证。被引用的证书文件必须包含一个或者多个证书颁发机构,用于验证API server的客户端证书。如果客户端提供并且通过了认证,the common name of the subject is used as the user name for the request(这句不会翻)。在k8s1.4中,客户端证书还可以使用证书的机构字段来指示用户的组成员身份。想要为用户添加多个组,将多个机构字段包含到证书中去。

例如,使用openssl命令行工具来生成证书签名请求:

    openssl req -new -key jbeda.pem -out jbeda-csr.pem -subj "/CN=jbeda/O=app1/O=app2"

这会为“jbeda”用户创建一个CSR,属与组“app1”和“app2”。

如何生成客户端证书参考Managing Certificates

Static Token File

apiserver 通过 --token-auth-file=SOMEFILE 参数来读取token.一般来说,token有效期无上限,token 列表修改后需要重启apiserver。

token file是一个csv文件最少包含3列:token, user name, user uid, 后面是可选的group name。如果你有多个组名,必须要用双引号来区分。e.g:

    token,user,uid,"group1,group2,group3"

使用token请求

从http客户端使用token鉴权的时候,需要在请求头内带上Authorization: token。token必须是字符序列,可以使用不超过http的编码和引用。例如:假设token值为: 31ada4fd-adec-460c-809a-9e56ceb75269,在http头部里面如下所示:

    Authorization: Bearer 31ada4fd-adec-460c-809a-9e56ceb75269

Bootstrap Tokens

这个特性当前在alpha 阶段。

为了简化新集群的引导, k8s加入了一个可动态管理的token类型叫做bootstrap token.这个token以Secret的形式存储在kube-system命名空间中。k8s的controller manager中有个 TokenCleaner controller会在该token过期后删除它。token的格式为[a-z0-9]{6}.[a-z0-9]{16},在http请求头中如下所示:

    Authorization: Bearer 781292.db7bc3a58fc5f07e

要启用bootstrap token 需要为apiserver添加--experimental-bootstrap-token-auth参数。同时需要在controller manager上开启TokenCleaner 通过参数--controllers.配置起来类似--controllers=*,tokencleaner. 如果是通过kubeadm 创建的集群,会自动执行上述步骤。

鉴权模块会将token作为system:bootstrap:<Token ID>。它包含在system:bootsrappers 组中。命名和组是有意限制的,为了防止用户通过引导非法使用这些令牌。用户名和组可以被使用(被kubeadm 所使用),来制定适当的授权策略以支持集群引导。

更多资料请参考Bootstrap Tokens

静态密码文件

基础的认证可以通过在apiserver中通过--basic-auth-file=SOMEFILE 来开启。基础认证不存在过期,对密码的修改也必须要重启apiserver.请注意,为了方便起见,目前支持基本身份验证,直到我们让上述更安全的模式更容易使用。

基础认证文件是一个csv文件,至少包含3列:password, username, user id. 在k8s 1.6及以后版本,你可定义额外行来指定所属的group。例如:

    password,user,uid,"group1,group2,group3"

从http客户端使用基本认证时,API服务器需要一个值为Basic: BASE64ENCODED(USER:PASSWORD)的授权请求头.

Service Account Tokens

service account 是默认开启的。使用承载令牌来验证请求。该插件需要开启一下两个参数:
- --service-account-key-file 一个包含了PEM编码的秘钥,用于token签名。如果未开启该参数,默认使用apiserver 的TLS私钥。
- --service-account-lookup 如果开启该参数,从API中删除的token将被撤销。

service account 通常会被apiserver自动创建,会和通过ServiceAccount Admission Controller 在集群中运行的pod相关联。token会被挂载到一个约定好的目录下,并允许集群进程与apiserver的通信。pod通过serviceAccountName 字段来和具体账户关联。

Note: serviceAccountName 一般会自动添加,因此大部分情况该参数会被省略。

apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: default
spec:
  replicas: 3
  template:
    metadata:
    # ...
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        serviceAccountName: bob-the-bot

service account token 在集群外部使用是完全有效的,并且可以用来为长期工作创建身份,以便与Kubernetes API通信。手动创建service account 通过命令kubectl create serviceaccount <name>. 这会在当前的namespace创建并且关联一个密码。

$ kubectl create serviceaccount jenkins
serviceaccount "jenkins" created
$ kubectl get serviceaccounts jenkins -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  # ...
secrets:
- name: jenkins-token-1yvwg

创建的秘钥包含apiserver的公共CA和签名的JSON Web Token(JWT)。

$ kubectl get secret jenkins-token-1yvwg -o yaml
apiVersion: v1
data:
  ca.crt: (APISERVER'S CA BASE64 ENCODED)
  namespace: ZGVmYXVsdA==
  token: (BEARER TOKEN BASE64 ENCODED)
kind: Secret
metadata:
  # ...
type: kubernetes.io/service-account-token

Note: 秘钥的值是经过base64编码的。按照惯例Secret都已base64编码后存储。

签过名的JWT可以当做承载令牌来验证给定的service account.在使用token请求章节可以看到请求如何使用token. 通常为了访问集群内的apiserver, 这些秘钥(这里应该指的是token)会挂载到相关的pod上。但是秘钥(token)可以在集群外部使用。

service account 鉴定通过用户名 system:serviceaccount:<NAMESPACE>:<SERVICEACCOUNT>, 然后指派到组system:serviceaccounts 以及 system:serviceaccounts:<NAMESPACE>

WARNING: 由于service account token 以secret形式保存,拥有该secret可读权限的用户都能够以此service account来进行认证。因此在给service account的secret可读权限时需要谨慎。

OpenID Connect Token

应为没用到,所以就不翻译了

Webhook Token Authentication

Webhook 认证是定义一个钩子方法来验证token.

  • --authentication-token-webhook-config-file 指定一个kubeconfig 文件,描述如何远程的webhook服务
  • --authentication-token-webhook-cache-ttl 决定认证信息保存多长时间。默认两分钟

配置文件使用kubeconfig 文件格式。在文件中,“user” 指的是 apiserver webhook, “cluster” 指的是远程服务。示例如下:

# clusters refers to the remote service.
clusters:
  - name: name-of-remote-authn-service
    cluster:
      certificate-authority: /path/to/ca.pem         # CA for verifying the remote service.
      server: https://authn.example.com/authenticate # URL of remote service to query. Must use 'https'.

# users refers to the API server's webhook configuration.
users:
  - name: name-of-api-server
    user:
      client-certificate: /path/to/cert.pem # cert for the webhook plugin to use
      client-key: /path/to/key.pem          # key matching the cert

# kubeconfig files require a context. Provide one for the API server.
current-context: webhook
contexts:
- context:
    cluster: name-of-remote-authn-service
    user: name-of-api-sever
  name: webhook

当客户端尝试使用token向apiserver进行认证时,webhook使用包含令牌的对象查询远程服务。如果客户端请求头中缺少token时,kubernetes不会发起上述认证步骤。

请注意,webhook API对象与其他Kubernetes API对象具有相同的版本控制兼容性规则。实现者应该意识到Beta对象的宽松兼容性承诺,并检查请求的“apiVersion”字段以确保正确的反序列化。 此外,API服务器必须启用authentication.k8s.io/v1beta1 API扩展组(--runtime-config=authentication.k8s.io/v1beta1=true)。

请求的body体格式如下:

{
  "apiVersion": "authentication.k8s.io/v1beta1",
  "kind": "TokenReview",
  "spec": {
    "token": "(BEARERTOKEN)"
  }
}

当token认证成功时,远程服务返回信息格式如下:

{
  "apiVersion": "authentication.k8s.io/v1beta1",
  "kind": "TokenReview",
  "status": {
    "authenticated": true,
    "user": {
      "username": "janedoe@example.com",
      "uid": "42",
      "groups": [
        "developers",
        "qa"
      ],
      "extra": {
        "extrafield1": [
          "extravalue1",
          "extravalue2"
        ]
      }
    }
  }
}

失败时,返回信息如下:

{
  "apiVersion": "authentication.k8s.io/v1beta1",
  "kind": "TokenReview",
  "status": {
    "authenticated": false
  }
}

HTTP状态代码可以用来提供额外的错误上下文。

Authenticating Proxy

可以将APIserver 配置为从请求头中鉴定用户。例如X-Remote-User。该头部结合认证代理一起使用,认证代理负责设置头部值。

  • --requestheader-username-headers 必选, 大小写敏感。头部名按顺序检查用户标识。 包含一个值的第一个头部被用作用户名。
  • --requestheader-group-headers k8s1.6+, 可选参数,大小写敏感。建议使用X-Remote-Group头部字段。头部名按顺序检查用户组。 所有在该字段中的值都将被作为组名使用。
  • --requesetheader-extra-headers-prefix 1.6+, 可选, 大小写敏感。 X-Remote-Extra-. 头部前缀可用于查找有关用户的额外信息(通常由配置的授权插件使用)。 任何以任何指定的前缀开头的标题都将删除前缀,头部名称的其余部分将成为额外的键值,而头部字段则是额外的值。

例如:

--requestheader-username-headers=X-Remote-User
--requestheader-group-headers=X-Remote-Group
--requestheader-extra-headers-prefix=X-Remote-Extra-

请求头:

GET / HTTP/1.1
X-Remote-User: fido
X-Remote-Group: dogs
X-Remote-Group: dachshunds
X-Remote-Extra-Scopes: openid
X-Remote-Extra-Scopes: profile

产生的用户信息:

name: fido
groups:
- dogs
- dachshunds
extra:
  scopes:
  - openid
  - profile

为了预防头部字段欺骗, 认证代理在检查请求头之前,需要客户端向apiserver提供由指定CA颁发合法的证书。

  • --requestheader-client-ca-file 必选。 PEM编码证书。在检查用户名的请求头之前,必须针对指定文件中的证书颁发机构提交并验证有效的客户端证书。
  • --requestheader-allowed-names 可选。comman names(cn)清单。如果设置了该参数,在检查用户名的请求头之前,必须提供指定列表中具有comman name(cn)的有效客户端证书。 如果为空,则允许使用任何cn。

Keystone Password

在apiserver启动时,通过参数--experimental-keystone-url=<AuthURL> 来开启Keystone 验证。该插件在plugin/pkg/auth/authenticator(认证者)/password/keystone/keystone.go 中实现,当前使用基础认证。验证用户名和密码。

如果你为keystone服务器配置了自签名证书,可能需要在apiserver启动时设置--experimental-keystone-ca-file=SOMEFILE 参数。如果已经设置,experimental-keystone-ca-file中定义的ca会认证Keystone 服务器证书. 不然的话,会使用主机的ca根证书来认证。

有关如何使用keystone来管理项目和用户的详细信息,请参阅Keystone文档。 请注意,这个插件仍处于试验阶段,正在积极开发之中,并可能在后续版本中进行更改。

请参考 discussion, blueprint以及proposed changes以获取更详细的信息。

Anonymous requests

启用时,未被其他已配置身份验证方法拒绝的请求将被视为匿名请求,并给予system:anonymous的用户名和一组system:unuthenticated

例如,在配置了令牌认证和启用匿名访问的服务器上,提供无效承载令牌的请求将收到401 Unauthorized错误。 提供不记名令牌的请求将被视为匿名请求。

在1.5.1-1.5.x中,默认情况下匿名访问是禁用的,可以通过将--anonymous-auth=true选项传递给API服务器来启用。

在1.6+版本中,如果使用AlwaysAllow以外的授权模式,则默认启用匿名访问,并且可以通过将--anonymous-auth=false选项传递给API服务器来禁用。 从1.6开始,ABAC和RBAC授权人需要明确授权system:anonymoussystem:unauthenticated的组,因此授予对* 用户或*组访问权限的传统策略规则不包括匿名用户。

User impersonation

用户可以通过模拟请求头部充当另一个用户。例如,管理员可以使用此功能通过暂时模仿其他用户并查看请求是否被拒绝来调试授权策略。

模拟请求首先认证为请求用户,然后切换到模拟的用户信息。

  • 用户使用他们的证书和模拟请求头部进行API调用。
  • apiserver 认证用户
  • apiserver 确认已授权用户拥有模拟权限
  • 请求中的用户信息被替换成模拟的用户信息
  • 请求被评估,授权对模拟的用户信息起作用。

以下HTTP头部可用于执行模拟请求:

  • Impersonate-User: 要扮演用户的名称
  • Impersonate-Group: 要扮演用户的组名。可以出现多次来设置多个组。是个可选的头部,需要预先定义Impersonate-User
  • Impersonate-Extra-<extrs name>: 用于将额外字段与用户关联的动态标题。是个可选的头部,需要预先定义Impersonate-User

示例如下:

Impersonate-User: jane.doe@example.com
Impersonate-Group: developers
Impersonate-Group: admins
Impersonate-Extra-dn: cn=jane,ou=engineers,dc=example,dc=com
Impersonate-Extra-scopes: view
Impersonate-Extra-scopes: development

使用kubelet的时,设置--as参数来配置Impersonate-User头部,--as-group来配置Impoersonate_Group头部。

$ kubectl drain mynode
Error from server (Forbidden): User "clark" cannot get nodes at the cluster scope. (get nodes mynode)

$ kubectl drain mynode --as=superman --as-group=system:masters
node "mynode" cordoned
node "mynode" drained

为模仿用户,组或设置额外字段,模拟用户必须能够对正在模拟的属性的种类(“用户”,“组”等)执行“模拟”动词。 对于启用RBAC授权插件的集群,以下ClusterRole包含设置用户和组模拟头部所需的规则:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: impersonator
rules:
- apiGroups: [""]
  resources: ["users", "groups", "serviceaccounts"]
  verbs: ["impersonate"]

额外的字段被评估为资源“userextras”的子资源。 要允许用户使用额外字段“范围”的模拟头部,应授予用户以下角色:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: scopes-impersonator
# Can set "Impersonate-Extra-scopes" header.
- apiGroups: ["authentication.k8s.io"]
  resources: ["userextras/scopes"]
  verbs: ["impersonate"]

模拟头部的值也可以通过限制资源可以使用的资源名称来限制:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: limited-impersonator
rules:
# Can impersonate the user "jane.doe@example.com"
- apiGroups: [""]
  resources: ["users"]
  verbs: ["impersonate"]
  resourceNames: ["jane.doe@example.com"]

# Can impersonate the groups "developers" and "admins"
- apiGroups: [""]
  resources: ["groups"]
- verbs: ["impersonate"]
  resourceNames: ["developers","admins"]

# Can impersonate the extras field "scopes" with the values "view" and "development"
- apiGroups: ["authentication.k8s.io"]
  resources: ["userextras/scopes"]
  verbs: ["impersonate"]
  resourceNames: ["view", "development"]
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值