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_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = 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: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: namespace-view
rules:
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "watch", "list"] # 允许读取 namespace 信息
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: tom-crb
roleRef:
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 namespace
NAME STATUS AGE
calico-apiserver Active 7d7h
calico-system Active 7d8h
default Active 7d8h
kube-node-lease Active 7d8h
kube-public Active 7d8h
kube-system Active 7d8h
tigera-operator Active 7d8h
# 没有获取 pod 的权限
$ kubectl --user tom get pod
Error 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 tom
kubectl 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 进行用户登录认证。
参考资料
欢迎关注
评论