使用映像清理器清理 Azure Kubernetes 服务 (AKS) 群集上的易受攻击的过时映像

通常使用管道在 Azure Kubernetes 服务 (AKS) 群集上生成和部署映像。 虽然非常适合创建映像,但此过程通常不考虑留下的过时映像,并且可能导致群集节点上的映像膨胀。 这些映像可能包含可能会导致安全问题的漏洞。 若要消除集群中的安全风险,可以清理这些未被引用的镜像。 手动清理映像可能会占用大量时间。 映像清理器可自动识别和移除映像,从而降低过期映像的风险,并减少清理映像所需的时间。

注意

映像清理器是一项基于擦除器的功能。 在 AKS 上,功能名称和属性名称是 Image Cleaner,而相关的图像清理器 Pod 的名称包含 Eraser

先决条件

  • Azure 订阅。 如果没有Azure订阅,可以创建 Trial
  • 对于通过 Azure CLI 进行的 AKS 标准配置,需要 Azure CLI 版本 2.49.0 或更高版本。 运行 az --version 即可查找版本。 如果需要进行安装或升级,请参阅安装 Azure CLI

限制

映像清理器尚不支持 Windows 节点池或 AKS 虚拟节点。

映像清理器的工作原理

在群集上激活 Image Cleaner 时,它会部署名为 “ eraser-controller-manager控制器管理器” 的 Pod。

显示 ImageCleaner 工作流的示意图截图。运行在集群上的 ImageCleaner Pod 可以生成 ImageList,也可以手动提供输入。

图像清理器支持自动和手动清理模式。

AKS 标准版的配置选项

使用 Azure CLI 在 AKS 标准版上配置图像清理器时使用这些选项。

名称 说明 必填
--enable-image-cleaner 为 AKS 群集启用映像清理器 是,除非指定禁用
--disable-image-cleaner 为 AKS 群集禁用映像清理器 是,除非指定启用
--image-cleaner-interval-hours 计划运行间隔(按小时计) Azure CLI默认值为一周。 最小值为 24 小时。 最大值为三个月。 对于 Azure CLI,不需要;对于 ARM 模板或其他客户端,则需要

注意

如果禁用映像清理器,以后无需显式传递配置即可重新启用它,则会重复使用以前的配置值。

自动模式

部署 eraser-controller-manager时,映像清理器会自动执行以下操作:

  • 开始清理,并为每个节点创建 eraser-aks-xxxxx 工作 Pod。
  • 使用 收集器 容器收集未使用的映像。
  • 使用 trivy-scanner 容器通过 trivy 扫描漏洞。
  • 使用 删除器 容器删除未使用的带有漏洞的映像。
  • 完成后删除辅助角色 Pod。
  • 根据 --image-cleaner-interval-hours 安排下一次清理。

手动模式

你还可以通过定义 CRD 对象 ImageList 来手动触发清理。 这会触发 eraser-contoller-manager 为每个节点创建 eraser-aks-xxxxx 工作 Pod,并完成手动移除流程。

注意

禁用映像清理器后,旧配置仍然存在。 这意味着,如果在未显式传递配置的情况下再次启用该功能,则会使用现有值而不是默认值。

在 AKS 标准上使用图像清理器

AKS 标准版:在新群集上启用

在新的 AKS 标准群集上,使用带有 az aks create 参数的 --enable-image-cleaner 命令启用 Image Cleaner。

az aks create \
    --resource-group myResourceGroup \
    --name myManagedCluster \
    --enable-image-cleaner \
    --generate-ssh-keys

AKS 标准版:在现有群集上启用

使用 az aks update 命令在现有 AKS 标准群集上启用映像清理器。

az aks update \
  --resource-group myResourceGroup \
  --name myManagedCluster \
  --enable-image-cleaner

AKS 标准版:新群集或现有群集的更新间隔

使用 --image-cleaner-interval-hours 参数更新新或现有 AKS 标准群集上的映像清理器间隔。

# Create a new cluster with specifying the interval
az aks create \
    --resource-group myResourceGroup \
    --name myManagedCluster \
    --enable-image-cleaner \
    --image-cleaner-interval-hours 48 \
    --generate-ssh-keys

# Update the interval on an existing cluster
az aks update \
    --resource-group myResourceGroup \
    --name myManagedCluster \
    --enable-image-cleaner \
    --image-cleaner-interval-hours 48

使用映像清理器手动删除映像

重要

name 必须设置为 imagelist

使用以下 kubectl apply 命令手动移除映像。 此示例将移除 docker.io/library/alpine:3.7.3 映像(如未使用)。

cat <<EOF | kubectl apply -f -
apiVersion: eraser.sh/v1
kind: ImageList
metadata:
  name: imagelist
spec:
  images:
    - docker.io/library/alpine:3.7.3
EOF

手动清理是一次性操作,只有在创建新 imagelist 或更改现有 imagelist 时才会触发。 删除映像后,不会自动删除 imagelist

如果您需要再次触发手动清理,则必须创建一个新的 imagelist 或修改现有的 imagelist。 如果要再次移除同一映像,则需要创建新的 imagelist

删除现有 ImageList 并创建一个新的 ImageList

  1. 使用 imagelist 命令删除旧 kubectl delete

    kubectl delete ImageList imagelist
    
  2. 创建具有相同镜像名称的新 imagelist。 以下示例使用与上一个示例相同的映像。

    cat <<EOF | kubectl apply -f -
    apiVersion: eraser.sh/v1
    kind: ImageList
    metadata:
      name: imagelist
    spec:
      images:
        - docker.io/library/alpine:3.7.3
    EOF
    

修改现有 ImageList

使用 kubectl edit 命令修改现有 imagelist

kubectl edit ImageList imagelist

# Add a new image to the list
apiVersion: eraser.sh/v1
kind: ImageList
metadata:
  name: imagelist
spec:
  images:
      docker.io/library/python:alpine3.18

使用手动模式时,eraser-aks-xxxxx Pod 会在工作完成后 10 分钟内删除。

图像排除列表

排除列表中指定的映像不会从群集中删除。 映像清理器支持系统和用户定义的排除列表。 不支持编辑系统排除列表。

检查系统排除列表

使用以下 kubectl get 命令检查系统排除列表。

kubectl get -n kube-system configmap eraser-system-exclusion -o yaml

创建用户定义的排除列表

  1. 创建包含排除映像的示例 JSON 文件。

    cat > sample.json <<EOF
    {"excluded": ["excluded-image-name"]}
    EOF
    
  2. 使用示例 JSON 文件并通过以下 kubectl createkubectl label 命令创建一个 configmap

    kubectl create configmap excluded --from-file=sample.json --namespace=kube-system
    kubectl label configmap excluded eraser.sh/exclude.list=true -n kube-system
    

在 AKS 标准版上禁用图像清理器

使用带有 az aks update 参数的 --disable-image-cleaner 命令,在 AKS 标准群集上禁用映像清理器。

az aks update \
  --resource-group myResourceGroup \
  --name myManagedCluster \
  --disable-image-cleaner

常见问题 (FAQ)

如何检查使用的是哪个版本的映像清理器?

kubectl describe configmap -n kube-system eraser-manager-config | grep tag -C 3

除三维扫描程序之外,图像清理器是否支持其他漏洞扫描程序?

不是。

是否可以指定要清理的映像的漏洞级别?

不是。 默认的漏洞级别设置包括:

  • LOW
  • MEDIUM
  • HIGH
  • CRITICAL

你无法自定义默认设置。

如何查看经 Image Cleaner 清理过的图像?

镜像日志存储在 eraser-aks-xxxxx worker Pod 中。 当 eraser-aks-xxxxx 处于活动状态时,可以运行以下命令来查看删除日志:

kubectl logs -n kube-system <worker-pod-name> -c collector
kubectl logs -n kube-system <worker-pod-name> -c trivy-scanner
kubectl logs -n kube-system <worker-pod-name> -c remover

eraser-aks-xxxxx Pod 会在工作完成后 10 分钟内被删除。 你可以按照以下步骤启用 Azure Monitor 插件,并使用 Container Insights Pod 日志表。 之后,系统将存储历史日志,因此你甚至可以在删除 eraser-aks-xxxxx 后查看这些日志。

  1. 确保群集上启用了Azure Monitor。 有关详细步骤,请参阅 在 AKS 群集上启用容器见解

  2. 默认情况下,不会收集命名空间中运行的容器的 kube-system 日志。 从 ConfigMap 中的 kube-system 删除 exclude_namespaces 命名空间,并应用该 ConfigMap 以启用这些日志的采集。 有关详细信息,请参阅配置容器见解数据收集

  3. 使用 az aks show 命令获取 Log Analytics 资源 ID。

      az aks show --resource-group myResourceGroup --name myManagedCluster
    

    在几分钟之后,该命令会返回有关解决方案的 JSON 格式的信息,包括工作区资源 ID:

    "addonProfiles": {
      "omsagent": {
        "config": {
          "logAnalyticsWorkspaceResourceID": "/subscriptions/<WorkspaceSubscription>/resourceGroups/<DefaultWorkspaceRG>/providers/Microsoft.OperationalInsights/workspaces/<defaultWorkspaceName>"
        },
        "enabled": true
      }
    }
    
  4. 在Azure门户中,搜索工作区资源 ID,然后选择“日志”。

  5. 复制以下查询之一并将其粘贴到查询窗口中。

    • 如果群集使用 ContainerLogV2 架构,请使用以下查询。 如果仍在使用 ContainerLog,请升级到 ContainerLogV2。

      ContainerLogV2
      | where PodName startswith "eraser-aks-" and PodNamespace == "kube-system"
      | project TimeGenerated, PodName, LogMessage, LogSource
      
    • 若要继续使用 ContainerLog,请改用以下查询:

      let startTimestamp = ago(1h);
      KubePodInventory
      | where TimeGenerated > startTimestamp
      | project ContainerID, PodName=Name, Namespace
      | where PodName startswith "eraser-aks-" and Namespace == "kube-system"
      | distinct ContainerID, PodName
      | join
      (
          ContainerLog
          | where TimeGenerated > startTimestamp
      )
      on ContainerID
      // at this point before the next pipe, columns from both tables are available to be "projected". Due to both
      // tables having a "Name" column, we assign an alias as PodName to one column which we actually want
      | project TimeGenerated, PodName, LogEntry, LogEntrySource
      | summarize by TimeGenerated, LogEntry
      | order by TimeGenerated desc
       ```
      
      
  6. 选择“运行”。 任何已删除的图像日志都显示在结果区域中。