对 Amazon EKS Pod 使用安全组策略
要将安全组用于 Pods,您必须拥有现有的安全组。以下步骤介绍如何将安全组策略用于 Pod。除非另有说明,请从同一个终端完成所有步骤,因为以下步骤中使用的变量不会在终端之间持续存在。
如果您具有带 Amazon EC2 实例的 Pod,则必须在使用此过程之前配置插件。有关更多信息,请参阅为 Amazon EKS Pods 的安全组配置 Amazon VPC CNI plugin for Kubernetes。
-
创建要将资源部署到该处的 Kubernetes 命名空间。您可以将
my-namespace
替换为您要使用的命名空间名称。kubectl create namespace my-namespace
-
将 Amazon EKS
SecurityGroupPolicy
部署到您的集群。-
将以下内容复制到您的设备。如果您宁愿根据服务账户标签选择 Pods,则可以将
podSelector
替换为serviceAccountSelector
。您必须指定一个或其他选择器。空的podSelector
(示例:podSelector: {}
)会选择命名空间中的所有 Pods。您可以将my-role
更改为您的角色名称。空的serviceAccountSelector
会选择命名空间中的所有服务账户。您可以将my-security-group-policy
替换为SecurityGroupPolicy
的名称,并将my-namespace
替换为要在其中创建SecurityGroupPolicy
的命名空间。您必须将
my_pod_security_group_id
替换为现有安全组的 ID。如果您没有现有安全组,则必须创建一个安全组。有关更多信息,请参阅《Amazon EC2 用户指南》https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/中的适用于 Linux 实例的 Amazon EC2 安全组。您可以指定 1-5 个安全组 ID。如果指定了多个 ID,则所有安全组中的所有规则的组合都会对选定的 Pods 生效。cat >my-security-group-policy.yaml <<EOF apiVersion: vpcresources.k8s.aws/v1beta1 kind: SecurityGroupPolicy metadata: name: my-security-group-policy namespace: my-namespace spec: podSelector: matchLabels: role: my-role securityGroups: groupIds: - my_pod_security_group_id EOF
重要
您为 Pods 指定的一个或多个安全组必须符合以下标准:
-
它们必须存在。如果它们不存在,那么当您部署与选择器匹配的 Pod 时,该 Pod 会在创建过程中处于卡住状态。如果您描述 Pod,则会看到类似于以下内容的错误消息:
An error occurred (InvalidSecurityGroupID.NotFound) when calling the CreateNetworkInterface operation: The securityGroup ID '
。sg-05b1d815d1EXAMPLE
' does not exist -
这些安全组必须允许通过您为其配置探测器的任何端口,从应用于您节点的安全组(对于
kubelet
)进行入站通信。 -
这些安全组必须允许通过
TCP
和UDP
端口 53 与分配到运行 CoreDNS 的 Pods(或 Pods 在其上运行的节点)的安全组进行出站通信。适用于您的 CoreDNS Pods 的安全组必须允许来自您指定的安全组的入站TCP
和UDP
端口 53 流量。 -
它们必须具备必要的入站和出站规则才能与它们需要与其通信的其他 Pods 进行通信。
-
如果您将安全组与 Fargate 结合使用,它们必须具有允许 Pods 与 Kubernetes 控制面板通信的规则。执行此操作的最简单方法是将集群安全组指定为安全组之一。
安全组策略仅适用于新调度的 Pods。不影响正在运行的 Pods。
-
-
部署策略。
kubectl apply -f my-security-group-policy.yaml
-
-
部署其标签与上一步中指定的
podSelector
的my-role
值相匹配的示例应用程序。-
将以下内容复制到您的设备。将
示例值
替换为您自己的值,然后运行修改后的命令。如果您替换my-role
,请确保它与上一步中为选择器指定的值相同。cat >sample-application.yaml <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: my-deployment namespace: my-namespace labels: app: my-app spec: replicas: 4 selector: matchLabels: app: my-app template: metadata: labels: app: my-app role: my-role spec: terminationGracePeriodSeconds: 120 containers: - name: nginx image: public.ecr.aws/nginx/nginx:1.23 ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: my-app namespace: my-namespace labels: app: my-app spec: selector: app: my-app ports: - protocol: TCP port: 80 targetPort: 80 EOF
-
使用以下命令部署应用程序。当您部署应用程序时,Amazon VPC CNI plugin for Kubernetes 插件将匹配
role
标注,并且您在上一步中指定的安全组将应用到 Pod。kubectl apply -f sample-application.yaml
-
-
查看使用示例应用程序部署的 Pods。对于本主题的其余部分,此终端称为
TerminalA
。kubectl get pods -n my-namespace -o wide
示例输出如下。
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-deployment-5df6f7687b-4fbjm 1/1 Running 0 7m51s 192.168.53.48 ip-192-168-33-28.region-code.compute.internal <none> <none> my-deployment-5df6f7687b-j9fl4 1/1 Running 0 7m51s 192.168.70.145 ip-192-168-92-33.region-code.compute.internal <none> <none> my-deployment-5df6f7687b-rjxcz 1/1 Running 0 7m51s 192.168.73.207 ip-192-168-92-33.region-code.compute.internal <none> <none> my-deployment-5df6f7687b-zmb42 1/1 Running 0 7m51s 192.168.63.27 ip-192-168-33-28.region-code.compute.internal <none> <none>
注意
如果遇到 Pods 问题,请遵循以下提示。
-
如果任何 Pods 卡在
Waiting
状态,则运行kubectl describe pod
。如果您看到了my-deployment-xxxxxxxxxx-xxxxx
-nmy-namespace
Insufficient permissions: Unable to create Elastic Network Interface.
,请确认您已在上一步中将 IAM 策略添加到 IAM 集群角色。 -
如果任何 Pods 卡在
Pending
状态,请确认您的节点实例类型已在 limits.go中列出,并且尚未达到实例类型支持的最大分支网络接口数与您的节点组中节点数的乘积。例如, m5.large
实例支持 9 个分支网络接口。如果节点组有 5 个节点,则最多可以为节点组创建 45 个分支网络接口。在删除另一个具有关联安全组的 Pod 前,您尝试部署的第 46 个 Pod 将会处于Pending
状态。
如果您运行
kubectl describe pod
并看到类似于以下消息内容的消息,则可以安全地忽略该消息。当 Amazon VPC CNI plugin for Kubernetes 尝试在创建网络接口时设置主机联网并失败时,可能会出现此消息。该插件会记录此事件,直到创建了网络接口为止。my-deployment-xxxxxxxxxx-xxxxx
-nmy-namespace
Failed to create Pod sandbox: rpc error: code = Unknown desc = failed to set up sandbox container "e24268322e55c8185721f52df6493684f6c2c3bf4fd59c9c121fd4cdc894579f" network for Pod "my-deployment-5df6f7687b-4fbjm": networkPlugin cni failed to set up Pod "my-deployment-5df6f7687b-4fbjm-c89wx_my-namespace" network: add cmd: failed to assign an IP address to container
不能超过可在实例类型上运行的 Pods 的最大数量。有关可在每种实例类型上运行的 Pods 的最大数量的列表,请参阅 GitHub 上的 eni-max-pods.txt
。当您删除具有关联安全组的 Pod 或删除运行该 Pod 的节点时,VPC 资源控制器会删除分支网络接口。如果您使用适用于安全组的 Pods 删除带有 Pods 的集群,则该控制器不会删除分支网络接口,因此您需要自行删除它们。有关如何删除网络接口的信息,请参阅《Amazon EC2 用户指南》中的删除网络接口。 -
-
在单独的终端中,shell 进入其中一个 Pods。对于本主题的其余部分,此终端称为
TerminalB
。将5df6f7687b
-4fbjm
kubectl exec -it -n my-namespace my-deployment-5df6f7687b-4fbjm -- /bin/bash
-
从
TerminalB
的 shell 中,确认示例应用程序是否有效。curl my-app
示例输出如下。
<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> [...]
您收到了输出,因为运行该应用程序的所有 Pods 与您创建的安全组关联。该组包含一条规则,允许安全组所关联的所有 Pods 之间的所有流量。允许 DNS 流量从该安全组出站到与您的节点关联的集群安全组。节点正在运行 CoreDNS Pods,您的 Pods 对该 DNS 进行了名称查找。
-
从
TerminalA
中,删除允许从安全组与集群安全组进行 DNS 通信的安全组规则。如果您在上一步中没有将 DNS 规则添加到集群安全组中,请将$my_cluster_security_group_id
替换为您在其中创建规则的安全组的 ID。aws ec2 revoke-security-group-ingress --group-id $my_cluster_security_group_id --security-group-rule-ids $my_tcp_rule_id aws ec2 revoke-security-group-ingress --group-id $my_cluster_security_group_id --security-group-rule-ids $my_udp_rule_id
-
从
TerminalB
中,尝试再次访问该应用程序。curl my-app
示例输出如下。
curl: (6) Could not resolve host: my-app
由于 Pod 不再能够访问具有与其关联的集群安全组的 CoreDNS Pods,尝试失败。集群安全组不再具有安全组规则,该规则允许从与 Pod 关联的安全组进行 DNS 通信。
如果您尝试使用上一步中的其中一个 Pods 返回的 IP 地址访问应用程序,您仍然会收到响应,因为在与安全组相关联的所有 Pods 之间允许所有端口,并且不需要名称查找。
-
完成实验后,您可以移除您创建的示例安全组策略、应用程序和安全组。从
TerminalA
运行以下命令。kubectl delete namespace my-namespace aws ec2 revoke-security-group-ingress --group-id $my_pod_security_group_id --security-group-rule-ids $my_inbound_self_rule_id wait sleep 45s aws ec2 delete-security-group --group-id $my_pod_security_group_id