【Kubernetes】K8s 的安全框架和用户认证

发布于:2024-09-18 ⋅ 阅读:(12) ⋅ 点赞:(0)

K8s 的安全认证》系列,共包含以下文章:

😊 如果您觉得这篇文章有用 ✔️ 的话,请给博主一个一键三连 🚀🚀🚀 吧 (点赞 🧡、关注 💛、收藏 💚)!!!您的支持 💖💖💖 将激励 🔥 博主输出更多优质内容!!!

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 命名空间中执行写操作(如 createupdate),则会被鉴权拒绝。另外,Jerry 只对 project-dev 命名空间有读取 Pod 的权限,对于其他命名空间则没有任何权限。

1.3 准入控制:Admission Control

在客户端请求通过了 认证 阶段和 鉴权 阶段后,API Server 不会立即处理客户端请求。因为,这时客户端请求还要通过最后一个阶段 —— 准入控制 阶段。在该阶段中将修改客户端请求中的参数以完成一些特殊的任务。

另外,Kubernetes 为准入控制阶段维护了一个插件列表,发送给 API Server 的所有客户端请求都需要通过该列表中的所有插件的检查。如果某个插件拒绝了客户端请求,则该请求将立即被拒绝,而不会被后续的插件检查。

🚀 Kubernetes 允许用户自己开发每一个阶段的插件,并集成到相应的阶段中以实现用户的访问控制。所有插件都是由 API Server 来启用的。

2.Kubernetes 的用户认证

在 Kubernetes 集群中,用户主要分为两类:User AccountService Account之前的博客使用的都是 User Account。通过使用 User Account,能够让用户访问 Kubernetes 集群中的资源。简单来说,User Account 是为人而设计的;但 Service Account 却是为 Pod 而设计的。

2.1 Kubernetes 的用户认证方式

通过指定 APl Server 的启动参数,可以让 Kubernetes 使用不同的用户认证方式。下表列举了 Kubernetes 主要支持的 3 3 3 种用户认证方式。

认证方式
API Server 启动参数设置
说明
密码 --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 集群的资源。