EKSのPodのSecurityGroupを試す


EKSは、3年前ぐらいに少しさわったぐらいで、あまり深くいじれてなかったので、再入門してみる。 今回は、2020年の9月ごろに利用できるようになった、Podへのセキュリティグループの割当てを試してみる。

セットアップ

ドキュメントを参考にセットアップする。

https://docs.aws.amazon.com/ja%5Fjp/eks/latest/userguide/security-groups-for-pods.html

やることは、eksクラスタのIAMロールに AmazonEKSVPCResourceController マネージドポリシーを追加することと 以下のコマンドで aws-node デーモンセットの環境変数でPodへのENI割当てを有効化するぐらい。

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

試してみる

実際にPodに適用して試してみる。

あまり複雑にしてもしょうがないので、nginxを3種類動かす。

$ kubectl create deployment nginx --image nginx
$ kubectl expose deployment nginx --port 80
$ kubectl create deployment nginx2 --image nginx
$ kubectl expose deployment nginx2 --port 80
$ kubectl create deployment nginx3 --image nginx
$ kubectl expose deployment nginx3 --port 80

$ kubectl get pod --show-labels
NAME                      READY   STATUS    RESTARTS   AGE   LABELS
nginx-596bdcb889-qbvsf    1/1     Running   0          30s   app=nginx,pod-template-hash=596bdcb889
nginx2-5fc4444698-srd9l   1/1     Running   0          20h   app=nginx2,pod-template-hash=5fc4444698
nginx3-5465449d99-7jfww   1/1     Running   0          34m   app=nginx3,pod-template-hash=5465449d99

まずは、何もセキュリティグループを設定していない状態なので、 各Pod間で通信できることを確認する。

$ kubectl exec nginx-596bdcb889-qbvsf  -- curl nginx2 -s --head
HTTP/1.1 200 OK

$ kubectl exec nginx-596bdcb889-qbvsf  -- curl nginx3 -s --head
HTTP/1.1 200 OK

$ kubectl exec nginx2-5fc4444698-srd9l -- curl nginx -s --head
HTTP/1.1 200 OK

$ kubectl exec nginx2-5fc4444698-srd9l -- curl nginx3 -s --head
HTTP/1.1 200 OK

$ kubectl exec nginx3-5465449d99-7jfww -- curl nginx -s --head
HTTP/1.1 200 OK

$ kubectl exec nginx3-5465449d99-7jfww -- curl nginx2 -s --head
HTTP/1.1 200 OK

同じセキュリティグループからのTCP80を許可するセキュリティグループを作成し、内容を確認する。

$ aws ec2 describe-security-groups --group-ids sg-0ee9cf2b805966c5a
{
    "SecurityGroups": [
        {
            "Description": "Allow access to 80",
            "GroupName": "eks-sg-policy-nginx",
            "IpPermissions": [
                {
                    "FromPort": 80,
                    "IpProtocol": "tcp",
                    "IpRanges": [],
                    "Ipv6Ranges": [],
                    "PrefixListIds": [],
                    "ToPort": 80,
                    "UserIdGroupPairs": [
                        {
                            "GroupId": "sg-0ee9cf2b805966c5a",
                            "UserId": "123456789012"
                        }
                    ]
                }
            ],
            "OwnerId": "123456789012",
            "GroupId": "sg-0ee9cf2b805966c5a",
            "IpPermissionsEgress": [
                {
                    "IpProtocol": "-1",
                    "IpRanges": [
                        {
                            "CidrIp": "0.0.0.0/0"
                        }
                    ],
                    "Ipv6Ranges": [],
                    "PrefixListIds": [],
                    "UserIdGroupPairs": []
                }
            ],
            "VpcId": "vpc-0d0d85fab71542349"
        }
    ]
}

次に nginxnginx2 にだけセキュリティグループが割当てられるようにラベルをつける。

$ kubectl label pod nginx-596bdcb889-qbvsf sg=true
pod/nginx-596bdcb889-qbvsf labeled
$ kubectl label pod nginx2-5fc4444698-srd9l sg=true
pod/nginx2-5fc4444698-srd9l labeled
$ kubectl label pod nginx3-5465449d99-7jfww sg=false
pod/nginx3-5465449d99-7jfww labeled

$ kubectl get pod --show-labels
NAME                      READY   STATUS    RESTARTS   AGE     LABELS
nginx-596bdcb889-qbvsf    1/1     Running   0          3m58s   app=nginx,pod-template-hash=596bdcb889,sg=true
nginx2-5fc4444698-srd9l   1/1     Running   0          20h     app=nginx2,pod-template-hash=5fc4444698,sg=true
nginx3-5465449d99-7jfww   1/1     Running   0          38m     app=nginx3,pod-template-hash=5465449d99,sg=false

最後に、 SecurityGroupPolicy を作成して、 sg=true のラベルがついたPodにのみ、 先ほど作成したTCP80を許可するセキュリティグループが割り当てられるように設定する。

$ cat <<EOF | kubectl apply -f -
apiVersion: vpcresources.k8s.aws/v1beta1
kind: SecurityGroupPolicy
metadata:
  name: sgp-eks-sg-policy-nginx
spec:
  podSelector:
    matchLabels:
      sg: "true"
  securityGroups:
    groupIds:
    - sg-0ee9cf2b805966c5a
EOF

これで nginxnginx2 間は通信できて、 nginx3 からは通信できなくなる、はずだったのだが、通信できてしまった。

$ kubectl exec nginx3-5465449d99-7jfww -- curl nginx -s --head
HTTP/1.1 200 OK

どうやら、 SecurityGroupPolicy を作成すると、該当するPodにENIが割り当てられることで、 セキュリティグループを利用できるようになるのだが、その動作はPod起動時にしか反映されないらしい。

しょうがないので、Deploymentの設定をいじって、Podを再作成する。 Podの再作成後、再度ラベルが付与されていることを確認する。

$ kubectl get pod --show-labels
NAME                      READY   STATUS    RESTARTS   AGE   LABELS
nginx-8667fff857-wsdsd    1/1     Running   0          49s   app=nginx,pod-template-hash=8667fff857,sg=true
nginx2-7bf6674f46-2nb2v   1/1     Running   0          31s   app=nginx2,pod-template-hash=7bf6674f46,sg=true
nginx3-5b6ffc5664-wl8k5   1/1     Running   0          18s   app=nginx3,pod-template-hash=5b6ffc5664,sg=false

ラベルが付与されていることを確認できたので、再度通信テストしてみる。

今度は期待通り、 nginx3 からの通信はおこなえず、それ以外の通信は許可されていることがわかる。 終了コードも7なので、ホストに接続できなかったことを示している。

$ kubectl exec nginx-8667fff857-wsdsd  -- curl nginx2 -s --head
HTTP/1.1 200 OK
$ kubectl exec nginx-8667fff857-wsdsd  -- curl nginx3 -s --head
HTTP/1.1 200 OK
$ kubectl exec nginx2-7bf6674f46-2nb2v  -- curl nginx -s --head
HTTP/1.1 200 OK
$ kubectl exec nginx2-7bf6674f46-2nb2v  -- curl nginx3 -s --head
HTTP/1.1 200 OK
$ kubectl exec nginx3-5b6ffc5664-wl8k5 -- curl nginx -s --head
command terminated with exit code 7
$ kubectl exec nginx3-5b6ffc5664-wl8k5 -- curl nginx2 -s --head
command terminated with exit code 7

EC2でしか利用できずFargateでは利用できないとか、EC2に割り当てられるENIの上限がそのままノードで起動できるPod数の上限になるとか、 使い勝手が必ずしもよいとは言えないが、NetworkPolicyよりも手軽には使えるな、という印象。

Podの違い

kubectl describe で見てみると、セキュリティグループを割り当てたPodには 割り当てていないPodよりもいくつか設定が追加されていることが確認できた。

セキュリティグループを割り当てないPod

いたって普通の設定内容。

$ kubectl describe pod nginx3-5b6ffc5664-wl8k5
Name:         nginx3-5b6ffc5664-wl8k5
Namespace:    default
Priority:     0
Node:         ip-10-0-0-161.ap-northeast-1.compute.internal/10.0.0.161
Start Time:   Sun, 25 Jul 2021 01:40:25 +0000
Labels:       app=nginx3
              pod-template-hash=5b6ffc5664
              sg=false
Annotations:  kubernetes.io/psp: eks.privileged
Status:       Running
IP:           10.0.0.180
IPs:
  IP:           10.0.0.180
Controlled By:  ReplicaSet/nginx3-5b6ffc5664
Containers:
  nginx:
    Container ID:   docker://bee90795077ee863e602f81950d34c6572c1018b9bea99d3e0167f8957ab9ed9
    Image:          nginx
    Image ID:       docker-pullable://nginx@sha256:8f335768880da6baf72b70c701002b45f4932acae8d574dedfddaf967fc3ac90
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Sun, 25 Jul 2021 01:40:29 +0000
    Ready:          True
Tolerations:     node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                 node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age    From               Message
  ----    ------     ----   ----               -------
  Normal  Scheduled  4m38s  default-scheduler  Successfully assigned default/nginx3-5b6ffc5664-wl8k5 to ip-10-0-0-161.ap-northeast-1.compute.internal
  Normal  Pulling    4m37s  kubelet            Pulling image "nginx"
  Normal  Pulled     4m35s  kubelet            Successfully pulled image "nginx" in 2.441671981s
  Normal  Created    4m35s  kubelet            Created container nginx
  Normal  Started    4m34s  kubelet            Started container nginx

セキュリティグループを割り当てたPod

アタッチしたENIに関するアノテーションや、Tolerationsが追加されていることがわかる。 また、起動時のイベントを見てみても、最初はENIがアタッチされておらず起動できなかったのが、 vpc-resource-controllerが動いてENIをアタッチすることで起動できたことがわかる。

$ kubectl describe pod nginx-8667fff857-wsdsd
Name:         nginx-8667fff857-wsdsd
Namespace:    default
Priority:     0
Node:         ip-10-0-0-161.ap-northeast-1.compute.internal/10.0.0.161
Start Time:   Sun, 25 Jul 2021 01:39:54 +0000
Labels:       app=nginx
              pod-template-hash=8667fff857
              sg=true
Annotations:  kubectl.kubernetes.io/restartedAt: 2021-07-25T01:31:55Z
              kubernetes.io/psp: eks.privileged
              vpc.amazonaws.com/pod-eni:
                [{"eniId":"eni-0e89d1162f64567cf","ifAddress":"06:e3:5d:e6:08:31","privateIp":"10.0.0.48","vlanId":1,"subnetCidr":"10.0.0.0/24"}]
Status:       Running
IP:           10.0.0.48
IPs:
  IP:           10.0.0.48
Controlled By:  ReplicaSet/nginx-8667fff857
Containers:
  nginx:
    Container ID:   docker://8b8288860b60c8f5212992706a1b7ee07acc3bfab95f2c386b21e7a8158fc9d4
    Image:          nginx
    Image ID:       docker-pullable://nginx@sha256:8f335768880da6baf72b70c701002b45f4932acae8d574dedfddaf967fc3ac90
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Sun, 25 Jul 2021 01:39:58 +0000
    Ready:          True
    Limits:
      vpc.amazonaws.com/pod-eni:  1
    Requests:
      vpc.amazonaws.com/pod-eni:  1
    Environment:                  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                 node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
                 vpc.amazonaws.com/pod-eni:NoSchedule op=Exists
Events:
  Type     Reason                  Age   From                     Message
  ----     ------                  ----  ----                     -------
  Normal   Scheduled               99s   default-scheduler        Successfully assigned default/nginx-8667fff857-wsdsd to ip-10-0-0-161.ap-northeast-1.compute.internal
  Normal   SecurityGroupRequested  99s   vpc-resource-controller  Pod will get the following Security Groups [sg-0ee9cf2b805966c5a]
  Warning  FailedCreatePodSandBox  99s   kubelet                  Failed to create pod sandbox: rpc error: code = Unknown desc = failed to set up sandbox container "863c69846507747844c18042d7ad2505b6316bcafd9395ca33f9480578599203" network for pod "nginx-8667fff857-wsdsd": networkPlugin cni failed to set up pod "nginx-8667fff857-wsdsd_default" network: add cmd: failed to assign an IP address to container
  Normal   ResourceAllocated       98s   vpc-resource-controller  Allocated [{"eniId":"eni-0e89d1162f64567cf","ifAddress":"06:e3:5d:e6:08:31","privateIp":"10.0.0.48","vlanId":1,"subnetCidr":"10.0.0.0/24"}] to the pod
  Normal   SandboxChanged          98s   kubelet                  Pod sandbox changed, it will be killed and re-created.
  Normal   Pulling                 97s   kubelet                  Pulling image "nginx"
  Normal   Pulled                  95s   kubelet                  Successfully pulled image "nginx" in 2.423182635s
  Normal   Created                 95s   kubelet                  Created container nginx
  Normal   Started                 95s   kubelet                  Started container nginx

Podのセキュリティグループが利用できないワーカーノードを使った場合

Podのセキュリティグループは、利用できるインスタンスタイプが限定されている。 たとえばT3インスタンスのワーカーノードしか存在しない状態で起動しようとすると、 条件を満たすノードがみつからずスケジューリングできずに起動に失敗する。

  $ kubectl describe pod nginx-8667fff857-qrxzj
(中略)
  Events:
    Type     Reason            Age                 From               Message
    ----     ------            ----                ----               -------
    Warning  FailedScheduling  1s (x3 over 46s)    default-scheduler  0/3 nodes are available: 1 Insufficient vpc.amazonaws.com/pod-eni, 2 node(s) were unschedulable

See also

comments powered by Disqus