Pods のセキュリティグループ - Amazon EKS

Pods のセキュリティグループ

Pods のセキュリティグループは、Amazon EC2 セキュリティグループを Kubernetes Pods と統合します。Amazon EC2 セキュリティグループを使用して、多くの Amazon EC2 インスタンスタイプと Fargate で実行されているノードにデプロイする Pods との間のインバウンドおよびアウトバウンドのネットワークトラフィックを許可するルールを定義できます。この機能の詳細な説明については、「Introducing security groups for Pods」 (ポッドのセキュリティグループの紹介) のブログを参照してください。

考慮事項

  • Pods のセキュリティグループをデプロイする前に、次の制限事項と条件を考慮してください。

  • Pods のセキュリティグループは、Windows ノードでは使用できません。

  • Pods のセキュリティグループは、バージョン 1.16.0 以降の、Amazon VPC CNI プラグインを使用して、Amazon EC2 ノードを含む IPv6 ファミリー用に設定されたクラスターで使用できます。バージョン 1.7.7 以降の Amazon VPC CNI プラグインを使用すると、Fargate ノードのみを含むクラスター設定の IPv6 ファミリーで Pods のセキュリティグループを使用できます。詳細については、「クラスター、Pods、services 用の IPv6 アドレス」を参照してください。

  • Pods のセキュリティグループは、ほとんどの Nitro ベースの Amazon EC2 インスタンスファミリーでサポートされていますが、ファミリーの全世代がサポートしているわけではありません。たとえば、m5c5r5p3m6gc6gr6g インスタンスファミリーと世代ではサポートされています。t ファミリーのインスタンスタイプは一切サポートされていません。サポートされているインスタンスの詳細なリストについては、GitHub で limits.go ファイルを参照してください。ノードは、そのファイルで一覧表示されているインスタンスタイプのうち、IsTrunkingCompatible: true を含むものである必要があります。

  • Pod のセキュリティポリシーを使用して Pod 変更へのアクセスを制限している場合、eks:vpc-resource-controller Kubernetes ユーザーは、psp が割り当てられた role に対して Kubernetes ClusterRoleBinding で指定する必要があります。デフォルトの Amazon EKS の psprole および ClusterRoleBinding を使用している場合、これは eks:podsecuritypolicy:authenticated ClusterRoleBinding です。例えば、次の例に示すように、ユーザーを subjects: セクションに追加します。

    [...] subjects: - kind: Group apiGroup: rbac.authorization.k8s.io name: system:authenticated - apiGroup: rbac.authorization.k8s.io kind: User name: eks:vpc-resource-controller - kind: ServiceAccount name: eks-vpc-resource-controller
  • カスタムネットワークと Pods のセキュリティグループを組み合わせて使用している場合、ENIConfig で指定されたセキュリティグループではなく、Pods のセキュリティグループによって指定されたセキュリティグループが使用されます。

  • Amazon VPC CNI プラグインのバージョン 1.10.2 以前を使用していて、Pod 仕様に terminationGracePeriodSeconds 設定を含める場合は、設定の値を「0」にすることはできません。

  • Amazon VPC CNI プラグインのバージョン 1.10 以前、またはデフォルト設定が 1.11=POD_SECURITY_GROUP_ENFORCING_MODE のバージョン strict を使用している場合、Kubernetes が NodePort に設定されたインスタンスターゲットを使用するタイプ LoadBalancer および externalTrafficPolicyLocal サービスは、セキュリティグループを割り当てる Pods ではサポートされていません。インスタンスターゲットでのロードバランサーの使用の詳細については、「Amazon EKS でのネットワーク負荷分散」を参照してください

  • Amazon VPC CNI プラグインのバージョン 1.10 以降、またはデフォルト設定が POD_SECURITY_GROUP_ENFORCING_MODE=strict のバージョン 1.11 を使用している場合、セキュリティグループが割り当てられた Pods からのアウトバウンドトラフィックに対してソース NAT が無効になり、その結果アウトバウンドセキュリティグループルールが適用されます。インターネットにアクセスするには、セキュリティグループが割り当てられた Pods を、NAT ゲートウェイまたはインスタンスで構成されたプライベートサブネットにデプロイされたノードで起動する必要があります。パブリックサブネットにデプロイされたセキュリティグループが割り当てられた Pods は、インターネットにアクセスできません。

    POD_SECURITY_GROUP_ENFORCING_MODE=standard に設定されたプラグインのバージョン 1.11 以降を使用している場合、VPC の外部を送信先とする Pod トラフィックは、インスタンスのプライマリネットワークインターフェイスの IP アドレスに変換されます。このトラフィックには、Pod's のセキュリティグループ内のルールではなく、プライマリネットワークインターフェイスのセキュリティグループ内のルールが適用されます。

  • セキュリティグループが関連付けられている Pods で Calico ネットワークポリシーを使用するには、Amazon VPC CNI プラグインのバージョン 1.11.0 以降を使用し、かつ POD_SECURITY_GROUP_ENFORCING_MODE=standard に設定することが必要になります。それ以外の場合、関連付けられたセキュリティグループを持つ Pods との間のトラフィックフローに、Calico ネットワークポリシー は適用されず、Amazon EC2 セキュリティグループの適用のみに限定されます。Amazon VPC CNI バージョンを更新するには、「Amazon VPC CNI plugin for Kubernetes Amazon EKS アドオンの使用」を参照してください

  • Nodelocal DNSCache を使用するクラスターのセキュリティグループを使用する Amazon EC2 ノードで実行されている Pods は、Amazon VPC CNI プラグインのバージョンが 1.11.0 以降で POD_SECURITY_GROUP_ENFORCING_MODE=standard に設定されている場合にのみサポートされます。Amazon VPC CNI プラグインのバージョンを更新するには、「Amazon VPC CNI plugin for Kubernetes Amazon EKS アドオンの使用」を参照してください

  • Pods のセキュリティグループは、解約率が高い Pods の場合、Pod の起動レイテンシーより高くなる可能性があります。これは、リソースコントローラーのレート制限によるものです。

Pods のセキュリティグループに Amazon VPC CNI plugin for Kubernetes を設定します

Pods のセキュリティグループをデプロイするには

Fargate Pods のセキュリティグループのみを使用し、クラスターに Amazon EC2 ノードがない場合は、サンプルアプリケーションをデプロイする に進みます。

  1. 次のコマンドで、現在の Amazon VPC CNI plugin for Kubernetes のバージョンを確認します。

    kubectl describe daemonset aws-node --namespace kube-system | grep amazon-k8s-cni: | cut -d : -f 3

    出力例は次のとおりです。

    v1.7.6

    Amazon VPC CNI plugin for Kubernetes バージョンが 1.7.7 より前の場合は、プラグインを 1.7.7 以降に更新してください。詳細については、「Amazon VPC CNI plugin for Kubernetes Amazon EKS アドオンの使用」を参照してください。

  2. AmazonEKSVPCResourceController マネージド IAM ポリシーを Amazon EKS クラスターに関連付けられているクラスターのロールに追加します。ポリシーにより、ロールはネットワークインターフェイス、プライベート IP アドレス、およびネットワークインスタンスへのアタッチとデタッチを管理できます。

    1. クラスター IAM ロールの名前を取得し、変数に格納します。my-cluster を自分のクラスター名に置き換えます。

      cluster_role=$(aws eks describe-cluster --name my-cluster --query cluster.roleArn --output text | cut -d / -f 2)
    2. ロールへのポリシーの付与

      aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/AmazonEKSVPCResourceController --role-name $cluster_role
  3. Amazon VPC CNI アドオンを有効にして Pods のネットワークインターフェイスを管理するには、aws-node DaemonSet で ENABLE_POD_ENI 変数を true に設定します。この設定が true になると、クラスター内の各ノードについて、アドオンはCNinode カスタムリソースを作成します。VPC リソースコントローラーは、1 つの特別なネットワークインターフェイスを作成してアタッチします。これは、トランクネットワークインターフェイスと呼ばれ、説明は aws-k8s-trunk-eni です。

    kubectl set env daemonset aws-node -n kube-system ENABLE_POD_ENI=true
    注記

    トランクネットワークインターフェイスは、インスタンスタイプでサポートされているネットワークインターフェイスの最大数に含まれます。各インスタンスタイプによりサポートされるネットワークインターフェイスの最大数のリストについては、「Amazon EC2 Linux インスタンス用ユーザーガイド」の「各インスタンスタイプのネットワークインターフェイスあたりの IP アドレス数」を参照してください。ノードにすでに最大数の標準ネットワークインターフェイスがアタッチされている場合、VPC リソースコントローラーはスペースを予約します。コントローラーが標準ネットワークインターフェイスをデタッチして削除し、トランクネットワークインターフェイスを作成し、インスタンスにアタッチできるように、実行中の Pods をスケールダウンする必要があります。

  4. CNINode カスタムリソースがどのノードにあるか、次のコマンドで確認できます。[No resources found] が返された場合、数秒待ってから、もう一度試してください。前のステップで、Amazon VPC CNI plugin for Kubernetes Pods を再起動する必要があります。再起動には数秒かかります。

    $ kubectl get cninode -A NAME FEATURES ip-192-168-64-141.us-west-2.compute.internal [{"name":"SecurityGroupsForPods"}] ip-192-168-7-203.us-west-2.compute.internal [{"name":"SecurityGroupsForPods"}]

    1.15 より古いバージョンの VPC CNI バージョンを使用している場合は、CNINode カスタムリソースの代わりにノードラベルが使用されていました。true に設定されているノードラベル aws-k8s-trunk-eni がどのノードにあるか、次のコマンドで確認できます。[No resources found] が返された場合、数秒待ってから、もう一度試してください。前のステップで、Amazon VPC CNI plugin for Kubernetes Pods を再起動する必要があります。再起動には数秒かかります。

    kubectl get nodes -o wide -l vpc.amazonaws.com/has-trunk-attached=true -

    トランクネットワークインターフェイスが作成されると、Pods にはトランクネットワークインターフェイスまたは標準ネットワークインターフェイスのセカンダリ IP アドレスが割り当てられます。ノードが削除されると、トランクインターフェイスは自動的に削除されます。

    後のステップで Pod のセキュリティグループをデプロイすると、VPC リソースコントローラーは、ブランチネットワークインターフェイスと呼ばれる特別なネットワークインターフェイスを aws-k8s-branch-eni の説明とともに作成し、セキュリティグループを関連付けます。ノードにアタッチされた標準ネットワークインターフェイスとトランクネットワークインターフェイスに加えて、ブランチネットワークインターフェイスが作成されます。

    Liveness プローブまたは Readiness プローブを使用している場合は、TCP Early Demux も無効にする必要があります。これにより、kubelet は TCP を使用してブランチネットワークインターフェイス上の Pods に接続できます。TCP Early Demux を無効にするには、次のコマンドを実行します。

    kubectl patch daemonset aws-node -n kube-system \ -p '{"spec": {"template": {"spec": {"initContainers": [{"env":[{"name":"DISABLE_TCP_EARLY_DEMUX","value":"true"}],"name":"aws-vpc-cni-init"}]}}}}'
    注記

    Amazon VPC CNI plugin for Kubernetes アドオンのバージョン 1.11.0 以降を使用し、かつ POD_SECURITY_GROUP_ENFORCING_MODE=standard に設定している場合、次のステップで説明されているように、前のコマンドを実行する必要はありません。

  5. クラスターで NodeLocal DNSCache が使用されている場合、独自のセキュリティグループを持つ Pods で Calico ネットワークポリシーを使用する場合、または割り当てたい Pods に対して externalTrafficPolicyLocal に設定したインスタンス ターゲットを使用するタイプ NodePort および LoadBalancer の Kubernetes サービスがある場合、セキュリティ グループを追加するには、バージョン 1.11.0 以降の Amazon VPC CNI plugin for Kubernetes アドオンを使用する必要があり、次の設定を有効にする必要があります。

    kubectl set env daemonset aws-node -n kube-system POD_SECURITY_GROUP_ENFORCING_MODE=standard
    重要
    • Pod セキュリティグループルールは、kubeletnodeLocalDNS など、同じノードにある Pods 間のトラフィックまたは Pods と services 間のトラフィックには適用されません。同じノードで異なるセキュリティグループを使用するポッドは、異なるサブネットに設定されているため通信できません。また、これらのサブネット間のルーティングは無効になっています。

    • Pods から VPC の外部のアドレスへのアウトバウンドトラフィックは、インスタンスのプライマリネットワークインターフェイスの IP アドレスに変換されたネットワークアドレスです (AWS_VPC_K8S_CNI_EXTERNALSNAT=true に設定していない場合)。このトラフィックには、Pod's のセキュリティグループ内のルールではなく、プライマリネットワークインターフェイスのセキュリティグループ内のルールが適用されます。

    • この設定を既存の Pods に適用するには、Pods または Pods が実行されているノードを再起動する必要があります。

サンプルアプリケーションをデプロイする

Pods にセキュリティグループを使用するには、既存のセキュリティグループがあり、かつ次の手順で説明するように、クラスターに Amazon EKS SecurityGroupPolicy をデプロイする必要があります。次のステップは、Pod に対してセキュリティグループポリシーを使用する方法を示しています。次のステップではターミナル間で保持されない変数が使用されるため、特に明記されていない限り、同じターミナルからすべてのステップを完了してください。

セキュリティグループでサンプル Pod をデプロイするには
  1. リソースをデプロイする Kubernetes 名前空間を作成します。my-namespace は、使用する名前空間の名前に置き換えることができます。

    kubectl create namespace my-namespace
  2. Amazon EKS SecurityGroupPolicy をクラスターにデプロイします。

    1. 次のコンテンツをデバイスにコピーします。サービスアカウントラベルに基づいて Pods を選択したい場合は、podSelectorserviceAccountSelector で置き換えることができます。セレクターをどちらか 1 つ指定する必要があります。podSelector が空 (例: podSelector: {}) であると、名前空間内のすべての Pods が選択されます。my-role は自分のロール名に変更できます。serviceAccountSelector が空であると、名前空間内のすべてのサービスアカウントが選択されます。my-security-group-policy を自分の SecurityGroupPolicy の名前に置き換え、my-namespaceSecurityGroupPolicy を作成する名前空間に置き換えることができます。

      my_pod_security_group_id を既存のセキュリティグループの ID に置き換える必要があります。既存のセキュリティグループがない場合は、作成する必要があります。詳細については、「Amazon EC2 Linux インスタンス用ユーザーガイド」の「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
      重要

      Pod に対して指定した 1 つまたは複数のセキュリティグループは、次の基準を満たす必要があります。

      • 存在している必要があります。セキュリティグループが存在しない場合、セレクターに一致する 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 コントロールプレーンとの通信を許可するルールを含める必要があります。最も簡単な方法は、クラスターセキュリティグループをセキュリティグループの 1 つとして指定することです。

      セキュリティグループポリシーは、新しくスケジュールされた Pods にのみ適用されます。実行中の Pods には影響しません。

    2. ポリシーをデプロイします。

      kubectl apply -f my-security-group-policy.yaml
  3. 前のステップで指定した podSelectormy-role の値に一致するラベルを持つサンプルアプリケーションをデプロイします。

    1. 次のコンテンツをデバイスにコピーします。サンプル値を独自のものに置き換えて、変更したコマンドを実行します。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
    2. 次のコマンドを使用して、アプリケーションをデプロイします。アプリケーションをデプロイすると、Amazon VPC CNI plugin for Kubernetes は role ラベルと一致し、前のステップで指定したセキュリティグループが Pod に適用されます。

      kubectl apply -f sample-application.yaml
  4. サンプルアプリケーションでデプロイされた 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>
    注記
    • Waiting 状態でスタックした Pods があれば、kubectl describe pod my-deployment-xxxxxxxxxx-xxxxx -n my-namespace を実行します。Insufficient permissions: Unable to create Elastic Network Interface. が表示された場合、前のステップで IAM クラスターロールに IAM ポリシーを追加したことを確認します。

    • Pods が Pending 状態でスタックした場合、ノードのインスタンスタイプが limits.go のリストに含まれていることを確認します。そのうえで、インスタンスタイプでサポートされるブランチネットワークインターフェイスの最大製品数とノードグループ内のノード数を乗算した数にまだ達していないことを確認します。例えば、m5.large インスタンスでは、9 つのブランチネットワークインターフェイスがサポートされています。ノードグループに 5 つのノードがある場合、ノードグループに対して最大 45 のブランチネットワークインターフェイスを作成できます。46 個目の Pod をデプロイしようとすると、セキュリティグループに関連付けられた別の Pod が削除されるまで Pending 状態のままになります。

    kubectl describe pod my-deployment-xxxxxxxxxx-xxxxx -n my-namespace を実行したときに次のようなメッセージが表示されている場合は、無視しても問題ありません。このメッセージは、Amazon VPC CNI plugin for Kubernetes がホストネットワークの設定を試み、ネットワークインターフェイスの作成中に失敗したときに表示される場合があります。プラグインは、ネットワークインターフェイスが作成されるまで、このイベントをログに記録します。

    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 で削除する場合、コントローラーがブランチネットワークインターフェイスを削除しないため、自分で削除する必要があります。ネットワークインターフェイスの削除方法の詳細については、「Linux インスタンス用の Amazon EC2 ユーザーガイド」の「ネットワークインターフェイスの削除」を参照してください。

  5. 別のターミナルから Pods のいずれかをシェルで操作します。このトピックの以降の説明では、このターミナルを TerminalB と呼びます。5df6f7687b-4fbjm を、前のステップの出力で返されたいずれかの Pods の ID で置き換えます。

    kubectl exec -it -n my-namespace my-deployment-5df6f7687b-4fbjm -- /bin/bash
  6. TerminalB のシェルから、サンプルアプリケーションが動作することを確認します。

    curl my-app

    出力例は次のとおりです。

    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    [...]

    アプリケーションを実行しているすべての Pods が、作成したセキュリティグループに関連付けられているため、出力を受信できます。そのグループには、セキュリティグループが関連付けられているすべての Pods 間のすべてのトラフィックを許可するルールが含まれています。DNS トラフィックは、そのセキュリティグループからノードに関連付けられているクラスターセキュリティグループへのアウトバウンドで許可されます。ノードは、Pods が名前のルックアップを実行した CoreDNS Podsを実行しています。

  7. 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
  8. TerminalB で、アプリケーションにもう一度アクセスしてみます。

    curl my-app

    出力例は次のとおりです。

    curl: (6) Could not resolve host: my-app

    クラスターセキュリティグループが関連付けられている CoreDNS Pods に Pod がアクセスできなくなったため、この試行は失敗します。クラスターセキュリティグループから、Pod に関連付けられたセキュリティグループからの DNS 通信を許可するセキュリティグループルールがなくなりました。

    前のステップで、いずれかの Pods に返された IP アドレスを使用してアプリケーションにアクセスしようとすると、セキュリティグループが関連付けられており、名前のルックアップが不要な Pods 間ですべてのポートが許可されているため、引き続き応答を受信します。

  9. 試行し終えたら、作成したサンプルのセキュリティグループポリシー、アプリケーション、およびセキュリティグループを削除できます。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