4. Kubernetes 架构与安全边界
在云原生安全工程师的面试中,Kubernetes 架构类问题几乎不会停留在“画一张组件图”的层面。面试官真正想确认的是:你是否理解每个组件的信任边界在哪里、默认配置下哪些端口和接口是暴露的、攻击者拿到某个组件的访问权限后能横向移动到什么程度,以及你能否给出可落地的加固动作。本节围绕控制平面与节点上的核心组件,逐一拆解其安全配置要点与攻击面。
一、API Server:整个集群的信任中枢
API Server 是唯一直接读写 etcd 的组件,也是所有认证、授权、准入控制的汇聚点。它的攻击面可以分成三层:网络暴露面、认证面、授权与准入面。
网络暴露面上,API Server 默认监听 6443(HTTPS)。危险配置是同时开启 --insecure-port(旧版本默认 8080,无认证无授权)。虽然该参数在新版本已废弃,但面试中常被用来考察你是否知道“匿名请求”的风险。更现实的风险是 --anonymous-auth=true 配合过宽的 RBAC,使未认证请求也能调用 API。加固时应显式设置 --anonymous-auth=false,并通过 --authorization-mode=Node,RBAC 启用节点授权器,限制 kubelet 只能读取与自己相关的资源。
认证面上,要区分用户认证与 ServiceAccount。生产集群应关闭静态 Token 文件(--token-auth-file),改用 OIDC 或 Webhook 对接企业身份源。ServiceAccount 的 Token 在 1.24 之后默认不再自动挂载,但旧集群仍可能把长期 Token 以 Secret 形式挂在 Pod 里。检查命令如下:
kubectl get pod <pod-name> -o jsonpath='{.spec.volumes[*].projected}'
kubectl get sa default -o yaml | grep -i automount
若返回中包含 serviceAccountToken 且 automountServiceAccountToken 为 true,说明该 Pod 持有可调用 API Server 的凭据。攻击者一旦通过应用漏洞拿到这个 Token,就能以该 ServiceAccount 的权限枚举集群资源。加固动作是:对不需要访问 API 的工作负载显式设置 automountServiceAccountToken: false,并为每个应用创建最小权限的独立 ServiceAccount,而不是共用 default。
授权与准入面上,要重点检查是否存在 cluster-admin 的过度绑定。一条常用审计命令是:
kubectl get clusterrolebindings -o json | jq -r '.items[] | select(.roleRef.name=="cluster-admin") | .subjects[]? | "\(.kind)/\(.name)"'
如果输出里出现普通业务 ServiceAccount 或 Group,就是高危信号。准入控制方面,建议启用 PodSecurity(替代已废弃的 PSP)、NodeRestriction,并按需接入 OPA Gatekeeper 或 Kyverno 做策略校验。
二、etcd:集群的“数据库”,一旦失守等于全盘失守
etcd 存储了集群全部对象,包括 Secret 的密文。它的攻击面主要有两个:客户端端口 2379 和对等端口 2380。默认情况下 etcd 只监听 localhost,但很多自建集群为了“方便”把它暴露到 0.0.0.0,且未开启客户端证书认证。攻击者只要能访问 2379 且无 TLS 校验,就能直接读取所有 Secret。
加固要点:--listen-client-urls 只绑定内网或本机;开启 --client-cert-auth=true 并配置受信任 CA;对 etcd 数据目录启用静态加密。静态加密的配置示例(EncryptionConfiguration):
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded-32-byte-key>
- identity: {}
然后在 API Server 启动参数中加入 --encryption-provider-config。验证是否生效的方法是创建一个 Secret 后直接查看 etcd 中的原始值:
ETCDCTL_API=3 etcdctl get /registry/secrets/default/test-secret \
--cacert=ca.crt --cert=client.crt --key=client.key | hexdump -C | head
若看到 k8s:enc:aescbc:v1:key1 前缀,说明加密已生效;若仍是明文 JSON,则配置未加载。这是面试中很能体现动手能力的细节。
三、kubelet:节点上的“小 API Server”
kubelet 监听 10250(HTTPS)和只读端口 10255(旧版本)。10250 提供 /pods、/exec、/run 等接口,一旦 --anonymous-auth=true 且 --authorization-mode=AlwaysAllow,未认证用户就能在节点上执行命令。这是历史上多起挖矿事件的核心入口。
加固配置应包含:--anonymous-auth=false、--authorization-mode=Webhook、--read-only-port=0、--protect-kernel-defaults=true。同时要限制 --client-ca-file 的信任范围,避免任意证书都能通过校验。检查 kubelet 配置的命令:
ps -ef | grep kubelet | tr ' ' '\n' | grep -E 'anonymous|authorization|read-only'
curl -k https://<node-ip>:10250/pods
如果第二条命令在无凭据情况下返回 Pod 列表,说明匿名访问未关闭。修复后应返回 401。
四、kube-proxy 与网络边界
kube-proxy 本身不直接暴露高危 API,但它决定了 Service 的流量转发规则。攻击面主要体现在 iptables/IPVS 规则被篡改后,流量可被重定向到恶意 Pod。安全上更值得关注的是:kube-proxy 以 DaemonSet 运行,拥有 hostNetwork 和较高权限,若其镜像或配置被替换,影响面覆盖所有节点。加固动作包括:使用只读根文件系统、限制其 ServiceAccount 权限、通过 NetworkPolicy 限制 Pod 间东西向流量。
下面给出一份可直接用于自查的组件安全基线检查表,字段按“组件—检查项—期望值—验证命令”组织,便于在面试或实际巡检中逐条核对。
| 组件 | 检查项 | 期望值 | 验证命令/方法 |
|---|---|---|---|
| API Server | 匿名认证 | false | ps 查 --anonymous-auth |
| API Server | 授权模式 | Node,RBAC | ps 查 --authorization-mode |
| etcd | 客户端证书认证 | true | ps 查 --client-cert-auth |
| etcd | Secret 静态加密 | 已启用 | etcdctl get 看前缀 |
| kubelet | 只读端口 | 0 | ps 查 --read-only-port |
| kubelet | 匿名认证 | false | curl 10250/pods 返回 401 |
| kube-proxy | ServiceAccount 权限 | 仅必要权限 | kubectl get clusterrolebinding |
面试中回答这类问题时,建议按“组件职责 → 默认风险 → 攻击者利用路径 → 加固参数 → 验证方式”的顺序展开,并主动给出上面这样的检查命令。这样既体现架构理解,也体现工程落地能力,比单纯背诵参数更有说服力。