基于X509证书的Kubernetes认证全流程

1. 客户端证书准备阶段

1.1 创建私钥

openssl genrsa -out jiege.key 2048
  • 作用:生成RSA私钥(2048位),用于证书签名
  • 结果jiege.key 文件,必须保密

1.2 创建证书签名请求(CSR)

openssl req -new -key jiege.key -out jiege.csr -subj "/CN=jiege/O=oldboyedu"
  • 作用:创建证书签名请求
  • 关键参数
    • CN=jiege:用户名(User)
    • O=oldboyedu:用户组(Group)
  • 结果jiege.csr 文件

1.3 Base64编码CSR

cat jiege.csr | base64 | tr -d '\n';echo

从这里可以获取到CSR

  • 作用:将CSR编码为base64,便于在K8s资源中存储

2. 服务端证书签发阶段

2.1 创建CSR资源清单

cat > csr-jiege.yaml << EOF 
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: jiege-csr
spec:
  request: [base64编码的CSR]
  signerName: kubernetes.io/kube-apiserver-client
  expirationSeconds: 86400
  usages:
  - client auth
EOF

kubectl apply -f csr-jiege.yaml 
  • 关键配置
    • signerName:指定证书签发者类型
    • expirationSeconds:证书有效期(24小时)
    • usages:证书用途(客户端认证)

2.2 批准CSR请求,手动签发

kubectl certificate approve jiege-csr
  • 作用:手动批准证书签发请求
  • 状态变化:Pending → Approved,Issued

2.3 获取签发后的证书

kubectl get csr jiege-csr -o jsonpath='{.status.certificate}' | base64 -d > jiege.crt
  • 作用:从CSR资源中提取已签发的证书

将证书拷贝到客户端节点,便于后续使用

[root@master231 ~]# scp /opt/jiege.crt 10.0.0.233:~

客户端测试验证233

查看本地证书文件

[root@worker233 ~]# ll jiege*
-rw-r--r-- 1 root root 1115 Sep 27 15:46 jiege.crt
-rw-r--r-- 1 root root  911 Sep 27 15:28 jiege.csr
-rw------- 1 root root 1704 Apr 14 10:43 jiege.key

3. kubeconfig配置阶段

3.1 添加用户凭证

kubectl config set-credentials jiege \
  --client-certificate=jiege.crt \
  --client-key=jiege.key \
  --embed-certs=true \
  --kubeconfig=./yinzhengjie-k8s-certs.conf
  • 作用:创建用户认证配置
  • --embed-certs=true:将证书内容嵌入kubeconfig文件
    ./yinzhengjie-k8s-certs.conf 创建用户的时候会第一次进行创建,随着集群和上下文创建会不断的填充。可以随时进行cat

3.2 配置集群信息

kubectl config set-cluster myk8s \
  --certificate-authority=/etc/kubernetes/pki/ca.crt \
  --server="https://10.0.0.231:6443" \
  --kubeconfig=./yinzhengjie-k8s-certs.conf
  • 作用:定义K8s集群连接信息
  • 关键参数
    • CA证书:验证API Server身份
    • Server地址:API Server端点

3.3 创建上下文

kubectl config set-context jiege@myk8s \
  --user=jiege \
  --cluster=myk8s \
  --kubeconfig=./yinzhengjie-k8s-certs.conf
  • 作用:绑定用户和集群,创建访问上下文

3.4 设置默认上下文

kubectl config use-context jiege@myk8s --kubeconfig=./yinzhengjie-k8s-certs.conf
  • 作用:设置默认使用的上下文

4. 测试验证阶段

4.1 设置环境变量

export KUBECONFIG=/root/yinzhengjie-k8s-certs.conf
  • 作用:指定kubeconfig文件路径

4.2 测试访问权限

kubectl get pods
# 返回:Error from server (Forbidden)
  • 结果分析:认证成功但授权失败
  • 说明:用户jiege已通过证书认证,但缺少RBAC权限

5. 关键知识点总结

认证流程

  1. 客户端:生成密钥对和CSR
  2. 服务端:审批CSR并签发证书 crt
  3. 配置:将证书集成到kubeconfig
  4. 认证:使用证书向API Server证明身份

当执行kubectl get pods --kubeconfig=./yinzhengjie-k8s-certs.conf时,api-server知道你是jiege了但是没授权

文件作用

  • .key:私钥,身份证明
  • .crt:公钥证书,CA签发
  • .csr:证书签名请求
  • .conf:kubeconfig配置文件

当前状态

用户jiege已成功通过X509证书认证,但需要配置RBAC授权才能访问集群资源。下一步应该创建相应的Role和RoleBinding来授权。

基于token证书的Kubernetes认证全流程

静态令牌认证完整流程总结

1. 生成令牌 Token

两种生成方式:

# 方式1:使用openssl
echo "$(openssl rand -hex 3).$(openssl rand -hex 8)"
# 示例:01b202.d5c4210389cbff08

# 方式2:使用kubeadm
kubeadm token generate
# 示例:jvt496.ls43vufojf45q73i
2. 创建令牌认证文件
cd /etc/kubernetes/pki/
cat > token.csv <<EOF
b4gp4h.tqnqlkov8zzbzuot,yinzhengjie,10001,k8s
53llgt.n4xci771guevocbk,jasonyin,10002,k8s
m7k336.omp1yul0w1i3t0pp,linux97,10003,k3s
EOF

格式: token,用户名,用户ID,用户组

3. 配置 API Server

修改 /etc/kubernetes/manifests/kube-apiserver.yaml

spec:
  containers:
  - command:
    - kube-apiserver
    - --token-auth-file=/etc/kubernetes/pki/token.csv  # 添加这行
    ...
    volumeMounts:
    - mountPath: /etc/kubernetes/pki/token.csv
      name: static-token-file
      readOnly: true
  volumes:
  - hostPath:
      path: /etc/kubernetes/pki/token.csv
      type: File
    name: static-token-file
4. 重启 API Server
# 通过移动文件触发重启
mv /etc/kubernetes/manifests/kube-apiserver.yaml /opt/
mv /opt/kube-apiserver.yaml /etc/kubernetes/manifests/
5. 创建 Kubeconfig 文件
5.1 创建集群配置
kubectl config set-cluster myk8s \
  --embed-certs=true \
  --certificate-authority=/etc/kubernetes/pki/ca.crt \
  --server="https://10.0.0.231:6443" \
  --kubeconfig=./yinzhengjie-k8s-token.conf
5.2 创建用户凭证
kubectl config set-credentials yinzhengjie \
  --token="b4gp4h.tqnqlkov8zzbzuot" \
  --kubeconfig=./yinzhengjie-k8s-token.conf
5.3 创建上下文
kubectl config set-context yinzhengjie@myk8s \
  --user=yinzhengjie \
  --cluster=myk8s \
  --kubeconfig=./yinzhengjie-k8s-token.conf
5.4 设置当前上下文
kubectl config use-context yinzhengjie@myk8s \
  --kubeconfig=./yinzhengjie-k8s-token.conf

以上都是232节点操作

6. 测试认证

拷贝kubeconfig文件:从这开始231操作

[root@worker232 ~]# scp yinzhengjie-k8s-token.conf 10.0.0.231:~

# 使用kubeconfig文件测试
kubectl get pods --kubeconfig=./yinzhengjie-k8s-token.conf

# 使用curl直接测试
curl -k -H "Authorization: Bearer b4gp4h.tqnqlkov8zzbzuot" \
  https://10.0.0.231:6443/api/v1/pods

Kubeconfig 加载优先级

  1. --kubeconfig 参数 (最高优先级)

    kubectl get nodes --kubeconfig=/root/yinzhengjie-k8s-token.conf
    
  2. KUBECONFIG 环境变量

    export KUBECONFIG=/path/to/kubeconfig
    kubectl get nodes
    
  3. ~/.kube/config 文件 (默认位置)(管理员文件,默认配置文件)

    kubectl get nodes  # 自动使用 ~/.kube/config
    
  4. 内建配置 (最低优先级)

    • 连接 localhost:8080

🔐 认证 vs 授权

当前状态:

  • 认证成功:用户能够通过token成功认证
  • 授权失败:用户没有相应的RBAC权限

认证成功但授权失败的典型错误

Error from server (Forbidden): nodes is forbidden: User "yinzhengjie" cannot list resource "nodes" in API group "" at the cluster scope

这个流程清晰地展示了从令牌生成到kubeconfig创建的完整过程,是非常好的静态令牌认证实践案例!

Master节点配置文件

# Master 节点默认使用这个配置文件
/etc/kubernetes/admin.conf
# 直接使用(默认已经配置好)
kubectl get nodes

kubectl加载kubeconfig文件的优先级总结

    1. 使用--kubeconfig的优先级最大,直接无视后面的两个配置文件;
    1. 使用KUBECONFIG变量的优先级次之;
    1. 如果没有定义上面两个配置,则默认使用的~/.kube/config文件;一般worker节点没有
    1. 如果前面3个环境都没有,则默认链接localhost:8080

K8S实现灰度发布案例

2.1 设计思路

  • A. 旧版本使用deploy部署副本数量3;
  • B. 新版本也是deploy部署副本数量0;
  • C. svc同时指向新旧的Pod;
  • D. 将旧版本的副本数量逐渐调小到3 --> 0;
  • E. 将新版本的副本数量逐渐调大到0 --> 3;

K8S实现蓝绿部署案例

3.1 设计思路

  • A. 旧版本使用deploy部署副本数量3;
  • B. 新版本也是deploy部署副本数量3;
  • C. svc将标签选择器指向旧的Pod;
  • D. 切换流量是将标签选择器指向新版本的Pod;

api-server认证体系

API Server内置了插件化的访问控制机制(每种访问控制机制均有一组专用的插件栈):

认证(Authentication):

核验请求者身份的合法性,进行身份识别,验证客户端身份。
身份核验过程遵循"或"逻辑,且任何一个插件核验成功后都将不再进行后续的插件验证。
均不成功,则失败,或以"匿名者"身份访问,建议禁用"匿名者"。

授权(Authorization):

核验请求的操作是否获得许可,验证客户端是否有权限操作资源对象。
鉴权过程遵循"或"逻辑,且任何一个插件对操作的许可授权后都将不再进行后续的插件验证。
均未许可,则拒绝请求的操作

准入控制(Admission Control):

检查操作内容是否合规,仅同"写"请求相关,负责实现"检验"字段类型是否合法及和补全默认字段。
内容合规性检查过程遵循"与"逻辑,且无论成败,每次的操作请求都要经由所有插件的检验。
将数据写入etcd前,负责检查内容的有效性,因此仅对"写"操作有效。
分两类:validating(校验)和 mutating(补全或订正)。

认证、授权、准入控制的关系:

  • 认证:你是谁
  • 授权:你有没有访问资源的权限
  • 准入控制:验证字段是否合法,修订补全(补充一些字段比如nodeName)

kubeconfig的组成部分

1. kubeconfig概述

kubeconfig是YAML格式的文件,用于存储身份认证信息,以便于客户端加载并认证到API Server。
kubeconfig保存有认证到一至多个Kubernetes集群的相关配置信息,并允许管理员按需在各配置间灵活切换:

clusters:

Kubernetes集群访问端点(API Server)列表。
说白了,就是可以定义多个K8S集群列表。

users:

认证到API Server的身份凭据列表。
说白了,可以定义多个用户列表,这个用户可以是token,或者x509证书凭据。

contexts:

将每一个user同可认证到的cluster建立关联的上下文列表。用户,集群进行绑定。
说白了,就是将多个用户和对应的集群进行关联,将来使用哪个用户,就会去关联的集群进行访问认证。也可以定义多个上下文的关系。

current-context:

当前默认使用的context。

Kubernetes系统的用户大体可分Service Account,User Account和Anonymous Account

Service Account:

Kubernetes内置的资源类型,用于Pod内的进程访问API Server时使用的身份信息。
引用格式: "system:serviceaccount:NAMESPACE:SA_NAME"

User Account:

用户账户,指非Pod类的客户端访问API Server时使用的身份标识,一般是现实中的"人"。
API Server没有为这类账户提供保存其信息的资源类型,相关的信息通常保存于外部的文件(特指"kubeconfig"文件)或认证系统中。
身份核验操作可由API Server进行,也可能是由外部身份认证服务完成。
可以手动定义证书,其中O字段表示组,CN字段表示用户名。

Anonymous Account:

不能被识别为Service Account,也不能被识别为User Account的用户。
这类账户K8S系统称之为"system:anonymous",即"匿名用户"。

API Server内置的访问控制机制

API Server的访问方式:

  • 集群外部: https://IP:Port
    比如: https://10.0.0.231:6443

  • 集群内部: https://kubernetes.default.svc.oldboyedu.com
    比如: 直接基于名为"kubernetes"的svc访问即可

hostNetwork指定dnsPolicy解析策略

当Pod使用hostNetwork: true时,表示Pod使用宿主机网络命名空间,此时DNS策略dnsPolicy有以下几种选择:

  1. ClusterFirstWithHostNet(推荐):

    • 使用Kubernetes集群DNS(CoreDNS)解析
    • 将集群域名的解析请求转发给CoreDNS
    • 非集群域名解析请求转发给宿主机DNS服务器
  2. Default

    • 继承宿主机/etc/resolv.conf配置
    • 直接使用宿主机DNS服务器
  3. ClusterFirst

    • 对hostNetwork Pod无效,K8s不允许这种组合
    • 如果设置会报错或忽略
  4. None

    • 不设置任何DNS配置
    • 需要手动配置dnsConfig

coreDNS组件验证是否正常工作

验证CoreDNS是否正常工作的完整流程:

1. 检查CoreDNS Pod状态

kubectl get pods -n kube-system -l k8s-app=kube-dns
# 期望:Running状态,READY为2/2

2. 检查CoreDNS Service

kubectl get svc -n kube-system kube-dns
# 期望:ClusterIP为10.96.0.10(默认)

3. 检查CoreDNS配置文件

kubectl get configmap -n kube-system coredns -o yaml
# 查看Corefile配置

4. 测试DNS解析

方法1:使用busybox测试

# 创建busybox测试Pod
kubectl run busybox --image=busybox:1.28 --restart=Never -- sleep 3600

# 测试集群内部服务解析
kubectl exec busybox -- nslookup kubernetes.default

# 测试外部域名解析
kubectl exec busybox -- nslookup www.baidu.com

# 清理
kubectl delete pod busybox

方法2:使用dig命令测试

# 在节点上安装dig
yum install bind-utils -y

# 测试集群DNS
dig @10.96.0.10 kubernetes.default.svc.cluster.local

# 测试外部域名
dig @10.96.0.10 www.baidu.com

方法3:创建DNS测试Pod

apiVersion: v1
kind: Pod
metadata:
  name: dns-test
  namespace: default
spec:
  containers:
  - name: dns-test
    image: busybox:1.28
    command:
      - sleep
      - "3600"
  dnsPolicy: ClusterFirst
# 执行测试
kubectl exec -it dns-test -- sh
# 在容器内执行
nslookup kubernetes.default
nslookup www.baidu.com
cat /etc/resolv.conf

5. 检查DNS查询日志

# 开启CoreDNS日志(如果未开启)
kubectl edit configmap coredns -n kube-system
# 在Corefile的.:53配置块中添加:log

# 查看CoreDNS日志
kubectl logs -n kube-system -l k8s-app=kube-dns -c coredns

6. 检查DNS服务器连通性

# 从节点测试DNS服务
nc -zv 10.96.0.10 53
telnet 10.96.0.10 53

7. 常见问题排查

问题1:DNS解析超时

# 检查网络策略
kubectl get networkpolicy -A

# 检查Calico/Flannel网络插件状态
kubectl get pods -n kube-system | grep -E 'calico|flannel'

问题2:无法解析外部域名

# 检查CoreDNS配置中的forward设置
kubectl get configmap coredns -n kube-system -o yaml | grep forward

# 检查节点DNS配置
cat /etc/resolv.conf

问题3:间歇性解析失败

# 检查CoreDNS副本数
kubectl get deployment -n kube-system coredns

# 检查节点资源使用情况
kubectl top nodes

8. 快速诊断命令汇总

# 检查CoreDNS整体状态
kubectl get all -n kube-system -l k8s-app=kube-dns

# 检查端点
kubectl get endpoints -n kube-system kube-dns

# 检查事件
kubectl describe svc -n kube-system kube-dns
kubectl describe pods -n kube-system -l k8s-app=kube-dns

# 测试连通性(从Pod内)
kubectl run test --rm -i --tty --image=busybox:1.28 --restart=Never -- nslookup kubernetes.default

# 查看CoreDNS配置
kubectl exec -n kube-system -c coredns $(kubectl get pods -n kube-system -l k8s-app=kube-dns -o jsonpath='{.items[0].metadata.name}') -- cat /etc/coredns/Corefile

通过以上步骤,可以全面验证CoreDNS组件是否正常工作,并及时发现和解决DNS相关问题。

问题:跨资源空间两个容器如何进行通信

更多推荐