多租户平台最危险的假设,是把某一种隔离机制当成完整的安全边界。命名空间配置错误、Pod 调度失误、网络规则遗漏或数据库凭证泄露,都可能让单层防线失效。面对高度敏感的企业数据,ReadyOn 在 Amazon EKS 上采用了“四道墙”模型:同时使用 Kubernetes 命名空间、Karpenter 节点池、Amazon VPC 安全组和租户独享的 Amazon Aurora 数据库,构成相互独立的纵深防御。
这里的重点不是简单叠加四项 AWS 与 Kubernetes 功能,而是让每一层都能阻止上一层漏掉的问题。
四道墙分别挡住什么
第一堵墙:Kubernetes 命名空间
命名空间负责划分 Kubernetes API 对象,是租户隔离最自然的起点。每个租户拥有独立的 Deployment、Service、Secret、ServiceAccount 和资源配额,RBAC 权限也限制在对应命名空间内。
但命名空间本身并不是完整的安全沙箱。它不会自动阻止跨命名空间网络访问,也不能保证不同租户的 Pod 不会落到同一台节点。因此,这一层主要解决对象归属、权限范围和资源治理问题。
建议至少配套:
- 为租户创建独立 ServiceAccount,避免共享默认身份;
- 使用 Role 和 RoleBinding,而不是授予宽泛的 ClusterRole;
- 设置 ResourceQuota 与 LimitRange,限制资源争抢;
- 配置默认拒绝的 NetworkPolicy,作为集群内网络控制的补充;
- 禁止租户工作负载使用 privileged、hostNetwork 和 hostPath 等高风险能力。
第二堵墙:Karpenter 节点池
ReadyOn 使用 Karpenter 节点池继续切分计算资源。租户工作负载通过标签、污点和调度约束进入指定节点池,避免不同租户的 Pod 默认混跑在同一台 EC2 实例上。
独立节点池能缩小容器逃逸、内核漏洞、节点资源耗尽和本地缓存残留等风险的影响范围。不过,污点和 nodeSelector 主要是调度机制,不能替代权限控制。平台必须限制谁能修改 Pod 的调度字段,也要防止租户自行添加其他租户的 toleration。
第三堵墙:Amazon VPC 安全组
网络层使用 Amazon VPC 安全组控制工作负载可以连接哪些服务。实践中,可以为租户工作负载关联独立安全组,并让租户 Aurora 数据库的入站规则只信任该安全组,而不是信任整个 VPC CIDR。
这种做法把控制点下沉到 AWS 网络层。即使某个 Pod 绕过 Kubernetes 层面的网络策略,它仍然需要通过安全组规则。反方向也一样:安全组配置错误时,命名空间、身份权限和数据库凭证仍应继续提供保护。
需要注意,EKS 中按 Pod 绑定安全组通常依赖 Amazon VPC CNI 的 Security Groups for Pods 能力,并受实例类型、网络模式和 CNI 配置影响,上线前必须核对当前集群支持情况。
第四堵墙:每租户独立的 Amazon Aurora 数据库
最后一道边界放在数据层。ReadyOn 为租户使用独立的 Amazon Aurora 数据库,而不是仅依赖共享数据库中的 tenant_id 字段。
这样可以减少应用查询遗漏租户条件、ORM 过滤器失效或数据库账号权限过宽带来的横向数据泄露。每个租户还应拥有独立凭证、备份策略、密钥和生命周期操作。即使应用层出现缺陷,一个租户的数据库身份也不应有能力读取另一个租户的数据。
独立数据库的代价是资源数量、连接管理、迁移编排和成本都会上升。因此,平台需要自动化租户开通、版本升级、凭证轮换和销毁流程,否则隔离越强,人工运维负担越重。
一套可以改造的 EKS 隔离骨架
下面的示例展示如何把命名空间、Karpenter 节点池和 Pod 安全组串起来。它是通用实践骨架,并不代表 ReadyOn 的完整生产配置。
运行前需要:
- 将
sg-0123456789abcdef0替换为租户工作负载使用的安全组; - 确认集群已经安装 Karpenter,并存在名为
default的EC2NodeClass; - 确认 Amazon VPC CNI 已启用 Security Groups for Pods;
- 根据集群中的 Karpenter 版本调整 API 版本。
apiVersion: v1
kind: Namespace
metadata:
name: tenant-acme
labels:
tenant: acme
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: tenant-quota
namespace: tenant-acme
spec:
hard:
requests.cpu: '8'
requests.memory: 16Gi
limits.cpu: '16'
limits.memory: 32Gi
pods: '50'
---
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: tenant-acme
spec:
template:
metadata:
labels:
tenant: acme
spec:
taints:
- key: tenant
value: acme
effect: NoSchedule
requirements:
- key: kubernetes.io/arch
operator: In
values: [amd64]
- key: karpenter.sh/capacity-type
operator: In
values: [on-demand]
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
limits:
cpu: '32'
---
apiVersion: vpcresources.k8s.aws/v1beta1
kind: SecurityGroupPolicy
metadata:
name: tenant-acme
namespace: tenant-acme
spec:
podSelector:
matchLabels:
tenant: acme
securityGroups:
groupIds:
- sg-0123456789abcdef0
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tenant-api
namespace: tenant-acme
spec:
replicas: 2
selector:
matchLabels:
app: tenant-api
tenant: acme
template:
metadata:
labels:
app: tenant-api
tenant: acme
spec:
nodeSelector:
tenant: acme
tolerations:
- key: tenant
operator: Equal
value: acme
effect: NoSchedule
containers:
- name: api
image: public.ecr.aws/nginx/nginx:1.27
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
保存为 tenant-acme.yaml 后执行:
kubectl apply -f tenant-acme.yaml
kubectl get pods -n tenant-acme -o wide
kubectl get nodes -L tenant,karpenter.sh/nodepool
kubectl describe securitygrouppolicy -n tenant-acme tenant-acme
数据库侧还需要建立对应关系:Acme 工作负载安全组只能访问 Acme Aurora 端点使用的安全组和端口;数据库凭证应放在 AWS Secrets Manager 等秘密存储中,再通过受控机制注入 Pod。不要把数据库密码直接写进 Deployment YAML,也不要让多个租户共用一个高权限数据库账号。
不要只验证“正常路径”
隔离系统的验收标准不应只是应用可以启动。更有价值的是持续运行负向测试:
# 检查租户 ServiceAccount 是否能读取其他命名空间的 Pod。
kubectl auth can-i list pods \
--namespace tenant-beta \
--as system:serviceaccount:tenant-acme:tenant-api
# 检查所有租户 Pod 实际落在哪些节点。
kubectl get pods -A -L tenant -o wide
# 查看节点的租户标签和所属 Karpenter NodePool。
kubectl get nodes -L tenant,karpenter.sh/nodepool
生产环境还应自动验证以下失败场景:
- Acme 身份不能读取 Beta 命名空间中的 Secret;
- Acme Pod 不能调度到 Beta 节点池;
- Acme 安全组不能连接 Beta Aurora 端点;
- Acme 数据库凭证不能登录 Beta 数据库;
- 删除租户后,其节点、网络规则、凭证、备份和数据库都能按策略清理。
这些测试适合放进发布流水线和周期性安全作业中。仅靠人工审查 YAML,很难发现云端规则漂移或后续变更造成的隔离退化。
采用四道墙时的取舍
“四道墙”的价值在于独立失败:命名空间约束对象与身份,节点池隔离计算环境,安全组限制网络路径,Aurora 隔离最终数据。任何一层都不应默认信任前一层已经做对,这正是零信任式纵深防御的核心。
落地时可以按风险分级推进。高度敏感或受监管的租户使用完整的独立节点池、网络身份和 Aurora 资源;风险较低的租户则可以在明确接受风险的前提下共享部分基础设施。无论选择哪一级,都应把租户标识作为贯穿 Kubernetes、AWS 网络、数据库、日志和成本标签的统一键,并通过自动化防止配置漂移。
最终需要关注的不是“部署了多少安全产品”,而是一次配置错误最多能穿透几层边界,以及团队能否用可重复的测试证明租户之间确实无法横向移动。