API Server 作为 Kubernetes 的网关,是用户访问和管理资源对象的入口。对于每个访问请求, API Server 都需要对访问者的合法性进行检查,包括身份验证、权限验证等等。Kubernetes 支持多种身份验证的方式,本文将对 OpenID Connect 认证进行介绍。
1 OpenID Connect(OIDC)介绍
OAuth(Open Authorization)是一个关于授权(authorization)的开放网络标准,允许用户授权第三方应用访问他们存储在其他服务提供者上的信息,而不需要将用户名和密码提供给第三方应用。OAuth 在全世界得到了广泛的应用,目前的版本是 2.0 。
OpenID Connect (OIDC) 是一种身份验证协议,基于 OAuth 2.0 系列规范。OAuth2 提供了 access_token 来解决授权第三方客户端访问受保护资源的问题,OpenID Connect 在这个基础上提供了 id_token 来解决第三方客户端标识用户身份的问题。
OpenID Connect 的核心在于,在 OAuth2 的授权流程中,同时提供用户的身份信息(id_token)给到第三方客户端。id_token 使用 JWT(JSON Web Token)格式进行封装,得益于 JWT 的自包含性,紧凑性以及防篡改机制等特点,使得 id_token 可以安全地传递给第三方客户端程序并且易于验证。
JSON Web Token(JWT)是一个开放的行业标准(RFC 7519),它定义了一种简洁的、自包含的协议格式,用于在通信双方间传递 JSON 对象,传递的信息经过数字签名可以被验证和信任。想要了解 JWT 的详细内容参见 JWT(JSON Web Token)。
2 Kubernetes OpenID Connect 认证流程
在 Kubernetes 中 OpenID Connect 的认证流程如下:
1.用户登录认证服务器。
2.认证服务器返回 access_token、id_token 和 refresh_token。
3.在使用 kubectl 时,将 id_token 设置为 --token 的参数值,或者将其直接添加到 kubeconfig 中。
4.kubectl 将 id_token 添加到 HTTP 请求的 Authorization 头部中,发送给 API Server。
5.API Server 通过检查配置中引用的证书来确认 JWT 的签名是否合法。
6.API Server 检查 id_token 是否过期。
7.API Server 确认用户是否有操作资源的权限。
8.鉴权成功之后,API 服务器向 kubectl 返回响应。
9.kubectl 向用户返回结果。
3 Keycloak 介绍
本文将会使用 Keycloak 作为 OpenID Connect 的认证服务器。keycloak 是一个开源的、面向现代应用和服务的 IAM(身份认证和访问控制)解决方案。Keycloak 提供了单点登录(SSO)功能,支持 OpenID Connect、OAuth 2.0、SAML 2.0 等协议,同时 Keycloak 也支持集成不同的身份认证服务,例如 LDAP、Active Directory、Github、Google 和 Facebook 等等。
在 Keycloak 中有以下几个主要概念:
领域(realms):领域管理着一批用户、证书、角色、组等等,不同领域之间的资源是相互隔离的,实现了多租户的效果。
客户端(clients):需要接入 Keycloak 实现用户认证的应用和服务。
用户(users):用户是能够登录到应用系统的实体,拥有相关的属性,例如电子邮件、用户名、地址、电话号码和生日等等。
组(groups):一组用户的集合,你可以将一系列的角色赋予定义好的用户组,一旦某用户属于该用户组,那么该用户将获得对应组的所有角色权限。
角色(roles):角色是 RBAC 的重要概念,用于表明用户的身份类型。
证书(credential):Keycloak 用于验证用户的凭证,例如密码、一次性密码、证书、指纹等等。
4 前提条件
接下来的章节将演示如何部署和配置 Keycloak 服务作为 API Server 的认证服务,需要确保完成了以下准备:
本实验使用的配置文件可以在:https://github.com/cr7258/kubernetes-guide/tree/master/authentication/openid 中获取。
5 部署 Keycloak 服务器
Kubernetes 要求使用的 OpenID Connect 认证服务必须是 HTTPS 加密的,运行以下脚本生成 Keycloak 服务器的私钥和证书签名请求,并使用 Kubernetes 的 CA 证书进行签发,当然这里你也可以另外生成自己的 CA 证书进行签发,如果这样做的话,请注意在 7.1 启用 OpenID Connect 认证章节中将 CA 证书挂载进 API Server 容器中。
#!/bin/bash# 创建目录存放生成的证书mkdir -p ssl
# 生成 x509 v3 扩展文件cat << EOF > ssl/req.cnf[req]req_extensions = v3_reqdistinguished_name = req_distinguished_name[req_distinguished_name][ v3_req ]basicConstraints = CA:FALSEkeyUsage = nonRepudiation, digitalSignature, keyEnciphermentsubjectAltName = IP:11.8.36.25 # Keycloak 服务器的 IP 地址EOF
# 生成 Keycloak 服务器私钥openssl genrsa -out ssl/tls.key 2048# 生成 Keycloak 服务器证书签名请求(CSR)openssl req -new -key ssl/tls.key -out ssl/tls.csr -subj "/CN=Keycloak" -config ssl/req.cnf# 使用 CA 签发 Keycloak 服务器证书openssl x509 -req -in ssl/tls.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out ssl/tls.crt -days 10 -extensions v3_req -extfile ssl/req.cnf
复制代码
这里使用 docker-compose 部署 Keycloak 以及依赖的数据库 PostgreSQL,docker-compose.yml 文件如下。需要将上面生成的服务器证书 tls.crt 和服务器私钥 tls.key 两个文件挂载到 Keycloak 容器的 /etc/x509/https 目录中。
version: '2'services: postgres: image: postgres:12.2 environment: POSTGRES_DB: keycloak POSTGRES_USER: keycloak POSTGRES_PASSWORD: keycloak keycloak: image: jboss/keycloak:16.1.1 environment: DB_VENDOR: POSTGRES DB_ADDR: postgres DB_DATABASE: keycloak DB_USER: keycloak DB_PASSWORD: keycloak KEYCLOAK_USER: admin # 用户名 KEYCLOAK_PASSWORD: czw123456 # 密码 volumes: - ./ssl:/etc/x509/https # 将服务器证书和私钥挂载到容器中 ports: - 80:8080 - 443:8443 depends_on: - postgres
复制代码
在后台启动 Keycloak 容器。
确认 Keycloak 和 PostgreSQL 已经成功启动。
浏览器输入 https://<IP 地址>:8443,访问 Keycloak 界面,用户名:admin,密码:czw123456。
6 配置 Keycloak
6.1 创建 Realm
首先,创建一个名称为 project-1 的 Realm(领域)。
6.2 创建 User
接下来手动创建一个用户。
用户名设置为 tom。
设置用户的密码,将 Temporary 参数置为 OFF,表示用户在第一次登陆时无需重新设置密码。
为用户添加属性 name,值设置为 tom,在 6.3 创建 Client 章节中会说明为什么这么做。
查看创建的用户。
6.3 创建 Client
Client (客户端)是请求 Keycloak 对用户进行身份验证的客户端,在本示例场景中,API Server 相当于一个客户端,负责向 Keycloak 发起身份认证请求。创建一个名为 kubernetes 的客户端,使用 openid-connect 协议对接。
客户端创建完成后,需要修改客户端的 Access Type 为 confidential,表示客户端通过 client secret 来获取令牌;Valid Redirect URIs 用于设置浏览器登录成功后有效的重定向 URL,http://* 匹配所有 HTTP 重定向的网址。默认情况下,登录成功后将会重定向到 http://localhost:8000。
要想让 Kubernetes 认识 Keycloak 中的用户,就需要在 Keycloak 返回的 id_token 中携带表明用户的身份的信息(例如用户名、组、邮箱等等),Keycloak 支持自定义声明并将它们添加到 id_token 中。如下所示,在 kubernetes 客户端中创建一个名为 name 的映射。
Keycloak 会将 Token Claim Name 中设置的内容作为键注入 JWT,值的内容来自 6.2 创建 User 章节中在用户属性中设置的 name 字段的值。也就是说在 JTW 的 payload 中可以看到 name:tom 这个键值对,在 7.1 启用 OpenID Connect 认证章节中将会使用 --oidc-username-claim=name 参数指定读取 JWT 中 name 字段的值作为用户名。
查看创建的 mapper。
6.4 延长 Token 时间(可选)
Keycloak 中设置的 access_token 和 id_token 的有效期默认是 1 分钟,为了方便后续的实验,这里将令牌的有效期延长至 30 分钟。
6.5 查看端点信息
点击 Realm Settings -> General -> Endpoints 可以看到请求 project-1 这个 Realm 相关的端点信息,在后面的章节中将会用到这些信息。
7 配置 Kubernetes
7.1 启用 OpenID Connect 认证
要启用 OpenID Connect 认证,需要在 API Server 容器的启动参数中添加以下配置:
--oidc-issuer-url:OpenID Connect 认证服务器的地址,只接受 HTTPS 加密的地址。
--oidc-client-id:客户端 ID。
--oidc-username:从 JWT Claim 中获取用户名的字段。
--oidc-username-claim:添加到 JWT Claim 中的用户名前缀,用于避免与现有的用户名产生冲突。例如,此标志值为 oidc: 时将创建形如 oidc:tom 的用户名,此标志值为 - 时,意味着禁止添加用户名前缀。 如果你为用户名添加的前缀是以 : 结尾的,在设置 API Server 时请用双引号包围,例如 "--oidc-username-prefix=oidc:" 。
--oidc-ca-file:签发 Keycloak 服务器证书的 CA 证书路径,如果签发证书的是受信任的 CA 机构,不用设置该参数。
关于 OpenID Connect 设置的参数详情参见 openid-connect-tokens。
7.2 设置 RBAC
创建一个名为 namespace-view 的角色,该角色拥有 namespaces 资源的读取权限,然后将该角色和用户 tom 进行绑定。
kind: ClusterRoleapiVersion: rbac.authorization.k8s.io/v1metadata: name: namespace-viewrules: - apiGroups: [""] resources: ["namespaces"] verbs: ["get", "watch", "list"] # 允许读取 namespace 信息---kind: ClusterRoleBindingapiVersion: rbac.authorization.k8s.io/v1metadata: name: tom-crbroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: namespace-view # 关联的角色subjects:- kind: User name: tom # 用户名 apiGroup: rbac.authorization.k8s.io
复制代码
8 获取身份验证令牌
现在我们已经完成了 Keycloak 和 Kubernetes 的设置,接下来我们尝试获取身份验证令牌,需要提供以下参数:
client_secret 可以在 kubernetes 客户端的 Credentials 中获取;请求的 URL 使用 6.5 查看端点信息章节中看到的 token_endpoint 的地址。
curl -ks -X POST https://11.8.36.25/auth/realms/project-1/protocol/openid-connect/token \-d grant_type=password -d client_id=kubernetes \-d username=tom -d password=tom123456 -d scope=openid \-d client_secret=YsXXff8TL5EXNmSpTeDLdKf99cYBLqqq
复制代码
以上命令将会返回 3 个令牌:access_token,id_token,refresh_token,令牌的有效期为 30 分钟(1800 秒)。
{ "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJZUFB3M0l2MHQ5WHEzMW0zLUtCemgyaHk3Um1LSEJ5dEtIdWhHSWY4Vkw0In0.eyJleHAiOjE2NDkxNTQ3MzgsImlhdCI6MTY0OTE1MjkzOCwianRpIjoiOTZmYzY2ZWMtMTFjNC00Y2JkLTkwNWYtMDhjMGQ4ODkyNjc3IiwiaXNzIjoiaHR0cHM6Ly8xMS44LjM2LjI1L2F1dGgvcmVhbG1zL3Byb2plY3QtMSIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiIwNGVjMDdjMy1mZjY0LTRjZDUtYTc3ZS03MzllOWU3OWVjMmIiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJrdWJlcm5ldGVzIiwic2Vzc2lvbl9zdGF0ZSI6IjQ1ODY1NjM2LTIyMTgtNGE0MC1hZDJlLTkzZGUyYmVkYmQzYiIsImFjciI6IjEiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsib2ZmbGluZV9hY2Nlc3MiLCJkZWZhdWx0LXJvbGVzLXByb2plY3QtMSIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCIsInNpZCI6IjQ1ODY1NjM2LTIyMTgtNGE0MC1hZDJlLTkzZGUyYmVkYmQzYiIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwibmFtZSI6InRvbSIsInByZWZlcnJlZF91c2VybmFtZSI6InRvbSJ9.h9F09-OZ9mFR4D6eUQ4lrTSRiSTcTXa8Kzd6B5NuWj7i_WpN4Lx_LKk9lVzb5Mh7ZeQScueYrTQ1ckn59MZdvZ3Y1c-zM8qhYsekSXLNk4HF9ijlIPi7NtlMdA_YUUc5IwcdzfSFJtcyP51CIsOxDto9-mwttlN1Cc-SotviTk4WEpy_T-Y4ZXFlBhrLjrx3o17nvMtEeM3SZbs2OlmlwnKNGs7AMC5FFq5hD-F_9eBR5GclIcLITsxLgRBI9QaSoWVWIVuvUSap04whHLLlQKKqo9sCr5bSUNRBDCCGhu3JLI5-wFZL8k59XSlxOu5MT7DeA8bXmkRdepUxfF6QWA", "expires_in": 1800, # access_token 和 id_token 的过期时间 "refresh_expires_in": 1800, # refresh_token 的过期时间 "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI3ZjMyMzBkNS0xNzZhLTQ1YjktOTUxNC0xZjBhY2JmODdhMzMifQ.eyJleHAiOjE2NDkxNTQ3MzgsImlhdCI6MTY0OTE1MjkzOCwianRpIjoiZTRjODllN2ItODllZi00MDFjLWEwZGMtZmQxZjc2MGMxN2UyIiwiaXNzIjoiaHR0cHM6Ly8xMS44LjM2LjI1L2F1dGgvcmVhbG1zL3Byb2plY3QtMSIsImF1ZCI6Imh0dHBzOi8vMTEuOC4zNi4yNS9hdXRoL3JlYWxtcy9wcm9qZWN0LTEiLCJzdWIiOiIwNGVjMDdjMy1mZjY0LTRjZDUtYTc3ZS03MzllOWU3OWVjMmIiLCJ0eXAiOiJSZWZyZXNoIiwiYXpwIjoia3ViZXJuZXRlcyIsInNlc3Npb25fc3RhdGUiOiI0NTg2NTYzNi0yMjE4LTRhNDAtYWQyZS05M2RlMmJlZGJkM2IiLCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIGVtYWlsIiwic2lkIjoiNDU4NjU2MzYtMjIxOC00YTQwLWFkMmUtOTNkZTJiZWRiZDNiIn0.B8k6olblNpS6aU5mrQ7_62K1pPibwhvlboxoVi3ENrA", "token_type": "Bearer", "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJZUFB3M0l2MHQ5WHEzMW0zLUtCemgyaHk3Um1LSEJ5dEtIdWhHSWY4Vkw0In0.eyJleHAiOjE2NDkxNTQ3MzgsImlhdCI6MTY0OTE1MjkzOCwiYXV0aF90aW1lIjowLCJqdGkiOiIxMzJkYzU4Zi0wNWQ4LTQwNGUtOTkyZi1mMmVkMDU3Y2QyOTciLCJpc3MiOiJodHRwczovLzExLjguMzYuMjUvYXV0aC9yZWFsbXMvcHJvamVjdC0xIiwiYXVkIjoia3ViZXJuZXRlcyIsInN1YiI6IjA0ZWMwN2MzLWZmNjQtNGNkNS1hNzdlLTczOWU5ZTc5ZWMyYiIsInR5cCI6IklEIiwiYXpwIjoia3ViZXJuZXRlcyIsInNlc3Npb25fc3RhdGUiOiI0NTg2NTYzNi0yMjE4LTRhNDAtYWQyZS05M2RlMmJlZGJkM2IiLCJhdF9oYXNoIjoiWm5UVUtwYUxKRno2RHZTSlNEckZQUSIsImFjciI6IjEiLCJzaWQiOiI0NTg2NTYzNi0yMjE4LTRhNDAtYWQyZS05M2RlMmJlZGJkM2IiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm5hbWUiOiJ0b20iLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJ0b20ifQ.jDTGKWsvg-2z-01isqOpdHqiGSpiXxC3JKdgcVnBLx26xIEZdrjjsQxEXMd0yXJCqdiD4VNaQ6eHHJCjg3gyJE6_TT3XsxLafpBcfNb0N2TEdxQQxmwfUwK18SWAPFoUqd0ErhvZ_LelecOqytHOV2fOgkH58LCTbTP6mVvSsRuxo5Yp74scMLV-UWxi0ABT6NC3U5L_iiQBct_VAqQMxHu1Inv0RRYBA14L6AHtjNmhGoXTYakXqH_4PqZqlxt9rx-uINkRSlY0rV-eWyS-8xaOhKDu4zLWhJTgE_4YguNi2jXcd5ppM6p6uOzM48-az1flXpsPo8VUDgNsfrzg3A", "not-before-policy": 0, "session_state": "45865636-2218-4a40-ad2e-93de2bedbd3b", "scope": "openid profile email"}
复制代码
id_token 被编码为 JTW 格式的数据,将内容复制到 https://jwt.io/ 网站上可以看到 id_token 的内容,在 payload 部分中可以看到标识的用户信息:name:tom。
请求 API Server 列出所有 namespace,在 curl 命令中使用 -H 参数将 id_token 附加到 HTTP 请求的 Header 中。
curl -k https://11.8.36.162:6443/api/v1/namespaces \ -H "Authorization: Bearer <id_token>" # 返回结果 { "kind": "NamespaceList", "apiVersion": "v1", "metadata": { "resourceVersion": "1120382" }, "items": [ { "metadata": { "name": "calico-apiserver", "uid": "3272d2ab-f842-4552-a87a-a9a7a14b3768", "resourceVersion": "1679", "creationTimestamp": "2022-03-29T02:21:45Z", "labels": { "kubernetes.io/metadata.name": "calico-apiserver", "name": "calico-apiserver" },......
复制代码
我们刚刚申请的令牌的有效期是 30 分钟,OAuth 2.0 允许用户自动更新令牌,在令牌到期之前,可以使用 refresh_token 发送一个请求,去更新令牌。
curl -ks -X POST https://11.8.36.25/auth/realms/project-1/protocol/openid-connect/token \-d grant_type=refresh_token -d client_id=kubernetes \-d client_secret=YsXXff8TL5EXNmSpTeDLdKf99cYBLqqq \-d refresh_token=<refresh_token>"
复制代码
Keycloak 服务器将会返回一个新的 access_token,id_token 和 refresh_token。
{ "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJZUFB3M0l2MHQ5WHEzMW0zLUtCemgyaHk3Um1LSEJ5dEtIdWhHSWY4Vkw0In0.eyJleHAiOjE2NDkxNTUwOTksImlhdCI6MTY0OTE1MzI5OSwianRpIjoiNDUzZTU0MzctOGM0MC00NjA4LThmZmEtM2M5Nzc3MGU2MDczIiwiaXNzIjoiaHR0cHM6Ly8xMS44LjM2LjI1L2F1dGgvcmVhbG1zL3Byb2plY3QtMSIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiIwNGVjMDdjMy1mZjY0LTRjZDUtYTc3ZS03MzllOWU3OWVjMmIiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJrdWJlcm5ldGVzIiwic2Vzc2lvbl9zdGF0ZSI6IjQ1ODY1NjM2LTIyMTgtNGE0MC1hZDJlLTkzZGUyYmVkYmQzYiIsImFjciI6IjEiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsib2ZmbGluZV9hY2Nlc3MiLCJkZWZhdWx0LXJvbGVzLXByb2plY3QtMSIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCIsInNpZCI6IjQ1ODY1NjM2LTIyMTgtNGE0MC1hZDJlLTkzZGUyYmVkYmQzYiIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwibmFtZSI6InRvbSIsInByZWZlcnJlZF91c2VybmFtZSI6InRvbSJ9.DUm3Ju1mmZbl_tyKCMHfUnXTJQ3-M33rcQ3WuuX_7yhEQLK086mC4TZwi0chayBB72Ge6gX9exNkhl8FPMEbw41Qrr8wHsLev-cfJWq_jnnjVKXH3hvwIR-APr-YOjL0UUDAmIGW9FUi4iPOHSvinyyii4AHy_PT4L7OlYdnG3SWGs-0g5qbIl4Sm8vMYMz7bkIU0r7Vu7bxzPnflT3yzP6rTd3Ej6DsWkddSseaAbEOLeDW6pv_YBkhMH8gbcxGtVS5THnnfC--Qr9iIw7v1OFXH3olUFK5S9_vt99fsaHjruwAKUXoSS-BbzJFsJFnXnSFeRuXsIx6M95O94pb4w", "expires_in": 1800, "refresh_expires_in": 1800, "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI3ZjMyMzBkNS0xNzZhLTQ1YjktOTUxNC0xZjBhY2JmODdhMzMifQ.eyJleHAiOjE2NDkxNTUwOTksImlhdCI6MTY0OTE1MzI5OSwianRpIjoiNmM2YTJmN2QtNzNlMi00MTY1LTg2MmEtZDU3YmJlYmMwNmU3IiwiaXNzIjoiaHR0cHM6Ly8xMS44LjM2LjI1L2F1dGgvcmVhbG1zL3Byb2plY3QtMSIsImF1ZCI6Imh0dHBzOi8vMTEuOC4zNi4yNS9hdXRoL3JlYWxtcy9wcm9qZWN0LTEiLCJzdWIiOiIwNGVjMDdjMy1mZjY0LTRjZDUtYTc3ZS03MzllOWU3OWVjMmIiLCJ0eXAiOiJSZWZyZXNoIiwiYXpwIjoia3ViZXJuZXRlcyIsInNlc3Npb25fc3RhdGUiOiI0NTg2NTYzNi0yMjE4LTRhNDAtYWQyZS05M2RlMmJlZGJkM2IiLCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIGVtYWlsIiwic2lkIjoiNDU4NjU2MzYtMjIxOC00YTQwLWFkMmUtOTNkZTJiZWRiZDNiIn0.N8jutxJkeEallahU5RdHkv4Lctgv8ojenuZFwrxDjPo", "token_type": "Bearer", "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJZUFB3M0l2MHQ5WHEzMW0zLUtCemgyaHk3Um1LSEJ5dEtIdWhHSWY4Vkw0In0.eyJleHAiOjE2NDkxNTUwOTksImlhdCI6MTY0OTE1MzI5OSwiYXV0aF90aW1lIjowLCJqdGkiOiIzYzljZmY2Ny01NGZlLTQ4MWItYjkwYy0xMmU4ODQwMGE3YmIiLCJpc3MiOiJodHRwczovLzExLjguMzYuMjUvYXV0aC9yZWFsbXMvcHJvamVjdC0xIiwiYXVkIjoia3ViZXJuZXRlcyIsInN1YiI6IjA0ZWMwN2MzLWZmNjQtNGNkNS1hNzdlLTczOWU5ZTc5ZWMyYiIsInR5cCI6IklEIiwiYXpwIjoia3ViZXJuZXRlcyIsInNlc3Npb25fc3RhdGUiOiI0NTg2NTYzNi0yMjE4LTRhNDAtYWQyZS05M2RlMmJlZGJkM2IiLCJhdF9oYXNoIjoiZHhfSDc2eFZEUUtseUd1Z2tHZlRlQSIsImFjciI6IjEiLCJzaWQiOiI0NTg2NTYzNi0yMjE4LTRhNDAtYWQyZS05M2RlMmJlZGJkM2IiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm5hbWUiOiJ0b20iLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJ0b20ifQ.IXnHePIhj7vjxPtENmTsv1PJ9xXrlowtMsR4akFblGEo__YYWs4GWY0aFOKGQTyFh6sVtGy7olOxEcHwgVRkp7Sfzeplx7o9Z-c5OYQORqmM0pX329oT9VfCBMMBX5ifIZPPfUlxZVLmygXUBk6LhnxD9MDzThEpHscoNnbHAODjSI2b_pTBOcLnr-inXl3klvaLi_Ti8SPCgd-cssd093DyvVK8Gb_UnpygtNVrailn-OU59wZu7wl-ah-pSqi9pAQTc3S4SJ_5aE722I23r6zxGwqghBxRKGqNS9vGcHsGgRfBHUQZOwa_w0cHyfvRfwVaqLn3_8JDrW-aCn3FuA", "not-before-policy": 0, "session_state": "45865636-2218-4a40-ad2e-93de2bedbd3b", "scope": "openid profile email"}
复制代码
9 用户访问资源
9.1 方式一:OIDC 身份认证组件
接下来使用以下命令在 kubeconfig 文件中为用户 tom 添加新的凭据,idp-issuer-url 参数的 URL 使用 6.5 查看端点信息章节中看到的 issuer 的地址。
kubectl config set-credentials tom \ --auth-provider=oidc \ --auth-provider-arg=idp-issuer-url=https://11.8.36.25/auth/realms/project-1 \ --auth-provider-arg=client-id=kubernetes \ --auth-provider-arg=client-secret=YsXXff8TL5EXNmSpTeDLdKf99cYBLqqq \ --auth-provider-arg=refresh-token=<refresh_token> \ --auth-provider-arg=id-token=<id_token> \ --auth-provider-arg=idp-certificate-authority=/etc/kubernetes/pki/ca.crt
复制代码
然后在 kubectl 命令中使用 --user 参数指定使用 tom 用户进行访问,可以看到该用户只有获取 namespace 的权限。
# 可以获取 namespace$ kubectl --user tom get namespaceNAME STATUS AGEcalico-apiserver Active 7d7hcalico-system Active 7d8hdefault Active 7d8hkube-node-lease Active 7d8hkube-public Active 7d8hkube-system Active 7d8htigera-operator Active 7d8h
# 没有获取 pod 的权限$ kubectl --user tom get podError from server (Forbidden): pods is forbidden: User "tom" cannot list resource "pods" in API group "" in the namespace "default"
复制代码
我们可以为该用户添加上下文,方便在多集群/多用户的环境下进行切换。
kubectl config set-context tom --cluster=<集群名> --user=tom
复制代码
查看 ~/.kube/config 文件可以看到为 tom 用户添加的凭据和上下文。
切换到用户 tom 进行访问。
# 切换用户上下文kubectl config use-context tomkubectl get namespaces
复制代码
9.2 方式二:使用 --token 选项
kubectl 命令允许使用 --token 选项传递一个令牌。
kubectl get namespace --user tom --token=<id_token>
复制代码
9.3 方式三:使用 Kubelogin
前面介绍的方式一和方式二有一个缺点,那就是在令牌过期后需要手动获取新的令牌,然后更新到 kubeconfig 文件或者 --token 参数中。好在社区提供了 kubelogin 插件可以解决这一繁琐的问题,kubelogin 是一个用于 Kubernetes OpenID Connect 进行身份认证的插件,也称为 kubectl oidc-login。当运行 kubectl 命令时,kubelogin 会打开浏览器,用户需要输入用户名和密码登录程序,认证通过后,kubelogin 会从认证服务器获取一个令牌,然后 kubectl 就可以使用该令牌和 API Server 进行通信,具体的流程图如下:
kubelogin 插件支持不同的方式安装,包括 Homebrew,Krew,Chocolatey 等等。
# Homebrew (macOS and Linux)brew install int128/kubelogin/kubelogin
# Krew (macOS, Linux, Windows and ARM)kubectl krew install oidc-login
# Chocolatey (Windows)choco install kubelogin
复制代码
使用以下命令在 kubeconfig 文件中添加用户 tom 的凭证,--insecure-skip-tls-verify 参数表示忽略自签名证书不安全的风险。当用户 tom 执行 kubectl 命令时,将会通过 kubectl oidc-login get-token 命令获取令牌。
kubectl config set-credentials tom \ --exec-api-version=client.authentication.k8s.io/v1beta1 \ --exec-command=kubectl \ --exec-arg=oidc-login \ --exec-arg=get-token \ --exec-arg=--oidc-issuer-url=https://11.8.36.25/auth/realms/project-1 \ --exec-arg=--oidc-client-id=kubernetes \ --exec-arg=--oidc-client-secret=YsXXff8TL5EXNmSpTeDLdKf99cYBLqqq \ --exec-arg=--insecure-skip-tls-verify
复制代码
有关 kubelogin 的详细参数参见:kubelogin usage and options。设置完毕后,使用 kubectl 命令访问时,浏览器会自动弹出 Keycloak 认证页面,输入用户名和密码后就可以正常访问相应的资源了。
kubectl --user=tom get namespace
复制代码
kubelogin 的 id_token 和 refresh_token 缓存在 ~/.kube/cache/oidc-login/ 目录中,没有超过令牌有效期时,无需再次输入用户名和密码进行认证。
10 总结
本文通过详细的步骤为大家展示了如何让 API Server 使用 OpenID Connect 协议集成 Keycloak 进行身份认证,同时介绍了如何使用 kubectl 和 kubelogin 进行用户登录认证。
参考资料
欢迎关注
评论