基于 ServiceAccount 的 kubeconfig 具有与 ServiceAccount 相同的权限,可以灵活地通过 ClusterRoleBinding 和/或 RoleBinding 进行权限控制,以及方便地进行账户吊销,本文介绍基于 ServiceAccount 快速生成 kubeconfig 文件的方法。
1. 准备 ServiceAccount
# 创建 ServiceAccount(例如 admin-user)
kubectl create sa admin-user -n kube-system
# 检查对应的 Secret 是否被自动创建
kubectl get secret -n kube-system admin-user
# 如果不存在,则需要手动创建 Secret(>=1.24 版本的 K8s 不再自动创建 Secret)
# 注意修改 kubernetes.io/service-account.name 为对应的 ServiceAccount 名字,这里即为 admin-user
# Secret 的 name 和 namespace 与 ServiceAccount 保持一致
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: admin-user
namespace: kube-system
annotations:
kubernetes.io/service-account.name: admin-user
type: kubernetes.io/service-account-token
EOF
# 为 ServiceAccount 绑定权限(这里以绑定最高权限 cluster-admin 为例)
kubectl create clusterrolebinding admin-user --clusterrole=cluster-admin --serviceaccount=kube-system:admin-user
执行完上述操作,ServiceAccount 就准备好了
2. 生成 kubeconfig 文件
创建 generate-kubeconfig.sh
脚本,内容如下:
#!/bin/bash
# 开启错误捕获和显示
set -e
trap 'echo "Error occurred at line $LINENO while executing command: $BASH_COMMAND"' ERR
# 参数校验
if [ "$#" -ne 3 ]; then
echo "Usage: $0 <serviceaccount-name> <namespace> <output-file>"
exit 1
fi
SERVICE_ACCOUNT_NAME=$1
NAMESPACE=$2
OUTPUT_FILE=$3
# 获取当前上下文和集群名称
CURRENT_CONTEXT=$(kubectl config current-context)
CLUSTER_NAME=$(kubectl config get-contexts "$CURRENT_CONTEXT" | awk '{print $3}' | tail -n 1)
# 获取集群 API server 地址
SERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
# 获取 ServiceAccount 的 Secret 名称,直接使用 SERVICE_ACCOUNT_NAME
SECRET_NAME=$SERVICE_ACCOUNT_NAME
# 获取 Token 和 CA 证书数据
TOKEN=$(kubectl get secret "$SECRET_NAME" -n "$NAMESPACE" -o jsonpath='{.data.token}' | base64 --decode)
CA_DATA=$(kubectl get secret "$SECRET_NAME" -n "$NAMESPACE" -o jsonpath='{.data.ca\.crt}')
# 创建 kubeconfig 文件
cat <<EOF > "$OUTPUT_FILE"
apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority-data: "$CA_DATA"
server: "$SERVER"
name: "$CLUSTER_NAME"
contexts:
- context:
cluster: "$CLUSTER_NAME"
user: "$SERVICE_ACCOUNT_NAME"
namespace: "$NAMESPACE"
name: "$SERVICE_ACCOUNT_NAME@$CLUSTER_NAME"
current-context: "$SERVICE_ACCOUNT_NAME@$CLUSTER_NAME"
users:
- name: "$SERVICE_ACCOUNT_NAME"
user:
token: "$TOKEN"
EOF
echo "Kubeconfig file has been written to $OUTPUT_FILE"
执行上述脚本,生成 kubeconfig:
用法参数列表:
generate-kubeconfig.sh [serviceaccount-name] [namespace] [output-file]
例如,本例即为:
bash generate-kubeconfig.sh admin-user kube-system admin-user-kubeconfig
3. 验证生成的 kubeconfig
kubectl get node --kubeconfig admin-user-kubeconfig
OUTPUT EXAMPLE:
NAME STATUS ROLES AGE VERSION
1.28-control-plane Ready control-plane 5d22h v1.28.0
4. 如何吊销该 kubeconfig
4.1 暂时禁用权限
可以通过删除 ServiceAccount 关联的 clusterrolebinding 禁用权限:
kubectl delete clusterrolebinding admin-user
kubeconfig 还能连接集群,但执行操作会报权限不足的错误:
kubectl get node --kubeconfig admin-user-kubeconfig
OUTPUT ERROR EXAMPLE:
Error from server (Forbidden): nodes is forbidden: User "system:serviceaccount:kube-system:admin-user" cannot list resource "nodes" in API group "" at the cluster scope
此种方式,可以暂时下掉用户权限,需要恢复时再创建 clusterrolebinding 恢复即可
4.2 完全禁止访问(永久)
可以通过删除 ServiceAccount 禁止访问:
kubectl delete sa admin-user -n kube-system
旧的 kubeconfig 已无法通过鉴权:
kubectl get node --kubeconfig admin-user-kubeconfig
OUTPUT ERROR EXAMPLE:
error: You must be logged in to the server (Unauthorized)
此种方式难以再恢复旧的 kubeconfig,属于永久删除,使用时需要重新生成新的 kubeconfig 文件。
附加 (基于 kubeadm 的方式)
使用 kubeadm 工具可以生成基于客户端证书鉴权的 kubeconfig 文件
例如生成 admin.conf 文件:
kubeadm kubeconfig user --client-name=kubernetes-admin --org system:masters > admin.conf
注意,上述命令生成的 kubeconfig 使用了 system:masters
特权组,不支持吊销,永久有效,不要泄漏!!!
可以通过使用 clusterrolebinding 的方式为 User 绑定权限,从而支持权限吊销,例如:
kubectl create clusterrolebinding foo-user --clusterrole=cluster-admin --user=foo-user
kubeadm kubeconfig user --client-name=foo-user > foo-user-kubeconfig
生成的 foo-user-kubeconfig 的样式如下,采用 client 证书鉴权:
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: XXXXX
server: https://172.18.0.2:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: foo-user
name: foo-user@kubernetes
current-context: foo-user@kubernetes
kind: Config
preferences: {}
users:
- name: foo-user
user:
client-certificate-data: XXXXX
client-key-data: XXXXX
验证 foo-user-kubeconfig 有效:
kubectl get node --kubeconfig foo-user-kubeconfig
OUTPUT EXAMPLE:
NAME STATUS ROLES AGE VERSION
1.28-control-plane Ready control-plane 5d22h v1.28.0
吊销时,可以直接删除 clusterrolebinding,下掉权限即可:
kubectl delete clusterrolebinding foo-user
验证权限已被吊销:
kubectl get node --kubeconfig foo-user-kubeconfig
Error from server (Forbidden): nodes is forbidden: User "foo-user" cannot list resource "nodes" in API group "" at the cluster scope