[AWS EKS] VPC Lattice for EKS 실습

주영·2025년 4월 26일
0

AWS EKS Workshop Study 3기

목록 보기
31/31

이 글은 CloudNet@팀의 AWS EKS Workshop Study(AEWS) 3기 스터디 내용을 바탕으로 작성되었습니다.
AEWS는 CloudNet@의 '가시다'님께서 진행하는 스터디로, EKS를 학습하는 과정입니다.
EKS를 깊이 있게 이해할 기회를 주시고, 소중한 지식을 나눠주시는 가시다님께 다시 한번 감사드립니다.
이 글이 EKS를 학습하는 분들께 도움이 되길 바랍니다.

Amazon VPC Lattice를 활용한 클라이언트-서버 통신 및 멀티 클러스터 보안 통신 환경 구축 실습 과정입니다.

1. Amazon VPC Lattice 기반 클라이언트-서버 통신 실습

1.1 실습 목적 및 개요

이 실습은 Terraform을 활용하여, 서로 다른 두 개의 VPC에 클라이언트와 서버 애플리케이션을 각각 배포하고, Amazon VPC Lattice를 통해 이들 간 통신을 구현하는 과정입니다.
서버 애플리케이션은 Amazon EKS 클러스터에 배포되며, 클라이언트 애플리케이션은 별도의 VPC에 배포됩니다.
Amazon Route53 및 External DNS Add-on을 통해 서버 서비스에 대해 사용자 지정 도메인 이름을 설정하는 방법도 함께 다룹니다.

공식 실습 문서: Amazon VPC Lattice - Client to Server Communication

1.2 실습 환경 Terraform 코드 준비 및 프로비저닝

1. 실습 코드 Clone

실습에 필요한 코드를 아래 명령어로 내려받습니다.

git clone https://github.com/aws-ia/terraform-aws-eks-blueprints.git

2. 작업 디렉터리 이동

클론한 프로젝트 내에서 실습에 해당하는 디렉터리로 이동합니다.

cd terraform-aws-eks-blueprints/patterns/vpc-lattice/client-server-communication

3. Region 설정 변경

main.tf 파일의 29번째 줄에서 region을 ap-northeast-2(서울 리전)로 수정합니다.

이 작업을 통해 리소스가 한국 리전에 배포됩니다.

4. Terraform 초기화

모듈과 provider 다운로드 및 초기 설정을 수행합니다.

terraform init

5. 리소스 단계별 배포

아래 명령어를 순서대로 실행해 단계별로 리소스를 배포합니다.

각 단계는 서로 의존성이 있으므로 제시된 순서대로 실행해야 합니다.

terraform apply -target="module.client_vpc" -auto-approve
terraform apply -target="module.cluster_vpc" -auto-approve
terraform apply -target=aws_route53_zone.primary -auto-approve
terraform apply -target="module.client_sg" -auto-approve
terraform apply -target="module.endpoint_sg" -auto-approve
terraform apply -target="module.client" -auto-approve
terraform apply -target="module.vpc_endpoints" -auto-approve
terraform apply -target="module.eks" -auto-approve
terraform apply -target="module.addons" -auto-approve

...

6. 전체 리소스 최종 배포

모든 리소스가 정상적으로 배포되었는지 최종적으로 전체를 apply합니다.

terraform apply -auto-approve

7. kubectl 접속 설정

EKS 클러스터에 kubectl로 접근할 수 있도록 kubeconfig 파일을 설정합니다.

aws eks update-kubeconfig --name client-server-communication --alias client-server-communication --region ap-northeast-2

8. EKS 클러스터 정상 동작 확인

클러스터에 배포된 모든 Pod가 정상적으로 기동되는지 확인합니다.

kubectl get po -A

모든 Pod가 정상적으로 조회된다면 인프라 구축이 완료된 것입니다.

1.3 Terraform 코드 상세 구조 및 설명

1. 프로젝트 디렉터리 구조 탐색

  • 폴더 경로
    terraform-aws-eks-blueprints > patterns > vpc-lattice > client-server-communication

  • 해당 경로에는 실습에 필요한 주요 Terraform 코드와 관련 리소스들이 위치합니다.

2. client.tf: 클라이언트 리소스 정의

2-1. EC2 인스턴스(클라이언트) 생성

  • 목적:
    클라이언트 역할을 하는 EC2 인스턴스를 별도의 VPC 내에 배포하여, EKS 내 서버 애플리케이션에 접근하도록 구성합니다.

  • 주요 코드 설명

module "client" {
  source  = "terraform-aws-modules/ec2-instance/aws"
  version = "~> 5.0"

  name = "client"

  instance_type               = "t2.micro"
  subnet_id                   = module.client_vpc.private_subnets[0]
  create_iam_instance_profile = true
  iam_role_description        = "IAM role for client"
  iam_role_policies = {
    AmazonSSMManagedInstanceCore = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
  }
  vpc_security_group_ids = [module.client_sg.security_group_id]

  tags = local.tags
}
  • EC2 인스턴스는 t2.micro 타입으로, 프라이빗 서브넷에 배치됩니다.
  • AWS Systems Manager(SSM) 사용을 위한 IAM Role(AmazonSSMManagedInstanceCore)을 할당합니다.
  • 보안 그룹(client_sg)은 별도 모듈로 구성되어 있습니다.

2-2. VPC Endpoint 구성

  • 목적:
    SSM을 비롯한 관리 서비스를 EC2 인스턴스가 프라이빗 네트워크에서 사용할 수 있도록 VPC Endpoint를 설정합니다.

  • 주요 코드 설명

module "vpc_endpoints" {
  source  = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints"
  version = "~> 5.0"

  vpc_id = module.client_vpc.vpc_id

  endpoints = { for service in toset(["ssm", "ssmmessages", "ec2messages"]) :
    replace(service, ".", "_") =>
    {
      service             = service
      subnet_ids          = module.client_vpc.private_subnets
      private_dns_enabled = true
      tags                = { Name = "${local.name}-${service}" }
    }
  }

  security_group_ids = [module.endpoint_sg.security_group_id]

  tags = local.tags
}
  • SSM, ssmmessages, ec2messages 서비스를 위한 Endpoint가 생성됩니다.
  • 보안 그룹(endpoint_sg)이 함께 적용되어, 통신 보안을 강화합니다.

2-3. Security Group 설정

  • client_sg
    • 모든 아웃바운드 트래픽(egress)을 허용하도록 구성됩니다.
module "client_sg" {
  source  = "terraform-aws-modules/security-group/aws"
  version = "~> 5.0"

  name        = "client"
  description = "Security Group for EC2 Instance Egress"

  vpc_id = module.client_vpc.vpc_id

  egress_with_cidr_blocks = [
    {
      from_port   = 0
      to_port     = 0
      protocol    = "-1"
      cidr_blocks = "0.0.0.0/0"
    },
  ]

  tags = local.tags
}
  • endpoint_sg
    • VPC의 프라이빗 서브넷 대역에서 443 포트로의 인바운드 트래픽(ingress)을 허용합니다.
module "endpoint_sg" {
  source  = "terraform-aws-modules/security-group/aws"
  version = "~> 5.0"

  name        = "ssm-endpoint"
  description = "Security Group for EC2 Instance Egress"

  vpc_id = module.client_vpc.vpc_id

  ingress_with_cidr_blocks = [for subnet in module.client_vpc.private_subnets_cidr_blocks :
    {
      from_port   = 443
      to_port     = 443
      protocol    = "TCP"
      cidr_blocks = subnet
    }
  ]

  tags = local.tags
}

2-4. client_vpc 모듈

  • 목적:
    클라이언트 리소스가 배치될 별도의 VPC를 정의합니다.

  • 주요 설정

module "client_vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.0"

  name = local.name
  cidr = local.client_vpc_cidr

  azs             = local.azs
  private_subnets = [for k, v in local.azs : cidrsubnet(local.client_vpc_cidr, 4, k)]

  tags = local.tags
}
  • CIDR, 가용영역(azs), 프라이빗 서브넷 생성 방식 등은 main.tf의 변수 값을 참조합니다.
  • cidrsubnet 함수로 서브넷을 동적으로 생성합니다.

3. eks.tf: EKS 클러스터 및 서버 리소스 정의

3-1. EKS 클러스터 생성

  • 주요 특징
    • 클러스터 버전: 1.30
    • 퍼블릭 엔드포인트 허용
    • 클러스터 VPC와 서브넷 지정
    • 관리형 노드그룹(m5.large, min 3/ max 10/ desired 3)
    • Terraform으로 클러스터 관리자 권한 부여
module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 20.11"

  cluster_name                   = local.name
  cluster_version                = "1.30"
  cluster_endpoint_public_access = true

  # Give the Terraform identity admin access to the cluster
  # which will allow resources to be deployed into the cluster
  enable_cluster_creator_admin_permissions = true

  vpc_id     = module.cluster_vpc.vpc_id
  subnet_ids = module.cluster_vpc.private_subnets

  eks_managed_node_groups = {
    initial = {
      instance_types = ["m5.large"]

      min_size     = 3
      max_size     = 10
      desired_size = 3
    }
  }

  tags = local.tags
}

3-2. cluster_vpc 모듈

  • 목적:
    EKS 클러스터가 생성될 별도의 VPC와, 퍼블릭/프라이빗 서브넷을 정의합니다.
  • 주요 설정
    • NAT Gateway 1개만 프로비저닝(single_nat_gateway)
    • 퍼블릭/프라이빗 서브넷의 태그를 통해 로드밸런서 연결 지원
module "cluster_vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.0"

  name = local.name
  cidr = local.cluster_vpc_cidr

  azs             = local.azs
  private_subnets = [for k, v in local.azs : cidrsubnet(local.cluster_vpc_cidr, 4, k)]
  public_subnets  = [for k, v in local.azs : cidrsubnet(local.cluster_vpc_cidr, 8, k + 48)]

  enable_nat_gateway = true
  single_nat_gateway = true

  public_subnet_tags = {
    "kubernetes.io/role/elb" = 1
  }

  private_subnet_tags = {
    "kubernetes.io/role/internal-elb" = 1
  }

  tags = local.tags
}

3-3. EKS Add-ons 설정

  • 주요 기능
    • AWS Gateway API Controller 배포
    • External DNS 연동
    • Addon별 상세 Helm chart 옵션, OIDC Provider 등 설정
    • Route53 Zone과 연동하여 DNS 자동화
module "addons" {
  source  = "aws-ia/eks-blueprints-addons/aws"
  version = "~> 1.16"

  cluster_name      = module.eks.cluster_name
  cluster_endpoint  = module.eks.cluster_endpoint
  cluster_version   = module.eks.cluster_version
  oidc_provider_arn = module.eks.oidc_provider_arn

  enable_aws_gateway_api_controller = true
  aws_gateway_api_controller = {
    chart_version           = "v1.0.3"
    create_namespace        = true
    namespace               = "aws-application-networking-system"
    source_policy_documents = [data.aws_iam_policy_document.gateway_api_controller.json]
    set = [
      {
        name  = "clusterName"
        value = module.eks.cluster_name
      },
      {
        name  = "log.level"
        value = "debug"
      },
      {
        name  = "clusterVpcId"
        value = module.cluster_vpc.vpc_id
      },
      {
        name  = "defaultServiceNetwork"
        value = ""
      },
      {
        name  = "latticeEndpoint"
        value = "https://vpc-lattice.${local.region}.amazonaws.com"
      }
    ]
    wait = true
  }
  enable_external_dns = true
  external_dns_route53_zone_arns = try([aws_route53_zone.primary.arn], [])
  external_dns = {
    set = [
      {
        name  = "domainFilters[0]"
        value = "example.com"
      },
      {
        name  = "policy"
        value = "sync"
      },
      {
        name  = "sources[0]"
        value = "crd"
      },
      {
        name  = "sources[1]"
        value = "ingress"
      },
      {
        name  = "txtPrefix"
        value = module.eks.cluster_name
      },
      {
        name  = "extraArgs[0]"
        value = "--crd-source-apiversion=externaldns.k8s.io/v1alpha1"
      },
      {
        name  = "extraArgs[1]"
        value = "--crd-source-kind=DNSEndpoint"
      },
      {
        name  = "crdSourceApiversion"
        value = "externaldns.k8s.io/v1alpha1"
      },
      {
        name  = "crdSourceKind"
        value = "DNSEndpoint"
      }
    ]
  }

  tags = local.tags
}

3-4. Gateway API Controller IAM Policy

  • 목적:
    VPC Lattice 및 클러스터 연동에 필요한 IAM 권한을 부여합니다.
    • vpc-lattice 리소스 조작, EC2/VPC 정보 조회, 로그 전송, 태그 조회 등
data "aws_iam_policy_document" "gateway_api_controller" {
  statement {
    sid       = ""
    effect    = "Allow"
    resources = ["*"] # For testing purposes only (highly recommended limit access to specific resources for production usage)

    actions = [
      "vpc-lattice:*",
      "iam:CreateServiceLinkedRole",
      "ec2:DescribeVpcs",
      "ec2:DescribeSubnets",
      "ec2:DescribeTags",
      "ec2:DescribeSecurityGroups",
      "logs:CreateLogDelivery",
      "logs:GetLogDelivery",
      "logs:UpdateLogDelivery",
      "logs:DeleteLogDelivery",
      "logs:ListLogDeliveries",
      "tag:GetResources",
    ]
  }
}

3-5. 데모 애플리케이션

  • Helm Chart를 통한 배포
    • EKS 클러스터 내 apps 네임스페이스에 데모 앱 설치
    • 서버용 Deployment, Service, GatewayClass, Gateway, HTTPRoute 리소스 포함
  • 주요 매니페스트 구조
    • GatewayClass, Gateway, HTTPRoute: VPC Lattice와 연동
    • Deployment/Service: 서버 역할(Pod 2개, 8090포트로 서비스)
resource "helm_release" "demo_application" {
  name             = "demo-application"
  chart            = "./charts/demo-application"
  create_namespace = true
  namespace        = "apps"

  depends_on = [module.addons]
}
apiVersion: gateway.networking.k8s.io/v1beta1
kind: GatewayClass
metadata:
  name: amazon-vpc-lattice
spec:
  controllerName: application-networking.k8s.aws/gateway-api-controller
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
  name: my-services
  namespace: apps
spec:
  gatewayClassName: amazon-vpc-lattice
  listeners:
    - name: http
      protocol: HTTP
      port: 80
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
  name: server
  namespace: apps
spec:
  hostnames:
    - server.example.com
  parentRefs:
    - name: my-services
      sectionName: http
  rules:
    - backendRefs:
        - name: server
          kind: Service
          port: 8090
      matches:
        - path:
            type: PathPrefix
            value: /
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: server
  labels:
    app: server
spec:
  replicas: 2
  selector:
    matchLabels:
      app: server
  template:
    metadata:
      labels:
        app: server
    spec:
      containers:
        - name: server
          image: public.ecr.aws/x2j8p8w7/http-server:latest
          env:
            - name: PodName
              value: "server pod"
---
apiVersion: v1
kind: Service
metadata:
  name: server
spec:
  selector:
    app: server
  ports:
    - protocol: TCP
      port: 8090
      targetPort: 8090

3-6. VPC Lattice Prefix List 및 보안 설정

  • prefix_list 사용
    • VPC Lattice 트래픽에 대한 보안그룹 Ingress 룰 생성
data "aws_ec2_managed_prefix_list" "vpc_lattice_ipv4" {
  name = "com.amazonaws.${local.region}.vpc-lattice"
}

resource "aws_vpc_security_group_ingress_rule" "cluster_sg_ingress" {
  security_group_id = module.eks.node_security_group_id

  prefix_list_id = data.aws_ec2_managed_prefix_list.vpc_lattice_ipv4.id
  ip_protocol    = "-1"
}

4. lattice.tf: VPC Lattice 네트워크 연동

4-1. VPC Lattice Service Network 생성

  • my-services라는 이름으로 서비스 네트워크를 생성
  • 인증 타입은 NONE으로 설정 (내부 통신만 허용)
resource "aws_vpclattice_service_network" "this" {
  name      = "my-services"
  auth_type = "NONE"

  tags = local.tags
}

4-2. 서비스 네트워크에 VPC 연동

  • cluster_vpc, client_vpc 모두 서비스 네트워크에 연결
  • 각 VPC의 ID와 Lattice Service Network ID로 Association 구성
resource "aws_vpclattice_service_network_vpc_association" "cluster_vpc" {
  vpc_identifier             = module.cluster_vpc.vpc_id
  service_network_identifier = aws_vpclattice_service_network.this.id
}

resource "aws_vpclattice_service_network_vpc_association" "client_vpc" {
  vpc_identifier             = module.client_vpc.vpc_id
  service_network_identifier = aws_vpclattice_service_network.this.id
}

4-3. 리소스 생성 후 대기

  • time_sleep
    • 데모 애플리케이션 배포 후, Lattice 리소스의 완전한 생성/연동을 위해 120초 대기
resource "time_sleep" "wait_for_lattice_resources" {
  depends_on = [helm_release.demo_application]

  create_duration = "120s"
}

4-4. Route53 Hosted Zone 및 도메인 연결

  • example.com 도메인으로 Route53 Public Hosted Zone 생성
  • client_vpc와 연결
  • 실제 DNS 레코드는 external-dns와 HTTPRoute에 의해 자동 생성
resource "aws_vpclattice_service_network_vpc_association" "cluster_vpc" {
  vpc_identifier             = module.cluster_vpc.vpc_id
  service_network_identifier = aws_vpclattice_service_network.this.id
}

resource "aws_vpclattice_service_network_vpc_association" "client_vpc" {
  vpc_identifier             = module.client_vpc.vpc_id
  service_network_identifier = aws_vpclattice_service_network.this.id
}

5. 전체 구조 요약

  • client_vpc에 EC2 인스턴스(클라이언트)와 VPC Endpoint를 배포
  • cluster_vpc에 Amazon EKS 클러스터와 데모 서버 애플리케이션을 배포
  • VPC Lattice 서비스 네트워크를 통해 두 VPC를 연동하고, 서버 서비스를 Lattice를 통해 외부에 노출
  • Security Group, IAM Role, Endpoint, NAT Gateway 등 인프라 구성 요소들을 안전하게 설계
  • External DNS, Route53으로 서비스 접근 도메인을 자동화
  • 모든 리소스는 모듈화된 Terraform 코드로 재사용성과 유지보수성을 높임

1.4 Terraform으로 구성된 인프라 확인

1. VPC 및 Subnet 구성 확인

1-1. VPC 확인

  • AWS VPC 콘솔(서울 리전)에서 Your VPCs 메뉴를 통해, 실습에서 사용된 VPC를 확인할 수 있습니다.
    • client vpc: 10.1.0.0/16 CIDR 범위로 생성
    • cluster vpc: 10.0.0.0/16 CIDR 범위로 생성
  • 이 두 VPC는 상호 분리되어 있으며, 각각 클라이언트와 서버 역할의 리소스를 배치하는데 사용됩니다.

1-2. Subnet 확인

  • Subnets 메뉴를 통해 VPC별 서브넷을 확인합니다.
    • client vpc: 프라이빗 서브넷 3개로 구성
    • cluster vpc: 퍼블릭 서브넷 3개, 프라이빗 서브넷 3개로 구성
  • EKS 클러스터와 서버 워크로드는 주로 cluster vpc의 프라이빗 서브넷에 위치합니다.

2. 워크로드(EC2, EKS 노드) 구성 확인

2-1. EC2 인스턴스 확인

  • EC2 콘솔의 Instances 메뉴에서, 실습 중 생성된 인스턴스를 확인합니다.
    • client: client vpc에 1개의 EC2 인스턴스가 배포되어 있습니다.
      이 인스턴스는 테스트 클라이언트 역할을 하며, 서버로 http 요청을 전송합니다.
    • cluster: cluster vpc에는 3개의 EC2 인스턴스(워크 노드)가 배포되어 있습니다.
      이 인스턴스들은 EKS 클러스터의 워커 노드로 작동합니다.

2-2. EKS 워커 노드 확인

  • 아래 명령을 통해 클러스터 내 워커 노드를 확인할 수 있습니다.
kubectl get nodes

  • 워커 노드가 정상적으로 Ready 상태임을 확인하면, EKS 인프라가 올바르게 구성된 것입니다.

1.5 VPC Lattice를 활용한 Client-to-Server 통신 테스트

1. client EC2 인스턴스 접속

  • Session Manager를 통해 인바운드 포트를 열지 않고, 안전하게 EC2 인스턴스에 접속합니다.
    • EC2 인스턴스를 선택 → Connect → Session Manager 탭 → Connect 클릭
  • AWS Systems Manager Session Manager를 활용하면 SSH Key 관리나 Bastion Host 없이 IAM 인증 기반으로 안전하게 접속이 가능합니다.

2. Server Pod 통신 테스트

  • client 인스턴스에서 cluster의 server pod로 http 요청을 전송하여 실제 통신이 가능한지 검증합니다.
    • Server pod의 로그를 실시간 모니터링합니다.
    kubectl logs -f deployment/server -n apps --all-containers=true --since=1m
    • client 인스턴스의 터미널에서 아래 명령을 수행하여 HTTP 요청을 보냅니다.
    curl -i http://server.example.com
    • 응답이 정상적으로 오면, VPC Lattice 및 서비스 네트워크 구성이 성공적으로 동작하고 있음을 의미합니다.

3. DNS 엔드포인트 확인

  • server.example.com에 대한 DNS 쿼리를 실행해봅니다.
    nslookup server.example.com
  • Amazon VPC Lattice를 통해 구성된 엔드포인트 정보가 반환됨을 확인할 수 있습니다.
    이는 서버 Pod의 서비스가 VPC Lattice 네트워크를 통해 도달 가능함을 보여줍니다.

4. Amazon VPC Lattice 리소스 및 라우팅 구조 확인

4-1. VPC Lattice 서비스 조회

  • VPC 콘솔의 PrivateLink 및 Lattice > Lattice 서비스 메뉴에서, 실습에서 생성된 VPC Lattice Service를 확인할 수 있습니다.

4-2. Lattice Target Group 및 라우팅 규칙 확인

  • Lattice Service의 상세 페이지에서 Routing → Listener rules → Action → Forward to를 차례로 클릭하여 대상 그룹(Target Group) 설정을 확인합니다.
  • 대상 그룹의 Registered targets에서, 실제 서버 pod의 IP 주소와 Port 번호로 라우팅이 설정되어 있음을 확인할 수 있습니다.
  • kubectl get po -n apps -o wide 명령으로 server pod의 IP를 확인할 수 있고,

    kubectl get svc -n apps 명령으로 서비스의 Port 번호를 확인할 수 있습니다.

5. AWS Gateway API Controller의 역할 및 동작 확인

5-1. Gateway API Controller 동작 로그 확인

  • EKS 클러스터 내에서 Gateway API Controller의 동작을 아래 명령으로 확인할 수 있습니다.

    kubectl logs deployment/aws-gateway-api-controller-aws-gateway-controller-chart -n aws-application-networking-system --all-containers=true > lattice.log
    vi lattice.log

  • 로그에서는 다음과 같은 동작이 확인됩니다.

    • server라는 Service와 my-services라는 Gateway의 생성을 감지
    • HTTPRoute(예: server-apps)에 따른 사용자 도메인(server.example.com) 및 PathPrefix, Backend 설정 반영
    • Listener Rule 생성, 대상 그룹 설정, 서비스 포드로의 라우팅 등 일련의 리소스 reconcile 작업

5-2. 구성 원리 요약

  • EKS 클러스터 내에서 GatewayClass, Gateway, HTTPRoute 리소스를 선언하면,
    • AWS Gateway API Controller가 이 리소스의 변경사항을 감지하여
    • AWS VPC Lattice 네트워크(서비스, 타겟그룹, 라우팅 등)를 자동으로 생성·연동
    • 결과적으로, 별도 VPC에 존재하는 클라이언트에서 지정한 도메인(server.example.com)으로 접근하면,
      VPC Lattice와 EKS, External DNS가 협력하여 서버 pod로 트래픽이 전달됨

1.6 실습 리소스 정리

terraform destroy -target="module.client_vpc" -auto-approve
terraform destroy -target="module.cluster_vpc" -auto-approve
terraform destroy -target=aws_route53_zone.primary -auto-approve

terraform destroy -target="module.client_sg" -auto-approve
terraform destroy -target="module.endpoint_sg" -auto-approve

terraform destroy -target="module.client" -auto-approve
terraform destroy -target="module.vpc_endpoints" -auto-approve

terraform destroy -target="module.eks" -auto-approve
terraform destroy -target="module.addons" -auto-approve

terraform destroy -auto-approve

2. Amazon VPC Lattice 기반 Multi Cluster Secure Communication 실습

이번 실습은 Amazon EKS Blueprints for Terraform에서 제공하는
Multi-cluster Secure Communication 패턴을 기반으로 합니다.
목표는 서로 다른 VPC에 위치한 두 개의 Amazon EKS 클러스터가 Amazon VPC Lattice와 IAM 인증, TLS 보안 구성을 활용하여
안전하게 서비스 간 통신을 수행하는 전체 과정을 이해하고 직접 실습하는 것입니다.

2.1 아키텍처 및 구성 요소

1. 인프라 구성

  • VPC 2개:
    각각 독립적으로 분리된 네트워크(클러스터 1용, 클러스터 2용)
  • EKS 클러스터 2개:
    각 VPC에 1개씩 배포 (EKS Cluster 1, EKS Cluster 2)
  • VPC Lattice:
    클러스터 간 서비스 연결을 담당하는 중앙 서비스 네트워크

2. 애플리케이션 구성

  • EKS Cluster 1 (App1 서비스)
    • App1 Pod에는 Envoy sidecar proxy가 주입되어 트래픽을 프록시 처리
    • HTTPRoute로 외부 요청 라우팅
  • EKS Cluster 2 (App2 서비스)
    • App2 Pod 역시 Envoy 사이드카와 HTTPRoute 구성

3. 정책 및 보안 구성

  • Kyverno
    • 쿠버네티스 정책 관리 툴로, 모든 Pod에 Envoy 프록시와 인증서 정보가 자동 주입됨
  • AM 인증 정책
    • 두 클러스터 간 서비스 접근을 IAM 정책으로 제어
  • AWS Private Certificate Authority (CA)
    • TLS 인증서의 발급과 관리
  • AWS Certificate Manager (ACM)
    • *.example.com 와일드카드 인증서 발급 및 라이프사이클 관리

4. 네트워킹 및 서비스 디스커버리

  • AWS Gateway API Controller
    • 클러스터 별 인그레스 트래픽(외부/클러스터 간 유입) 관리를 담당
  • ExternalDNS
    • 쿠버네티스 서비스에 대응하는 DNS 레코드를 Route 53에 자동 등록
    • 예시:
      • EKS Cluster 1 → demo-cluster1.example.com
      • EKS Cluster 2 → demo-cluster2.example.com
  • Amazon Route 53
    • 서비스 도메인(Private Hosted Zone) 관리

2.2 주요 흐름 및 동작 원리

  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 레코드를 생성하여 서비스 디스커버리 지원

2.3 Terraform 코드 준비 및 프로비저닝

1. 사전 코드 준비

실습에 필요한 코드는 GitHub에서 아래 명령어로 내려받습니다. (실습 1에서 받은 경우 생략)

git clone https://github.com/aws-ia/terraform-aws-eks-blueprints.git

프로젝트 디렉터리는 사용하기 편한 위치에 설정합니다.

2. environment 환경 프로비저닝

2-1. 목적 및 구성

  • environment 디렉터리의 Terraform 코드는 실습 전반에 필요한 사전 인프라(도메인, VPC Lattice, IAM Role, ACM 등)를 먼저 구성합니다.
  • 주요 리소스: Route53 Private Hosted Zone, 더미 VPC, IAM Role 및 Policy, Private CA, ACM 인증서

2-2. 주요 코드 구성

main.tf

  • 리전(region):
    • us-west-2에서 실습에 맞게 ap-northeast-2 등으로 수정
  • 로컬 변수로 이름, 리전, 도메인, 태그 정의
  • Route53 Private Hosted Zone 생성
    • 더미 VPC와 연결해 Private Hosted Zone 생성
    • 실습 중 실제 VPC와의 association은 이후 스택에서 진행
  • IAM Role 및 Policy
    • VPC Lattice 서비스 호출, ACM Private CA 접근 권한 부여
    • EKS에서 Pod Identity가 사용할 역할 정의

pca.tf

  • Private CA 생성
    • RSA_4096, SHA512WITHRSA 기반의 Root CA 구성, 10년 유효 기간
    • ACM PCA Certificate Authority와 연결
  • ACM 인증서
    • 실습용 custom domain 및 와일드카드(*.example.com) 인증서 발급
    • Private CA 기반으로 발급

2-3. environment 인프라 배포 절차

  1. 디렉터리 이동

    cd terraform-aws-eks-blueprints/patterns/vpc-lattice/cross-cluster-pod-communication/environment/
  2. main.tf에서 region을 실습 리전으로 수정

  3. Terraform 명령어로 인프라 배포

    terraform init
    terraform apply --auto-approve

3. cluster 환경 프로비저닝

3-1. 목적 및 구성

  • cluster 디렉터리의 Terraform 코드는 실습에서 사용할 두 개의 EKS 클러스터, 관련 VPC, Addons, 데모 애플리케이션 등을 구성합니다.
  • 각 클러스터는 별도의 워크스페이스(cluster1, cluster2)에서 배포됩니다.

3-2. 주요 코드 구성

main.tf

  • 공통 변수 및 환경 정보
    • 이름, 리전, VPC CIDR, AZs, 도메인, 인증서 등
    • environment 스택의 output을 remote state로 받아와 사용
  • AWS 및 Helm Provider
    • Helm provider는 EKS 클러스터 인증 정보와 연동

eks.tf

  • EKS 클러스터
    • v1.30, 관리형 노드그룹(m5.large, 3개 노드), 퍼블릭 엔드포인트
    • enable_cluster_creator_admin_permissions로 Terraform 계정에 admin 권한 부여
  • EKS Blueprints Addons
    • AWS Gateway API Controller, ExternalDNS, Kyverno, eks-pod-identity-agent 등
    • ExternalDNS는 Route53 Private Hosted Zone과 연동
  • Helm을 통한 앱 배포
    • /charts/platform 차트로 GatewayClass, Gateway, IAMAuthPolicy 등 인프라 배포
    • /charts/demo 차트로 실제 데모 서비스 및 HTTPRoute, IAMAuthPolicy 등 배포
  • Kyverno ClusterPolicy
    • 모든 Deployment에 Envoy sidecar, iptables-init 컨테이너 자동 주입
  • Security Group 규칙 추가
    • VPC Lattice 서비스(IPv4 prefix list)로부터 클러스터 노드 접근 허용
  • Pod Identity 적용
    • 애플리케이션에 IAM Role을 직접 부여하여 Lattice 서비스 호출 및 인증서 접근권한 제공

vpc.tf

  • EKS용 VPC 및 서브넷
    • 퍼블릭/프라이빗 서브넷, NAT Gateway 포함
  • Route53 Private Hosted Zone Association
    • 클러스터 VPC를 미리 생성된 Private Hosted Zone에 연결

3-3. cluster 인프라 배포 절차

  1. 디렉터리 이동

    cd ../cluster/
  2. main.tf에서 region을 실습 리전으로 수정

  3. 첫 번째 EKS 클러스터 배포 실행

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

  4. 두 번째 EKS 클러스터 배포 실행

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

2.4 프로비저닝된 인프라 및 애플리케이션 확인

1. Amazon EKS 클러스터 상태 확인

  • EKS 콘솔 접속
    • 두 개의 EKS 클러스터(예: eks-cluster1, eks-cluster2)가 정상적으로 생성된 것을 확인할 수 있습니다.
    • 각 클러스터는 독립된 VPC 상에 배포되어, 멀티클러스터 아키텍처를 구현합니다.
  • Pod Identity 연계 확인
    • Access > Pod Identity associations 메뉴에서,
      apps 네임스페이스의 default ServiceAccount에 vpc-lattice-sig4-client IAM Role이 연결되어 있음을 확인합니다.
    • 이 Role은 EKS Pod(특히 데모 애플리케이션)에 필요한 AWS 리소스 접근 권한을 제공합니다.
  • IAM Role 권한 상세 확인
    • 해당 Role에는 ACM Private CA 접근 권한과 VPC Lattice 서비스 invoke 권한이 모두 포함되어 있습니다.
    • 실제로는 AWS Certificate Manager와 VPC Lattice 서비스 연동에 필수적인 정책이 적용되어 있습니다.

2. VPC Lattice 구성 확인

  • VPC 콘솔 > PrivateLink and Lattice > Service networks
    • 멀티클러스터 통신을 위해 VPC Lattice Service Network가 구성되어 있음을 확인할 수 있습니다.
    • 각 클러스터의 VPC가 이 Service Network에 연결되어, 격리된 네트워크 환경에서도 상호 통신이 가능해집니다.
  • Lattice Services
    • Lattice 서비스 목록에서 각 서비스가 커스텀 도메인명(예: demo-cluster1.example.com)에 매핑되어 노출된 것을 확인할 수 있습니다.
    • 각 서비스는 Route53 Private Hosted Zone과 연결되어 있으며,
      PCA(Private Certificate Authority)를 활용한 인증서가 적용되어 있습니다.

  • Route53 Private Hosted Zone
    • 도메인(예: example.com)에 대한 Private Hosted Zone이 생성되어 있고,
      각 클러스터의 VPC와 연동되어 있습니다.
    • 해당 영역 내 서비스의 DNS 레코드는 자동으로 관리됩니다.
  • AWS Certificate Manager(ACM) 및 PCA 연동
    • ACM에 PCA 기반의 커스텀 도메인 인증서와 와일드카드 인증서가 등록되어 있습니다.
    • 이를 통해 각 서비스의 HTTPS 트래픽에 대해 암호화 및 인증이 적용됩니다.

3. EKS 클러스터별 애플리케이션 상태 확인

  • kubectl context 전환 및 Pod 목록 조회
    • eks-cluster1에 대해 아래 명령으로 context를 전환합니다.
    kubectl config use-context eks-cluster1
    • 모든 네임스페이스의 Pod 상태를 조회합니다.
    kubectl get po -A
  • 데모 애플리케이션 상세 확인
    • 예시: demo-cluster1-v1 Pod의 상세 정보를 확인
    kubectl describe po demo-cluster1-v1-xxxxxx -n apps
    • Init Container를 통해 envoy-sigv4 프록시용 IPTables 설정이 적용된 것을 확인할 수 있습니다.
    • Pod 내에는 두 개의 컨테이너가 있습니다:
      • envoy-sigv4: VPC Lattice 통신 및 IAM 인증·TLS 연계용 사이드카 프록시
      • demo-cluster1-v1: 실제 애플리케이션 컨테이너
  • eks-cluster2 애플리케이션 확인
    • context 전환 후, 동일하게 Pod 목록 및 애플리케이션 상태를 확인할 수 있습니다.
    kubectl config use-context eks-cluster2
    kubectl get po -A

2.5 통신 테스트 및 동작방식 확인

1. 클러스터 간 통신 테스트

1-1. 클러스터 간 통신(정상 케이스)

  • 아래 명령어를 통해 eks-cluster1의 데모 애플리케이션에서 eks-cluster2의 데모 애플리케이션으로 HTTP 요청을 전송합니다.
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-xxxxxx): Hello from demo-cluster2-v1
  • 실제로 VPC Lattice, ACM 인증서, Envoy 프록시, IAM 인증, HTTPRoute 정책이 모두 정상 작동하여 클러스터 간 통신이 허용됩니다.

1-2. 동일 클러스터 내 통신(권한 거부 케이스)

  • 이번에는 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::12345678910:assumed-role/vpc-lattice-sigv4-client/eks-... is not authorized to perform: vpc-lattice-svcs:Invoke on resource: ...
  • 이는 IAMAuthPolicy에 따라 eks-cluster2에서 들어오는 요청만 허용하고, 동일 클러스터 요청(eks-cluster1 → eks-cluster1)은 차단되기 때문입니다.

2. IAMAuthPolicy(액세스 제어 정책) 구조 및 확인

2-1. IAMAuthPolicy란?

2-2. IAMAuthPolicy 실 예시 확인

  • 아래 명령으로 현재 정책을 확인할 수 있습니다.
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::12345678910:root"
      },
      "Action": "vpc-lattice-svcs:Invoke",
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "aws:PrincipalTag/eks-cluster-name": "eks-cluster2",
          "aws:PrincipalTag/kubernetes-namespace": "apps"
        }
      }
    }
  ]
}
  • 해석:
    • Invoke 권한은 eks-cluster2apps 네임스페이스에서 온 요청에만 부여됨

2-3. 정책 적용 구조 확인

  • kubectl describe IAMAuthPolicy demo-cluster1-iam-auth-policy -n apps 명령을 통해,
    정책이 apps 네임스페이스의 demo-cluster1 HTTPRoute에 적용되어 있음을 알 수 있습니다.
  • kubectl describe HTTPRoute demo-cluster1 -n apps
    이 HTTPRoute는 demo-cluster1-v1 Service로 라우팅됨을 확인할 수 있습니다.
  • kubectl describe svc demo-cluster1-v1 -n apps
    • Service는 실제 Pod(예: 10.0.26.50:8090)로 트래픽을 전달합니다.
  • VPC 콘솔의 Lattice Service의 Routing 탭에서도 동일한 대상을 확인할 수 있습니다.

3. Kyverno의 역할: 프록시·트래픽 정책 자동화

  • Kyverno의 ClusterPolicy는 모든 Deployment에
    • iptables InitContainer: 트래픽을 Envoy 프록시로 리디렉션
    • Envoy Sidecar: 인증, 서명, TLS 통신, VPC Lattice 연동
    • 자동으로 주입하여, 애플리케이션 개발자가 별도 수동작업 없이 보안정책이 강제 적용되게 합니다.
  • iptables 규칙은 GID가 0이 아닌 프로세스(즉, 일반 앱 프로세스)의 트래픽만 Envoy로 라우팅합니다.

4. Envoy 프록시 컨테이너의 동작 방식

  • Envoy 컨테이너의 시작 스크립트(launch_envoy.sh) 주요 단계:
    1. 환경 변수 기반 envoy.yaml 생성: 템플릿 파일의 변수 치환
    2. AWS PCA 인증서 획득: AWS CLI로 CA 인증서를 받아 시스템에 반영
    3. 신뢰 저장소 갱신: 인증서 갱신 반영
    4. Envoy 실행: trace 레벨 로깅으로 상세 동작 확인
  • envoy.yaml 구성의 핵심:
    • 8080 포트에서 HTTP 수신, 모든 요청을 outbound_proxy 클러스터로 라우팅
    • 동적 DNS 기반 포워드, AWS SigV4 서명, TLS 인증서 적용
  • Dockerfile 내
    • Envoy distroless 바이너리, Amazon Linux, AWS CLI, 필수 유틸 설치,
    • 시작점은 launch_envoy.sh로 설정

5. 동작 원리 요약

  1. Pod의 트래픽이 iptables 규칙에 따라 Envoy로 리디렉션
  2. Envoy 프록시가 TLS, SigV4로 서명 및 인증서 검증 후 VPC Lattice 서비스 호출
  3. IAMAuthPolicy에 따라 인가된 트래픽만 허용
  4. 애플리케이션과 Envoy, 정책 자동화는 Kyverno로 일관성 보장

2.6 실습 리소스 정리

# 클러스터 정리
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

0개의 댓글