209 lines
6.0 KiB
Markdown
209 lines
6.0 KiB
Markdown
|
|
---
|
||
|
|
tags: [kubernetes, resource-quota, limit-range, network-policy, security]
|
||
|
|
create time: 2026-05-18 00:30
|
||
|
|
---
|
||
|
|
|
||
|
|
# K8s 资源与安全管控 — Quota、LimitRange & NetworkPolicy
|
||
|
|
|
||
|
|
## 概述
|
||
|
|
|
||
|
|
多人共享集群或多租户环境中,需要两道防线来保障稳定:**资源管控**防止单个团队耗尽集群,**网络策略**防止横向越权访问。这两者构成了 K8s 多环境的安全基线。
|
||
|
|
|
||
|
|
## ResourceQuota — 命名空间资源总量上限
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
apiVersion: v1
|
||
|
|
kind: ResourceQuota
|
||
|
|
metadata:
|
||
|
|
name: production-quota
|
||
|
|
namespace: production
|
||
|
|
spec:
|
||
|
|
hard:
|
||
|
|
requests.cpu: "16" # 所有 Pod 的 CPU request 总和不超过 16核
|
||
|
|
requests.memory: 32Gi # 内存 request 不超过 32G
|
||
|
|
limits.cpu: "32" # 所有 Pod 的 CPU limit 不超过 32核
|
||
|
|
limits.memory: 64Gi # 内存 limit 不超过 64G
|
||
|
|
pods: "50" # 最多 50 个 Pod
|
||
|
|
services: "20" # 最多 20 个 Service
|
||
|
|
persistentvolumeclaims: "10" # 最多 10 个 PVC
|
||
|
|
```
|
||
|
|
|
||
|
|
> [!warning] 配额打满怎么办?
|
||
|
|
>
|
||
|
|
> 当某个命名空间的配额被占满时,该 namespace 内的新创建请求会直接失败(Return Error)。解决方法:清理不再使用的资源,或申请管理员增加配额 (`kubectl edit quota <name> -n <namespace>`)。
|
||
|
|
|
||
|
|
## LimitRange — 单容器资源边界
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
apiVersion: v1
|
||
|
|
kind: LimitRange
|
||
|
|
metadata:
|
||
|
|
name: default-limits
|
||
|
|
namespace: production
|
||
|
|
spec:
|
||
|
|
limits:
|
||
|
|
# 默认 Limits/Requests(不指定的 Pod 自动套用)
|
||
|
|
- type: Container
|
||
|
|
default:
|
||
|
|
cpu: "500m"
|
||
|
|
memory: "512Mi"
|
||
|
|
defaultRequest:
|
||
|
|
cpu: "250m"
|
||
|
|
memory: "256Mi"
|
||
|
|
# 单个容器的边界
|
||
|
|
max:
|
||
|
|
cpu: "2"
|
||
|
|
memory: "4Gi"
|
||
|
|
min:
|
||
|
|
cpu: "50m"
|
||
|
|
memory: "64Mi"
|
||
|
|
```
|
||
|
|
|
||
|
|
> [!info] Quota vs LimitRange — 别搞混
|
||
|
|
>
|
||
|
|
> - **ResourceQuota** = namespace 总量天花板(整个房间能住多少人)
|
||
|
|
> - **LimitRange** = 单容器边界(每人占多大床位)
|
||
|
|
>
|
||
|
|
> 两者配合使用,既能防止个体乱配资源,又能防止群体耗尽配额。
|
||
|
|
|
||
|
|
## NetworkPolicy — 网络安全策略
|
||
|
|
|
||
|
|
默认情况下,K8s 集群内所有 Pod 可以自由互访(零信任缺失)。NetworkPolicy 提供 L3/L4 层的双向流量控制:
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
apiVersion: networking.k8s.io/v1
|
||
|
|
kind: NetworkPolicy
|
||
|
|
metadata:
|
||
|
|
name: order-service-policy
|
||
|
|
namespace: production
|
||
|
|
spec:
|
||
|
|
podSelector:
|
||
|
|
matchLabels:
|
||
|
|
app: order-service
|
||
|
|
policyTypes:
|
||
|
|
- Ingress
|
||
|
|
- Egress
|
||
|
|
|
||
|
|
ingress:
|
||
|
|
# 允许来自 Ingress Controller 和 user-service 的流量
|
||
|
|
- from:
|
||
|
|
- namespaceSelector:
|
||
|
|
matchLabels:
|
||
|
|
name: ingress-ns
|
||
|
|
- podSelector:
|
||
|
|
matchLabels:
|
||
|
|
app: user-service
|
||
|
|
ports:
|
||
|
|
- protocol: TCP
|
||
|
|
port: 8080
|
||
|
|
|
||
|
|
egress:
|
||
|
|
# 允许 outbound DB 连接和 DNS 查询
|
||
|
|
- to:
|
||
|
|
- podSelector:
|
||
|
|
matchLabels:
|
||
|
|
app: mysql
|
||
|
|
ports:
|
||
|
|
- protocol: TCP
|
||
|
|
port: 3306
|
||
|
|
- to:
|
||
|
|
- namespaceSelector: {}
|
||
|
|
ports:
|
||
|
|
- protocol: UDP
|
||
|
|
port: 53 # DNS(必备!否则 Pod 无法解析域名)
|
||
|
|
```
|
||
|
|
|
||
|
|
### NetworkPolicy 最佳实践
|
||
|
|
|
||
|
|
| 原则 | 说明 |
|
||
|
|
|------|------|
|
||
|
|
| **默认拒绝全部** | 先用 `podSelector: {}` + 空 ingress/egress 拦截一切 |
|
||
|
|
| **白名单精确匹配** | 每个 Policy 只放开一个方向的流量 |
|
||
|
|
| **DNS 永远放行** | 没有 egress DNS 规则,Service 发现全部失效 |
|
||
|
|
| **跨命名空间要显式声明** | namespaceSelector 为空 `{}` 表示允许所有命名空间 |
|
||
|
|
|
||
|
|
### 支持 NetworkPolicy 的网络插件
|
||
|
|
|
||
|
|
> [!warning] NetworkPolicy 生效前提
|
||
|
|
>
|
||
|
|
> NetworkPolicy **需要集群网络插件支持**。默认的 Kubenet / Flannel 不一定支持,推荐使用:
|
||
|
|
> - **Calico** — 功能最完整,支持 L7 策略(与 Istio 配合)
|
||
|
|
> - **Cilium** — 基于 eBPF,性能最优,原生支持 L7 过滤
|
||
|
|
> - **Antrea** — VMware 出品,兼容性好
|
||
|
|
|
||
|
|
### 补充:Zero-Trust 默认策略模板
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# ========== 全局:默认拒绝所有入站 ==========
|
||
|
|
apiVersion: networking.k8s.io/v1
|
||
|
|
kind: NetworkPolicy
|
||
|
|
metadata:
|
||
|
|
name: default-deny-all-ingress
|
||
|
|
namespace: production
|
||
|
|
spec:
|
||
|
|
podSelector: {} # 选择所有 Pod
|
||
|
|
policyTypes:
|
||
|
|
- Ingress
|
||
|
|
|
||
|
|
---
|
||
|
|
# ========== 全局:默认拒绝所有出站 ==========
|
||
|
|
apiVersion: networking.k8s.io/v1
|
||
|
|
kind: NetworkPolicy
|
||
|
|
metadata:
|
||
|
|
name: default-deny-all-egress
|
||
|
|
namespace: production
|
||
|
|
spec:
|
||
|
|
podSelector: {}
|
||
|
|
policyTypes:
|
||
|
|
- Egress
|
||
|
|
```
|
||
|
|
|
||
|
|
> [!tip] 渐进式实施 NetworkPolicy
|
||
|
|
>
|
||
|
|
> 不要在已有集群上一夜之间切换所有策略——这会立刻打飞所有服务。正确的做法:
|
||
|
|
>
|
||
|
|
> 1. 先以 **audit** 模式运行 Calico/Cilium,观察现有流量
|
||
|
|
> 2. 对每个服务编写 allowlist Policy,在 **测试环境** 验证
|
||
|
|
> 3. 逐步推广到生产,从非关键服务开始
|
||
|
|
> 4. 最终启用 deny-all 作为兜底
|
||
|
|
|
||
|
|
## 补充:SecurityContext — 容器级安全加固
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
spec:
|
||
|
|
containers:
|
||
|
|
- name: order-service
|
||
|
|
securityContext:
|
||
|
|
runAsNonRoot: true # 禁止 root 运行
|
||
|
|
readOnlyRootFilesystem: true # 根文件系统只读
|
||
|
|
allowPrivilegeEscalation: false # 禁止提权
|
||
|
|
capabilities:
|
||
|
|
drop: ["ALL"] # 丢弃所有内核能力
|
||
|
|
add: ["NET_BIND_SERVICE"] # 仅保留绑定 <1024 端口需要的能力
|
||
|
|
|
||
|
|
# Pod 级别的 DNS 配置
|
||
|
|
dnsPolicy: ClusterFirstWithHostNet # DNS 策略
|
||
|
|
automountServiceAccountToken: false # 不挂载 SA Token(不需要 API 时)
|
||
|
|
```
|
||
|
|
|
||
|
|
> [!warning] readOnlyRootFilesystem 的坑
|
||
|
|
>
|
||
|
|
> 某些应用(如 Python 的 pip 缓存、Java 的 temp 目录)会尝试写入 `/tmp` 或应用目录。解决方案:
|
||
|
|
>
|
||
|
|
> ```yaml
|
||
|
|
> volumeMounts:
|
||
|
|
> - name: tmp-volume
|
||
|
|
> mountPath: /tmp
|
||
|
|
> volumes:
|
||
|
|
> - name: tmp-volume
|
||
|
|
> emptyDir: {}
|
||
|
|
> ```
|
||
|
|
>
|
||
|
|
> 通过 `emptyDir` 挂载临时卷,既保持了根文件系统只读,又给了应用必要的写权限。
|
||
|
|
|
||
|
|
## 关联笔记
|
||
|
|
|
||
|
|
- [[../02-配置管理]] — Secret 资源与 RBAC 共同构成安全基线
|
||
|
|
- [[../05-调度控制]] — 调度控制 + 网络策略 = 纵深防御
|
||
|
|
- [[../03-CICD与GitOps/04-安全与发布策略]] — GitOps 中的 Secret 安全
|