Amazon EKS Pod용 보안 그룹 정책 사용

Amazon EKS Pod용 보안 그룹 정책 사용

Pod용 보안 그룹을 사용하려면 기존 보안 그룹이 있어야 합니다. 다음 단계는 Pod에 보안 그룹 정책을 사용하는 방법을 보여 줍니다. 특별히 명시되지 않는 한 모든 단계를 같은 터미널에서 완료하세요. 다음 단계에서 사용되는 변수는 터미널 간에 유지되지 않기 때문입니다.

Amazon EC2 인스턴스가 있는 Pod가 있다면 이 절차를 사용하기 전에 플러그인을 구성해야 합니다. 자세한 내용은 Amazon EKS Pod용 보안 그룹으로 Amazon VPC CNI 플러그인 구성을 참조하세요.

출처: 문서

본문

리소스를 배포할 Kubernetes 네임스페이스를 만듭니다. my-namespace를 사용하려는 네임스페이스 이름으로 바꿀 수 있습니다.

kubectl create namespace my-namespace

클러스터에 Amazon EKS SecurityGroupPolicy를 배포합니다. 다음 내용을 기기에 복사합니다. Pod를 서비스 계정 레이블을 기준으로 선택하려면 podSelector를 serviceAccountSelector로 바꿀 수 있습니다. 선택자는 둘 중 하나를 지정해야 합니다. 빈 podSelector(예: podSelector: {})는 네임스페이스의 모든 Pod를 선택합니다. my-role을 역할 이름으로 바꿀 수 있습니다. 빈 serviceAccountSelector는 네임스페이스의 모든 서비스 계정을 선택합니다. my-security-group-policy를 SecurityGroupPolicy 이름으로, my-namespace를 SecurityGroupPolicy를 만들 네임스페이스로 바꿀 수 있습니다.

my_pod_security_group_id를 기존 보안 그룹의 ID로 바꿔야 합니다. 기존 보안 그룹이 없으면 하나를 만들어야 합니다. 자세한 내용은 Amazon EC2 User Guide의 Linux 인스턴스용 Amazon EC2 보안 그룹을 참조하세요. 보안 그룹 ID를 1~5개 지정할 수 있습니다. 둘 이상의 ID를 지정하면 선택된 Pod에 모든 보안 그룹의 모든 규칙 조합이 적용됩니다.

cat >my-security-group-policy.yaml

중요

Pod에 지정하는 보안 그룹은 다음 기준을 충족해야 합니다.

  • 존재해야 합니다. 존재하지 않으면 선택자와 일치하는 Pod를 배포할 때 Pod가 생성 과정에 계속 멈춰 있게 됩니다. Pod를 describe하면 다음 오류와 유사한 메시지가 표시됩니다. An error occurred (InvalidSecurityGroupID.NotFound) when calling the CreateNetworkInterface operation: The securityGroup ID 'sg-05b1d815d1EXAMPLE' does not exist.
  • 프로브를 구성한 포트에서 노드에 적용된 보안 그룹으로부터의 인바운드 통신(kubelet용)을 허용해야 합니다.
  • CoreDNS를 실행하는 Pod(또는 Pod가 실행되는 노드)에 할당된 보안 그룹으로 TCP 및 UDP 포트 53의 아웃바운드 통신을 허용해야 합니다. CoreDNS Pod의 보안 그룹은 지정한 보안 그룹으로부터의 인바운드 TCP 및 UDP 포트 53 트래픽을 허용해야 합니다.
  • 통신해야 하는 다른 Pod와 통신하는 데 필요한 인바운드 및 아웃바운드 규칙이 있어야 합니다.
  • Fargate와 함께 보안 그룹을 사용한다면 Pod가 Kubernetes 컨트롤 플레인과 통신할 수 있게 하는 규칙이 있어야 합니다. 가장 쉬운 방법은 클러스터 보안 그룹을 보안 그룹 중 하나로 지정하는 것입니다.

보안 그룹 정책은 새로 예약된 Pod에만 적용됩니다. 실행 중인 Pod에는 영향을 주지 않습니다.

정책을 배포합니다.

kubectl apply -f my-security-group-policy.yaml

이전 단계에서 지정한 podSelector의 my-role 값과 일치하는 레이블이 있는 샘플 애플리케이션을 배포합니다.

다음 내용을 기기에 복사합니다. 예시 값을 사용자의 값으로 바꾼 다음 수정된 명령을 실행합니다. my-role을 바꾸는 경우 이전 단계에서 선택자에 지정한 값과 동일한지 확인하세요.

cat >sample-application.yaml
my-deployment-5df6f7687b-j9fl4   1/1     Running   0          7m51s   192.168.70.145   ip-192-168-92-33.region-code.compute.internal
my-deployment-5df6f7687b-rjxcz   1/1     Running   0          7m51s   192.168.73.207   ip-192-168-92-33.region-code.compute.internal
my-deployment-5df6f7687b-zmb42   1/1     Running   0          7m51s   192.168.63.27    ip-192-168-33-28.region-code.compute.internal

참고

Pod가 멈춰 있으면 다음 팁을 시도하세요.

  • Pod가 Waiting 상태로 멈춰 있으면 kubectl describe pod my-deployment-xxxxxxxxxx-xxxxx -n my-namespace를 실행하세요. Insufficient permissions: Unable to create Elastic Network Interface.가 보이면 이전 단계에서 IAM 정책을 IAM 클러스터 역할에 추가했는지 확인하세요.
  • Pod가 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 플러그인 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

인스턴스 유형에서 실행할 수 있는 최대 Pod 수를 초과할 수 없습니다. 각 인스턴스 유형에서 실행할 수 있는 최대 Pod 수 목록은 GitHub의 eni-max-pods.txt를 참조하세요. 보안 그룹이 연결된 Pod를 삭제하거나 Pod가 실행 중인 노드를 삭제하면 VPC 리소스 컨트롤러가 분기 네트워크 인터페이스를 삭제합니다. 보안 그룹용 Pod를 사용하는 Pod가 있는 클러스터를 삭제하면 컨트롤러가 분기 네트워크 인터페이스를 삭제하지 않으므로 직접 삭제해야 합니다. 네트워크 인터페이스 삭제 방법은 Amazon EC2 User Guide의 네트워크 인터페이스 삭제를 참조하세요.

별도의 터미널에서 Pod 중 하나에 셸로 접속합니다. 이 주제의 나머지 부분에서는 이 터미널을 TerminalB라고 합니다. 5df6f7687b-4fbjm을 이전 단계의 출력에서 반환된 Pod 중 하나의 ID로 바꿉니다.

kubectl exec -it -n my-namespace my-deployment-5df6f7687b-4fbjm -- /bin/bash

TerminalB의 셸에서 샘플 애플리케이션이 동작하는지 확인합니다.

curl my-app

예시 출력은 다음과 같습니다.


Welcome to nginx!
[...]

애플리케이션을 실행하는 모든 Pod가 만든 보안 그룹과 연결되어 있기 때문에 이 출력을 받았습니다. 그 그룹에는 보안 그룹이 연결된 모든 Pod 사이의 모든 트래픽을 허용하는 규칙이 포함되어 있습니다. DNS 트래픽은 해당 보안 그룹에서 노드와 연결된 클러스터 보안 그룹으로 아웃바운드 허용됩니다. 노드는 Pod가 이름 조회를 수행한 CoreDNS Pod를 실행합니다.

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

클러스터 보안 그룹이 연결된 CoreDNS Pod에 Pod가 더 이상 접근할 수 없어 시도가 실패합니다. 클러스터 보안 그룹에는 더 이상 Pod에 연결된 보안 그룹에서 DNS 통신을 허용하는 보안 그룹 규칙이 없습니다.

이전 단계에서 반환된 Pod 중 하나의 IP 주소를 사용해 애플리케이션에 접근을 시도하면 여전히 응답을 받습니다. 보안 그룹이 연결된 Pod 사이에는 모든 포트가 허용되고 이름 조회가 필요하지 않기 때문입니다.

실험이 끝나면 만든 샘플 보안 그룹 정책, 애플리케이션, 보안 그룹을 제거할 수 있습니다. 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

더 알아보기 (Learn more)