镜像仓库验证策略

本指南演示如何配置 Kyverno 来控制 Kubernetes 集群中可使用的容器镜像仓库。它实现了仓库访问控制策略,确保只部署来自批准且可信的仓库的镜像。

目录

什么是镜像仓库验证?

仓库验证提供了对镜像来源的集中控制。它能够:

  • 控制镜像来源:仅允许来自可信仓库的镜像
  • 阻止风险仓库:防止使用未知或被攻破的仓库
  • 强制合规:满足关于镜像来源的安全要求
  • 针对不同环境制定不同规则:生产环境严格,开发环境宽松
  • 跟踪使用情况:监控使用了哪些仓库

快速开始

1. 阻止除公司仓库外的所有仓库

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: company-registry-only
spec:
  validationFailureAction: Enforce  # 阻止非批准镜像
  background: false
  rules:
    - name: check-registry
      match:
        any:
        - resources:
            kinds:
            - Pod
      validate:
        message: "仅允许公司仓库:registry.company.com"
        pattern:
          spec:
            containers:
            - image: "registry.company.com/*"

2. 测试策略

# 应用策略
kubectl apply -f registry-policy.yaml

# 这条命令会失败(nginx 来自 Docker Hub)
kubectl run test --image=nginx:latest

# 这条命令会成功(如果镜像存在于仓库中)
kubectl run test --image=registry.company.com/nginx:latest

常见场景

场景 1:允许多个可信仓库

组织通常使用多个仓库:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: multiple-trusted-registries
spec:
  validationFailureAction: Enforce
  background: false
  rules:
    - name: check-approved-registries
      match:
        any:
        - resources:
            kinds:
            - Pod
      validate:
        message: "镜像必须来自批准的仓库:公司仓库、GCR 或官方 Docker 镜像"
        anyPattern:
        - spec:
            containers:
            - image: "registry.company.com/*"      # 公司仓库
        - spec:
            containers:
            - image: "gcr.io/project-name/*"       # Google Container Registry
        - spec:
            containers:
            - image: "docker.io/library/*"         # 仅官方 Docker 镜像
        - spec:
            containers:
            - image: "quay.io/organization/*"      # Red Hat Quay

场景 2:不同环境不同规则

生产环境应严格,开发环境可更灵活:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: environment-based-registry-rules
spec:
  validationFailureAction: Enforce
  background: false
  rules:
    # 生产环境:仅允许 Certified 镜像
    - name: production-strict-registries
      match:
        any:
        - resources:
            kinds:
            - Pod
            namespaces:
            - production
            - prod-*
      validate:
        message: "生产环境仅允许 Certified 公司镜像"
        pattern:
          spec:
            containers:
            - image: "registry.company.com/certified/*"
    
    # 开发环境:允许更多仓库
    - name: development-flexible-registries
      match:
        any:
        - resources:
            kinds:
            - Pod
            namespaces:
            - development
            - dev-*
            - staging
            - test-*
      validate:
        message: "开发环境允许使用公司仓库、GCR 或官方 Docker 镜像"
        anyPattern:
        - spec:
            containers:
            - image: "registry.company.com/*"
        - spec:
            containers:
            - image: "gcr.io/dev-project/*"
        - spec:
            containers:
            - image: "docker.io/library/*"
        - spec:
            containers:
            - image: "docker.io/organization/*"

场景 3:阻止特定风险仓库

阻止特定仓库,同时允许其他仓库:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: block-risky-registries
spec:
  validationFailureAction: Enforce
  background: false
  rules:
    # 方法 1:使用拒绝列表方式
    - name: block-untrusted-registries
      match:
        any:
        - resources:
            kinds:
            - Pod
      validate:
        message: "不允许使用来自 untrusted-registry.com 的镜像"
        deny:
          conditions:
          - key: "{{ request.object.spec.containers[?contains(image, 'untrusted-registry.com')] | length(@) }}"
            operator: GreaterThan
            value: 0
    
    # 方法 2:Docker Hub 仅允许官方镜像
    - name: allow-only-official-dockerhub
      match:
        any:
        - resources:
            kinds:
            - Pod
      validate:
        message: "仅允许官方 Docker Hub 镜像(docker.io/library/*)"
        deny:
          conditions:
          - key: "{{ request.object.spec.containers[?starts_with(image, 'docker.io/') && !starts_with(image, 'docker.io/library/')] | length(@) }}"
            operator: GreaterThan
            value: 0

场景 4:团队专属仓库访问

不同团队可访问不同仓库:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: team-specific-registries
spec:
  validationFailureAction: Enforce
  background: false
  rules:
    # 前端团队可使用 Node.js 镜像
    - name: frontend-team-registries
      match:
        any:
        - resources:
            kinds:
            - Pod
            namespaces:
            - frontend-*
      validate:
        message: "前端团队可使用公司仓库和官方 Node.js 镜像"
        anyPattern:
        - spec:
            containers:
            - image: "registry.company.com/*"
        - spec:
            containers:
            - image: "docker.io/library/node:*"
        - spec:
            containers:
            - image: "docker.io/library/nginx:*"
    
    # 数据团队可使用 ML/AI 镜像仓库
    - name: data-team-registries
      match:
        any:
        - resources:
            kinds:
            - Pod
            namespaces:
            - data-*
            - ml-*
      validate:
        message: "数据团队可使用公司仓库和 ML/AI 镜像"
        anyPattern:
        - spec:
            containers:
            - image: "registry.company.com/*"
        - spec:
            containers:
            - image: "docker.io/tensorflow/*"
        - spec:
            containers:
            - image: "docker.io/pytorch/*"
        - spec:
            containers:
            - image: "nvcr.io/nvidia/*"

高级模式

有效使用通配符

# 匹配模式:
- image: "registry.company.com/*"           # 来自该仓库的任意镜像
- image: "registry.company.com/team-a/*"    # 仅 team-a 的镜像
- image: "*/database:*"                     # 来自任意仓库的数据库镜像
- image: "gcr.io/project-*/app:*"          # GCR 中 project-* 下的任意 app 镜像

最佳实践

从警告模式开始

spec:
  validationFailureAction: Audit  # 从审计模式开始,不阻止

排除系统命名空间

rules:
  - name: check-registries
    match:
      any:
      - resources:
          kinds:
          - Pod
    exclude:
      any:
      - resources:
          namespaces:
          - kube-system
          - kyverno
          - kube-public

常见问题

  1. 镜像格式错误

    • registry.company.com:5000/app(缺少协议)
    • registry.company.com/app:latest
  2. 通配符使用错误

    • registry.company.com*(缺少斜杠)
    • registry.company.com/*
  3. Docker Hub 格式

    • nginx(隐式 docker.io)
    • docker.io/library/nginx