

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 映像安全性
<a name="image-security"></a>

您應該將容器映像視為對抗攻擊的第一道防線。不安全、構造不良的映像可允許攻擊者逸出容器的邊界並取得主機的存取。在主機上，攻擊者可以存取敏感資訊，或在叢集內或您的 AWS 帳戶橫向移動。下列最佳實務將有助於降低發生這種情況的風險。

## 建議
<a name="_recommendations"></a>

### 建立最小影像
<a name="_create_minimal_images"></a>

首先從容器映像中刪除所有無關的二進位檔案。如果您使用來自 Dockerhub 的不熟悉映像，請使用 [Dive](https://github.com/wagoodman/dive) 之類的應用程式來檢查映像，該應用程式可以向您顯示每個容器層的內容。移除具有 SETUID 和 SETGID 位元的所有二進位檔，因為它們可用於提升權限，並考慮移除可用於惡意目的的所有 shell 和公用程式，例如 nc 和 curl。您可以使用下列命令找到具有 SETUID 和 SETGID 位元的檔案：

```
find / -perm /6000 -type f -exec ls -ld {} \;
```

若要從這些檔案移除特殊許可，請將下列指令新增至您的容器映像：

```
RUN find / -xdev -perm /6000 -type f -exec chmod a-s {} \; || true
```

以共通方式來說，這稱為取消分散您的映像。

### 使用多階段建置
<a name="_use_multi_stage_builds"></a>

使用多階段建置是一種建立最小影像的方式。多階段建置通常用於自動化持續整合週期的一部分。例如，多階段組建可用來固定原始程式碼或執行靜態程式碼分析。這讓開發人員有機會取得近乎立即的意見回饋，而不是等待管道執行。從安全角度來看，多階段建置很有吸引力，因為它們可讓您將推送至容器登錄檔的最終映像大小降至最低。沒有構建工具和其他無關二進位檔案的容器映像透過減少映像的受攻擊面來改善您的安全狀態。如需多階段建置的其他資訊，請參閱 [Docker 的多階段建置文件](https://docs.docker.com/develop/develop-images/multistage-build/)。

### 為您的容器映像建立軟體物料清單 SBOMs)
<a name="_create_software_bill_of_materials_sboms_for_your_container_image"></a>

「軟體物料清單」(SBOM) 是構成容器映像之軟體成品的巢狀清查。SBOM 是軟體安全和軟體供應鏈風險管理的關鍵建置區塊。在[中央儲存庫中產生、儲存 SBOMS 和掃描 SBOMs是否有漏洞](https://anchore.com/sbom/)，有助於解決下列問題：
+  **可見性**：了解哪些元件構成您的容器映像。存放在中央儲存庫中可讓 SBOMs 隨時接受稽核和掃描，甚至在部署後偵測和回應新的漏洞，例如零時差漏洞。
+  **實證驗證**：確保成品來源位置和方式的現有假設為 true，且成品或其隨附的中繼資料在建置或交付程序期間並未遭到竄改。
+  **可信度**：確保可信任指定的成品及其內容來執行其據稱要執行的動作，即 適用於特定用途。這涉及判斷程式碼是否可安全執行，並針對與執行程式碼相關的風險做出明智的決策。透過建立已證明的管道執行報告以及已證明的 SBOM 和已證明的 CVE 掃描報告來確保可信度，以確保映像的消費者透過安全方式 （管道） 使用安全元件建立此映像。
+  **相依性信任驗證**：遞迴檢查成品的相依性樹狀結構是否有可信性和成品的來源。SBOMs中的漂移有助於偵測惡意活動，包括未經授權、不受信任的相依性、滲透嘗試。

下列工具可用於產生 SBOM：
+  [Amazon Inspector](https://docs.aws.amazon.com/inspector) 可用來[建立和匯出 SBOMs](https://docs.aws.amazon.com/inspector/latest/user/sbom-export.html)。
+  [來自 Anchore 的 Syft](https://github.com/anchore/syft) 也可以用於產生 SBOM。為了更快地掃描漏洞，為容器映像產生的 SBOM 可以用作要掃描的輸入。然後[，SBOM 和掃描報告會經過證明並連接到](https://github.com/sigstore/cosign/blob/main/doc/cosign_attach_attestation.md)映像，然後再將映像推送到中央 OCI 儲存庫，例如 Amazon ECR 以供檢閱和稽核。

請參閱 [CNCF 軟體供應鏈最佳實務指南，進一步了解如何保護您的軟體供應鏈](https://project.linuxfoundation.org/hubfs/CNCF_SSCP_v1.pdf)。

### 定期掃描映像是否有漏洞
<a name="_scan_images_for_vulnerabilities_regularly"></a>

如同其虛擬機器對等，容器映像可以包含具有漏洞的二進位檔和應用程式程式庫，或隨著時間開發漏洞。防止漏洞攻擊的最佳方法是使用映像掃描器定期掃描映像。存放在 Amazon ECR 中的影像可以在推送或隨需時掃描 (24 小時期間內掃描一次）。ECR 目前支援[兩種類型的掃描 - Basic 和 Enhanced](https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-scanning.html)。基本掃描會免費利用 [Clair](https://github.com/quay/clair) 開放原始碼映像掃描解決方案。[增強型掃描](https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-scanning-enhanced.html)使用 Amazon Inspector 來提供自動持續掃描，以[增加成本](https://aws.amazon.com/inspector/pricing/)。掃描影像後，結果會記錄到 EventBridge 中 ECR 的事件串流。您也可以在 ECR 主控台中查看掃描的結果。應刪除或重建具有 HIGH 或 CRITICAL 漏洞的影像。如果已部署的映像出現漏洞，則應盡快更換。

了解具有漏洞的映像部署位置對於確保環境安全至關重要。雖然您可以自行建置映像追蹤解決方案，但已有數個商業產品提供這項和其他進階功能，包括：
+  [Grype](https://github.com/anchore/grype) 
+  [Palo Alto - Prisma Cloud (twistcli)](https://docs.paloaltonetworks.com/prisma/prisma-cloud/prisma-cloud-admin-compute/tools/twistcli_scan_images) 
+  [水藍色](https://www.aquasec.com/) 
+  [Kubei](https://github.com/Portshift/kubei) 
+  [Trivy](https://github.com/aquasecurity/trivy) 
+  [Snyk](https://support.snyk.io/hc/en-us/articles/360003946917-Test-images-with-the-Snyk-Container-CLI) 

Kubernetes 驗證 Webhook 也可以用來驗證映像沒有重大漏洞。驗證 Webhook 會在 Kubernetes API 之前叫用。它們通常用於拒絕不符合 Webhook 中定義的驗證條件的請求。[這是](https://aws.amazon.com/blogs/containers/building-serverless-admission-webhooks-for-kubernetes-with-aws-sam/)無伺服器 Webhook 的範例，可呼叫 ECR describeImageScanFindings API 來判斷 Pod 是否正在提取具有關鍵漏洞的映像。如果找到漏洞，則會拒絕 Pod，並傳回包含 CVEs清單的訊息做為事件。

### 使用證明來驗證成品完整性
<a name="_use_attestations_to_validate_artifact_integrity"></a>

證明是以密碼編譯方式簽署的「陳述式」，宣告某些項目 -「述詞」，例如 管道執行或 SBOM 或漏洞掃描報告，對於另一個物件為 true，即「主體」，即 容器映像。

聲明可協助使用者驗證成品是否來自軟體供應鏈中的信任來源。例如，我們可能會使用容器映像，而不知道該映像中包含的所有軟體元件或相依性。不過，如果我們信任容器映像的生產者所說的軟體，我們可以使用生產者的證明來依賴該成品。這表示我們可以繼續在工作流程中安全地使用成品，而不是自行進行分析。
+ 您可以使用 [AWS Signer](https://docs.aws.amazon.com/signer/latest/developerguide/Welcome.html) 或 [Sigstore cosign](https://github.com/sigstore/cosign/blob/main/doc/cosign_attest.md) 建立證明。
+ [Kyverno](https://kyverno.io/) 等 Kubernetes 許可控制器可用來[驗證證明](https://kyverno.io/docs/writing-policies/verify-images/sigstore/)。
+ 請參閱本[研討會](https://catalog.us-east-1.prod.workshops.aws/workshops/49343bb7-2cc5-4001-9d3b-f6a33b3c4442/en-US/0-introduction)，進一步了解如何使用開放原始碼工具在 AWS 上使用軟體供應鏈管理最佳實務，主題包括建立和連接證明至容器映像。

### 為 ECR 儲存庫建立 IAM 政策
<a name="_create_iam_policies_for_ecr_repositories"></a>

現在，組織在共用 AWS 帳戶中擁有多個獨立運作的開發團隊並不常見。如果這些團隊不需要共用資產，您可能想要建立一組 IAM 政策，限制存取每個團隊可以互動的儲存庫。實作此項目的好方法是使用 ECR [命名空間](https://docs.aws.amazon.com/AmazonECR/latest/userguide/Repositories.html#repository-concepts)。命名空間是將類似的儲存庫分組在一起的一種方式。例如，團隊 A 的所有登錄檔都可以在 team-a/ 前面，而團隊 B 的登錄檔可以使用 team-b/ 字首。限制存取的政策可能如下所示：

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "AllowPushPull",
      "Effect": "Allow",
      "Action": [
        "ecr:GetDownloadUrlForLayer",
        "ecr:BatchGetImage",
        "ecr:BatchCheckLayerAvailability",
        "ecr:PutImage",
        "ecr:InitiateLayerUpload",
        "ecr:UploadLayerPart",
        "ecr:CompleteLayerUpload"
      ],
      "Resource": [
        "arn:aws:ecr:us-east-1:123456789012:repository/team-a/*"
      ]
    }
  ]
}
```

### 考慮使用 ECR 私有端點
<a name="_consider_using_ecr_private_endpoints"></a>

ECR API 具有公有端點。因此，只要請求已經過 IAM 驗證和授權，就可以從網際網路存取 ECR 登錄檔。對於需要在叢集 VPC 缺少網際網路閘道 (IGW) 的沙盒環境中操作的人員，您可以設定 ECR 的私有端點。建立私有端點可讓您透過私有 IP 地址私下存取 ECR API，而不是將流量路由到網際網路。如需本主題的詳細資訊，請參閱 [Amazon ECR 介面 VPC 端點](https://docs.aws.amazon.com/AmazonECR/latest/userguide/vpc-endpoints.html)。

### 實作 ECR 的端點政策
<a name="_implement_endpoint_policies_for_ecr"></a>

的預設端點政策允許存取區域內的所有 ECR 儲存庫。這可能會允許攻擊者/內部人員將資料封裝為容器映像，並將其推送到另一個 AWS 帳戶中的登錄檔，藉此滲透資料。降低此風險需要建立端點政策，以限制對 ECR 儲存庫的 API 存取。例如，下列政策允許帳戶中的所有 AWS 原則針對您的 執行所有動作，並且只針對您的 ECR 儲存庫執行所有動作：

```
{
  "Statement": [
    {
      "Sid": "LimitECRAccess",
      "Principal": "*",
      "Action": "*",
      "Effect": "Allow",
      "Resource": "arn:aws:ecr:<region>:<account_id>:repository/*"
    }
  ]
}
```

您可以透過設定使用新`PrincipalOrgID`屬性的條件來進一步增強這一點，以防止透過不屬於 AWS Organization 的 IAM 原則推送/提取映像。如需其他詳細資訊，請參閱 [aws：PrincipalOrgID](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-principalorgid)。建議對 `com.amazonaws.<region>.ecr.dkr` 和 `com.amazonaws.<region>.ecr.api` 端點套用相同的政策。由於 EKS 從 ECR 提取 kube-proxy、Coredns 和 aws-node 的映像，因此您需要將登錄檔的帳戶 ID 新增至端點政策中的資源清單， `602401143452.dkr.ecr.us-west-2.amazonaws.com/ `或修改政策以允許提取``並限制推送至您的帳戶 ID。下表顯示從 和 叢集區域提供 EKS 映像的 AWS 帳戶之間的映射。


| 帳戶號碼 | 區域 | 
| --- | --- | 
|  602401143452  |  所有商業區域，但下列區域除外  | 
|  —  |  —  | 
|  800184023465  |  ap-east-1 - 亞太區域 （香港）  | 
|  558608220178  |  me-south-1 - 中東 （巴林）  | 
|  918309763551  |  cn-north-1 - 中國 （北京）  | 
|  961992271922  |  cn-northwest-1 - 中國 （寧夏）  | 

如需使用端點政策的詳細資訊，請參閱[使用 VPC 端點政策來控制 Amazon ECR 存取](https://aws.amazon.com/blogs/containers/using-vpc-endpoint-policies-to-control-amazon-ecr-access/)。

### 實作 ECR 的生命週期政策
<a name="_implement_lifecycle_policies_for_ecr"></a>

[NIST 應用程式容器安全指南](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-190.pdf)會警告「登錄檔中的過時映像」的風險，請注意，隨著時間的推移，應該移除具有易受攻擊、out-of-date軟體套件的舊映像，以防止意外部署和暴露。每個 ECR 儲存庫都可以有一個生命週期政策，可設定映像過期時的規則。[AWS 官方文件](https://docs.aws.amazon.com/AmazonECR/latest/userguide/LifecyclePolicies.html)說明如何設定測試規則、進行評估，然後套用它們。官方文件中有數個[生命週期政策範例](https://docs.aws.amazon.com/AmazonECR/latest/userguide/lifecycle_policy_examples.html)，顯示篩選儲存庫中映像的不同方式：
+ 依影像存留期或計數篩選
+ 依已標記或未標記的影像進行篩選
+ 在多個規則或單一規則中，依影像標籤篩選

？？？\$1 警告 如果從 ECR 清除長時間執行應用程式的映像，則當應用程式重新部署或水平擴展時，可能會導致映像提取錯誤。使用映像生命週期政策時，請確定您擁有良好的 CI/CD 實務，以保持部署及其參考的映像為最新狀態，並一律建立 【映像】 過期規則，以說明您執行發行/部署的頻率。

### 建立一組精選映像
<a name="_create_a_set_of_curated_images"></a>

與其允許開發人員建立自己的映像，請考慮為組織中的不同應用程式堆疊建立一組經過審核的映像。透過執行此動作，開發人員可以放棄學習如何編寫 Dockerfile 並專注於編寫程式碼。當變更合併到主節點時，CI/CD 管道可以自動編譯資產，將其存放在成品儲存庫中，並將成品複製到適當的映像，然後再推送到 Docker 登錄檔，例如 ECR。您至少應該建立一組基礎映像，讓開發人員從中建立自己的 Dockerfile。理想情況下，您想要避免從 Dockerhub 提取映像，因為 1/ 您不一定知道映像中的內容，2/ 大約[五分](https://www.kennasecurity.com/blog/one-fifth-of-the-most-used-docker-containers-have-at-least-one-critical-vulnerability/)之一的前 1000 個映像有漏洞。您可以在[此處](https://vulnerablecontainers.org/)找到這些映像及其漏洞的清單。

### 將 USER 指令新增至 Dockerfiles，以非根使用者身分執行
<a name="_add_the_user_directive_to_your_dockerfiles_to_run_as_a_non_root_user"></a>

如 Pod 安全章節所述，您應該避免將容器做為根執行。雖然您可以將此設定為 podSpec 的一部分，但使用 `USER`Dockerfiles 的指令是很好的習慣。`USER` 指令會將 UID 設定為在執行 USER 指令之後出現的 `ENTRYPOINT`、 `RUN`或 `CMD`指令時使用。

### Lint 您的 Dockerfiles
<a name="_lint_your_dockerfiles"></a>

內嵌可用來驗證您的 Dockerfiles 是否遵循一組預先定義的準則，例如 包含 `USER`指令或所有映像都必須加上標籤的要求。[Dockerfile\$1lint](https://github.com/projectatomic/dockerfile_lint) 是來自 RedHat 的開放原始碼專案，可驗證常見的最佳實務，並包含規則引擎，可用來建置自己的 Dockerfiles 規則。它可以整合到 CI 管道中，其中使用違反規則的 Dockerfile 建置會自動失敗。

### 從 Scratch 建置映像
<a name="_build_images_from_scratch"></a>

在建置映像時，減少容器映像的攻擊面應該是主要目標。理想方法是建立不含二進位檔的最小映像，以利用漏洞。幸運的是，Docker 具有從 建立映像的機制[https://docs.docker.com/develop/develop-images/baseimages/#create-a-simple-parent-image-using-scratch](https://docs.docker.com/develop/develop-images/baseimages/#create-a-simple-parent-image-using-scratch)。使用 Go 等語言，您可以建立靜態連結二進位檔，並在 Dockerfile 中參考它，如本範例所示：

```
############################
# STEP 1 build executable binary
############################
FROM golang:alpine AS builder# Install git.
# Git is required for fetching the dependencies.
RUN apk update && apk add --no-cache gitWORKDIR $GOPATH/src/mypackage/myapp/COPY . . # Fetch dependencies.
# Using go get.
RUN go get -d -v# Build the binary.
RUN go build -o /go/bin/hello

############################
# STEP 2 build a small image
############################
FROM scratch# Copy our static executable.
COPY --from=builder /go/bin/hello /go/bin/hello# Run the hello binary.
ENTRYPOINT ["/go/bin/hello"]
```

這會建立包含您的應用程式和任何其他項目的容器映像，使其非常安全。

### 搭配 ECR 使用不可變標籤
<a name="_use_immutable_tags_with_ecr"></a>

 [不可變標籤](https://aws.amazon.com/about-aws/whats-new/2019/07/amazon-ecr-now-supports-immutable-image-tags/)會強制您在每次推送至映像儲存庫時更新映像標籤。這可以阻止攻擊者以惡意版本覆寫映像，而不會變更映像的標籤。此外，它可讓您輕鬆且唯一地識別影像。

### 簽署您的映像、SBOMs、管道執行和漏洞報告
<a name="_sign_your_images_sboms_pipeline_runs_and_vulnerability_reports"></a>

初次推出 Docker 時，沒有用於驗證容器映像的密碼編譯模型。使用 v2 時，Docker 會將摘要新增至映像資訊清單。這允許對影像的組態進行雜湊，並使雜湊用於產生影像的 ID。啟用映像簽署時，Docker 引擎會驗證資訊清單的簽章，確保內容是從信任的來源產生，而且不會發生竄改。下載每個 layer 之後，引擎會驗證 layer 的摘要，確保內容符合資訊清單中指定的內容。影像簽署可讓您透過驗證與影像相關聯的數位簽章，有效地建立安全的供應鏈。

我們可以使用 [AWS Signer](https://docs.aws.amazon.com/signer/latest/developerguide/Welcome.html) 或 [Sigstore Cosign](https://github.com/sigstore/cosign) 來簽署容器映像、為 SBOMs建立證明、漏洞掃描報告和管道執行報告。這些證明可確保映像的可信度和完整性，事實上，它是由受信任管道建立的，沒有任何干擾或篡改，並且它只包含由映像發佈者驗證和信任的文件化軟體元件 （在 SBOM 中）。這些證明可以連接到容器映像並推送到儲存庫。

在下一節中，我們將了解如何使用已證明的成品進行稽核和許可控制器驗證。

### 使用 Kubernetes 許可控制器進行映像完整性驗證
<a name="_image_integrity_verification_using_kubernetes_admission_controller"></a>

在使用[動態許可控制器](https://kubernetes.io/blog/2019/03/21/a-guide-to-kubernetes-admission-controllers/)將映像部署到目標 Kubernetes 叢集之前，我們可以自動驗證映像簽章、已證明的成品，並只在成品的安全中繼資料符合許可控制器政策時，才允許部署。

例如，我們可以撰寫政策，以密碼編譯方式驗證映像的簽章、已驗證的 SBOM、已驗證的管道執行報告或已驗證的 CVE 掃描報告。我們可以在政策中寫入條件來檢查報告中的資料，例如 CVE 掃描不應有任何重要的 CVEs。只有滿足這些條件的映像才允許部署，所有其他部署都會遭到許可控制器拒絕。

許可控制器的範例包括：
+  [基佛諾](https://kyverno.io/) 
+  [OPA Gatekeeper](https://github.com/open-policy-agent/gatekeeper) 
+  [Portieris](https://github.com/IBM/portieris) 
+  [Ratify](https://github.com/deislabs/ratify) 
+  [Kritis](https://github.com/grafeas/kritis) 
+  [Grafeas 教學課程](https://github.com/kelseyhightower/grafeas-tutorial) 
+  [抵用券](https://github.com/Shopify/voucher) 

### 更新容器映像中的套件
<a name="_update_the_packages_in_your_container_images"></a>

您應該在 Dockerfiles `apt-get update && apt-get upgrade`中包含 RUN，以升級映像中的套件。雖然升級需要您以根身分執行，但在映像建置階段期間會發生這種情況。應用程式不需要以根執行。您可以安裝更新，然後使用 USER 指令切換到不同的使用者。如果您的基礎映像以非根使用者身分執行，請切換到根和後；不要只依賴基礎映像的維護器來安裝最新的安全性更新。

執行 從 `apt-get clean`刪除安裝程式檔案`/var/cache/apt/archives/`。您也可以在安裝套件`rm -rf /var/lib/apt/lists/*`後執行 。這會移除索引檔案或可供安裝的套件清單。請注意，每個套件管理員的這些命令可能不同。例如：

```
RUN apt-get update && apt-get install -y \
    curl \
    git \
    libsqlite3-dev \
    && apt-get clean && rm -rf /var/lib/apt/lists/*
```

## 工具和資源
<a name="_tools_and_resources"></a>
+  [Amazon EKS 安全浸入研討會 - Image Security](https://catalog.workshops.aws/eks-security-immersionday/en-US/12-image-security) 
+  [docker-slim](https://github.com/docker-slim/docker-slim) Build 安全最小映像
+  [dockle](https://github.com/goodwithtech/dockle) 驗證您的 Dockerfile 是否符合建立安全映像的最佳實務
+  [Dockerfiles 的 dockerfile-lint](https://github.com/projectatomic/dockerfile_lint) 規則型 linter
+  [hadolint](https://github.com/hadolint/hadolint) 智慧型 dockerfile linter
+  [Gatekeeper 和 OPA](https://github.com/open-policy-agent/gatekeeper) 以政策為基礎的許可控制器
+  [Kyverno](https://kyverno.io/) Kubernetes 原生政策引擎
+  [in-to](https://in-toto.io/) 允許使用者驗證供應鏈中的步驟是否打算執行，以及步驟是否由正確的執行者執行
+  [公證人](https://github.com/theupdateframework/notary) 用於簽署容器映像的專案
+  [公證人 v2](https://github.com/notaryproject/nv2) 
+  [Grafeas](https://grafeas.io/) 開放成品中繼資料 API，用於稽核和控管您的軟體供應鏈
+  [NeuVector by SUSE](https://www.suse.com/neuvector/) 開放原始碼、零信任容器安全平台，提供容器、映像和登錄檔掃描，以找出漏洞、秘密和合規。