从默认拒绝开始搭集群
目标
熟练掌握先将一个命名空间设为默认拒绝,再逐一重新开放必要通道的顺序,并亲自写出控制平面配置文件中需要检查的内容。
为什么重要
Kubernetes 默认全部开放。没有任何策略的 Pod 可以与集群中任意 Pod 通信,也能直接访问节点元数据地址。因此,安全设计的第一步不是添加阻止某项行为的规则,而是先阻止一切,再恢复必要部分。如果顺序相反,就永远无法知道“遗漏了什么”。配置文件审计也是同一思路。与观察运行中的进程相比,阅读一份清单更快,也能列出缺少的内容。
此实验环境没有真实数据平面,因此无法确认策略是否真的切断了流量。评分检查对象规范是否按意图编写。考试要求的同样是准确的规范。
步骤
- 创建命名空间
cks-net,并添加标签tier=restricted。 - 在
cks-net中创建 NetworkPolicydefault-deny-all。将podSelector留空, 在policyTypes中同时写入Ingress和Egress,但不设置任何 ingress/egress 规则。 - 在
cks-net中创建 NetworkPolicyallow-dns-egress。目标为所有 Pod,policyTypes仅为Egress;egress 目标是带有kubernetes.io/metadata.name=kube-system标签的 命名空间中带有k8s-app=kube-dns标签的 Pod,端口为 UDP 53 和 TCP 53。 - 在
cks-net中创建 NetworkPolicyallow-frontend-to-api。目标为app=apiPod, ingress 允许来源为同一命名空间中的app=frontendPod,端口为 TCP 8080。 - 在
cks-net中创建 NetworkPolicydeny-node-metadata。目标为所有 Pod,policyTypes为Egress;egress 目标使用ipBlock,设置cidr: 0.0.0.0/0和except: [169.254.169.254/32]。 - 在
cks-net中创建类型为kubernetes.io/tls的 Secretshop-tls。tls.crt和tls.key均不得为空。 - 在
cks-net中创建 Ingressshop。spec.tls[0]的hosts为shop.cks.local,secretName为shop-tls;spec.rules[0].host也为shop.cks.local,路径/将流量 发送到 Serviceapi的 8080 端口。 - 在
/root/cks-cluster-setup/kube-apiserver.yaml中编写反映 CIS 建议的静态 Pod 清单。kind: Pod,容器名称为kube-apiserver,command数组中包含--anonymous-auth=false、--authorization-mode=Node,RBAC、--profiling=false、--audit-log-path=/var/log/kubernetes/audit.log、--enable-admission-plugins=NodeRestriction,PodSecurity,且不得包含任何以--insecure-port开头的标志。
参考
- 执行
kubectl create ns cks-net后,再执行kubectl label ns cks-net tier=restricted - 无法使用
kubectl create networkpolicy生成策略草稿。通过kubectl explain networkpolicy.spec.egress查看字段并直接编写 YAML 会更快。 - 自签名证书示例:执行
openssl req -x509 -newkey rsa:2048 -nodes -keyout tls.key -out tls.crt -days 365 -subj "/CN=shop.cks.local",然后执行kubectl create secret tls shop-tls --cert=tls.crt --key=tls.key -n cks-net - 常见错误 1:设置默认拒绝后忘记开放 DNS egress,应用会因“无法解析名称”而失败,而不是“连接被拒绝”。
- 常见错误 2:如果
except网段不在cidr范围内,API 服务器会拒绝该策略。
创建要隔离的命名空间
创建命名空间 cks-net,并添加标签 tier=restricted。
创建命名空间并添加标签。可先执行 kubectl create ns,再执行 kubectl label ns,也可以用一份清单完成。
默认策略:阻止所有 ingress 与 egress
在 cks-net 中创建 NetworkPolicy default-deny-all。将 podSelector 留空,
在 policyTypes 中同时写入 Ingress 和 Egress,但不设置任何 ingress/egress 规则。
podSelector: {} 会选择命名空间中的所有 Pod。在 policyTypes 中指定方向,但完全不设置 ingress/egress 规则列表,即会拒绝该方向的所有流量。
仅为 DNS 开放 egress 例外
在 cks-net 中创建 NetworkPolicy allow-dns-egress。目标为所有 Pod,
policyTypes 仅为 Egress;egress 目标是带有 kubernetes.io/metadata.name=kube-system 标签的
命名空间中带有 k8s-app=kube-dns 标签的 Pod,端口为 UDP 53 和 TCP 53。
kube-dns Pod 位于 kube-system 命名空间,并带有 k8s-app=kube-dns 标签。可以通过 kubernetes.io/metadata.name 标签选择命名空间。53 端口需要同时开放 UDP 和 TCP。
只开放必要 Pod 对的 ingress
在 cks-net 中创建 NetworkPolicy allow-frontend-to-api。目标为 app=api Pod,
ingress 允许来源为同一命名空间中的 app=frontend Pod,端口为 TCP 8080。
使用 podSelector 选择接收方,使用 ingress[].from[].podSelector 选择发送方。不指定端口会开放所有端口。
排除通往节点元数据的路径
在 cks-net 中创建 NetworkPolicy deny-node-metadata。目标为所有 Pod,policyTypes 为
Egress;egress 目标使用 ipBlock,设置 cidr: 0.0.0.0/0 和 except: [169.254.169.254/32]。
ipBlock 可以为一个 cidr 附加 except 列表,且 except 的网段必须位于 cidr 内。
用于 Ingress 的 TLS Secret
在 cks-net 中创建类型为 kubernetes.io/tls 的 Secret shop-tls。tls.crt 和 tls.key
均不得为空。
kubernetes.io/tls 类型的 Secret 必须包含 tls.crt 和 tls.key 两个键。可使用 openssl 创建自签名证书,也可以在清单中直接填入 base64 值。
为 Ingress 连接 TLS
在 cks-net 中创建 Ingress shop。spec.tls[0] 的 hosts 为 shop.cks.local,
secretName 为 shop-tls;spec.rules[0].host 也为 shop.cks.local,路径 / 将流量
发送到 Service api 的 8080 端口。
Ingress 的 spec.tls 将 hosts 列表与 secretName 配对。spec.rules 中的主机与 spec.tls[].hosts 不一致时,证书不会生效。
审计 kube-apiserver 清单
在 /root/cks-cluster-setup/kube-apiserver.yaml 中编写反映 CIS 建议的静态 Pod 清单。
kind: Pod,容器名称为 kube-apiserver,command 数组中包含
--anonymous-auth=false、--authorization-mode=Node,RBAC、--profiling=false、
--audit-log-path=/var/log/kubernetes/audit.log、
--enable-admission-plugins=NodeRestriction,PodSecurity,且不得包含任何以
--insecure-port 开头的标志。
静态 Pod 清单使用 kind: Pod,标志位于 spec.containers[0].command 数组中。CIS 建议禁用匿名认证、使用 Node+RBAC 授权、禁用性能分析并启用 NodeRestriction Admission;同时应完全移除未经认证的明文端口标志。