

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

# 每個 Pod 的安全群組
<a name="sgpp"></a>

**提示**  
 透過 Amazon EKS 研討會[探索](https://aws-experience.com/emea/smb/events/series/get-hands-on-with-amazon-eks?trk=4a9b4147-2490-4c63-bc9f-f8a84b122c8c&sc_channel=el)最佳實務。

AWS 安全群組可做為 EC2 執行個體的虛擬防火牆，以控制傳入和傳出流量。根據預設，Amazon VPC CNI 將使用與節點上主要 ENI 相關聯的安全群組。更具體地說，與執行個體相關聯的每個 ENI 都會有相同的 EC2 安全群組。因此，節點上的每個 Pod 都會與其執行節點共用相同的安全群組。

如下圖所示，在工作者節點上執行的所有應用程式 Pod 都可以存取 RDS 資料庫服務 （考量 RDS 傳入允許節點安全群組）。安全群組太粗精細，因為它們適用於節點上執行的所有 Pod。Pod 的安全群組為工作負載提供網路分段，這是良好深度防禦策略的重要部分。

![連接 RDS 的安全群組節點圖](http://docs.aws.amazon.com/zh_tw/eks/latest/best-practices/images/networking/sgpp_image.png)


透過 Pod 的安全群組，您可以執行對共用運算資源具有不同網路安全需求的應用程式，以提高運算效率。多種類型的安全規則，例如 Pod-to-Pod 和 Pod-to-External AWS 服務，可以使用 EC2 安全群組在單一位置定義，並使用 Kubernetes 原生 APIs 套用至工作負載。下圖顯示 Pod 層級套用的安全群組，以及它們如何簡化您的應用程式部署和節點架構。Pod 現在可以存取 Amazon RDS 資料庫。

![Pod 和節點的圖解，具有連接到 RDS 的不同安全群組](http://docs.aws.amazon.com/zh_tw/eks/latest/best-practices/images/networking/sgpp_image-2.png)


您可以透過設定 VPC CNI `ENABLE_POD_ENI=true`來啟用 Pod 的安全群組。啟用後，在控制平面上執行的 [VPC 資源控制器](https://github.com/aws/amazon-vpc-resource-controller-k8s) （由 EKS 管理） 會建立並連接名為 "`aws-k8s-trunk-eni"` 的幹線界面至節點。幹線界面可做為連接至執行個體的標準網路界面。若要管理幹線介面，您必須將 `AmazonEKSVPCResourceController`受管政策新增至 Amazon EKS 叢集隨附的叢集角色。

控制器也會建立名為 "aws-k8s-branch-eni" 的分支界面，並將其與幹線界面建立關聯。Pod 會使用 [SecurityGroupPolicy](https://github.com/aws/amazon-vpc-resource-controller-k8s/blob/master/config/crd/bases/vpcresources.k8s.aws_securitygrouppolicies.yaml) 自訂資源指派安全群組，並與分支介面相關聯。由於安全群組是以網路介面指定，我們現在能夠在這些額外的網路介面上排程需要特定安全群組的 Pod。檢閱 [Pod 安全群組的 EKS 使用者指南章節，](https://docs.aws.amazon.com/eks/latest/userguide/security-groups-for-pods.html)包括部署先決條件。

![工作者子網路與 ENIs 相關聯之安全群組的圖解](http://docs.aws.amazon.com/zh_tw/eks/latest/best-practices/images/networking/sgpp_image-3.png)


分支界面容量會*附加*至次要 IP 地址的現有執行個體類型限制。使用安全群組的 Pod 不會計入 max-Pod 公式中，而且當您將安全群組用於 Pod 時，您需要考慮提高 max-Pod 值，或者執行的 Pod 數量比節點實際支援的 Pod 少。

m5.large 最多可指派 9 個分支網路介面，以及最多 27 個次要 IP 地址給其標準網路介面。如以下範例所示，m5.large 的預設最大 Pod 為 29，EKS 會將使用安全群組的 Pod 計入最大 Pod。如需如何變更節點最大 Pod 的說明，請參閱 [EKS 使用者指南](https://docs.aws.amazon.com/eks/latest/userguide/cni-increase-ip-addresses.html)。

當 Pod 的安全群組與[自訂聯網](https://docs.aws.amazon.com/eks/latest/userguide/cni-custom-network.html)搭配使用時，會使用 Pod 安全群組中定義的安全群組，而不是 ENIConfig 中指定的安全群組。因此，啟用自訂聯網時，請仔細評估安全群組排序，同時使用每個 Pod 的安全群組。

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

### 停用 TCP Early Demux for Liveness 探查
<a name="_disable_tcp_early_demux_for_liveness_probe"></a>

如果您是使用即時或整備探查，您還需要停用 TCP 早期 demux，以便 kubelet 可以透過 TCP 連接到分支網路介面上的 Pod。這只有在嚴格模式下才需要。若要執行此操作，請執行下列命令：

```
kubectl edit daemonset aws-node -n kube-system
```

在 `initContainer`區段下，將 的值變更為 `DISABLE_TCP_EARLY_DEMUX` `true.` 

### 使用安全群組 Pod 來利用現有的 AWS 組態投資。
<a name="_use_security_group_for_pods_to_leverage_existing_aws_configuration_investment"></a>

安全群組可讓您更輕鬆地限制對 VPC 資源的網路存取，例如 RDS 資料庫或 EC2 執行個體。每個 Pod 的安全群組的一個明顯優勢是有機會重複使用現有的 AWS 安全群組資源。如果您使用安全群組做為網路防火牆來限制對 AWS 服務的存取，建議您使用分支 ENIs 將安全群組套用至 Pod。如果您要將應用程式從 EC2 執行個體轉移到 EKS，並限制存取具有安全群組的其他 AWS 服務，請考慮使用 Pod 的安全群組。

### 設定 Pod 安全群組強制執行模式
<a name="_configure_pod_security_group_enforcing_mode"></a>

Amazon VPC CNI 外掛程式 1.11 版新增了名為 `POD_SECURITY_GROUP_ENFORCING_MODE`(「強制執行模式」) 的新設定。強制執行模式會控制哪些安全群組適用於 Pod，以及是否啟用來源 NAT。您可以指定強制執行模式為嚴格或標準。嚴格是預設值，反映將 `ENABLE_POD_ENI`設為 的 VPC CNI 先前行為`true`。

在嚴格模式下，只會強制執行分支 ENI 安全群組。來源 NAT 也會停用。

在標準模式中，會套用與主要 ENI 和分支 ENI （與 Pod 關聯） 相關聯的安全群組。網路流量必須符合兩個安全群組。

**警告**  
任何模式變更都只會影響新啟動的 Pod。現有的 Pod 將使用建立 Pod 時所設定的模式。如果客戶想要變更流量行為，則需要回收具有安全群組的現有 Pod。

### 強制執行模式：使用嚴格模式隔離 Pod 和節點流量：
<a name="_enforcing_mode_use_strict_mode_for_isolating_pod_and_node_traffic"></a>

根據預設，Pod 的安全群組會設為「嚴格模式」。如果您必須完全將 Pod 流量與節點的其餘流量分開，請使用此設定。在嚴格模式下，來源 NAT 會關閉，以便可以使用分支 ENI 傳出安全群組。

**警告**  
啟用嚴格模式時，來自 Pod 的所有傳出流量都會離開節點並進入 VPC 網路。相同節點上 Pod 之間的流量會經過 VPC。這會增加 VPC 流量並限制節點型功能。嚴格模式不支援 NodeLocal DNSCache。

### 強制執行模式：在下列情況下使用標準模式
<a name="_enforcing_mode_use_standard_mode_in_the_following_situations"></a>

 **Pod 中容器可見的用戶端來源 IP** 

如果您需要讓 Pod 中的容器可看見用戶端來源 IP，請考慮`POD_SECURITY_GROUP_ENFORCING_MODE`將 設定為 `standard`。Kubernetes 服務支援 externalTrafficPolicy=local，以支援保留用戶端來源 IP （預設類型叢集）。您現在可以使用執行個體目標執行 NodePort 和 LoadBalancer 類型的 Kubernetes 服務，並在標準模式中將 externalTrafficPolicy 設定為 Local。 會`Local`保留用戶端來源 IP，並避免 LoadBalancer 和 NodePort 類型的服務的第二個跳轉。

 **部署 NodeLocal DNSCache** 

使用 Pod 的安全群組時，請設定標準模式以支援使用 [NodeLocal DNSCache](https://kubernetes.io/docs/tasks/administer-cluster/nodelocaldns/) 的 Pod。NodeLocal DNSCache 透過在叢集節點上執行 DNS 快取代理程式作為 DaemonSet 來改善叢集 DNS 效能。這將有助於具有最高 DNS QPS 需求的 Pod 查詢具有本機快取的本機 kube-dns/CoreDNS，這將改善延遲。

NodeLocal DNSCache 在嚴格模式下不受支援，因為即使節點的所有網路流量都會進入 VPC。

 **支援 Kubernetes 網路政策** 

我們建議您在搭配具有相關聯安全群組的 Pod 使用網路政策時，使用標準強制執行模式。

我們強烈建議使用 Pod 的安全群組來限制網路層級存取不屬於叢集的 AWS 服務。考慮網路政策來限制叢集內 Pod 之間的網路流量，通常稱為東部/西部流量。

### 識別每個 Pod 與安全群組的不相容
<a name="_identify_incompatibilities_with_security_groups_per_pod"></a>

Windows 型和非 nitro 執行個體不支援 Pod 的安全群組。若要使用具有 Pod 的安全群組，執行個體必須以 isTrunkingEnabled 標記。如果您的 Pod 不依賴 VPC 內外的任何 AWS 服務，請使用網路政策來管理 Pod 之間的存取，而不是安全群組。

### 每個 Pod 使用安全群組來有效控制 AWS Services 的流量
<a name="_use_security_groups_per_pod_to_efficiently_control_traffic_to_aws_services"></a>

如果在 EKS 叢集中執行的應用程式必須與 VPC 中的其他資源通訊，例如 RDS 資料庫，請考慮使用 SGs進行 Pod。雖然有政策引擎可讓您指定 CIDR 或 DNS 名稱，但與端點位於 VPC 內的 AWS 服務通訊時，它們是較不理想的選擇。

相反地，Kubernetes [網路政策](https://kubernetes.io/docs/concepts/services-networking/network-policies/)提供控制叢集內外輸入和輸出流量的機制。如果您的應用程式對其他 AWS 服務的相依性有限，應考慮使用 Kubernetes 網路政策。您可以設定網路政策，根據 CIDR 範圍指定輸出規則，以限制對 AWS 服務的存取，而不是 SGs 等 AWS 原生語意。您可以使用 Kubernetes 網路政策來控制 Pod 之間的網路流量 （通常稱為東部/西部流量），以及 Pod 與外部服務之間的網路流量。Kubernetes 網路政策會在 OSI 層級 3 和 4 實作。

Amazon EKS 可讓您使用網路政策引擎，例如 [Calico](https://projectcalico.docs.tigera.io/getting-started/kubernetes/managed-public-cloud/eks) 和 [Cilium](https://docs.cilium.io/en/stable/intro/)。根據預設，不會安裝網路政策引擎。如需如何設定的指示，請參閱個別的安裝指南。如需如何使用網路政策的詳細資訊，請參閱 [EKS 安全最佳實務](https://docs.aws.amazon.com/eks/latest/best-practices/network-security.html#iam-network-policy)。DNS 主機名稱功能適用於網路政策引擎的企業版本，這可能有助於控制 Kubernetes Services/Pod 與在 AWS 外部執行的資源之間的流量。此外，您可以考慮對預設不支援安全群組的 AWS 服務的 DNS 主機名稱支援。

### 標記單一安全群組以使用 AWS Loadbalancer 控制器
<a name="_tag_a_single_security_group_to_use_aws_loadbalancer_controller"></a>

當許多安全群組配置到 Pod 時，Amazon EKS 建議標記具有[http://kubernetes.io/cluster/$name](http://kubernetes.io/cluster/$name)共用或擁有的單一安全群組。標籤允許 AWS Loadbalancer 控制器更新安全群組的規則，將流量路由到 Pod。如果只將一個安全群組提供給 Pod，則標籤的指派是選擇性的。安全群組中設定的許可是累加的，因此標記單一安全群組就足以讓負載平衡器控制器尋找和協調規則。它也有助於遵守安全群組定義的[預設配額](https://docs.aws.amazon.com/vpc/latest/userguide/amazon-vpc-limits.html#vpc-limits-security-groups)。

### 設定傳出流量的 NAT
<a name="_configure_nat_for_outbound_traffic"></a>

來源 NAT 會針對來自指派安全群組之 Pod 的傳出流量停用。對於使用安全群組的 Pod，這些安全群組需要存取使用 NAT 閘道或執行個體設定的私有子網路上的網際網路啟動工作者節點，並在 CNI 中啟用[外部 SNAT](https://docs.aws.amazon.com/eks/latest/userguide/external-snat.html)。

```
kubectl set env daemonset -n kube-system aws-node AWS_VPC_K8S_CNI_EXTERNALSNAT=true
```

### 使用安全群組將 Pod 部署至私有子網路
<a name="_deploy_pods_with_security_groups_to_private_subnets"></a>

指派給安全群組的 Pod 必須在部署到私有子網路的節點上執行。請注意，已將指派安全群組部署到公有子網路的 Pod 將無法存取網際網路。

### 在 Pod 規格檔案中驗證 *terminationGracePeriodSeconds*
<a name="_verify_terminationgraceperiodseconds_in_pod_specification_file"></a>

請確定 Pod 規格檔案中`terminationGracePeriodSeconds`的 不是零 （預設 30 秒）。這對於 Amazon VPC CNI 從工作者節點刪除 Pod 網路至關重要。設為零時，CNI 外掛程式不會從主機移除 Pod 網路，而且分支 ENI 不會有效清除。

### 將 Pod 的安全群組與 Fargate 搭配使用
<a name="_using_security_groups_for_pods_with_fargate"></a>

在 Fargate 上執行之 Pod 的安全群組的運作方式與在 EC2 工作者節點上執行的 Pod 非常類似。例如，您必須先建立安全群組，才能在與 Fargate Pod 建立關聯的 SecurityGroupPolicy 中參考安全群組。根據預設，當您未明確將 SecurityGroupPolicy 指派給 Fargate Pod 時，[叢集安全群組](https://docs.aws.amazon.com/eks/latest/userguide/sec-group-reqs.html)會連接至所有 Fargate Pod。為了簡單起見，您可能想要將叢集安全群組新增至 Fagate Pod 的 SecurityGroupPolicy，否則您必須將最低安全群組規則新增至安全群組。您可以使用 describe-cluster API 尋找叢集安全群組。

```
 aws eks describe-cluster --name CLUSTER_NAME --query 'cluster.resourcesVpcConfig.clusterSecurityGroupId'
```

```
cat >my-fargate-sg-policy.yaml <<EOF
apiVersion: vpcresources.k8s.aws/v1beta1
kind: SecurityGroupPolicy
metadata:
  name: my-fargate-sg-policy
  namespace: my-fargate-namespace
spec:
  podSelector:
    matchLabels:
      role: my-fargate-role
  securityGroups:
    groupIds:
      - cluster_security_group_id
      - my_fargate_pod_security_group_id
EOF
```

[此處](https://docs.aws.amazon.com/eks/latest/userguide/sec-group-reqs.html)列出最低安全群組規則。這些規則允許 Fargate Pods 與叢集內服務通訊，例如 kube-apiserver、kubelet 和 CoreDNS。您也需要新增規則，以允許進出 Fargate Pod 的傳入和傳出連線。這可讓您的 Pod 與 VPC 中的其他 Pod 或資源通訊。此外，您必須包含 Fargate 規則，才能從 Amazon ECR 或其他容器登錄檔提取容器映像，例如 DockerHub。如需詳細資訊，請參閱 AWS [一般參考中的 AWS](https://docs.aws.amazon.com/general/latest/gr/aws-ip-ranges.html) IP 地址範圍。

您可以使用下列命令來尋找套用至 Fargate Pod 的安全群組。

```
kubectl get pod FARGATE_POD -o jsonpath='{.metadata.annotations.fargate\.amazonaws\.com/pod-sg}{"\n"}'
```

從上述命令記下 eniId。

```
aws ec2 describe-network-interfaces --network-interface-ids ENI_ID --query 'NetworkInterfaces[*].Groups[*]'
```

必須刪除並重新建立現有的 Fargate Pod，才能套用新的安全群組。例如，下列命令會啟動 example-app 的部署。若要更新特定 Pod，您可以在下列命令中變更命名空間和部署名稱。

```
kubectl rollout restart -n example-ns deployment example-pod
```