K8s 的安全框架和用户认证
- 1.Kubernetes 的安全框架
- 1.1 认证:Authentication
- 1.2 鉴权:Authorization
- 1.3 准入控制:Admission Control
- 2.Kubernetes 的用户认证
- 2.1 Kubernetes 的用户认证方式
- 2.2 配置 Kubernetes 集群使用密码认证
Kubernetes 作为一个分布式的虚拟化集群管理工具,保证其集群的安全性就显得非常重要。由于 API Server 是访问集群资源的唯一入口,因此 Kubernetes 的安全机制都是围绕保护 API Server 来设计的。
1.Kubernetes 的安全框架
Kubernetes 的安全框架主要由 认证、鉴权 和 准入控制 这 3 3 3 个阶段组成。这 3 3 3 个阶段的关系如下图所示。
1.1 认证:Authentication
当客户端与 Kubernetes 集群建立 HTTP 通信时,HTTP 请求会先进入认证阶段。由于 API Server 是操作集群资源的唯一入口,因此,可以在 API Server 上配置一个或者多个认证模块,API Server 将逐个验证每一个认证模块,直到其中一个认证成功。如果认证失败,则 API Server 返回 401
状态码给客户端,表示 Kubernetes 拒绝了客户端的连接请求。一般情况下,认证模块只会检查 HTTP 的头部信息(这里包含 用户名、密码、客户端证书、令牌 等信息),而不会检查整个 HTTP 请求。
1.2 鉴权:Authorization
客户端请求在通过了认证阶段后,会进入鉴权阶段。这个阶段会检查请求者是否拥有相应的权限来执行操作。因此,在鉴权阶段需要提供 请求者的用户名、请求的权限或行为,以及 操作的资源对象。如果请求者无法提供,则 Kubernetes 将拒绝该请求。
下面是 Kubernetes 鉴权的一个例子。
{
"apiVersion": "abac.authorization.kubernetes.io/v1beta1",
"kind": "Policy",
"spec": {
"user": "Jerry",
"namespace": "project-dev",
"resource": "pods",
"readonly": true
}
}
其中指定了 Jerry 能够在 project-dev
命名空间中读取 Pod。当 Jerry 执行以下操作后就可以正常读取 proiect-dev
名称空间中的 Pod 对象了。
{
"apiVersion": "authorization.k8s.io/v1beta1",
"kind": "SubjectAccessReview",
"spec": {
"resourceAttributes": {
"namespace": "project-dev",
"verb": "get",
"group": "dev.example.org",
"resource": "pods"
}
}
}
🚀 如果 Jerry 在
project-dev
命名空间中执行写操作(如create
和update
),则会被鉴权拒绝。另外,Jerry 只对project-dev
命名空间有读取 Pod 的权限,对于其他命名空间则没有任何权限。
1.3 准入控制:Admission Control
在客户端请求通过了 认证 阶段和 鉴权 阶段后,API Server 不会立即处理客户端请求。因为,这时客户端请求还要通过最后一个阶段 —— 准入控制 阶段。在该阶段中将修改客户端请求中的参数以完成一些特殊的任务。
另外,Kubernetes 为准入控制阶段维护了一个插件列表,发送给 API Server 的所有客户端请求都需要通过该列表中的所有插件的检查。如果某个插件拒绝了客户端请求,则该请求将立即被拒绝,而不会被后续的插件检查。
🚀 Kubernetes 允许用户自己开发每一个阶段的插件,并集成到相应的阶段中以实现用户的访问控制。所有插件都是由 API Server 来启用的。
2.Kubernetes 的用户认证
在 Kubernetes 集群中,用户主要分为两类:User Account
和 Service Account
。之前的博客使用的都是 User Account。通过使用 User Account,能够让用户访问 Kubernetes 集群中的资源。简单来说,User Account 是为人而设计的;但 Service Account 却是为 Pod 而设计的。
2.1 Kubernetes 的用户认证方式
通过指定 APl Server 的启动参数,可以让 Kubernetes 使用不同的用户认证方式。下表列举了 Kubernetes 主要支持的 3 3 3 种用户认证方式。
认证方式 |
|
|
---|---|---|
密码 | --basic-auth-file=密码文件 | 最基本的认证方式,通过 用户名 和 密码 对用户进行认证。密码文件是一个 CSV 格式的文件,该文件中至少包含密码、用户名和用户 ID 这 3 3 3 列。 |
证书 | --client-ca-file=证书文件 | 通过证书文件进行用户的认证。证书中的 CN(common name )会作为用户名,而证书中的 O(organization )所指定的信息会成为用户的组。 |
令牌 | --token-auth-file=令牌文件 | 如果在 API Server 的启动参数中设置了 --token-auth-file 参数,则 Kubernetes 会从指定文件中读取用户的令牌信息,从而进行用户认证。 |
通过以下命令可以看出,在默认情况下 Kubernetes 使用的是 证书认证。
cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep client-ca
输出的信息如下:
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
2.2 配置 Kubernetes 集群使用密码认证
创建 /etc/kubernetes/pki/basic_auth_file.csv
文件用于保存用户名与密码,在文件中输入以下内容。
password123,myadmin,1
🚀 该 CSV 文件的格式为:密码、用户名、用户ID
按照以下内容修改 /etc/kubernetes/manifests/kube-apiserver.yaml
文件。增加如下参数:
- --basic-auth-file=/etc/kubernetes/pki/basic_auth_file.csv
将下面这一行注释掉:
# - --client-ca-file=/etc/kubernetes/pki/ca.crt
🚀 这样的配置使得 Kubernetes 集群采用密码认证。如果使用的是用
kubeadmin
部署的 Kubermetes 集群,则 API Server 会自动重启以加载新的kube-apiserver.yaml
文件。
尝试访问 Kubernetes 集群。
kubectl get node
这时将出现以下错误:
error: You must be logged in to the server (Unauthorized)
由于使用密码认证登录时需要 集群的 CA 证书,所以先创建相关的目录。
mkdir -p /opt/kubernetes/bin/
cd /opt/kubernetes/bin/
下载需要的软件,并授予可执行的权限。
wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
chmod +x cfssl*
mv cfssl-certinfo_linux-amd64 /opt/kubernetes/bin/cfssl-certinfo
mv cfssljson_linux-amd64 /opt/kubernetes/bin/cfssljson
mv cfssl_linux-amd64 /opt/kubernetes/bin/cfssl
编辑 ~/.bash_profile
文件加入以下内容设置环境变量。
export PATH=/opt/kubernetes/bin/:$PATH
生效环境变量。
source ~/.bash_profile
初始化 cfssl
,并创建临时证书目录。
cd ~
mkdir ssl && cd ssl
cfssl print-defaults config > config.json
cfssl print-defaults csr > csr.json
创建用于生成 CA 证书文件的 JSON 配置信息。
cat > ca-config.json <<EOF
{
"signing": {
"default": {
"expiry": "8760h"
},
"profiles": {
"kubernetes": {
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
],
"expiry": "8760h"
}
}
}
}
EOF
创建用于生成 CA 证书签名请求(CSR)的 JSON 配置信息。
cat > ca-csr.json <<EOF
{
"CN" : "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
EOF
生成 CA 证书(ca.pem
)和密钥(ca-key.pem
)。
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
将生成的证书复制到 /opt/kubernetes/ssl
目录下。
mkdir -p /opt/kubernetes/ssl
cp ca.csr ca.pem ca-key.pem ca-config.json /opt/kubernetes/ssl
创建 myadmin
用户的信息。
kubectl config set-credentials myadmin --username myadmin --password password123
配置需要访问的集群。
kubectl config set-cluster k8s-cluster \
--server https://172.30.1.2:6443 \
--certificate-authority /opt/kubernetes/ssl/ca.pem
设置 myadmin
用户访问的上下文信息。
kubectl config set-context k8s-cluster-ctx --cluster k8s-cluster --user myadmin
切换到 myadmin
用户访问的上下文。
kubectl config use-context k8s-cluster-ctx
再次访问 Kubernetes 集群。
kubectl get node
这时出现以下错误:
Error from server (Forbidden): nodes is forbidden: User "myadmin" cannot list nodes at the cluster scope
这与前面的错误不一样。这里的错误表示:用户已经通过了认证阶段,但不具备任何权限,因此也不能操作 Kubernetes 集群的资源。