container-security

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Container Security

容器安全

Overview

概述

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

容器安全层级

LayerControlsTools
ImageMinimal base, vulnerability scanning, signingTrivy, Cosign, Grype
BuildMulti-stage builds, non-root, no secretsDocker, Buildah, Kaniko
RegistryScanning, signing verification, access controlHarbor, ECR, ACR
RuntimeSeccomp, AppArmor, read-only rootgVisor, Kata, Falco
OrchestrationPod security, RBAC, network policiesKubernetes, OPA/Gatekeeper
SecretsEncrypted at rest, external providersVault, 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

dockerfile
undefined
dockerfile
undefined

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)

先复制依赖文件(利用层缓存)

COPY package*.json ./
COPY package*.json ./

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 . .

Build if needed

若需要则构建

RUN npm run build
RUN npm run build

--- 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

切换到非根用户

USER appuser
USER appuser

Security: Use dumb-init to handle signals

安全设置:使用dumb-init处理信号

ENTRYPOINT ["dumb-init", "--"]
ENTRYPOINT ["dumb-init", "--"]

Health check

健康检查

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"]
undefined
EXPOSE 3000
CMD ["node", "dist/server.js"]
undefined

Distroless Production Image

无基础镜像(Distroless)生产镜像

dockerfile
undefined
dockerfile
undefined

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"]
undefined
USER 65532:65532
EXPOSE 8080
ENTRYPOINT ["/server"]
undefined

Image Scanning

镜像扫描

Trivy Scanning

Trivy扫描

bash
undefined
bash
undefined

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
undefined
trivy image --ignore-unfixed myapp:latest
undefined

CI Pipeline Image Scanning

CI流水线镜像扫描

yaml
undefined
yaml
undefined

.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 }}
undefined
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 }}
undefined

Kubernetes Pod Security

Kubernetes Pod安全

Pod Security Standards (PSS)

Pod安全标准(PSS)

yaml
undefined
yaml
undefined

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
undefined
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
undefined

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

Network Policies

网络策略

Default Deny All

默认拒绝所有流量

yaml
undefined
yaml
undefined

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
undefined
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-all namespace: production spec: podSelector: {} policyTypes: - Ingress - Egress
undefined

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

最小权限服务账号

yaml
undefined
yaml
undefined

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
undefined
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
undefined

Audit RBAC Permissions

审计RBAC权限

bash
undefined
bash
undefined

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}'
undefined
kubectl get roles,clusterroles -A -o json | jq '.items[] | select(.rules[]?.resources[]? == "" or .rules[]?.verbs[]? == "") | {name: .metadata.name, namespace: .metadata.namespace}'
undefined

Secrets Management

密钥管理

External Secrets Operator

External Secrets Operator

yaml
undefined
yaml
undefined

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
undefined
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
undefined

Sealed Secrets

Sealed Secrets

bash
undefined
bash
undefined

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

Seal a secret

加密密钥

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仓库

cat sealed-secret.yaml
undefined
cat sealed-secret.yaml
undefined

Runtime Security

运行时安全

Falco Rules

Falco规则

yaml
undefined
yaml
undefined

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]
undefined
  • 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]
undefined

Quick Reference

快速参考

Dockerfile Security Checklist

Dockerfile安全检查清单

CheckCommand/Pattern
No latest tag
FROM image:specific-version
Non-root user
USER 1000
No secrets in image
trivy fs --security-checks secret .
Multi-stage buildSeparate builder and production stages
Read-only filesystem
--read-only
or
readOnlyRootFilesystem: true
Minimal base imageAlpine, distroless, or scratch
Signed image
cosign sign
/
cosign verify
检查项命令/模式
不使用latest标签
FROM image:specific-version
非根用户运行
USER 1000
镜像中不包含密钥
trivy fs --security-checks secret .
多阶段构建分离构建阶段与生产阶段
只读文件系统
--read-only
readOnlyRootFilesystem: true
最小化基础镜像Alpine、distroless或scratch
镜像签名
cosign sign
/
cosign verify

Kubernetes Security Checklist

Kubernetes安全检查清单

CheckSetting
Non-root
runAsNonRoot: true
No privilege escalation
allowPrivilegeEscalation: false
Drop capabilities
capabilities: {drop: [ALL]}
Read-only root
readOnlyRootFilesystem: true
Resource limits
resources.limits
defined
Network policiesDefault deny + explicit allow
Seccomp profile
seccompProfile: {type: RuntimeDefault}
No host namespaces
hostNetwork/PID/IPC: false
检查项设置
非根用户运行
runAsNonRoot: true
禁止权限升级
allowPrivilegeEscalation: false
移除不必要的权限
capabilities: {drop: [ALL]}
只读根文件系统
readOnlyRootFilesystem: true
资源限制定义
resources.limits
网络策略默认拒绝+显式允许
Seccomp配置
seccompProfile: {type: RuntimeDefault}
禁用主机命名空间
hostNetwork/PID/IPC: false

References

参考资料

  • 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