Kubernetes 认证

Kubernetes 账户

所有Kubernetes集群有两类用户:由Kubernetes管理的Service Accounts (服务账户)和(Users Accounts) 普通账户。

普通账户是假定被外部或独立服务管理的,由管理员分配keys,用户像使用Keystone或google账号一样,被存储在包含usernames和passwords的list的文件里。

需要注意:在Kubernetes中不能通过API调用将普通用户添加到集群中

相比之下,Service Accounts是由Kubernetes API管理的帐户。它们被绑定到特定的命名空间,并由APIserver自动创建或通过API调用手动创建。Service Accounts与存储为Secrets的一组证书相关联,这些凭据被挂载到pod中,以便集群进程与Kubernetes API通信。

验证策略

Kubernetes用户可以使用client certificates、bearer tokens、authenticating proxy、HTTP basic auth等认证插件来验证API请求。比如HTTP请求到达API Server,插件会尝试将以下属性与请求关联:

  • UserName:普通用户的字符串。比如“kube-admin”或“xxxx@kubernetes.org.cn”。
  • UID:普通用户的字符串,比UserName更具有唯一性。
  • Groups:一组字符串,将常用的user分组的组合字符串。
  • Extra fields:将一些有用的字符串信息映射成的列表。

所有values值对于认证系统都是不透明的,只有当授权解释后才有意义。

可以同时启用多个认证方法。最少使用两种:

  • 为Service Accounts使用service account tokens方法。
  • 使用另外一种用户认证方法。

system:authenticated组被包括在所有已认证用户的组列表中。

X509 客户证书

使用API Server启动时配置–client-ca-file = SOMEFILE选项来启用客户端证书认证。引用的文件必须包含,提交给API Server的客户端证书的证书颁发机构。如果客户端提交的证书通过,通用名称(common name)将被用作请求的用户名。

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

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

将为“jbeda”用户名创建一个CSR,所属组为”app1”和“app2”的签名请求。

Static Token File

启动静态Token文件需要API Server启动时配置- -token-auth-file=SOMEFILE选项时,目前,tokens状态可以持续存在,需要重新启用 API server,token last 才会重启。

token文件是至少包含3列的csv格式文件: token, user name, user uid,第四列为可选group 名项。注意:如果有多个group名,列必须用””双引号包含其中,例如

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

Putting a Bearer Token in a Request

当http客户端使用 bearer token 认证时,API Server需要一个值为Bearer THETOKEN的授权头。bearer token必须可以放在HTTP请求头中且值不需要转码和引用的一个字符串。例如:bearer token :31ada4fd-adec-460c-809a-9e56ceb75269,会在HTTP header中按下面的方式呈现:

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

Bootstrap Tokens

功能目前为Alpha级别

Kubernetes包括一个dynamically-managed的Bearer token类型,称为Bootstrap Token。这些token作为Secret存储在kube-system namespace中,可以动态管理和创建。Controller Manager包含一个TokenCleaner Controller,如果到期时可以删除Bootstrap Tokens Controller。

Tokens的形式是[a-z0-9]{6}.[a-z0-9]{16}。第一个组件是Token ID,第二个组件是Token Secret。可以在HTTP header中指定Token,如下所示:

Authorization: Bearer 781292.db7bc3a58fc5f07e

如何使用Kubeadm来管理Token,以及想了解更多BootstrapToken文档,请参考Bootstrap Token

Static Password File

Basic Authentication是通过在API Server启动是配置-Basic-authfile=file选项实现,Basic认证凭证一直有效,并且如果没有重新启动API Server,密码将无法更改。

Basic Authentication文件csv也是格式文件,且必须包含:password, user, uid。在Kubernetes 1.6+版本中,可以指定一个可选的第四列,使用逗号来分隔group名,如果有多个组,必须使用双引号(“)。参考以下示例:

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

当从http客户端使用Basic Authentication时,API Server需要在请求头加入Basic BASE64ENCODED(USER:PASSWORD)

OpenID Connect Tokens

OpenID Connect 是由一些云提供商支持的OAuth2认证机制,特别是Azure Active Directory,Salesforce和Google。OAuth2协议的主要扩展是增加一个额外字段,返回ID Token的access token。这个token被服务器签名的JSON Web Token (JWT) ,常见的字段如user’s email。

为了鉴定user,认证器使用OAuth2 token响应的id_token 步骤如下:

Kubernetes OpenID Connect Flow

  1. 登录identity provider
  2. identity provider提供一个access_token,id_token和refresh_token
  3. 在使用kubectl时,使用id_token的—token flag或者直接添加到kubeconfig
  4. kubectl 在header通过Authorization字段将id_token发送到 API server
  5. API Server检查配置中证书来确保JWT签名的有效性
  6. 检查id_token是否过期
  7. 确保user被授权
  8. 当被授权API Server会返回对kubectl响应
  9. kubectl向user提供反馈

由于所有认证需要的数据在id_token中,所以Kubernetes不需要向身份提供者“phone home”,每个请求都是在无状态的模型中,它为认证提供可扩展的解决方案。 也带来了一些挑战:

  1. Kubernetes没有“web interface”来触发认证过程,没有任何浏览器或接口来收集凭据,这就是为什么需要首先向身份提供者进行认证的原因。
  2. id_token不能被撤销,它像一个certificate持续时间非常短(只有几分钟),所以每隔几分钟就得到一个新的token。
  3. 如果不使用kubectl -proxy命令或注入id_token的反向代理,将无法向Kubernetes dashboard 进行认证。

Configuring the API Server

启用插件,请在API Server上配置如下的选项:

Parameter Description Example Required
- -oidc-issuer-url URL of the provider which allows the API server to discover public signing keys. Only URLs which use the https:// scheme are accepted. This is typically the provider’s discovery URL without a path, for example “https://accounts.google.com” or “https://login.salesforce.com”. This URL should point to the level below .well-known/openid-configuration If the discovery URL is https://accounts.google.com/.well-known/openid-configuration the value should be https://accounts.google.com
- -oidc-client-id A client id that all tokens must be issued for. kubernetes
- -oidc-username-claim WT claim to use as the user name. By default sub, which is expected to be a unique identifier of the end user. Admins can choose other claims, such as email or name, depending on their provider. However, claims other than email will be prefixed with the issuer URL to prevent naming clashes with other plugins. sub
- -oidc-groups-claim JWT claim to use as the user’s group. If the claim is present it must be an array of strings. groups
- -oidc-ca-file The path to the certificate for the CA that signed your identity provider’s web certificate. Defaults to the host’s root CAs. /etc/kubernetes/ssl/kc-ca.pem

如果--oidc-username-claim选择除Email以外的声明,该值将以--oidc-issuer-url为前缀,以防止与现有Kubernetes名称(例如system:users)的冲突。 例如,如果提供商URL是https://accounts.google.com,username声明映射到jane,该插件对user进行认证为:

https://accounts.google.com#jane

Kubernetes不提供OpenID Connect Identity Provider。可以使用现有公开的OpenID Connect  Identity Provider(如Google或其他)。或者可以使用者些CoreOS dexKeycloak,CloudFoundry UAA或Tremolo Security的OpenUnison

For an identity provider to work with Kubernetes it must

  1. 支持OpenID connect discovery;(not all do)
  2. 在TLS中确保密码有效
  3. 一个CA签名的证书(商业或个人的)

其他安装设置说明:

使用kubectl

选项1-OIDC AUTHENTICATOR

第一个选择使用oidc authenticator。这个认证需要使用id_token,refresh_token和OIDC client_secret,并会自动更新你的token令牌。

kubectl config set-credentials USER_NAME \
   --auth-provider=oidc \
   --auth-provider-arg=idp-issuer-url=( issuer url ) \
   --auth-provider-arg=client-id=( your client id ) \
   --auth-provider-arg=client-secret=( your client secret ) \
   --auth-provider-arg=refresh-token=( your refresh token ) \
   --auth-provider-arg=idp-certificate-authority=( path to your ca certificate ) \
   --auth-provider-arg=id-token=( your id_token ) \
   --auth-provider-arg=extra-scopes=( comma separated list of scopes to add to "openid email profile", optional )

例如,在对身份提供商进行认证之后,运行下面的命令:

kubectl config set-credentials mmosley  \
        --auth-provider=oidc  \
        --auth-provider-arg=idp-issuer-url=https://oidcidp.tremolo.lan:8443/auth/idp/OidcIdP  \
        --auth-provider-arg=client-id=kubernetes  \
        --auth-provider-arg=client-secret=1db158f6-177d-4d9c-8a8b-d36869918ec5  \
        --auth-provider-arg=refresh-token=q1bKLFOyUiosTfawzA93TzZIDzH2TNa2SMm0zEiPKTUwME6BkEo6Sql5yUWVBSWpKUGphaWpxSVAfekBOZbBhaEW+VlFUeVRGcluyVF5JT4+haZmPsluFoFu5XkpXk5BXqHega4GAXlF+ma+vmYpFcHe5eZR+slBFpZKtQA= \
        --auth-provider-arg=idp-certificate-authority=/root/ca.pem \
        --auth-provider-arg=extra-scopes=groups \
        --auth-provider-arg=id-token=eyJraWQiOiJDTj1vaWRjaWRwLnRyZW1vbG8ubGFuLCBPVT1EZW1vLCBPPVRybWVvbG8gU2VjdXJpdHksIEw9QXJsaW5ndG9uLCBTVD1WaXJnaW5pYSwgQz1VUy1DTj1rdWJlLWNhLTEyMDIxNDc5MjEwMzYwNzMyMTUyIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL29pZGNpZHAudHJlbW9sby5sYW46ODQ0My9hdXRoL2lkcC9PaWRjSWRQIiwiYXVkIjoia3ViZXJuZXRlcyIsImV4cCI6MTQ4MzU0OTUxMSwianRpIjoiMm96US15TXdFcHV4WDlHZUhQdy1hZyIsImlhdCI6MTQ4MzU0OTQ1MSwibmJmIjoxNDgzNTQ5MzMxLCJzdWIiOiI0YWViMzdiYS1iNjQ1LTQ4ZmQtYWIzMC0xYTAxZWU0MWUyMTgifQ.w6p4J_6qQ1HzTG9nrEOrubxIMb9K5hzcMPxc9IxPx2K4xO9l-oFiUw93daH3m5pluP6K7eOE6txBuRVfEcpJSwlelsOsW8gb8VJcnzMS9EnZpeA0tW_p-mnkFc3VcfyXuhe5R3G7aa5d8uHv70yJ9Y3-UhjiN9EhpMdfPAoEB9fYKKkJRzF7utTTIPGrSaSU6d2pcpfYKaxIwePzEkT4DfcQthoZdy9ucNvvLoi1DIC-UocFD8HLs8LYKEqSxQvOcvnThbObJ9af71EwmuE21fO5KzMW20KtAeget1gnldOosPtz1G5EwvaQ401-RPQzPGMVBld0_zMCAwZttJ4knw

将产生如下配置:

users:
- name: mmosley
  user:
    auth-provider:
      config:
        client-id: kubernetes
        client-secret: 1db158f6-177d-4d9c-8a8b-d36869918ec5
        extra-scopes: groups
        id-token: eyJraWQiOiJDTj1vaWRjaWRwLnRyZW1vbG8ubGFuLCBPVT1EZW1vLCBPPVRybWVvbG8gU2VjdXJpdHksIEw9QXJsaW5ndG9uLCBTVD1WaXJnaW5pYSwgQz1VUy1DTj1rdWJlLWNhLTEyMDIxNDc5MjEwMzYwNzMyMTUyIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL29pZGNpZHAudHJlbW9sby5sYW46ODQ0My9hdXRoL2lkcC9PaWRjSWRQIiwiYXVkIjoia3ViZXJuZXRlcyIsImV4cCI6MTQ4MzU0OTUxMSwianRpIjoiMm96US15TXdFcHV4WDlHZUhQdy1hZyIsImlhdCI6MTQ4MzU0OTQ1MSwibmJmIjoxNDgzNTQ5MzMxLCJzdWIiOiI0YWViMzdiYS1iNjQ1LTQ4ZmQtYWIzMC0xYTAxZWU0MWUyMTgifQ.w6p4J_6qQ1HzTG9nrEOrubxIMb9K5hzcMPxc9IxPx2K4xO9l-oFiUw93daH3m5pluP6K7eOE6txBuRVfEcpJSwlelsOsW8gb8VJcnzMS9EnZpeA0tW_p-mnkFc3VcfyXuhe5R3G7aa5d8uHv70yJ9Y3-UhjiN9EhpMdfPAoEB9fYKKkJRzF7utTTIPGrSaSU6d2pcpfYKaxIwePzEkT4DfcQthoZdy9ucNvvLoi1DIC-UocFD8HLs8LYKEqSxQvOcvnThbObJ9af71EwmuE21fO5KzMW20KtAeget1gnldOosPtz1G5EwvaQ401-RPQzPGMVBld0_zMCAwZttJ4knw
        idp-certificate-authority: /root/ca.pem
        idp-issuer-url: https://oidcidp.tremolo.lan:8443/auth/idp/OidcIdP
        refresh-token: q1bKLFOyUiosTfawzA93TzZIDzH2TNa2SMm0zEiPKTUwME6BkEo6Sql5yUWVBSWpKUGphaWpxSVAfekBOZbBhaEW+VlFUeVRGcluyVF5JT4+haZmPsluFoFu5XkpXk5BXq
      name: oidc

如果id_token过期,kubectl将尝试使用refresh_token和client_secret来刷新id_token,在kube/.config中存储refresh_token和id_token新的值。

选项 2 - USE THE --TOKEN OPTION

kubectl命令允许你使用--token选项传入一个token。只需将idtoken粘贴到这个选项中:

kubectl --token=eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL21sYi50cmVtb2xvLmxhbjo4MDQzL2F1dGgvaWRwL29pZGMiLCJhdWQiOiJrdWJlcm5ldGVzIiwiZXhwIjoxNDc0NTk2NjY5LCJqdGkiOiI2RDUzNXoxUEpFNjJOR3QxaWVyYm9RIiwiaWF0IjoxNDc0NTk2MzY5LCJuYmYiOjE0NzQ1OTYyNDksInN1YiI6Im13aW5kdSIsInVzZXJfcm9sZSI6WyJ1c2VycyIsIm5ldy1uYW1lc3BhY2Utdmlld2VyIl0sImVtYWlsIjoibXdpbmR1QG5vbW9yZWplZGkuY29tIn0.f2As579n9VNoaKzoF-dOQGmXkFKf1FMyNV0-va_B63jn-_n9LGSCca_6IVMP8pO-Zb4KvRqGyTP0r3HkHxYy5c81AnIh8ijarruczl-TK_yF5akjSTHFZD-0gRzlevBDiH8Q79NAr-ky0P4iIXS8lY9Vnjch5MF74Zx0c3alKJHJUnnpjIACByfF2SCaYzbWFMUNat-K1PaUk5-ujMBG7yYnr95xD-63n8CO8teGUAAEMx6zRjzfhnhbzX-ajwZLGwGUBT4WqjMs70-6a7_8gZmLZb2az1cZynkFRj2BaCkVT3A2RrjeEwZEtGXlMqKJ1_I2ulrOVsYx01_yD35-rw get nodes

Webhook Token Authentication

Webhook authentication is a hook for verifying bearer tokens

  • - -authentication-token-webhook-config-file 配置文件描述了如何访问远程webhook服务
  • - -authentication-token-webhook-cache-ttl 缓存认证时间。默认2分钟

配置文件使用kubeconfig file format。在文件中,“users”指的是API服务器的webhook,“clusters”指的是远程服务。示例如下:

# 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

当客户端使用如上所述的bearer token与API服务器进行认证时,认证webhook通过一个包含token的review 对象来查询远程服务。Kubernetes不会对缺少这样的头的请求提出质疑。( Kubernetes will not challenge a request that lacks such a header.)??

注意 webhook API对象与其他Kubernetes API对象一样受版本兼容性规则的约束,选择需谨慎。

请求主体采用的格式:

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

远程服务预计将填写请求的TokenAccessReviewStatus字段,以示登录成功。 响应主体体的“spec”字段被忽略。 bearer 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 status codes can be used to supply additional error context

Authenticating Proxy

API服务器可以根据header values配置来识别users ,如X-Remote-User。

  • –requestheader-username-headers 必选,不区分大小写。按顺序检查Header names用于识别用户身份,第一包含Value的Header用于username。
  • –requestheader-group-headers 1.6+以上,可选,不区分大小写。 建议使用“X-Remote-Group”。按顺序检查Header Names用于识别user’s groups。Header中指定的所有Value均用作Group Names。
  • –requestheader-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.1X-Remote-User: fidoX-Remote-Group: dogsX-Remote-Group: dachshundsX-Remote-Extra-Scopes: openidX-Remote-Extra-Scopes: profile

将会产生的用户信息:

name: fidogroups:- dogs- dachshundsextra:  scopes:  - openid  - profile

为了防止header欺骗,Authenticating Proxy需要在检查请求header之前,向API服务器提交有效的客户端证书,以针对指定的CA进行验证。

–requestheader-client-ca-file  必选, PEM-encoded的证书包。在为用户名检查请求header之前,必须根据指定文件中的证书颁发机构呈现和验证有效的客户端证书。

–requestheader-allowed-names 可选,(common names)通用名称(cn)List。如果设置,则在检查请求header用户名之前,必须提交List中指定(common names)通用名中有效的客户端证书。

Keystone Password

Keystone认证通过--experimental-keystone-url=<AuthURL> 在启动期间将选项传递给API服务器来启用。该插件已实现,plugin/pkg/auth/authenticator/password/keystone/keystone.go目前使用basic auth来验证用户名和密码。

如果为Keystone服务器配置了自签名证书,则需要--experimental-keystone-ca-file=SOMEFILE在启动Kubernetes API服务器时设置该选项。设置完成后Keystone服务器的证书将由其中一个authorities进行验证 experimental-keystone-ca-file。否则将由主机的根证书颁发机构验证。

有关如何使用keystone管理项目和users的详细信息,请参阅 Keystone文档。需要注意此插件目前处于测试开发阶段。

更多详细信息,请参阅 discussionblueprintproposed changes

K8S中文社区微信公众号

译者

蒲公英

我是一朵蒲公英,哗啦啦的飞!