容器安全:Docker和Kubernetes安全
容器安全架构
容器安全层次:
├── 镜像安全: 扫描和验证镜像
├── 运行时安全: 容器运行时保护
├── 网络安全: 网络策略和隔离
├── 存储安全: 数据加密和访问控制
└── 编排安全: Kubernetes安全配置
镜像安全
镜像扫描
# 使用Trivy扫描镜像
trivy image nginx:latest
trivy image --severity HIGH,CRITICAL nginx:latest
# 扫描本地镜像
trivy image -f json -o results.json myapp:latest
# 扫描并修复
trivy image --fix --remove myapp:latest
安全基础镜像
# 使用最小化基础镜像
FROM alpine:3.18
# 添加非root用户
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# 设置文件权限
COPY --chown=appuser:appgroup app /app
# 切换到非root用户
USER appuser
# 运行应用
CMD ["/app/server"]
镜像签名验证
# 使用cosign签名镜像
cosign sign --key cosign.key myregistry/myapp:latest
# 验证签名
cosign verify --key cosign.pub myregistry/myapp:latest
# 在Kubernetes中验证
apiVersion: v1
kind: Pod
metadata:
name: verified-app
spec:
containers:
- name: app
image: myregistry/myapp:latest
imagePullSecrets:
- name: registry-credentials
运行时安全
Seccomp配置
{
"defaultAction": "SCMP_ACT_ERRNO",
"defaultErrnoRet": 1,
"architectures": ["SCMP_ARCH_X86_64"],
"syscalls": [
{
"names": [
"accept", "access", "arch_prctl", "bind", "brk",
"clone", "close", "connect", "dup", "epoll_create1",
"epoll_ctl", "epoll_wait", "execve", "exit",
"exit_group", "fcntl", "fstat", "futex",
"getdents64", "getpid", "getsockname", "getsockopt",
"ioctl", "listen", "mmap", "mprotect",
"nanosleep", "newfstatat", "openat", "pipe",
"poll", "prlimit64", "read", "recvfrom",
"rt_sigaction", "rt_sigprocmask", "sendto",
"set_robust_list", "set_tid_address", "setsockopt",
"socket", "stat", "statfs", "write", "writev"
],
"action": "SCMP_ACT_ALLOW"
}
]
}
AppArmor配置
# /etc/apparmor.d/docker-nginx
#include <tunables/global>
profile docker-nginx flags=(attach_disconnected,mediate_deleted) {
#include <abstractions/base>
network inet tcp,
network inet udp,
deny /proc/sys/[^f]** w,
deny /sys/[^f]** w,
/app/** r,
/app/server ix,
/tmp/** rw,
/var/log/nginx/** rw,
}
Kubernetes安全
Pod安全策略
# pod-security-policy.yaml
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted
annotations:
seccomp.security.alpha.kubernetes.io/allowedProfiles: 'runtime/default'
apparmor.security.alpha.kubernetes.io/allowedProfiles: 'runtime/default'
spec:
privileged: false
allowPrivilegeEscalation: false
requiredDropCapabilities:
- ALL
volumes:
- 'configMap'
- 'emptyDir'
- 'projected'
- 'secret'
- 'downwardAPI'
- 'persistentVolumeClaim'
hostNetwork: false
hostIPC: false
hostPID: false
runAsUser:
rule: 'MustRunAsNonRoot'
seLinux:
rule: 'RunAsAny'
supplementalGroups:
rule: 'MustRunAs'
ranges:
- min: 1
max: 65535
fsGroup:
rule: 'RunAsAny'
RBAC配置
# rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: production
subjects:
- kind: ServiceAccount
name: default
namespace: production
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
网络策略
# network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
密钥管理
Kubernetes Secrets加密
# encrypted-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: app-secret
namespace: production
type: Opaque
data:
username: YWRtaW4= # base64 encoded
password: cGFzc3dvcmQ=
使用外部密钥管理
# external-secrets.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: app-secret
namespace: production
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: ClusterSecretStore
target:
name: app-secret
data:
- secretKey: username
remoteRef:
key: prod/app/credentials
property: username
- secretKey: password
remoteRef:
key: prod/app/credentials
property: password
安全扫描
自动化安全扫描
# github-actions-security.yaml
name: Security Scan
on: [push, pull_request]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Run Snyk security scan
uses: snyk/actions/docker@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: '--severity-threshold=high'
监控和审计
# falco-rules.yaml
- rule: Detect outbound connections to C2 servers
desc: Detect connections to known command and control servers
condition: >
outbound and
fd.sip.name in c2_servers
output: >
Outbound connection to C2 server
(user=%user.name command=%proc.cmdline connection=%fd.name)
priority: CRITICAL
tags: [network, c2]
- rule: Container Drift Detected
desc: Detect new executable created in running container
condition: >
evt.type = execve and
container and
proc.name != sysdig and
not proc.name in (known_binaries)
output: >
Drift detected in container
(user=%user.name container=%container.name command=%proc.cmdline)
priority: WARNING
最佳实践
- 最小化基础镜像: 使用Alpine等最小化镜像
- 非root运行: 容器使用非root用户运行
- 只读文件系统: 设置只读根文件系统
- 资源限制: 设置CPU和内存限制
- 网络策略: 实施网络隔离策略
- 定期扫描: 定期扫描镜像和运行时漏洞