12주차 - Amazon VPC Lattice for Amazon EKS(2)

728x90

 

[실습 2] Multi Cluster secure communication

 

  • 멀티 클러스터 환경 간에서 Amazon VPC Lattice를 활용한 안전한 통신 방법에 대해 실습

 

 주요 컴포넌트

  • 인프라 구성
    • 두 개의 VPC: VPC cluster 1과 VPC cluster 2가 독립적으로 구성
    • 두 개의 EKS 클러스터: 각 VPC에 EKS Cluster 1과 EKS Cluster 2 배포
    • VPC Lattice: 두 VPC 간의 서비스 통신을 위한 중앙 관리형 연결 서비스
  • 애플리케이션 구성
    • EKS Cluster 1 애플리케이션:
      • App1 Service가 Pod로 배포됨
      • Envoy sidecar 프록시를 통한 서비스 메시 구성
      • HTTP Route를 통한 외부 트래픽 라우팅
    • EKS Cluster 2 애플리케이션:
      • App2 Service가 Pod로 배포됨
      • 마찬가지로 Envoy sidecar 프록시와 HTTP Route 구성
  • 정책 및 보안
    • Kyverno: 각 클러스터에 적용된 정책 관리 도구로 사이드카 주입 등을 관리
    • IAM Auth Policy: 두 클러스터 간의 인증 및 권한 정책 설정
    • Private Certificate Authority: 중앙 인증서 관리
    • Certificate Manager: *.example.com 도메인을 위한 인증서 관리
  • 네트워킹
    • AWS Gateway API Controller: 각 클러스터의 API 트래픽 제어
    • DNS 구성:
      • ExternalDNS를 통한 DNS 레코드 관리
      • demo-cluster1.example.com 및 demo-cluster2.example.com으로 각 클러스터 서비스 노출
      • Amazon Route 53을 통한 도메인 관리

 주요 흐름 및 프로세스

  1. VPC Lattice를 통해 HTTPS 트래픽이 두 클러스터 간에 라우팅됨
  2. 각 클러스터의 IAM Auth Policy가 접근 권한을 제어
  3. Pod Identity 기능을 통해 Envoy SigV4 proxy 컨테이너에 ACM에 대한 권한 및 VPC Lattice service invoke 권한 부여
  4. AWS Gateway API Controller가 각 클러스터의 인그레스 트래픽을 관리
  5. ExternalDNS가 자동으로 DNS 레코드를 생성하여 서비스 디스커버리 지원

 

 Terraform 코드 준비 및 프로비저닝

  • environment 프로비저닝
    • environment 환경에서는 실습에 필요한 사전 환경(Route53, VPC Lattice, IAM Role, ACM 등)을 프로비저닝

cd terraform-aws-eks-blueprints/patterns/vpc-lattice/cross-cluster-pod-communication/environment/

#main.tf 파일을 열고, 7번째 라인의 region을 ap-northeast-2로 수정
  5 locals {
  6   name   = "vpc-lattice"
  7   region = "ap-northeast-2"
  8 
  9   domain = var.custom_domain_name
 10 
 11   tags = {
 12     Blueprint  = local.name
 13     GithubRepo = "github.com/aws-ia/terraform-aws-eks-blueprints"
 14   }
 15 }
 
terraform init
terraform apply --auto-approve

 

  • cluster 프로비저닝
    • 실습에 사용할 두 개의 EKS 클러스터 및 데모 애플리케이션을 구성
cd ../cluster/

#main.tf 파일을 열고, 31번째 라인의 region을 ap-northeast-2로 수정
 29 locals {
 30   name   = "eks-${terraform.workspace}"
 31   region = "us-west-2"
 32 
 33   cluster_vpc_cidr = "10.0.0.0/16"
 34   azs              = slice(data.aws_availability_zones.available.names, 0, 3)
 35 
 36   domain          = data.terraform_remote_state.environment.outputs.custom_domain_name
 37   certificate_arn = data.terraform_remote_state.environment.outputs.aws_acm_cert_arn
 38   acmpca_arn      = data.terraform_remote_state.environment.outputs.aws_acmpca_cert_authority_arn
 39   custom_domain   = data.terraform_remote_state.environment.outputs.custom_domain_name
 
./deploy.sh cluster1
# 배포 완료 후, 아래 명령으로 kubectl config 설정을 완료합니다.
eval `terraform output -raw configure_kubectl`

./deploy.sh cluster2
# 배포 완료 후, 아래 명령으로 kubectl config 설정을 완료합니다.
eval `terraform output -raw configure_kubectl`

2개 VPC 확인
2개 EKS 클러스터 확인

  • Access > Pod Identity associations 순으로 콘솔을 이동하면 아래와 같은 내용을 확인
    • vpc-lattice-sig4-client라는 IAM role이 apps라는 네임스페이스의 default라는 Service account에 associate 된 것을 확인

  • IAM role은 ACM의 PCA에 대한 여러 액세스 권한과 VPC Lattice Service에 대한 invoke 권한이 설정

Lattice > Service networks
Service가 커스텀 도메인 명에 매핑된 것을 확인
Route53 확인
ACM 확인

 

  • 데모 애플리케이션 Pod(demo-cluster1-v1)의 구성을 확인
kubectl describe po demo-cluster1-v1-7b8b98f676-mq7mp -n apps

..
..
#Init Containers를 통해 envoy-sigv4 컨테이너를 위한 IPTables 세팅이 수행

Init Containers:
  iptables-init:
    Container ID:  containerd://2970fc0a891bae5b736d6e2b15714bad5d81f199150e80802c40e0f0ed1055c7
    Image:         public.ecr.aws/seb-demo/iptables:v1
    Image ID:      public.ecr.aws/seb-demo/iptables@sha256:32f68e35a3c5925c7ee4cc664411063579418975e99754e0b9a53b1405b49e03
    Port:          <none>
    Host Port:     <none>
    Command:
      /bin/sh
      -c
      iptables -t nat -N EGRESS_PROXY; iptables -t nat -A OUTPUT -p tcp -d 169.254.171.0/24 -j EGRESS_PROXY; iptables -t nat -A EGRESS_PROXY -m owner --gid-owner 0 -j RETURN; iptables -t nat -A EGRESS_PROXY -p tcp -j REDIRECT --to-ports 8080; iptables -t nat -L -n -v;
      ..
      ..
#envoy-sigv4 컨테이너와 데모 애플리케이션 컨테이너 확인
      Containers:
  envoy-sigv4:
    Container ID:  containerd://8e738c2e008c3337cc6dd89d60f95435253eff26b3f49b4afc93f0cba1e7bf4d
    Image:         public.ecr.aws/seb-demo/envoy-sigv4:v0.5
    Image ID:      public.ecr.aws/seb-demo/envoy-sigv4@sha256:097a68853c38c9cc2cf44d1de31e10538dd5b312cbc9092b12d2e49f7f92fdee
    Port:          8080/TCP
    Host Port:     0/TCP
    Args:
      -l
      info
    State:          Running
      Started:      Mon, 28 Apr 2025 01:29:01 +0900
    Ready:          True
    Restart Count:  0
    Environment:
      APP_DOMAIN:                              example.com
      CA_ARN:                                  arn:aws:acm-pca:ap-northeast-2:890742582773:certificate-authority/eba23575-525f-41c1-8038-8c965a2cf1b3
      AWS_STS_REGIONAL_ENDPOINTS:              regional
      AWS_DEFAULT_REGION:                      ap-northeast-2
      AWS_REGION:                              ap-northeast-2
      AWS_CONTAINER_CREDENTIALS_FULL_URI:      http://169.254.170.23/v1/credentials
      AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE:  /var/run/secrets/pods.eks.amazonaws.com/serviceaccount/eks-pod-identity-token
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-8wvph (ro)
      /var/run/secrets/pods.eks.amazonaws.com/serviceaccount from eks-pod-identity-token (ro)
  demo-cluster2-v1:
    Container ID:   containerd://9c8e91ce1521559befbd12414fd21c7378d7edb15362c4343cef3150c4be2eb1
    Image:          public.ecr.aws/seb-demo/http-server:latest
    Image ID:       public.ecr.aws/seb-demo/http-server@sha256:05b913f6c411303f8967ed556b12c80ca49c63a9a37005bc8651c18df54266a6
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Mon, 28 Apr 2025 01:29:15 +0900
    Ready:          True
    Restart Count:  0
    Environment:
      PodName:                                 Hello from demo-cluster2-v1
      AWS_STS_REGIONAL_ENDPOINTS:              regional
      AWS_DEFAULT_REGION:                      ap-northeast-2
      AWS_REGION:                              ap-northeast-2
      AWS_CONTAINER_CREDENTIALS_FULL_URI:      http://169.254.170.23/v1/credentials
      AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE:  /var/run/secrets/pods.eks.amazonaws.com/serviceaccount/eks-pod-identity-token
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-8wvph (ro)
      /var/run/secrets/pods.eks.amazonaws.com/serviceaccount from eks-pod-identity-token (ro)

 

  • 통신 테스트 및 동작방식 확인
  • eks-cluster1의 데모 애플리케이션에서 eks-cluster2의 데모 애플리케이션으로 간단한 요청
kubectl --context eks-cluster1 \
  exec -ti -n apps deployments/demo-cluster1-v1 -c demo-cluster1-v1 \
  -- curl demo-cluster2.example.com
  
  ##응답
  Requsting to Pod(demo-cluster2-v1-69cdbfd45b-mpkjt): Hello from demo-cluster2-v1

 

  • eks-cluster1의 데모 애플리케이션에서 그대로 eks-cluster1의 데모 애플리케이션으로 요청
kubectl --context eks-cluster1 \
  exec -ti -n apps deployments/demo-cluster1-v1 -c demo-cluster1-v1 \
	-- curl demo-cluster1.example.com
    
    
##응답
AccessDeniedException: User: arn:aws:sts::890742582773:assumed-role/vpc-lattice-sigv4-client/eks-eks-cluste-demo-clust-583f641c-89e6-4242-8833-14b2f7ce4044 is not authorized to perform: vpc-lattice-svcs:Invoke on resource: arn:aws:vpc-lattice:ap-northeast-2:890742582773:service/svc-05a011bb3aacd80e4/ because no service-based policy allows the vpc-lattice-svcs:Invoke action

  • eks-cluster1의 IAMAuthPolicy에서 eks-cluster2 으로만 호출 가능하도록 설정되어 있기 때문에 에러가 발생
app-httproute.yaml 확인

...
...
apiVersion: application-networking.k8s.aws/v1alpha1
kind: IAMAuthPolicy
metadata:
    name: {{ .Release.Name }}-iam-auth-policy
    namespace: {{ .Release.Namespace }}
spec:
    targetRef:
        group: "gateway.networking.k8s.io"
        kind: HTTPRoute
        namespace: {{ .Release.Namespace }}
        name: {{ .Release.Name }}
    policy: |
        {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                      "AWS": "arn:aws:iam::{{ .Values.awsAccountID }}:root"
                    },
                    "Action": "vpc-lattice-svcs:Invoke",
                    "Resource": "*",
                    "Condition": {
                        "StringEquals": {
                            "aws:PrincipalTag/eks-cluster-name": "{{ .Values.allowedCluster }}",
                            "aws:PrincipalTag/kubernetes-namespace": "{{ .Values.allowedNamespace }}"

 

  • IAMAuthPolicy란?
    • IAMAuthPolicy는 Gateway API의 직접 정책 연결(Direct Policy Attachment)을 구현(implements)하는 GEP-713: 메타리소스 및 정책 연결
    • IAMAuthPolicy는 Gateway, HTTPRoute 또는 GRPCRoute에 연결될 수 있습니다.
    • IAMAuthPolicy는 VPC Lattice의 Service Network 또는 Service에 첨부되는 IAM Policy 문서로, 주체(principal)가 첨부된 Service Network의 Service 또는 특정 첨부된 Service에 접근하는 권한을 제어
    • IAMAuthPolicy는 Gateway, HTTPRoute, GRPCRoute를 통해 이동하는 트래픽에 대해서만 권한 부여를 수행할 수 있습니다. 클라이언트가 직접 k8s 서비스 DNS로 트래픽을 전송하는 경우에는 권한 부여가 적용되지 않습니다.
  • eks-cluster1의 IAMAuthPolicy 설정 확인
    • VPC Lattice Serivce를 invoke하는 액션 중에서 클러스터 명(eks-cluster-name)이 eks-cluster2 여야하고, 네임스페이스가 apps일 때에만 Invoke를 허용
kubectl --context eks-cluster1 \
  get IAMAuthPolicy -n apps demo-cluster1-iam-auth-policy  \
  -o json | jq ".spec.policy | fromjson"
  
  {
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::890742582773:root"
      },
      "Action": "vpc-lattice-svcs:Invoke",
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "aws:PrincipalTag/eks-cluster-name": "eks-cluster2",
          "aws:PrincipalTag/kubernetes-namespace": "apps"
        }
      }
    }
  ]
}

 

  • IAMAuthPolicy의 자세한 내용을 확인
kubectl describe IAMAuthPolicy demo-cluster1-iam-auth-policy -n apps

 

  • IAMAuthPolicy의 적용 대상(Target Ref)이 demo-cluster1 라는 이름을 가진, apps 네임스페이스의 HTTPRoute 리소스임을 확인

 

  • 대상이 되는 HTTPRoute를 조회하기 위해 아래 명령을 수행
kubectl describe HTTPRoute demo-cluster1 -n apps

Name:         demo-cluster1
Namespace:    apps
Labels:       app.kubernetes.io/managed-by=Helm
Annotations:  application-networking.k8s.aws/lattice-assigned-domain-name:
                demo-cluster1-apps-05a011bb3aacd80e4.7d67968.vpc-lattice-svcs.ap-northeast-2.on.aws
              meta.helm.sh/release-name: demo-cluster1
              meta.helm.sh/release-namespace: apps
API Version:  gateway.networking.k8s.io/v1beta1
Kind:         HTTPRoute
Metadata:
  Creation Timestamp:  2025-04-27T16:13:21Z
  Finalizers:
    httproute.k8s.aws/resources
  Generation:        1
  Resource Version:  7133
  UID:               d4c02e23-a61b-4ccd-a7e5-a0d2612283e7
Spec:
  Hostnames:
    demo-cluster1.example.com
  Parent Refs:
    Group:         gateway.networking.k8s.io
    Kind:          Gateway
    Name:          lattice-gateway
    Namespace:     lattice-gateway
    Section Name:  http-listener
    Group:         gateway.networking.k8s.io
    Kind:          Gateway
    Name:          lattice-gateway
    Namespace:     lattice-gateway
    Section Name:  https-listener-with-custom-domain
  Rules:
    Backend Refs:
      Group:   
      Kind:    Service
      Name:    demo-cluster1-v1
      Port:    80
      Weight:  1
    Matches:
      Path:
        Type:   PathPrefix
        Value:  /
..        
..
  • HTTPRoute로 라우팅 되는 대상이 demo-cluster1-v1 이라는 Service임을 확인

 

  • 해당 Service 명세를 확인
kubectl describe svc demo-cluster1-v1 -n apps

Name:                     demo-cluster1-v1
Namespace:                apps
Labels:                   app.kubernetes.io/managed-by=Helm
Annotations:              meta.helm.sh/release-name: demo-cluster1
                          meta.helm.sh/release-namespace: apps
Selector:                 app=demo-cluster1-v1
Type:                     ClusterIP
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       172.20.251.14
IPs:                      172.20.251.14
Port:                     <unset>  80/TCP
TargetPort:               8090/TCP
Endpoints:                10.0.30.19:8090
Session Affinity:         None
Internal Traffic Policy:  Cluster
Events:                   <none>
  • Service를 통해 라우팅 되는 대상이 10.0.30.19:8090 임을 확인할 수 있습니다. (demo-cluster1-v1)\

 

  • VPC 콘솔 > PrivateLink and Lattice > Lattice service 로 이동하여 demo-cluster1-apps의 체크박스를 클릭하고, Routing 탭을 클릭하면 아래와 같이 라우팅 대상 그룹을 확인

 

  • 실습 리소스 정리
#클러스터 정리
cd /workshop/terraform-aws-eks-blueprints/patterns/vpc-lattice/cross-cluster-pod-communication/cluster/

./destroy.sh cluster2

./destroy.sh cluster1

#environment 환경 정리
SN=$(aws vpc-lattice list-service-networks --query 'items[?name==`lattice-gateway`].id' --output text)
if [ -n "$SN" ]; then
    aws vpc-lattice delete-service-network --service-network-id "$SN"
fi

cd /workshop/terraform-aws-eks-blueprints/patterns/vpc-lattice/cross-cluster-pod-communication/environment/

terraform destroy -auto-approve

 

 

728x90