

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 每个 Pod 的安全组数
<a name="sgpp"></a>

**提示**  
 [通过亚马逊 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 实例的虚拟防火墙，以控制入站和出站流量。默认情况下，亚马逊 VPC CNI 将使用与节点上的主 ENI 关联的安全组。更具体地说，与实例关联的每个 ENI 都将具有相同的 EC2 安全组。因此，节点上的每个 Pod 都与其运行的节点共享相同的安全组。

如下图所示，所有在工作节点上运行的应用程序 Pod 都将有权访问 RDS 数据库服务（考虑到 RDS 入站允许节点安全组）。安全组的粒度过于粗糙，因为它们适用于在节点上运行的所有 Pod。Pod 的安全组为工作负载提供网络分段，这是良好的深度防御策略的重要组成部分。

![带有安全组连接到 RDS 的节点的图示](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/networking/sgpp_image.png)


使用 Pod 安全组，您可以通过在共享计算资源上运行具有不同网络安全要求的应用程序来提高计算效率。可以使用 EC2 安全组在一个地方定义多种类型的安全规则，例如 Pod-to-Pod 和 Pod-to-External AWS 服务，并将其应用于使用 Kubernetes 原生 API 的工作负载。下图显示了在 Pod 级别应用的安全组以及它们如何简化您的应用程序部署和节点架构。Pod 现在可以访问亚马逊 RDS 数据库。

![连接到 RDS 的具有不同安全组的 Pod 和节点的插图](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/networking/sgpp_image-2.png)


您可以通过设置 VPC CNI 来为 `ENABLE_POD_ENI=true` Pod 启用安全组。启用后，[运行在控制平面（由 EKS 管理）上的 ](https://github.com/aws/amazon-vpc-resource-controller-k8s) VPC 资源控制器会创建名为 “`aws-k8s-trunk-eni” 的中继接口并将其连接到该节点。中继接口充当连接到实例的标准网络接口。要管理中继接口，您必须将`AmazonEKSVPCResourceController`托管策略添加到 Amazon EKS 集群附带的集群角色中。

控制器还创建名为 “aws-k8s-branch-eni” 的分支接口，并将它们与中继接口关联起来。使用[SecurityGroupPolicy](https://github.com/aws/amazon-vpc-resource-controller-k8s/blob/master/config/crd/bases/vpcresources.k8s.aws_securitygrouppolicies.yaml)自定义资源为 Pod 分配安全组，并与分支接口相关联。由于安全组是使用网络接口指定的，因此我们现在能够在这些额外的网络接口上调度需要特定安全组的 Pod。查看 [ EKS 用户指南中关于 Pod 安全组的章节，](https://docs.aws.amazon.com/eks/latest/userguide/security-groups-for-pods.html)包括部署先决条件。

![工作器子网以及与 ENI 关联的安全组的图示](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/networking/sgpp_image-3.png)


分支接口容量是**对辅助 IP 地址的现有实例类型限制的补充。使用安全组的 Pod 不包含在 max-pods 公式中，当你为 pod 使用安全组时，你需要考虑提高 max-pod 的值，或者运行的 pod 少于节点实际支持的数量。

m5.large 可以为其标准网络接口分配多达 9 个分支网络接口和多达 27 个辅助 IP 地址。如下例所示，m5.large 的默认最大容量为 29，EKS 将使用安全组的 Pod 计入最大容量中。有关如何更改节点最大容[量的说明，请参阅 ](https://docs.aws.amazon.com/eks/latest/userguide/cni-increase-ip-addresses.html) EKS 用户指南。

当 Pod 的安全组与[自定义网络结合使用时](https://docs.aws.amazon.com/eks/latest/userguide/cni-custom-network.html)，将使用在 Pod 安全组中定义的安全组，而不是 Eniconfig 中指定的安全组。因此，启用自定义网络后，在每个 Pod 使用安全组的同时，仔细评估安全组的顺序。

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

### 为活跃度探测禁用 TCP Early Demux
<a name="_disable_tcp_early_demux_for_liveness_probe"></a>

如果你使用的是活跃度或就绪探测器，你还需要禁用 TCP 早期解复器，这样 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 服务的访问，我们建议使用分支 ENI 将安全组应用于 Pod。如果您要将应用程序从 EC2 实例转移到 EKS，并使用安全组限制对其他 AWS 服务的访问，请考虑为 Pod 使用安全组。

### 配置 Pod 安全组强制模式
<a name="_configure_pod_security_group_enforcing_mode"></a>

亚马逊 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 ** 

如果你需要保持客户端源 IP 对 Pod 中的容器可见，可以考虑设置`POD_SECURITY_GROUP_ENFORCING_MODE`为`standard`。Kubernetes 服务支持 externetes TrafficPolicy =local 以支持保留客户端源 IP（默认类型集群）。现在，您可以运行类型为 Kubernetes 的服务， NodePort 并在 LoadBalancer 标准模式下使用外部TrafficPolicy 设置为 “本地” 的实例目标。`Local`保留客户机源 IP，避免第二次跳转 LoadBalancer 并 NodePort 键入 Services。

 **部署 NodeLocal DNSCache ** 

为 pod 使用安全组时，请配置标准模式以支持使用 [ NodeLocal DNSC ](https://kubernetes.io/docs/tasks/administer-cluster/nodelocaldns/) ache 的 Pod。 NodeLocal DNSCache 通过在群集节点上将 DNS 缓存代理作为来提高集群 DNS 性能。 DaemonSet这将帮助 DNS QPS 要求最高的 pod 查询dns/CoreDNS 具有本地缓存的本地 kube，这将改善延迟。

NodeLocal 严格模式不支持 DNSCache，因为所有网络流量，即使是到节点的流量，都会进入 VPC。

 **支持 Kubernetes 网络策略 ** 

我们建议在对具有关联安全组的 Pod 使用网络策略时使用标准强制模式。

我们强烈建议使用 Pod 的安全组来限制对不属于集群的 AWS 服务的网络级访问。考虑使用网络策略来限制集群内 Pod 之间的网络流量，通常称为 East/West 流量。

### 识别每个 Pod 与安全组的不兼容性
<a name="_identify_incompatibilities_with_security_groups_per_pod"></a>

Windows-based 而且非 nitro 实例不支持 Pod 的安全组。要在 Pod 中使用安全组，必须使用 is 标记实例TrunkingEnabled。如果您的 Pod 不依赖于 VPC 内外的任何 AWS 服务，请使用网络策略来管理 Pod 之间的访问权限，而不是安全组。

### 使用每个 Pod 的安全组来有效控制 AWS 服务的流量
<a name="_use_security_groups_per_pod_to_efficiently_control_traffic_to_aws_services"></a>

如果在 EKS 集群中运行的应用程序必须与 VPC 中的其他资源（例如 RDS 数据库）通信，则可以考虑将 SG 用于 pod。虽然有些策略引擎允许您指定 CIDR 或 DNS 名称，但在与终端节点位于 VPC 中的 AWS 服务进行通信时，它们并不是最佳选择。

相比之下，Kubernetes [ 网络策略](https://kubernetes.io/docs/concepts/services-networking/network-policies/)提供了一种控制集群内外的入口和出口流量的机制。如果您的应用程序对其他 AWS 服务的依赖性有限，则应考虑 Kubernetes 网络策略。您可以配置网络策略，根据 CIDR 范围指定出口规则，以限制对 AWS 服务的访问，而不是 SG 等 AWS 原生语义。你可以使用 Kubernetes 网络策略来控制 Pod 之间的网络流量（通常称为流 East/West 量）以及 Pod 与外部服务之间的网络流量。Kubernetes 网络策略在 OSI 级别 3 和 4 中实施。

亚马逊 EKS 允许您使用 C [ alico ](https://projectcalico.docs.tigera.io/getting-started/kubernetes/managed-public-cloud/eks) 和 [ C ](https://docs.cilium.io/en/stable/intro/) ilium 等网络策略引擎。默认情况下，未安装网络策略引擎。请查看相应的安装指南，了解有关如何设置的说明。有关如何使用网络策略的更多信息，请参阅 [ EKS 安全最佳实践](https://docs.aws.amazon.com/eks/latest/best-practices/network-security.html#iam-network-policy)。DNS 主机名功能在网络策略引擎的企业版中可用，这可能有助于控制 Kubernetes 与在 AWS 之外运行的资源 Services/Pods 之间的流量。此外，您可以考虑为默认不支持安全组的 AWS 服务提供 DNS 主机名支持。

### 标记单个安全组以使用 AWS 负载均衡器控制器
<a name="_tag_a_single_security_group_to_use_aws_loadbalancer_controller"></a>

当为一个 Pod 分配了多个安全组时，Amazon EKS 建议将单个安全组标记为`kubernetes.io/cluster/$name`共享或自有。该标签允许 AWS 负载均衡器控制器更新安全组的规则，以将流量路由到 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>

对于来自分配了安全组的 Pod 的出站流量，源 NAT 处于禁用状态。对于使用需要访问互联网的安全组的 Pod，在配置了 NAT 网关或实例的私有子网上启动工作节点，并在 CNI [ 中启用](https://docs.aws.amazon.com/eks/latest/userguide/external-snat.html)外部 SNAT。

```
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 部署到公共子网将无法访问互联网。

### Verify *终止 GracePeriodSeconds* 在 Pod 规格文件中
<a name="_verify_terminationgraceperiodseconds_in_pod_specification_file"></a>

确保你`terminationGracePeriodSeconds`的 Pod 规格文件中不为零（默认 30 秒）。这对于亚马逊 VPC CNI 从工作节点删除 Pod 网络至关重要。当设置为零时，CNI 插件不会从主机上移除 Pod 网络，分支 ENI 也无法有效清理。

### 使用 Fargate 为 Pod 使用安全组
<a name="_using_security_groups_for_pods_with_fargate"></a>

在 Fargate 上运行的 Pod 的安全组的工作方式与在 EC2 工作节点上运行的 Pod 非常相似。例如，在与 Fargate Pod 关联的中引用安全组之前， SecurityGroupPolicy 你必须先创建安全组。默认情况下，当你没有明确分配给 Fargate Pod 时，[集群安全组](https://docs.aws.amazon.com/eks/latest/userguide/sec-group-reqs.html)会分配给所有 Fargate Pod。 SecurityGroupPolicy 为简单起见，你可能需要将集群安全组添加到 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 Pod 与 kube-apiserver、kubelet 和 CoreDNS 等集群内服务进行通信。你还需要添加规则，允许进出你的 Fargate Pod 的入站和出站连接。这将允许您的 Pod 与您的 VPC 中的其他 Pod 或资源进行通信。此外，您必须包括规则，让 Fargate 从亚马逊 ECR 或其他容器注册表（例如）提取容器映像。 DockerHub有关更多信息，请参阅 AWS 一般参考中的 [ AWS IP 地址范围](https://docs.aws.amazon.com/general/latest/gr/aws-ip-ranges.html)。

你可以使用以下命令来查找应用于 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，你可以在以下命令中更改命名空间和部署名称。

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