Kubelet 认证授权通信流程

目标

这篇文档只回答一个核心问题:kubelet 如何验证和授权对 kubelet API 的访问请求?

重点放在 kubelet 的认证模块、授权模块以及与 API Server 的交互流程。

一句话摘要

kubelet 通过 webhook 认证和授权,将客户端请求转发给 API Server 进行验证,支持匿名访问、证书认证和 bootstrap token 认证等多种方式。


1. 流程总览

从通信视角看,这条链路包含三个层次:

  1. **认证层 (Authentication)**:验证客户端身份。
  2. **授权层 (Authorization)**:验证客户端是否有权限执行操作。
  3. **准入层 (Admission)**:对请求进行额外检查和修改(仅部分操作)。

架构总览图

flowchart TB
    subgraph 客户端["请求来源"]
        direction LR
        API[kube-apiserver<br/>proxy/attach/exec]
        KUBECTL[kubectl<br/>直接访问 kubelet]
        PROBE[探针/监控<br/>healthz/metrics]
        ANON[匿名请求<br/>未认证]
    end

    subgraph 认证["认证层 (Authentication)"]
        direction TB
        ANONYMOUS[Anonymous<br/>匿名认证]
        X509[X509 Cert<br/>证书认证]
        BOOTSTRAP[Bootstrap Token<br/>启动引导]
        WEBHOOK[Webhook<br/>委托 API Server]
    end

    subgraph 授权["授权层 (Authorization)"]
        direction TB
        ALWAYS_ALLOW[AlwaysAllow<br/>允许所有]
        WEBHOOK_AUTHZ[Webhook<br/>委托 API Server]
    end

    subgraph Kubelet["Kubelet API"]
        direction TB
        HANDLERS[请求处理器]
        PODS[/pods 端点]
        EXEC[/exec 端点]
        METRICS[/metrics 端点]
    end

    API --> WEBHOOK
    KUBECTL --> X509
    KUBECTL --> WEBHOOK
    PROBE --> ANONYMOUS
    ANON --> ANONYMOUS

    WEBHOOK --> WEBHOOK_AUTHZ
    X509 --> WEBHOOK_AUTHZ
    BOOTSTRAP --> WEBHOOK_AUTHZ
    ANONYMOUS --> ALWAYS_ALLOW

    WEBHOOK_AUTHZ --> HANDLERS
    ALWAYS_ALLOW --> HANDLERS

    HANDLERS --> PODS
    HANDLERS --> EXEC
    HANDLERS --> METRICS

认证授权流程图

flowchart TD
    subgraph 请求["HTTP 请求"]
        A1[客户端发起请求] --> A2{检查认证配置}
    end

    subgraph 认证["认证流程"]
        A2 --> B1{authentication.anonymous.enabled?}

        B1 -->|true| B2{有认证信息?}
        B2 -->|无| B3[匿名用户]
        B2 -->|有| B4{认证方式}

        B1 -->|false| B4

        B4 -->|X509 证书| B5[证书认证]
        B4 -->|Bearer Token| B6{Token 类型}
        B6 -->|Bootstrap Token| B7[Bootstrap 认证]
        B6 -->|Service Account| B8[Webhook 认证]

        B5 --> B9[提取用户信息]
        B7 --> B9
        B8 --> B9
        B3 --> B9
    end

    subgraph 授权["授权流程"]
        B9 --> C1{authorization.mode?}

        C1 -->|AlwaysAllow| C2[允许所有请求]
        C1 -->|Webhook| C3[构建 SubjectAccessReview]

        C3 --> C4[POST API Server /apis/authorization.k8s.io/v1/subjectaccessreviews]
        C4 --> C5{API Server 返回}
        C5 -->|allowed: true| C6[授权通过]
        C5 -->|allowed: false| C7[拒绝请求]
    end

    subgraph 处理["请求处理"]
        C2 --> D1[执行请求]
        C6 --> D1
        C7 --> D2[403 Forbidden]
        D1 --> D3[返回响应]
    end

这张图想表达什么

  • kubelet 支持多种认证方式,可以委托给 API Server。
  • 授权默认使用 Webhook 模式,需要 API Server 批准。
  • 匿名访问只适用于特定端点(如 /healthz)。

2. 分阶段通信流程


阶段一:认证 (Authentication)

这个阶段的本质是:验证请求者的身份。

步骤 1.1:检查认证配置

kubelet 启动时根据配置初始化认证器:

  • --anonymous-auth=true/false:是否允许匿名访问
  • --client-ca-file:客户端 CA 证书文件
  • --authentication-token-webhook:使用 webhook 认证

通信方向:kubelet 启动配置

步骤 1.2:提取认证信息

从请求中提取认证信息:

  • TLS 证书(X509)
  • Bearer Token(Header: Authorization: Bearer xxx)

通信方向:HTTP 请求解析

步骤 1.3:匿名认证

如果允许匿名且请求没有认证信息,则识别为匿名用户 system:anonymous

通信方向:认证模块内部处理

步骤 1.4:证书认证

如果配置了 --client-ca-file,kubelet 会验证客户端证书,提取 Common Name (CN) 作为用户名。

通信方向:kubelet → 证书验证

步骤 1.5:Webhook 认证

如果启用 webhook 认证,kubelet 将 Token 发送给 API Server 进行验证。

通信方向:kubelet → API Server(POST /apis/authentication.k8s.io/v1/tokenreviews)

步骤 1.6:构建用户信息

认证成功后,构建用户信息(用户名、组、UID 等)。

通信方向:认证模块内部构建


阶段二:授权 (Authorization)

这个阶段的本质是:验证用户是否有权限执行请求的操作。

步骤 2.1:检查授权配置

kubelet 启动时根据配置初始化授权器:

  • --authorization-mode=AlwaysAllow/Webhook:授权模式

通信方向:kubelet 启动配置

步骤 2.2:AlwaysAllow 模式

如果配置为 AlwaysAllow,所有请求都被授权。

通信方向:授权模块内部处理

步骤 2.3:Webhook 授权

如果配置为 Webhook,kubelet 构建 SubjectAccessReview 对象发送给 API Server。

通信方向:kubelet → API Server(POST /apis/authorization.k8s.io/v1/subjectaccessreviews)

步骤 2.4:API Server 授权检查

API Server 检查用户是否有权限执行该操作:

  • 检查 RBAC 规则
  • 检查 Node 授权规则(针对 kubelet 节点)

通信方向:API Server 内部 RBAC/Node 授权器

步骤 2.5:返回授权结果

API Server 返回 allowed: true/false

通信方向:API Server → kubelet


阶段三:请求处理

这个阶段的本质是:执行授权通过的请求。

步骤 3.1:路由请求

kubelet 根据请求路径路由到对应的处理器。

通信方向:HTTP 路由

步骤 3.2:执行处理逻辑

处理器执行具体逻辑,如获取 Pod 列表、执行命令等。

通信方向:kubelet 内部处理

步骤 3.3:返回响应

返回处理结果给客户端。

通信方向:kubelet → 客户端


3. 详细流程图

3.1 kubelet API 端点与权限要求

flowchart TB
    subgraph 只读端点["只读端点 (无需特殊权限)"]
        direction LR
        H1[/healthz]
        H2[/healthz/syncloop]
        H3[/healthz/log]
    end

    subgraph 认证端点["需要认证"]
        direction TB
        P1[/pods - list pods]
        P2[/spec - node spec]
        P3[/stats - resource stats]
        P4[/metrics - prometheus metrics]
    end

    subgraph 敏感端点["需要认证+授权"]
        direction TB
        S1[/exec - container exec]
        S2[/portForward - port forward]
        S3[/attach - container attach]
        S4[/logs - container logs]
        S5[/runningpods - running pods]
        S6[/configz - kubelet config]
    end

    subgraph 权限要求["所需 RBAC 权限"]
        direction TB
        R1[nodes/proxy]
        R2[nodes/stats]
        R3[pods/exec]
        R4[pods/portForward]
        R5[pods/log]
    end

    P1 --> R1
    P3 --> R2
    S1 --> R3
    S2 --> R4
    S4 --> R5

3.2 kubectl exec 完整流程图

sequenceDiagram
    autonumber
    participant K as kubectl
    participant API as kube-apiserver
    participant AUTHZ as Authorization
    participant KL as Kubelet
    participant CRI as Container Runtime

    K->>API: POST /api/v1/namespaces/default/pods/pod-1/exec
    Note over API: API Server 认证+授权

    API->>AUTHZ: 检查 pods/exec 权限
    AUTHZ-->>API: allowed

    API->>KL: POST /exec/<pod-uid>/<container>?command=...
    Note over KL: Kubelet 认证

    KL->>KL: 提取 TLS 客户端证书
    KL->>KL: 验证证书 (CN=system:node:node-1)

    Note over KL: Kubelet 授权 (Webhook)
    KL->>API: POST /apis/authorization.k8s.io/v1/subjectaccessreviews
    Note over KL,API: SubjectAccessReview{<br/>  user: system:node:node-1,<br/>  verb: create,<br/>  resource: pods/exec<br/>}

    API->>AUTHZ: Node 授权器检查
    Note over AUTHZ: 检查节点是否有权限访问该 Pod
    AUTHZ-->>API: allowed: true
    API-->>KL: allowed: true

    KL->>CRI: ExecSync/Exec in container
    CRI-->>KL: exec stream

    KL-->>API: WebSocket/SPDY stream
    API-->>K: exec stream

    K->>K: 显示终端输出

3.3 证书认证流程图

flowchart TD
    subgraph 客户端["客户端"]
        C1[生成 CSR]
        C2[获取签名证书]
        C3[使用证书访问 kubelet]
    end

    subgraph CA["证书签发"]
        CA1[kubelet 启动<br/>生成私钥和 CSR]
        CA2[发送 CSR 到 API Server]
        CA3[Controller Manager 签名]
        CA4[获取签名证书]
    end

    subgraph 认证["证书认证"]
        A1[客户端发送请求<br/>带 TLS 证书]
        A2[kubelet 验证证书<br/>使用 client-ca-file]
        A3[提取 CN 作为用户名<br/>system:node:node-1]
        A4[提取 O 作为组<br/>system:nodes]
    end

    C1 --> C2 --> C3
    CA1 --> CA2 --> CA3 --> CA4
    C3 --> A1 --> A2 --> A3 --> A4

4. 关键配置

4.1 kubelet 认证配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# kubelet 配置
authentication:
anonymous:
enabled: true # 允许匿名访问
webhook:
enabled: true # 启用 webhook 认证
cacheTTL: 2m # 认证结果缓存时间
x509:
clientCAFile: /etc/kubernetes/pki/ca.crt # 客户端 CA 证书

authorization:
mode: Webhook # AlwaysAllow / Webhook
webhook:
cacheAuthorizedTTL: 5m # 授权结果缓存时间
cacheUnauthorizedTTL: 30s

4.2 RBAC 规则示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# API Server 访问 kubelet 的权限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: system:kubelet-api-admin
rules:
- apiGroups: [""]
resources: ["nodes/proxy", "nodes/stats", "nodes/log", "nodes/spec", "nodes/metrics"]
verbs: ["*"]

---
# kubelet 节点授权(Node Authorizer 自动处理)
# system:nodes 组的节点可以访问:
# - 读取自己节点上的 Pod
# - 读取自己节点上的 Secret/ConfigMap
# - 创建/更新自己的 Node status

4.3 端点权限映射

端点 所需权限 说明
/healthz 健康检查
/pods nodes/proxy Pod 列表
/stats nodes/stats 资源统计
/metrics nodes/metrics Prometheus 指标
/exec/* pods/exec 容器执行
/portForward/* pods/portForward 端口转发
/attach/* pods/exec 容器附加
/logs/* pods/log 容器日志

5. 详细时序图

5.1 Webhook 认证时序图

sequenceDiagram
    autonumber
    participant CLIENT as 客户端
    participant KL as Kubelet
    participant AUTH as Authenticator
    participant CACHE as 认证缓存
    participant API as kube-apiserver

    CLIENT->>KL: GET /pods (Authorization: Bearer <token>)
    KL->>AUTH: AuthenticateRequest(req)

    AUTH->>AUTH: 提取 Bearer Token
    AUTH->>CACHE: 检查缓存

    alt 缓存命中
        CACHE-->>AUTH: 返回缓存的用户信息
    else 缓存未命中
        AUTH->>API: POST /apis/authentication.k8s.io/v1/tokenreviews
        Note over AUTH,API: TokenReview{<br/>  spec.token: <token><br/>}

        API->>API: 验证 Token
        API-->>AUTH: TokenReview.status{<br/>  authenticated: true,<br/>  user: {username, groups, uid}<br/>}

        AUTH->>CACHE: 缓存认证结果
    end

    AUTH-->>KL: user.Info
    KL->>KL: 继续授权流程

5.2 Webhook 授权时序图

sequenceDiagram
    autonumber
    participant KL as Kubelet
    participant AUTHZ as Authorizer
    participant CACHE as 授权缓存
    participant API as kube-apiserver

    Note over KL: 认证完成,用户为 system:node:node-1

    KL->>AUTHZ: AuthorizeRequest(req, user)
    AUTHZ->>AUTHZ: 提取请求属性
    Note over AUTHZ: verb=get, resource=pods, name=pod-1

    AUTHZ->>CACHE: 检查缓存

    alt 缓存命中
        CACHE-->>AUTHZ: 返回缓存结果
    else 缓存未命中
        AUTHZ->>API: POST /apis/authorization.k8s.io/v1/subjectaccessreviews
        Note over AUTHZ,API: SubjectAccessReview{<br/>  spec: {<br/>    user: system:node:node-1,<br/>    groups: [system:nodes, system:authenticated],<br/>    resourceAttributes: {<br/>      verb: get,<br/>      resource: pods,<br/>      name: pod-1,<br/>      namespace: default<br/>    }<br/>  }<br/>}

        API->>API: Node Authorizer 检查
        Note over API: 检查 Pod 是否调度到此节点

        API-->>AUTHZ: SubjectAccessReview.status{<br/>  allowed: true<br/>}

        AUTHZ->>CACHE: 缓存授权结果
    end

    AUTHZ-->>KL: authorized=true
    KL->>KL: 执行请求

5.3 匿名访问时序图

sequenceDiagram
    autonumber
    participant PROBE as 健康检查器
    participant KL as Kubelet
    participant AUTH as Authenticator
    participant AUTHZ as Authorizer

    PROBE->>KL: GET /healthz (无认证信息)

    KL->>AUTH: AuthenticateRequest(req)
    AUTH->>AUTH: 检查请求头 - 无 Authorization

    alt anonymous.enabled=true
        AUTH->>AUTH: 识别为匿名用户
        Note over AUTH: user=system:anonymous<br/>groups=[system:unauthenticated]
        AUTH-->>KL: user.Info{system:anonymous}
    else anonymous.enabled=false
        AUTH-->>KL: 认证失败
        KL-->>PROBE: 401 Unauthorized
    end

    KL->>AUTHZ: AuthorizeRequest(req, anonymous)

    alt authorization.mode=AlwaysAllow
        AUTHZ-->>KL: allowed
    else authorization.mode=Webhook
        Note over AUTHZ: 检查匿名用户权限
        alt /healthz 端点
            AUTHZ-->>KL: allowed (默认允许)
        else 其他端点
            AUTHZ-->>KL: denied
            KL-->>PROBE: 403 Forbidden
        end
    end

    KL->>KL: 执行健康检查
    KL-->>PROBE: 200 OK

6. 故障排查指南

6.1 常见问题与诊断方法

问题 1:kubectl exec 失败 (403 Forbidden)

症状

1
Error from server: error dialing backend: x509: certificate signed by unknown authority

1
error: unable to upgrade connection: Unauthorized

排查流程图

flowchart TD
    A[kubectl exec 失败] --> B{检查错误类型}

    B -->|401 Unauthorized| C[认证问题]
    C --> C1[检查 API Server token]
    C --> C2[检查 kubelet client-ca-file]

    B -->|403 Forbidden| D[授权问题]
    D --> D1[检查 RBAC 规则]
    D1 --> D2[检查 nodes/proxy 权限]
    D1 --> D3[检查 pods/exec 权限]

    B -->|x509 错误| E[证书问题]
    E --> E1[检查 CA 证书配置]
    E --> E2[检查证书有效期]
    E --> E3[检查证书链]

    A --> F{检查 kubelet 配置}
    F --> F1[authentication.anonymous.enabled]
    F --> F2[authorization.mode]
    F --> F3[client-ca-file 路径]

诊断命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 检查 RBAC 权限
kubectl auth can-i create pods/exec --as=system:node:node-1
kubectl auth can-i get nodes/proxy --as=system:anonymous

# 检查 kubelet 配置
ps aux | grep kubelet | grep -E "anonymous|authorization"
cat /var/lib/kubelet/config.yaml | grep -A 10 "authentication\|authorization"

# 检查证书
openssl x509 -in /etc/kubernetes/pki/ca.crt -text -noout
openssl verify -CAfile /etc/kubernetes/pki/ca.crt <client-cert>

# 检查 kubelet 日志
journalctl -u kubelet | grep -iE "auth|forbidden|unauthorized"

问题 2:metrics 端点无法访问

症状:Prometheus 无法抓取 kubelet metrics

排查流程图

flowchart TD
    A[metrics 不可访问] --> B{检查匿名访问}

    B --> B1[anonymous.enabled?]
    B1 -->|false| B2[需要认证]
    B2 --> B3[配置 ServiceAccount token]

    B1 -->|true| C{检查授权}

    C --> C1[authorization.mode]
    C1 -->|Webhook| C2[需要 nodes/metrics 权限]
    C1 -->|AlwaysAllow| C3[应该可以访问]

    A --> D{检查网络}
    D --> D1[防火墙规则]
    D --> D2[kubelet 端口]
    D --> D3[HTTPS 配置]

    A --> E{检查证书}
    E --> E1[client-ca-file]
    E --> E2[tls-cert-file]
    E --> E3[tls-private-key-file]

诊断命令

1
2
3
4
5
6
7
8
9
10
# 测试 metrics 端点
curl -k https://<node-ip>:10250/metrics
curl -k --cert <client-cert> --key <client-key> https://<node-ip>:10250/metrics

# 检查 kubelet 端口
netstat -tlnp | grep kubelet

# 检查 ServiceAccount
kubectl get serviceaccount <sa-name> -n <namespace>
kubectl get secret <sa-token-secret> -n <namespace> -o jsonpath='{.data.token}' | base64 -d

问题 3:节点状态无法更新

症状:kubelet 无法更新 Node status

排查流程图

flowchart TD
    A[Node status 更新失败] --> B{检查 kubelet 证书}

    B --> B1[证书是否存在]
    B1 -->|否| B2[检查 bootstrap 过程]
    B1 -->|是| B3[检查证书有效期]

    A --> C{检查 RBAC}
    C --> C1[检查 system:nodes 组]
    C --> C2[检查 Node 授权器]

    A --> D{检查 API Server 连接}
    D --> D1[网络连通性]
    D --> D2[kubeconfig 配置]
    D --> D3[API Server 可用性]

诊断命令

1
2
3
4
5
6
7
8
9
10
11
12
13
# 检查 kubelet 证书
ls -la /var/lib/kubelet/pki/
openssl x509 -in /var/lib/kubelet/pki/kubelet-client-current.pem -text -noout

# 检查 Node 授权
kubectl get clusterrolebinding system:node -o yaml

# 检查 kubelet 与 API Server 连接
curl -k https://<api-server>:6443/healthz --cert /var/lib/kubelet/pki/kubelet-client-current.pem

# 检查 bootstrap 过程
journalctl -u kubelet | grep -i bootstrap
kubectl get csr

6.2 关键日志关键词

场景 日志关键词 含义
认证失败 Authentication failed 认证失败
授权失败 Forbidden 授权拒绝
证书错误 x509 证书相关错误
Token 验证 TokenReview Token 验证请求
授权检查 SubjectAccessReview 授权检查请求
匿名访问 system:anonymous 匿名用户访问

6.3 配置参数参考

参数 默认值 说明
--anonymous-auth true 允许匿名访问
--client-ca-file 客户端 CA 证书
--authentication-token-webhook false 启用 webhook 认证
--authentication-token-webhook-cache-ttl 2m 认证缓存时间
--authorization-mode AlwaysAllow 授权模式
--authorization-webhook-cache-authorized-ttl 5m 授权缓存时间

6.4 一键诊断命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# kubelet 认证授权诊断脚本
NODE_NAME=${1:-"<node-name>"}

echo "=== Kubelet Config ===" && \
ps aux | grep kubelet | grep -oE '\-\-[a-z-]+' | head -20 && \
echo -e "\n=== Auth Config ===" && \
cat /var/lib/kubelet/config.yaml 2>/dev/null | grep -A 5 -E "authentication|authorization" && \
echo -e "\n=== Client Certificates ===" && \
ls -la /var/lib/kubelet/pki/ 2>/dev/null && \
echo -e "\n=== CSR Status ===" && \
kubectl get csr && \
echo -e "\n=== Node Permissions ===" && \
kubectl auth can-i list nodes --as=system:node:$NODE_NAME && \
kubectl auth can-i update nodes/status --as=system:node:$NODE_NAME && \
echo -e "\n=== Recent Auth Logs ===" && \
echo "Run on node: journalctl -u kubelet | grep -iE 'auth|forbidden' | tail -20"

7. 安全最佳实践

7.1 生产环境推荐配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# kubelet 安全配置
authentication:
anonymous:
enabled: false # 禁用匿名访问
webhook:
enabled: true # 启用 webhook 认证
cacheTTL: 2m
x509:
clientCAFile: /etc/kubernetes/pki/ca.crt

authorization:
mode: Webhook # 使用 Webhook 授权
webhook:
cacheAuthorizedTTL: 5m
cacheUnauthorizedTTL: 30s

# 禁用只读端口
readOnlyPort: 0

# 启用 HTTPS
serverTLSBootstrap: true

7.2 RBAC 最小权限原则

1
2
3
4
5
6
7
8
9
10
11
# 监控系统需要的最小权限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: prometheus-kubelet
rules:
- apiGroups: [""]
resources: ["nodes/metrics", "nodes/stats", "nodes/proxy"]
verbs: ["get", "list"]
- nonResourceURLs: ["/metrics", "/stats"]
verbs: ["get"]

8. 版本差异说明

1.27 → 1.28 变化

变化点 说明
TLS Bootstrap 改进 更安全的证书轮换机制
认证缓存优化 更高效的缓存实现

1.28 → 1.29 变化

变化点 说明
匿名访问限制 默认更严格的匿名访问控制
授权日志增强 更详细的授权日志

9. 代码入口(精简版)

如果读者想从流程跳回实现,可从下面几个入口开始:


10. 面试题与详细解答

问题 1:kubelet 的认证方式有哪些?生产环境应该如何配置?

回答要点

kubelet 支持的认证方式

认证方式 配置参数 适用场景
匿名认证 --anonymous-auth=true 健康检查端点
X509 证书 --client-ca-file API Server 访问
Bootstrap Token --bootstrap-token-auth 节点初始化
Webhook 认证 --authentication-token-webhook=true 统一身份认证

认证流程优先级

1
2
3
4
1. 检查是否有 TLS 客户端证书 → X509 认证
2. 检查 Authorization Header → Token 认证
3. 检查匿名认证是否启用 → 匿名用户
4. 认证失败 → 401 Unauthorized

生产环境推荐配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# kubelet 配置
authentication:
anonymous:
enabled: false # 禁用匿名访问
webhook:
enabled: true # 启用 webhook 认证
cacheTTL: 2m # 缓存认证结果
x509:
clientCAFile: /etc/kubernetes/pki/ca.crt

authorization:
mode: Webhook # 使用 webhook 授权
webhook:
cacheAuthorizedTTL: 5m
cacheUnauthorizedTTL: 30s

# 禁用只读端口
readOnlyPort: 0

# 启用 HTTPS
serverTLSBootstrap: true # 自动生成服务端证书

安全最佳实践

  1. 禁用匿名访问anonymous.enabled: false
  2. 使用 Webhook 认证:与 API Server 统一身份管理
  3. 启用证书轮换rotateCertificates: true
  4. 禁用只读端口readOnlyPort: 0

问题 2:kubectl exec 是如何通过 API Server 访问 kubelet 的?认证授权流程是什么?

回答要点

完整流程

1
kubectl → API Server (认证+授权) → kubelet (认证+授权) → CRI → 容器

详细步骤

  1. kubectl 发起请求

    1
    kubectl exec -it pod-name -- /bin/sh
  2. API Server 认证

    • 验证 kubectl 的 token/certificate
    • 确认用户身份
  3. API Server 授权

    • 检查 pods/exec 权限
    • RBAC 规则匹配
  4. API Server 转发请求

    • 构建 kubelet 请求 URL
    • 使用 kubelet 客户端证书
  5. kubelet 认证

    • 验证 API Server 的客户端证书
    • 提取用户信息(CN=system:node:node-1)
  6. kubelet 授权(Webhook)

    • 构建 SubjectAccessReview
    • 发送到 API Server
    • Node Authorizer 检查
  7. kubelet 执行命令

    • 调用 CRI Exec
    • 返回流式输出

认证授权时序图

sequenceDiagram
    participant K as kubectl
    participant API as kube-apiserver
    participant KL as Kubelet

    K->>API: POST /api/v1/namespaces/default/pods/pod-1/exec
    Note over API: API Server 认证<br/>验证用户身份
    Note over API: API Server 授权<br/>检查 pods/exec 权限

    API->>KL: POST /exec/<pod-uid>/<container>
    Note over KL: Kubelet 认证<br/>验证 API Server 证书

    KL->>API: POST /apis/authorization.k8s.io/v1/subjectaccessreviews
    Note over KL,API: SubjectAccessReview{<br/>  user: system:node:node-1,<br/>  verb: create,<br/>  resource: pods/exec<br/>}

    API-->>KL: allowed: true
    Note over KL: 授权通过

    KL->>KL: 调用 CRI Exec
    KL-->>API: WebSocket/SPDY stream
    API-->>K: exec stream

Node Authorizer 检查逻辑

1
2
3
4
5
// Node Authorizer 只允许节点访问自己节点上的 Pod
// 检查条件:
// 1. 用户在 system:nodes 组
// 2. 用户名为 system:node:<node-name>
// 3. Pod 调度到该节点

问题 3:kubelet 的 Node Authorizer 是如何工作的?为什么需要 Node Authorizer?

回答要点

Node Authorizer 设计目的

  1. 最小权限原则:节点只能访问自己节点上的资源
  2. 隔离性:防止一个节点访问另一个节点的数据
  3. 安全性:即使节点被攻破,影响范围有限

Node Authorizer 检查规则

资源 允许的操作 限制条件
Pod 读取、状态更新 只能访问调度到本节点的 Pod
Secret 读取 只能访问本节点 Pod 使用的 Secret
ConfigMap 读取 只能访问本节点 Pod 使用的 ConfigMap
Node 状态更新 只能更新自己的 Node 对象
PV/PVC 读取 只能访问本节点 Pod 使用的卷

授权检查流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 1. 检查用户身份
if !strings.HasPrefix(user.GetName(), "system:node:") {
return false
}

// 2. 检查用户组
if !contains(user.GetGroups(), "system:nodes") {
return false
}

// 3. 检查资源访问权限
// Node Authorizer 维护 Pod 到 Node 的映射
// 只有 Pod 调度到的节点才能访问相关资源
nodeName := strings.TrimPrefix(user.GetName(), "system:node:")
return podIsScheduledToNode(pod, nodeName)

为什么需要 Node Authorizer

  1. RBAC 的局限性

    • RBAC 只能基于角色授权
    • 无法表达”节点只能访问自己的资源”
  2. 安全场景

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    假设没有 Node Authorizer:
    1. 攻击者攻破 node-1
    2. 获取 node-1 的 kubelet 证书
    3. 可以访问所有节点的 Secret/Pod 信息
    4. 集群完全暴露

    有 Node Authorizer:
    1. 攻击者攻破 node-1
    2. 只能访问 node-1 上的 Pod 和相关资源
    3. 影响范围受限

配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# kube-apiserver 配置
--authorization-mode=Node,RBAC

# kubelet RBAC 绑定(自动创建)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubeadm:node-proxier
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:node-proxier
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:nodes

问题 4:如何为监控系统配置访问 kubelet metrics 的权限?

回答要点

方案一:使用 ServiceAccount + RBAC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 1. 创建 ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: prometheus
namespace: monitoring

---
# 2. 创建 ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: prometheus-kubelet
rules:
- apiGroups: [""]
resources: ["nodes/metrics", "nodes/stats", "nodes/proxy"]
verbs: ["get", "list"]
- nonResourceURLs: ["/metrics", "/stats", "/metrics/cadvisor"]
verbs: ["get"]

---
# 3. 创建 ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: prometheus-kubelet
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: prometheus-kubelet
subjects:
- kind: ServiceAccount
name: prometheus
namespace: monitoring

方案二:配置 kubelet 允许匿名访问 metrics

1
2
3
4
5
6
7
8
# kubelet 配置(不推荐生产环境)
authentication:
anonymous:
enabled: true
authorization:
mode: Webhook

# 需要配置 RBAC 允许匿名用户访问

Prometheus 抓取配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Prometheus 配置
scrape_configs:
- job_name: 'kubelet'
kubernetes_sd_configs:
- role: node
relabel_configs:
- source_labels: [__address__]
regex: (.+):10250
target_label: __address__
replacement: ${1}:10250
- source_labels: [__metrics_path__]
regex: /metrics
target_label: __metrics_path__
replacement: /metrics
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
insecure_skip_verify: true
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token

访问 kubelet metrics 的方式

方式 URL 权限要求
通过 API Server 代理 /api/v1/nodes/{node}/proxy/metrics nodes/proxy
直接访问 kubelet https://{node}:10250/metrics nodes/metrics

安全建议

  1. 使用 ServiceAccount:避免使用匿名访问
  2. 最小权限:只授予必要的 metrics 权限
  3. 网络隔离:限制监控系统的网络访问
  4. 证书管理:定期轮换 ServiceAccount token

问题 5:kubelet 的 TLS Bootstrap 是什么?如何工作?

回答要点

TLS Bootstrap 概念

TLS Bootstrap 允许 kubelet 在没有预分配证书的情况下启动,通过向 API Server 发送 CSR(Certificate Signing Request)来获取证书。

工作流程

1
2
3
4
5
1. kubelet 启动,使用 bootstrap token 认证
2. 向 API Server 发送 CSR
3. Controller Manager 签署 CSR
4. kubelet 获取签名证书
5. 使用证书进行正常认证

配置步骤

  1. 创建 Bootstrap Token

    1
    2
    3
    4
    5
    6
    7
    8
    # 创建 token secret
    kubectl create secret generic bootstrap-token-abcdef \
    --namespace kube-system \
    --type bootstrap.kubernetes.io/token \
    --from-literal=token-id=abcdef \
    --from-literal=token-secret=0123456789abcdef \
    --from-literal=usage-bootstrap-authentication=true \
    --from-literal=usage-bootstrap-signing=true
  2. 配置 kubelet

    1
    2
    3
    4
    5
    # kubelet 配置
    bootstrapKubeconfig: /etc/kubernetes/bootstrap-kubelet.conf
    certDir: /var/lib/kubelet/pki
    rotateCertificates: true # 自动轮换证书
    serverTLSBootstrap: true # 启用服务端证书 bootstrap
  3. 配置 RBAC

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    # 允许 kubelet 创建 CSR
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
    name: kubeadm:node-autoapprove-csr
    roleRef:
    apiGroup: rbac.authorization.k8s.io
    kind: ClusterRole
    name: system:certificates.k8s.io:certificatesigningrequests:nodeclient
    subjects:
    - apiGroup: rbac.authorization.k8s.io
    kind: Group
    name: system:bootstrappers

    ---
    # 允许自动批准 CSR
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
    name: kubeadm:node-autoapprove-certificate
    roleRef:
    apiGroup: rbac.authorization.k8s.io
    kind: ClusterRole
    name: system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
    subjects:
    - apiGroup: rbac.authorization.k8s.io
    kind: Group
    name: system:nodes

证书轮换

1
2
3
4
5
6
7
8
证书有效期:1 年
轮换时机:剩余有效期 < 30%
轮换流程:
1. kubelet 生成新私钥
2. 发送新 CSR
3. Controller Manager 签署
4. kubelet 使用新证书
5. 旧证书失效

安全考虑

  1. Bootstrap Token 安全

    • Token 有时效性
    • 使用后应销毁
  2. CSR 审批

    • 可以配置自动审批
    • 也可以手动审批(更安全)
  3. 证书撤销

    • 目前 Kubernetes 不支持证书撤销
    • 依赖证书短期有效

问题 6:如何排查 kubectl exec/logs 失败的问题?常见错误有哪些?

回答要点

常见错误及原因

错误信息 原因 解决方法
error dialing backend kubelet 不可达 检查 kubelet 状态
x509: certificate signed by unknown authority 证书问题 检查 CA 证书
Unauthorized 认证失败 检查 token/证书
Forbidden 授权失败 检查 RBAC 规则
connection refused kubelet 端口未监听 检查 kubelet 配置

排查流程

flowchart TD
    A[kubectl exec 失败] --> B{检查错误类型}

    B -->|401 Unauthorized| C[认证问题]
    C --> C1[检查 API Server token]
    C --> C2[检查 kubelet client-ca-file]

    B -->|403 Forbidden| D[授权问题]
    D --> D1[检查 RBAC 规则]
    D --> D2[检查 nodes/proxy 权限]
    D --> D3[检查 pods/exec 权限]

    B -->|x509 错误| E[证书问题]
    E --> E1[检查 CA 证书配置]
    E --> E2[检查证书有效期]
    E --> E3[检查证书链]

    B -->|connection refused| F[连接问题]
    F --> F1[检查 kubelet 是否运行]
    F --> F2[检查防火墙规则]
    F --> F3[检查端口配置]

详细排查步骤

步骤 1:检查 API Server 日志

1
2
3
4
5
6
7
# 查看 API Server 日志
kubectl logs -n kube-system kube-apiserver-master

# 查看认证授权日志
# API Server 配置添加
--audit-log-path=/var/log/audit.log
--audit-log-maxage=30

步骤 2:检查 kubelet 状态

1
2
3
4
5
6
7
8
# 检查 kubelet 服务
systemctl status kubelet

# 查看 kubelet 日志
journalctl -u kubelet -f

# 检查 kubelet 端口
netstat -tlnp | grep kubelet

步骤 3:检查证书配置

1
2
3
4
5
6
7
8
# 检查 kubelet 证书
ls -la /var/lib/kubelet/pki/

# 查看证书详情
openssl x509 -in /var/lib/kubelet/pki/kubelet-client-current.pem -text -noout

# 验证证书链
openssl verify -CAfile /etc/kubernetes/pki/ca.crt /var/lib/kubelet/pki/kubelet-client-current.pem

步骤 4:检查 RBAC 权限

1
2
3
4
5
6
7
# 检查用户权限
kubectl auth can-i create pods/exec --as=system:node:node-1
kubectl auth can-i get nodes/proxy --as=system:anonymous

# 查看相关 ClusterRoleBinding
kubectl get clusterrolebinding | grep node
kubectl describe clusterrolebinding system:node

步骤 5:网络连通性测试

1
2
3
4
5
6
7
8
9
10
11
# 从 API Server 测试 kubelet 连接
kubectl get --raw "/api/v1/nodes/node-1/proxy/healthz"

# 直接测试 kubelet 端口
curl -k https://node-1:10250/healthz

# 使用正确的证书测试
curl --cert /var/lib/kubelet/pki/kubelet-client-current.pem \
--key /var/lib/kubelet/pki/kubelet-client-current.pem \
--cacert /etc/kubernetes/pki/ca.crt \
https://node-1:10250/pods

一键诊断脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash
NODE=${1}
POD=${2}
NAMESPACE=${3:-default}

echo "=== API Server Health ===" && \
kubectl get --raw "/healthz" && \
echo -e "\n=== Kubelet Health ===" && \
kubectl get --raw "/api/v1/nodes/$NODE/proxy/healthz" && \
echo -e "\n=== Node RBAC ===" && \
kubectl auth can-i list nodes --as=system:node:$NODE && \
kubectl auth can-i update nodes/status --as=system:node:$NODE && \
echo -e "\n=== Pod Status ===" && \
kubectl get pod $POD -n $NAMESPACE -o wide && \
echo -e "\n=== Pod Events ===" && \
kubectl get events -n $NAMESPACE --field-selector involvedObject.name=$POD

问题 7:kubelet 的认证缓存机制是如何工作的?如何调优缓存参数?

回答要点

缓存机制目的

  1. 减少 API Server 压力:避免每次请求都调用 API Server
  2. 降低延迟:缓存命中时直接返回结果
  3. 提高可用性:API Server 短暂不可用时仍可工作

认证缓存

1
2
3
4
authentication:
webhook:
enabled: true
cacheTTL: 2m # 认证结果缓存时间

缓存工作原理

1
2
3
请求到达 → 检查缓存 → 命中 → 返回缓存结果

未命中 → 调用 API Server → 缓存结果 → 返回

授权缓存

1
2
3
4
5
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 5m # 授权成功缓存时间
cacheUnauthorizedTTL: 30s # 授权失败缓存时间

为什么授权失败缓存时间短

  1. 权限变化:用户可能刚获得权限
  2. 安全考虑:减少未授权窗口
  3. 重试需求:允许快速重试

缓存 Key 计算

1
2
3
4
5
// 认证缓存 Key
key := token + username

// 授权缓存 Key
key := user.Name + strings.Join(user.Groups, ",") + verb + resource + namespace + name

调优建议

场景 认证缓存 授权成功缓存 授权失败缓存
高安全要求 30s 1m 10s
正常生产环境 2m 5m 30s
高性能要求 5m 10m 1m

监控缓存效率

1
2
3
4
5
6
7
8
# 查看 kubelet 指标
curl -s https://localhost:10250/metrics | grep -i cache

# 关键指标
# authentication_attempts_total
# authentication_successes_total
# authorization_attempts_total
# authorization_successes_total

缓存失效场景

  1. TTL 到期:自动失效
  2. kubelet 重启:缓存清空
  3. 配置变更:重新加载

最佳实践

  1. 根据安全需求调整 TTL:高安全环境使用短 TTL
  2. 监控缓存命中率:评估缓存效果
  3. 平衡性能和安全:找到合适的平衡点