

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

# 每个 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。Pods 安全组为工作负载提供网络分段，这是良好的深度防御策略的重要组成部分。

![带有安全组的节点连接到 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 现在可以访问 Amazon RDS 数据库了。

![带有不同安全组的 Pod 和节点连接到 RDS 的插图](http://docs.aws.amazon.com/zh_cn/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” 的分支接口，并将它们与中继接口关联起来。使用[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-pods 值，或者可以运行的容量少于节点实际支持的数量。

m5.large 最多可以有 9 个分支网络接口和最多 27 个辅助 IP 地址分配给其标准网络接口。如下例所示，m5.large 的默认最大容量为 29，EKS 将使用安全组的 Pod 计入最大 Pod 数。有关如何更改节点的最大 pod 数的说明，请参阅 E [KS 用户指南](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 早期解复用以进行存活探测
<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>

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 服务支持外部 TrafficPolicy =local，以支持保留客户端源 IP（默认类型的集群）。现在，你可以在标准模式下运行类型为 Kubernetes 的服务， NodePort 并 LoadBalancer 使用外部TrafficPolicy 设置为 “本地” 的实例目标。 `Local`保留客户端源 IP，避免再次跳转 LoadBalancer 并 NodePort 键入服务。

 **部署 NodeLocal dnsCache** 

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

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 数据库）通信，则可以考虑对 Pod 使用 SG。虽然有些策略引擎允许您指定 CIDR 或 DNS 名称，但在与终端节点位于 VPC 中的 AWS 服务通信时，它们并不是最佳选择。

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

Amazon EKS 允许你使用 C [alico 和 [C](https://docs.cilium.io/en/stable/intro/) ilium](https://projectcalico.docs.tigera.io/getting-started/kubernetes/managed-public-cloud/eks) 等网络策略引擎。默认情况下，不安装网络策略引擎。有关如何设置的说明，请查看相应的安装指南。有关如何使用网络策略的更多信息，请参阅 [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 建议将单个安全组标记为[http://kubernetes.io/cluster/$name](http://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 中启用外部 SN](https://docs.aws.amazon.com/eks/latest/userguide/external-snat.html) AT。

```
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 将无法访问互联网。

### GracePeriodSeconds在 Pod 规范文件中验证*终止*
<a name="_verify_terminationgraceperiodseconds_in_pod_specification_file"></a>

确保`terminationGracePeriodSeconds`在 Pod 规范文件中该值为非零（默认为 30 秒）。要让 Amazon VPC CNI 从工作节点中删除 Pod 网络，这是必不可少的。设置为零时，CNI 插件不会从主机上移除 Pod 网络，也无法有效清理分支 ENI。

### 对带有 Fargate 的 Pod 使用安全组
<a name="_using_security_groups_for_pods_with_fargate"></a>

在 Fargate 上运行的 Pod 的安全组的工作方式与在 EC2 工作节点上运行的 Pod 非常相似。例如，在与 Fargate Pod 关联的 Fargate Pod 中引用安全组之前， SecurityGroupPolicy 您必须先创建安全组。默认情况下，如果您没有明确分配给 Fargate 容器，则会将[集群安全组](https://docs.aws.amazon.com/eks/latest/userguide/sec-group-reqs.html)分配给 SecurityGroupPolicy 所有 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 Pod 与 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，可以在以下命令中更改命名空间和部署名称。

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