This skill covers security best practices for containerized applications, including Docker image hardening, Kubernetes security configurations, image vulnerability scanning, and runtime protection.
Keywords: container security, Docker, Kubernetes, image scanning, Dockerfile, pod security, network policies, RBAC, container runtime, Trivy, Falco, gVisor, seccomp, AppArmor, distroless, rootless containers
本技能涵盖容器化应用的安全最佳实践,包括Docker镜像加固、Kubernetes安全配置、镜像漏洞扫描以及运行时防护。
关键词: 容器安全, Docker, Kubernetes, 镜像扫描, Dockerfile, Pod安全, 网络策略, RBAC, 容器运行时, Trivy, Falco, gVisor, seccomp, AppArmor, 无基础镜像(distroless), 无根容器
When to Use This Skill
适用场景
- Building secure Docker images
- Configuring Kubernetes pod security
- Setting up container vulnerability scanning
- Implementing Kubernetes RBAC
- Configuring network policies
- Managing secrets in Kubernetes
- Setting up runtime security monitoring
- 构建安全的Docker镜像
- 配置Kubernetes Pod安全策略
- 搭建容器漏洞扫描机制
- 实现Kubernetes RBAC权限控制
- 配置网络策略
- 在Kubernetes中管理密钥
- 搭建运行时安全监控
Container Security Layers
容器安全层级
| Layer | Controls | Tools |
|---|
| Image | Minimal base, vulnerability scanning, signing | Trivy, Cosign, Grype |
| Build | Multi-stage builds, non-root, no secrets | Docker, Buildah, Kaniko |
| Registry | Scanning, signing verification, access control | Harbor, ECR, ACR |
| Runtime | Seccomp, AppArmor, read-only root | gVisor, Kata, Falco |
| Orchestration | Pod security, RBAC, network policies | Kubernetes, OPA/Gatekeeper |
| Secrets | Encrypted at rest, external providers | Vault, Sealed Secrets, ESO |
| 层级 | 管控措施 | 工具 |
|---|
| 镜像层 | 最小化基础镜像、漏洞扫描、镜像签名 | Trivy, Cosign, Grype |
| 构建层 | 多阶段构建、非根用户运行、不嵌入密钥 | Docker, Buildah, Kaniko |
| 镜像仓库层 | 扫描、签名验证、访问控制 | Harbor, ECR, ACR |
| 运行时层 | Seccomp、AppArmor、只读根文件系统 | gVisor, Kata, Falco |
| 编排层 | Pod安全、RBAC、网络策略 | Kubernetes, OPA/Gatekeeper |
| 密钥层 | 静态加密、外部密钥管理 | Vault, Sealed Secrets, ESO |
Secure Dockerfile Patterns
安全Dockerfile示例
Minimal Secure Dockerfile
最小化安全Dockerfile
Use specific version, not :latest
使用特定版本,而非:latest
FROM node:20.10-alpine3.19 AS builder
FROM node:20.10-alpine3.19 AS builder
Create non-root user early
提前创建非根用户
RUN addgroup -g 1001 -S appgroup &&
adduser -u 1001 -S appuser -G appgroup
WORKDIR /app
RUN addgroup -g 1001 -S appgroup &&
adduser -u 1001 -S appuser -G appgroup
WORKDIR /app
Copy dependency files first (layer caching)
先复制依赖文件(利用层缓存)
Install dependencies with security flags
带安全参数安装依赖
RUN npm ci --only=production --ignore-scripts &&
npm cache clean --force
RUN npm ci --only=production --ignore-scripts &&
npm cache clean --force
Copy application code
复制应用代码
COPY --chown=appuser:appgroup . .
COPY --chown=appuser:appgroup . .
--- Production Stage ---
--- 生产阶段 ---
FROM node:20.10-alpine3.19 AS production
FROM node:20.10-alpine3.19 AS production
Security: Don't run as root
安全设置:不以root用户运行
RUN addgroup -g 1001 -S appgroup &&
adduser -u 1001 -S appuser -G appgroup
RUN addgroup -g 1001 -S appgroup &&
adduser -u 1001 -S appuser -G appgroup
Security: Remove unnecessary packages
安全设置:移除不必要的包
RUN apk --no-cache add dumb-init &&
rm -rf /var/cache/apk/*
WORKDIR /app
RUN apk --no-cache add dumb-init &&
rm -rf /var/cache/apk/*
WORKDIR /app
Copy only production artifacts
仅复制生产环境产物
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
COPY --from=builder --chown=appuser:appgroup /app/package.json ./
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
COPY --from=builder --chown=appuser:appgroup /app/package.json ./
Security: Read-only filesystem support
安全设置:支持只读文件系统
RUN mkdir -p /app/tmp && chown appuser:appgroup /app/tmp
RUN mkdir -p /app/tmp && chown appuser:appgroup /app/tmp
Switch to non-root user
切换到非根用户
Security: Use dumb-init to handle signals
安全设置:使用dumb-init处理信号
ENTRYPOINT ["dumb-init", "--"]
ENTRYPOINT ["dumb-init", "--"]
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3
CMD node healthcheck.js || exit 1
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3
CMD node healthcheck.js || exit 1
Expose port (non-privileged)
暴露非特权端口
EXPOSE 3000
CMD ["node", "dist/server.js"]
EXPOSE 3000
CMD ["node", "dist/server.js"]
Distroless Production Image
无基础镜像(Distroless)生产镜像
Build stage with full toolchain
带完整工具链的构建阶段
FROM golang:1.22-alpine AS builder
RUN apk add --no-cache git ca-certificates
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
FROM golang:1.22-alpine AS builder
RUN apk add --no-cache git ca-certificates
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
Build static binary
构建静态二进制文件
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64
go build -ldflags='-w -s -extldflags "-static"'
-o /app/server ./cmd/server
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64
go build -ldflags='-w -s -extldflags "-static"'
-o /app/server ./cmd/server
--- Distroless production image ---
--- Distroless生产镜像 ---
FROM gcr.io/distroless/static-debian12:nonroot
FROM gcr.io/distroless/static-debian12:nonroot
Copy binary and CA certs
复制二进制文件和CA证书
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /app/server /server
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /app/server /server
Run as non-root (65532 is the nonroot user in distroless)
以非根用户运行(65532是distroless中的非根用户ID)
USER 65532:65532
EXPOSE 8080
ENTRYPOINT ["/server"]
USER 65532:65532
EXPOSE 8080
ENTRYPOINT ["/server"]
Scan image for vulnerabilities
扫描镜像中的漏洞
trivy image --severity CRITICAL,HIGH myapp:latest
trivy image --severity CRITICAL,HIGH myapp:latest
Scan with SBOM generation
扫描并生成SBOM
trivy image --format cyclonedx --output sbom.json myapp:latest
trivy image --format cyclonedx --output sbom.json myapp:latest
Scan filesystem (for CI before building)
扫描文件系统(CI构建前执行)
trivy fs --security-checks vuln,secret,config .
trivy fs --security-checks vuln,secret,config .
Scan with exit code for CI
扫描并返回退出码用于CI流程
trivy image --exit-code 1 --severity CRITICAL myapp:latest
trivy image --exit-code 1 --severity CRITICAL myapp:latest
Ignore unfixed vulnerabilities
忽略未修复的漏洞
trivy image --ignore-unfixed myapp:latest
trivy image --ignore-unfixed myapp:latest
CI Pipeline Image Scanning
CI流水线镜像扫描
.github/workflows/container-security.yml
.github/workflows/container-security.yml
name: Container Security
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- 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
exit-code: '1'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: trivy-results.sarif
- name: Run Dockle linter
uses: erzz/dockle-action@v1
with:
image: myapp:${{ github.sha }}
failure-threshold: high
- name: Sign image with Cosign
if: github.ref == 'refs/heads/main'
env:
COSIGN_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
run: |
cosign sign --key env://COSIGN_KEY myapp:${{ github.sha }}
name: Container Security
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- 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
exit-code: '1'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: trivy-results.sarif
- name: Run Dockle linter
uses: erzz/dockle-action@v1
with:
image: myapp:${{ github.sha }}
failure-threshold: high
- name: Sign image with Cosign
if: github.ref == 'refs/heads/main'
env:
COSIGN_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
run: |
cosign sign --key env://COSIGN_KEY myapp:${{ github.sha }}
Kubernetes Pod Security
Kubernetes Pod安全
Pod Security Standards (PSS)
Pod安全标准(PSS)
Enforce Pod Security Standards at namespace level
在命名空间级别强制实施Pod安全标准
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
# Enforce restricted policy
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
# Warn on baseline violations
pod-security.kubernetes.io/warn: baseline
pod-security.kubernetes.io/warn-version: latest
# Audit all violations
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/audit-version: latest
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
# 强制实施restricted策略
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
# 对baseline违规发出警告
pod-security.kubernetes.io/warn: baseline
pod-security.kubernetes.io/warn-version: latest
# 审计所有违规行为
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/audit-version: latest
Secure Pod Specification
安全Pod配置
yaml
apiVersion: v1
kind: Pod
metadata:
name: secure-app
labels:
app: secure-app
spec:
# Prevent privilege escalation across containers
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
# Service account with minimal permissions
serviceAccountName: app-minimal-sa
automountServiceAccountToken: false
containers:
- name: app
image: myapp:v1.0.0@sha256:abc123...
imagePullPolicy: Always
# Container-level security context
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
# Resource limits (prevent DoS)
resources:
limits:
cpu: "500m"
memory: "256Mi"
ephemeral-storage: "100Mi"
requests:
cpu: "100m"
memory: "128Mi"
# Writable directories via emptyDir
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /app/cache
# Health probes
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
volumes:
- name: tmp
emptyDir:
sizeLimit: 10Mi
- name: cache
emptyDir:
sizeLimit: 50Mi
# DNS policy for security
dnsPolicy: ClusterFirst
# Host settings (all disabled for security)
hostNetwork: false
hostPID: false
hostIPC: false
yaml
apiVersion: v1
kind: Pod
metadata:
name: secure-app
labels:
app: secure-app
spec:
# 防止容器间权限升级
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
# 最小权限的服务账号
serviceAccountName: app-minimal-sa
automountServiceAccountToken: false
containers:
- name: app
image: myapp:v1.0.0@sha256:abc123...
imagePullPolicy: Always
# 容器级安全上下文
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
# 资源限制(防止DoS攻击)
resources:
limits:
cpu: "500m"
memory: "256Mi"
ephemeral-storage: "100Mi"
requests:
cpu: "100m"
memory: "128Mi"
# 通过emptyDir挂载可写目录
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /app/cache
# 健康探针
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
volumes:
- name: tmp
emptyDir:
sizeLimit: 10Mi
- name: cache
emptyDir:
sizeLimit: 50Mi
# 安全DNS策略
dnsPolicy: ClusterFirst
# 主机设置(全部禁用以提升安全性)
hostNetwork: false
hostPID: false
hostIPC: false
Default deny all ingress and egress
默认拒绝所有入站和出站流量
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: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Application-Specific Policy
应用专属策略
yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-network-policy
namespace: production
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
- Egress
ingress:
# Allow from ingress controller only
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
podSelector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
ports:
- protocol: TCP
port: 8080
# Allow from specific services
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
egress:
# Allow DNS
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
# Allow database access
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
# Allow external HTTPS
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
ports:
- protocol: TCP
port: 443
yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-network-policy
namespace: production
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
- Egress
ingress:
# 仅允许来自Ingress控制器的流量
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
podSelector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
ports:
- protocol: TCP
port: 8080
# 仅允许来自特定服务的流量
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
egress:
# 允许DNS请求
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
# 允许访问数据库
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
# 允许外部HTTPS访问
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
ports:
- protocol: TCP
port: 443
Kubernetes RBAC
Kubernetes RBAC
Minimal Service Account
最小权限服务账号
Service account with no auto-mounted token
不自动挂载令牌的服务账号
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-minimal-sa
namespace: production
automountServiceAccountToken: false
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-minimal-sa
namespace: production
automountServiceAccountToken: false
Role with minimal permissions
最小权限角色
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: app-role
namespace: production
rules:
Only allow reading configmaps
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["app-config"]
verbs: ["get"]
Only allow reading specific secrets
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["app-credentials"]
verbs: ["get"]
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: app-role
namespace: production
rules:
仅允许读取指定ConfigMap
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["app-config"]
verbs: ["get"]
仅允许读取指定Secret
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["app-credentials"]
verbs: ["get"]
Bind role to service account
将角色绑定到服务账号
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-role-binding
namespace: production
subjects:
- kind: ServiceAccount
name: app-minimal-sa
namespace: production
roleRef:
kind: Role
name: app-role
apiGroup: rbac.authorization.k8s.io
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-role-binding
namespace: production
subjects:
- kind: ServiceAccount
name: app-minimal-sa
namespace: production
roleRef:
kind: Role
name: app-role
apiGroup: rbac.authorization.k8s.io
Audit RBAC Permissions
审计RBAC权限
List all cluster-admin bindings (high risk)
列出所有cluster-admin绑定(高风险)
kubectl get clusterrolebindings -o json | jq '.items[] |
select(.roleRef.name == "cluster-admin") |
{name: .metadata.name, subjects: .subjects}'
kubectl get clusterrolebindings -o json | jq '.items[] |
select(.roleRef.name == "cluster-admin") |
{name: .metadata.name, subjects: .subjects}'
Check service account permissions
检查服务账号权限
kubectl auth can-i --list --as=system:serviceaccount:production:app-minimal-sa
kubectl auth can-i --list --as=system:serviceaccount:production:app-minimal-sa
Find overly permissive roles (using wildcards)
查找权限过度宽松的角色(使用通配符)
kubectl get roles,clusterroles -A -o json | jq '.items[] |
select(.rules[]?.resources[]? == "" or .rules[]?.verbs[]? == "") |
{name: .metadata.name, namespace: .metadata.namespace}'
kubectl get roles,clusterroles -A -o json | jq '.items[] |
select(.rules[]?.resources[]? == "" or .rules[]?.verbs[]? == "") |
{name: .metadata.name, namespace: .metadata.namespace}'
External Secrets Operator
External Secrets Operator
SecretStore pointing to HashiCorp Vault
指向HashiCorp Vault的SecretStore
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: vault-backend
namespace: production
spec:
provider:
vault:
server: "https://vault.example.com"
path: "secret"
version: "v2"
auth:
kubernetes:
mountPath: "kubernetes"
role: "production-role"
serviceAccountRef:
name: "vault-auth-sa"
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: vault-backend
namespace: production
spec:
provider:
vault:
server: "https://vault.example.com"
path: "secret"
version: "v2"
auth:
kubernetes:
mountPath: "kubernetes"
role: "production-role"
serviceAccountRef:
name: "vault-auth-sa"
External Secret syncing from Vault
从Vault同步的外部密钥
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: app-secrets
namespace: production
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: app-secrets
creationPolicy: Owner
template:
type: Opaque
data:
DATABASE_URL: "{{ .database_url }}"
API_KEY: "{{ .api_key }}"
data:
- secretKey: database_url
remoteRef:
key: production/app
property: database_url
- secretKey: api_key
remoteRef:
key: production/app
property: api_key
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: app-secrets
namespace: production
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: app-secrets
creationPolicy: Owner
template:
type: Opaque
data:
DATABASE_URL: "{{ .database_url }}"
API_KEY: "{{ .api_key }}"
data:
- secretKey: database_url
remoteRef:
key: production/app
property: database_url
- secretKey: api_key
remoteRef:
key: production/app
property: api_key
Sealed Secrets
Sealed Secrets
Install sealed-secrets controller
安装sealed-secrets控制器
helm install sealed-secrets sealed-secrets/sealed-secrets
--namespace kube-system
helm install sealed-secrets sealed-secrets/sealed-secrets
--namespace kube-system
kubectl create secret generic my-secret
--from-literal=password=supersecret
--dry-run=client -o yaml |
kubeseal --format yaml > sealed-secret.yaml
kubectl create secret generic my-secret
--from-literal=password=supersecret
--dry-run=client -o yaml |
kubeseal --format yaml > sealed-secret.yaml
The sealed secret can be safely committed to git
加密后的密钥可安全提交到Git仓库
Custom Falco rules
自定义Falco规则
-
rule: Unauthorized Process in Container
desc: Detect unauthorized processes running in containers
condition: >
spawned_process and
container and
not proc.name in (allowed_processes) and
not container.image.repository in (trusted_images)
output: >
Unauthorized process started (user=%user.name command=%proc.cmdline
container=%container.name image=%container.image.repository)
priority: WARNING
tags: [container, process]
-
rule: Write to Sensitive Directories
desc: Detect writes to sensitive directories in containers
condition: >
open_write and
container and
(fd.name startswith /etc/ or
fd.name startswith /bin/ or
fd.name startswith /sbin/ or
fd.name startswith /usr/bin/)
output: >
Write to sensitive directory (file=%fd.name user=%user.name
container=%container.name image=%container.image.repository)
priority: ERROR
tags: [container, filesystem]
-
rule: Container Shell Spawned
desc: Detect shell spawned in container
condition: >
spawned_process and
container and
proc.name in (shell_binaries) and
not proc.pname in (allowed_shell_parents)
output: >
Shell spawned in container (user=%user.name shell=%proc.name
parent=%proc.pname container=%container.name)
priority: WARNING
tags: [container, shell]
-
list: shell_binaries
items: [bash, sh, zsh, ash, dash, ksh, tcsh, csh]
-
list: allowed_shell_parents
items: [crond, sshd, sudo]
-
rule: Unauthorized Process in Container
desc: Detect unauthorized processes running in containers
condition: >
spawned_process and
container and
not proc.name in (allowed_processes) and
not container.image.repository in (trusted_images)
output: >
Unauthorized process started (user=%user.name command=%proc.cmdline
container=%container.name image=%container.image.repository)
priority: WARNING
tags: [container, process]
-
rule: Write to Sensitive Directories
desc: Detect writes to sensitive directories in containers
condition: >
open_write and
container and
(fd.name startswith /etc/ or
fd.name startswith /bin/ or
fd.name startswith /sbin/ or
fd.name startswith /usr/bin/)
output: >
Write to sensitive directory (file=%fd.name user=%user.name
container=%container.name image=%container.image.repository)
priority: ERROR
tags: [container, filesystem]
-
rule: Container Shell Spawned
desc: Detect shell spawned in container
condition: >
spawned_process and
container and
proc.name in (shell_binaries) and
not proc.pname in (allowed_shell_parents)
output: >
Shell spawned in container (user=%user.name shell=%proc.name
parent=%proc.pname container=%container.name)
priority: WARNING
tags: [container, shell]
-
list: shell_binaries
items: [bash, sh, zsh, ash, dash, ksh, tcsh, csh]
-
list: allowed_shell_parents
items: [crond, sshd, sudo]
Dockerfile Security Checklist
Dockerfile安全检查清单
| Check | Command/Pattern |
|---|
| No latest tag | FROM image:specific-version
|
| Non-root user | |
| No secrets in image | trivy fs --security-checks secret .
|
| Multi-stage build | Separate builder and production stages |
| Read-only filesystem | or readOnlyRootFilesystem: true
|
| Minimal base image | Alpine, distroless, or scratch |
| Signed image | / |
| 检查项 | 命令/模式 |
|---|
| 不使用latest标签 | FROM image:specific-version
|
| 非根用户运行 | |
| 镜像中不包含密钥 | trivy fs --security-checks secret .
|
| 多阶段构建 | 分离构建阶段与生产阶段 |
| 只读文件系统 | 或 readOnlyRootFilesystem: true
|
| 最小化基础镜像 | Alpine、distroless或scratch |
| 镜像签名 | / |
Kubernetes Security Checklist
Kubernetes安全检查清单
| Check | Setting |
|---|
| Non-root | |
| No privilege escalation | allowPrivilegeEscalation: false
|
| Drop capabilities | capabilities: {drop: [ALL]}
|
| Read-only root | readOnlyRootFilesystem: true
|
| Resource limits | defined |
| Network policies | Default deny + explicit allow |
| Seccomp profile | seccompProfile: {type: RuntimeDefault}
|
| No host namespaces | hostNetwork/PID/IPC: false
|
| 检查项 | 设置 |
|---|
| 非根用户运行 | |
| 禁止权限升级 | allowPrivilegeEscalation: false
|
| 移除不必要的权限 | capabilities: {drop: [ALL]}
|
| 只读根文件系统 | readOnlyRootFilesystem: true
|
| 资源限制 | 定义 |
| 网络策略 | 默认拒绝+显式允许 |
| Seccomp配置 | seccompProfile: {type: RuntimeDefault}
|
| 禁用主机命名空间 | hostNetwork/PID/IPC: false
|
- Dockerfile Hardening: See
references/dockerfile-security.md
for detailed patterns
- Kubernetes Security: See
references/kubernetes-security.md
for comprehensive K8s guidance
- Container Scanning: See
references/container-scanning.md
for scanner configurations
Last Updated: 2025-12-26
- Dockerfile加固: 详见
references/dockerfile-security.md
获取详细模式
- Kubernetes安全: 详见
references/kubernetes-security.md
获取全面的K8s安全指南
- 容器扫描: 详见
references/container-scanning.md
获取扫描器配置说明
最后更新: 2025-12-26