在Kubernetes 1.24及更高版本中,ServiceAccount token的认证机制发生了重大变化。这个变化直接影响了许多依赖SA token的外部系统集成,比如Prometheus监控、CI/CD系统等。作为一名长期工作在Kubernetes运维一线的工程师,我最近在配置Prometheus监控时也遇到了这个问题,经过多次实践和验证,总结出了这套可靠的解决方案。
在Kubernetes 1.24之前,当我们创建一个ServiceAccount时,系统会自动生成一个对应的Secret,其中包含长期有效的token。这种方式虽然方便,但也带来了安全隐患:
Kubernetes 1.24+引入了更安全的token管理机制:
kubectl create token命令生成的token才能通过API Server认证重要提示:虽然我们可以生成10年有效期的token,但从安全角度考虑,建议定期轮换token,特别是用于生产环境的关键服务。
首先,我们需要为外部监控系统创建一个独立的命名空间和专用的ServiceAccount。这样做的好处是:
bash复制# 创建专用命名空间
kubectl create namespace monitor-external
# 创建专用ServiceAccount
kubectl create sa external-monitor-sa -n monitor-external
权限最小化是Kubernetes安全实践的核心原则之一。我们需要为监控SA配置仅包含必要权限的RBAC。
yaml复制cat > external-monitor-role.yaml << EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: external-monitor-role
rules:
# 监控节点/Pod/服务等核心资源的只读权限
- apiGroups: [""]
resources:
- nodes
- nodes/metrics
- pods
- services
- endpoints
- namespaces
- configmaps
verbs: ["get", "list", "watch"]
# 监控metrics.k8s.io指标(节点/Pod指标)
- apiGroups: ["metrics.k8s.io"]
resources: ["pods", "nodes"]
verbs: ["get", "list", "watch"]
# 监控部署类资源(可选)
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets", "daemonsets"]
verbs: ["get", "list", "watch"]
EOF
kubectl apply -f external-monitor-role.yaml
yaml复制cat > external-monitor-binding.yaml << EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: external-monitor-binding
subjects:
- kind: ServiceAccount
name: external-monitor-sa
namespace: monitor-external
roleRef:
kind: ClusterRole
name: external-monitor-role
apiGroup: rbac.authorization.k8s.io
EOF
kubectl apply -f external-monitor-binding.yaml
这是最关键的一步,我们需要使用kubectl create token命令生成官方认可的token。
bash复制SA_UID=$(kubectl get sa external-monitor-sa -n monitor-external -o json | grep '"uid":' | head -1 | awk -F'"' '{print $4}')
bash复制CA_FILE=$(find /etc/kubernetes /opt/k8s /usr/local/k8s -name "ca.crt" 2>/dev/null | head -1)
if [ -z "$CA_FILE" ]; then
echo "ERROR: 未找到CA证书,请手动指定路径!"
exit 1
fi
CA_CRT=$(cat "$CA_FILE" | base64 -w0)
bash复制# 生成10年有效期的token
TOKEN_PLAIN=$(kubectl create token external-monitor-sa -n monitor-external --duration=87600h)
echo "K8s签发的长期token:$TOKEN_PLAIN"
TOKEN_B64=$(echo -n "$TOKEN_PLAIN" | base64 -w0)
NAMESPACE_B64=$(echo -n "monitor-external" | base64 -w0)
yaml复制cat > external-monitor-token.yaml << EOF
apiVersion: v1
kind: Secret
metadata:
name: external-monitor-token
namespace: monitor-external
annotations:
kubernetes.io/service-account.name: external-monitor-sa
kubernetes.io/service-account.uid: $SA_UID
type: kubernetes.io/service-account-token
data:
ca.crt: ${CA_CRT}
namespace: ${NAMESPACE_B64}
token: ${TOKEN_B64}
EOF
kubectl apply -f external-monitor-token.yaml
bash复制echo -e "\n=== 长期有效Token(供外部使用)==="
TOKEN_PLAIN=$(kubectl get secret external-monitor-token -n monitor-external -o jsonpath='{.data.token}' | base64 -d)
echo $TOKEN_PLAIN
echo -e "\n=== CA证书已保存到本地 ==="
kubectl get secret external-monitor-token -n monitor-external -o jsonpath='{.data.ca\.crt}' | base64 -d > /root/external-monitor-ca.crt
echo "CA证书路径:/root/external-monitor-ca.crt"
最后,我们需要验证生成的token是否真的有效。
bash复制# 获取APIServer地址
APISERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
# 使用token访问APIServer
curl -k $APISERVER/api/v1/pods \
--header "Authorization: Bearer $TOKEN_PLAIN" \
--cacert /root/external-monitor-ca.crt
如果返回了Pod列表,说明token配置成功;如果返回"Forbidden",则需要检查RBAC权限配置。
可能的原因:
kubectl create token生成的解决方案:
kubectl create token命令生成tokenkubectl auth can-i命令检查权限有时外部系统需要使用kubeconfig文件而不是直接使用token。下面是生成kubeconfig的步骤:
bash复制# 获取集群名称和上下文名称
CLUSTER_NAME=$(kubectl config view --minify -o jsonpath='{.clusters[0].name}')
CONTEXT_NAME=$(kubectl config view --minify -o jsonpath='{.current-context}')
# 生成kubeconfig文件
cat > external-monitor-kubeconfig.yaml << EOF
apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority: /root/external-monitor-ca.crt
server: $APISERVER
name: $CLUSTER_NAME
contexts:
- context:
cluster: $CLUSTER_NAME
user: external-monitor-sa
namespace: monitor-external
name: $CONTEXT_NAME
current-context: $CONTEXT_NAME
users:
- name: external-monitor-sa
user:
token: $TOKEN_PLAIN
EOF
虽然我们生成了长期有效的token,但从安全角度考虑,建议定期轮换:
在实际工作中,我发现很多团队因为图方便而忽略了这些安全实践,结果导致安全事件。遵循这些原则可以大大降低风险。