Kubernetes 认证
Mar 17, 2020 20:30 · 1417 words · 3 minute read
Kubernetes API 请求访问控制
向 Kubernetes API server 发起请求有两种情况:
- 人机交互的过程(kubetl 客户端操作)
- Pod 中的应用程序调用 Kubernetes API
当 API server 收到请求,会进入访问控制流程:
- 认证阶段(Authentication):判断请求用户是否能够合法访问 Kubernetes 集群,如果请求非法,API server 会返回 401 HTTP 状态码;
- 鉴权阶段(Authorization):API server 根据 Kubernetes 集群中已定义的 RBAC 规则判断用户是否有权限操作,如果无权限 API server 会返回 403 HTTP 状态码;
- 访问控制阶段(AdmissionControl):API server 的 adminssion controller (用户可自行定制)会判断请求是否合法。
Kubernetes 中的用户
Kubernetes 集群中有两种用户:
- service account 是由 Kubernetes API 管理的“用户”,被绑定到特定的命名空间,并由 API server 创建。
- 普通用户(比如 kubectl 的使用者)由外部独立的服务管理。Kubernetes 分发私钥、用户系统,本身没有用户账号对象。也没法通过 API 调用将普通用户添加到集群中。
API 请求将与普通用户或 service account 绑定,否则会被视为匿名请求。使用 kubectl 向 API server 发出请求时必须先验证身份,否则被视为匿名请求。
认证策略
- X509 客户端证书
- bearer tokens(JWT 格式)
- 认证代理
- 通过插件的 HTTP 认证请求
- Username 用户名或邮箱
- UID 唯一的字符串
- Groups 组
- Extra fields 字符串表,包含其他一些有用的信息
X509 客户端证书
这是 Kubernetes 系统组件之间默认使用的认证方式,也是 kubectl 需要读取 kube-config 来访问 API server 的原因。
通过 API server 启动时带上 --client-ca-file=SOMEFILE
选项启用客户端证书认证。引用的文件必须包含一个或多个证书颁发机构(CA),用于检验提供给 API server 的客户端证书。
认证机构:
- 公钥 /etc/kubernetes/pki/ca.crt
- 私钥 /etc/kubernetes/pki/ca.key
举个例子,使用 openssl 工具来创建 CSR:
$ openssl genrsa -out test.key 2048
$ openssl req -new -key jbeda.pem -out jbeda-csr.pem -subj "/CN=foo/O=org1/O=org2"
- Common Name (CN):用户
- Organization (O):组
每个 Kubernetes 系统组件在集群创建时都签发了自身对应的客户端证书:
组件 | Common Name | Organizations |
---|---|---|
controller-manager | system:kube-controller-manager | |
scheduler | system:kube-scheduler | |
kube-proxy | system:kube-proxy | |
kubelet | system-node:$(NODE_HOSTNAME) | system-nodes |
证书签发 API certficates.k8s.io/v1beta1
- 客户端将证书的签发请求发送到 API server
- 签发请求会以 CertificateSigningRequest 资源持久化
- 新创建好的 csr 资源会先处于 Pending 状态,直到有权限的管理员执行 approve 操作
- csr 完全 approve,请求对应的证书会被签发
静态 token 文件
通过 API server 启动时带上 --token-auth-file=SOMEFILE
,API server 将读取 bearer token。token 改变后除非重启 API server,否则不会生效。
静态 token 文件是一个至少 3 列的 .csvL:token、用户名、UID,第四列是组名(可选):
token,user,uid,"group1,group2,group3"
当 HTTP 客户端调用 API 时要带上名为 Authorization
值为 ${TOKEN_STRING}
的键值对作为 HTTP 请求头。
静态密码文件
通过 API server 启动时带上 --basic-auth-file=SOMEFILE
选项启动基本认证。修改密码后除非重启 API server,否则不会生效。
基本密码文件是一个至少 3 列的 .csv,每行对应一个用户,前 3 列为密码、用户名和 UID,第四列是可选的组名(和静态 token 文件就第一列不一样):
password,user,uid,"group1,group2,group3"
客户端调用 API 时要带上名为 Authorization
值为 Basic BASE64ENCODED(USER:PASSWORD)
的键值对作为 HTTP 请求头。
这种方式既不灵活也不安全,不推荐使用。
OIDC
OpenID Connect 基于 OAuth2 扩展了一个额外的字段用于返回 ID token,一般是由服务端生成的 JWT。
- 在 identity provider 方登录
- identity provider 将提供 access_token、id_token 和 refresh_token
- 当使用 kubectl 时,带上
--token ${id_token}
或直接添加至 kubeconfig 文件中 - kubectl 在访问 API server 的 HTTP 请求头中带上
Authorization: ${id_token}
字段 - API server 通过检查配置中的证书确保 JWT 签名有效
- 检查 id_token 是否过期
- 检查用户是否有权限
- 如果有权限向 kubectl 返回 200
既然身份验证所需的所有数据都在 id_token 中,Kubernetes 就不用与 identity provider 通讯了。
如何配置 API server 请查看官方文档:https://kubernetes.io/docs/reference/access-authn-authz/authentication/#configuring-the-api-server