[AWES 3기] 12주차 스터디 내용 정리

ajufresh·2025년 4월 25일
0

Kubernetes의 애플리케이션 네트워킹 변화 과정

  1. 첫 시작: 한 개의 k8s 클러스터 사용
  • 단일 클러스터 내부에 배포되는 Kubernetes 서비스들은 클러스터 내부의 DNS인 CoreDNS 및 Ingress 리소스를 통해서 내부 서비스 간 통신 및 외부로의 통신을 모두 네이티브하게 구현할 수 있음.
  • 사용되는 방법들
    • 기본 Service 리소스로 시작
    • NodePort, ClusterIP, LoadBalancer 타입의 서비스 구현
    • Ingress 활용
      • 경로 기반 라우팅으로 서비스 구조화 및 관리 개선
      • SSL/TLS 종단점 제공을 통한 보안 강화
    • 단순한 내부 통신과 외부 노출 기능에 중점
  1. 워크로드의 진화 : 여러 개의 Kubernetes 클러스터를 사용할 때

  • 애플리케이션이 진화하고, 조직이 발전하면서 서비스들이 독자적인 VPC 및 Kubernetes 클러스터에 운영되기 시작하면서 클러스터 운영자들은 이런 VPC 간 / 클러스터 간의 애플리케이션 네트워킹에 대해서 고민하게 됨.
  • 애플리케이션 끼리 통신을 하기 위해선 가장 먼저 내가 통신하고 싶은 서비스 혹은 마이크로 서비스가 어디에 있는지를 아는 것이 선행 되어야 함 → Service Discovery

[Service Discovery?]
Service Discovery 패턴은 분산 시스템, 특히 마이크로서비스 아키텍처에서 서비스 간의 통신을 용이하게 하기 위한 핵심 패턴으로 작용한다. 이 패턴은 네트워크 위치가 동적으로 변경될 수 있는 서비스 인스턴스의 위치를 자동으로 감지하고 추적하는 메커니즘을 제공한다.

Service Discovery는 크게 클라이언트 사이드와 서버 사이드 두 가지 방식으로 구현된다. 클라이언트 사이드 방식에서는 서비스를 호출하는 클라이언트가 직접 레지스트리에 쿼리하여 가용한 서비스 인스턴스 목록을 받아 선택한다. 반면 서버 사이드 방식에서는 중앙 로드 밸런서나 API 게이트웨이가 레지스트리를 참조하여 클라이언트 요청을 적절한 서비스 인스턴스로 라우팅한다.

이 패턴의 핵심 구성 요소는 서비스 레지스트리로, 모든 서비스 인스턴스의 네트워크 위치 정보를 저장하고 관리한다. 각 서비스 인스턴스는 시작 시 자신의 위치 정보를 레지스트리에 등록하고, 종료 시 등록을 해제한다. 또한 대부분의 서비스 디스커버리 솔루션은 헬스 체크 메커니즘을 통해 각 서비스 인스턴스의 가용성을 주기적으로 확인한다.

실제 구현에는 Consul, Eureka, etcd, ZooKeeper 등과 같은 도구들이 널리 사용되며, Kubernetes와 같은 컨테이너 오케스트레이션 플랫폼에서는 내장된 서비스 디스커버리 기능을 제공한다. 클라우드 제공업체들도 AWS의 Route 53, Azure의 Service Fabric과 같은 관리형 서비스 디스커버리 솔루션을 제공한다.

Service Discovery 패턴을 통해 개발자는 하드코딩된 서비스 위치 정보에 의존할 필요 없이 동적이고 탄력적인 서비스 환경을 구축할 수 있다. 이는 자동 확장, 장애 복구, 무중단 배포와 같은 클라우드 네이티브 기능을 효과적으로 지원하며, 시스템의 전반적인 복원력과 확장성을 향상시킨다. 결과적으로 마이크로서비스 아키텍처의 복잡성을 관리하고 신뢰성 높은 서비스 간 통신을 보장하는 데 필수적인 패턴으로 자리 잡고 있다.


(출처: https://www.f5.com/company/blog/nginx/service-discovery-in-a-microservices-architecture)

그러다가 마이크로 서비스가 늘어나면서 네트워크 복잡성 증가 및 공통 기능 적용(서킷브레이커, 재시도 로직, 타임아웃, 인증 등)의 요구사항 이 생김 → Service Mesh의 탄생!

[Service Mesh]
https://aws.amazon.com/what-is/service-mesh/

서비스 메시는 애플리케이션의 서비스 간 모든 통신을 처리하는 소프트웨어 계층이다. 이 계층은 컨테이너화된 마이크로서비스로 구성된다. 애플리케이션이 확장되고 마이크로서비스의 수가 증가함에 따라 서비스의 성능을 모니터링하기가 점점 어려워지고 있다. 서비스 메시는 서비스 간 연결을 관리하기 위해 모니터링, 로깅, 추적, 트래픽 제어와 같은 새로운 기능을 제공한다. 이러한 기능은 각 서비스의 코드와 독립적이므로 네트워크 경계를 넘어 여러 서비스 관리 시스템에서 작동할 수 있다.

동작 원리 -> 컨테이너 애플리케이션 앞에 AWS AppMesh, Istio, Linkerd 등의 사이드카 프록시 컨테이너를 배치

즉, 컨테이너 애플리케이션으로 들어오고 나가는 모든 트래픽은 프록시 컨테이너를 통해 라우팅 되는 방식

[이러한 방식의 애플리케이션 네트워킹의 한계점]

Ingress의 한계

  • HTTP, HTTPS와 같은 L7 트래픽에 최적화 되어있어 gRPC 및 TPC, UDP와 같은 비 L7 프로토콜에 대한 라우팅 기능이 제한적이다.
  • 고급 기능(인증, 속도 제한 정책, 고급 트래픽 관리 등)을 사용하려면 벤더별(AWS, NGINX, HAProxy 등) 사용자 정의 어노테이션이 필요하여 이식성과 표준화에 한계가 존재한다.

Service Mesh의 한계

  • 주로 동-서 트래픽(서비스 간 내부 통신)에 초점을 맞추어 설계되어 북-남 트래픽(외부-내부 통신)에 대한 기능이 제한적이다.
    • Amazon EKS의 경우, VPC Peering 및 TGW가 필요 → 점점 늘어나는 설정들과 네트워크 리소스들
    • 여러 AWS 계정을 사용할 경우, 각각 교차 계정 액세스 설정이 필요 → 권한 관리의 어려움
  • 사이드카 프록시 배포가 필수적이며, 멀티 VPC 클라우드 환경에서 네트워크 복잡도가 증가했다. (멀티 클러스터, 멀티 메시의 수많은 프록시 운영 및 관리의 어려움)

또한, 클라우드 환경에서 점차 마이크로 서비스가 확장되고 인프라 구성이 복잡해짐에 따라 아래와 같은 요구사항도 생겨났다.

  • 다양한 팀 간의 책임 분리(인프라 담당자, 애플리케이션 개발자, DevOps 엔지니어 등)가 필요해졌다.
  • 여러 VPC 또는 멀티 클러스터 환경에 걸친 리소스들을 일관되게 관리해야 했다.
  • 다양한 컴퓨팅 형태(인스턴스, 컨테이너, 서버리스 등)를 통합적으로 관리할 수 있는 네트워킹 레이어가 필요했다.

Gateway API의 등장

이러한 한계를 극복하기 위해 SIG-NETWORK 커뮤니티에서 Gateway API가 고안되었습니다. Gateway API는 다음과 같은 목표를 가지고 설계되었다.

  • 역할 기반 설계: 인프라 관리자, 클러스터 운영자, 애플리케이션 개발자 각각의 요구사항을 반영할 수 있도록 설계되었다.
  • 범용성: HTTP, HTTPS, gRPC 등 다양한 프로토콜을 지원하고 확장성 있게 설계되었다.
  • 표준화: Kubernetes Ingress와 같이 포터블한 표준 API가 되도록 설계되었다.
  • 확장성: 멀티 클러스터 환경 및 다양한 VPC 간의 원활한 네트워크 통합이 가능하도록 설계되었다.

[주요 구성 요소]

  1. GatewayClass
  • GatewayClass는 특정 구현체나 컨트롤러가 관리하는 게이트웨이 유형의 템플릿 역할을 수행한다.
  • 클러스터 내에서 사용 가능한 게이트웨이 유형을 정의하며, 각각 다양한 기능과 구성을 제공한다.
  • 주로 인프라 관리자가 담당하며, 모든 게이트웨이는 반드시 하나의 GatewayClass를 참조해야 한다.
  1. Gateway
  • Gateway는 실제 트래픽 진입점을 정의하는 리소스로, 특정 네트워크 경계에 위치한다.
  • 리스너(listener)를 통해 프로토콜, 포트, TLS 설정 등 트래픽 수신 방식을 지정한다.
  • 네트워크 인프라 관리자가 주로 담당하며, 애플리케이션 트래픽이 클러스터로 유입되는 방식을 제어한다.
  1. Routes
  • Routes는 수신된 트래픽을 클러스터 내 특정 서비스로 매핑하는 규칙을 정의한다.
  • 프로토콜별로 특화된 다양한 Route 타입이 존재한다:
    • HTTPRoute: HTTP/HTTPS 트래픽 라우팅을 처리한다
    • TLSRoute: TLS 트래픽 라우팅을 담당한다
    • TCPRoute: TCP 연결 라우팅을 관리한다
    • UDPRoute: UDP 트래픽 라우팅을 수행한다
    • GRPCRoute: gRPC 통신 라우팅을 처리한다
  • 주로 애플리케이션 개발자가 담당하며, 트래픽을 어떤 서비스로 전달할지 결정한다.

Amazon VPC Lattice란

Amazon VPC Lattice 는 AWS에서 제공하는 완전관리형 애플리케이션 네트워킹 서비스로, 다양한 컴퓨팅 환경에서 애플리케이션 서비스를 연결, 보호 및 모니터링하는 통합 솔루션입니다. VPC Lattice는 단일 VPC 내에서는 물론, 계정 간 여러 VPC에 걸쳐 서비스를 연결하는 데 활용할 수 있다.

[구성 요소]

Amazon VPC Lattice의 장점

  • 여러 VPC, EC2 인스턴스, 컨테이너, 서버리스로 구성한 애플리케이션의 네트워크 구성을 중앙 집중화 할 수 있습니다.
  • 별도의 사이드카 프록시를 구성할 필요가 없습니다. (+ 완전 관리형 서비스)
  • 복잡한 네트워크 구성을 단순화 해서 쉽게 사용할 수 있습니다.
  • IAM 및 SigV4를 통해 각 애플리케이션으로의 보안 구성을 손쉽게 적용 할 수 있습니다.
  • CloudWatch, S3, Kinesis Data Firehose를 통해 쉽게 로깅, 트래픽 패턴 분석 등을 수행할 수 있습니다.

AWS Gateway API Controller

AWS Gateway API Controller는 Gateway API에 의해 정의된 사용자 지정 리소스를 확장하여 Kubernetes API를 사용하여 VPC Lattice 리소스를 생성한다. 이 Controller가 클러스터에 설치되면 Controller는 Gateway API의 리소스(Gateway 및 Route)의 생성을 감시하고 적절한 Amazon VPC Lattice 오브젝트를 프로비저닝 하며, 이를 통해 사용자는 커스텀 코드를 작성하거나 사이드카 프록시를 관리할 필요 없이 Kubernetes API를 사용하여 VPC Lattice Service, VPC Lattice Service Network 및 Target Group을 구성할 수 있게 된다.

[실습 1] Simple Client to Server communication

해당 실습에서는 Amazon EKS Blueprints for Terraform : Amazon VPC Lattice - Simple Client to Server Communication을 활용하며, VPC quota가 늘려져 있지 않은 상태라 실습하는 화면의 캡처본으로 대신했다.

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

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

# region 값 수정

terraform init

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-

kubectl get po -A

파드가 조회되는 것을 확인할 수 있다.

[프로비저닝 된 인프라 확인]

2개의 VPC가 생성된 것을 확인할 수 있다.

  • client vpc10.1.0.0/16 CIDR 주소 범위로 구성되어 있다.
  • cluster vpc10.0.0.0/16 CIDR 주소 범위로 구성되어 있다.

Service networks에 association된 VPC들을 확인할 수 있다.

[VPC Lattice를 통한 Client to Server 통신 테스트]

kubectl logs -f deployment/server -n apps --all-containers=true --since=1m

아래에서는 kubectl logs 명령어로 애플리케이션 로그를 실시간으로 모니터링하고,

curl -i http://server.example.com

위 터미널에서는 curl 명령어로 네트워크 통신 테스트를 진행한다.

되는 이유: VPC Lettice를 사용해 도메인이 등록되었기 때문이다.

(확인) Route53에서 확인하면 server.example.com => vpc lattice service에 등록이 되어 있다

[AWS 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 명령을 통해 로그를 조회하면, AWS Gateway API Controller의 동작을 확인 해볼 수 있다.

vi lattice.log

로그의 내용처럼 EKS 클러스터 내에 GatewayClass, Gateway, Route에 대한 오브젝트가 추가되면 AWS Gateway API Controller에서 이를 감지하여 조정(reconcile)하게 되는 것이다.

  • server라는 이름의 service와 my-services라는 이름의 gateway의 생성을 감지하여, reconcile 작업을 수행한다.
  • 이어서 server-apps라는 이름(HTTPRoute의 metadata.name 및 metadata.namespace를 사용)으로 구성된 Route 대상에 라우팅 하기 위해 server.example.com이라는 사용자 지정 도메인 이름을 세팅하고, VPC Lattice Service를 구성한다.
  • 그리고 VPC Lattice Service에 대해 Listener rule을 생성하고 HTTPRoute 매니페스트 내용에 맞춰 PathPrefix를 구성하고, backendRefs에 대한 대상 그룹을 생성한다.
  • 대상 그룹에는 Service를 참조하여 라우팅 대상 Pod의 IP 주소 및 Port 번호를 세팅한다.

[실습 2] Multi Cluster secure communication]

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

이 패턴에서는 Amazon VPC Lattice와 IAM authorization을 사용하여 서로 다른 VPC에 있는 두 EKS 클러스터 간의 안전한 멀티 클러스터 통신 방식을 보여주게 된다.

  • 이 솔루션에서는 Service Discovery가 어떻게 이루어지는지를 설명하고, VPC Lattice가 겹치는 CIDR을 가진 EKS 클러스터 간 통신을 어떻게 용이하게 하는지 강조한다.
  • 이를 통해 프라이빗 NAT 게이트웨이와 Transit Gateway와 같은 네트워킹 구조가 필요하지 않도록 하는 방법을 소개한다.
  • 클러스터 간 통신을 안전하게 수행하기 위해, 인증서 관리자(ACM)에서 발행하고 AWS Private CA에서 지원하는 TLS 인증서로 보호되는 Amazon Route53 Private Hosted Zone을 사용하여 Amazon VPC Lattice를 통해 설정된다.
  • 이를 위해 Kyverno를 사용하여 Envoy SigV4 proxy 컨테이너를 Pod에 추가하고, 여기에 PCA를 주입한다.

[envoy proxy란?]

Envoy Proxy는 고성능 C++ 기반의 오픈소스 에지 및 서비스 프록시로, 2016년 Lyft에서 처음 개발되었으며 현재는 Cloud Native Computing Foundation(CNCF)의 졸업 프로젝트이다. 모던 서비스 아키텍처 환경에서 네트워크 통신을 단순화하고 추상화하기 위해 설계되었다.

주요 특징
1. 고성능 아키텍처
C++로 작성된 고성능 단일 프로세스 멀티스레드 설계를 가진다.
작은 메모리 공간에서 높은 처리량과 낮은 지연 시간을 제공한다.
비동기 이벤트 기반 아키텍처로 많은 연결을 효율적으로 처리한다.

  1. L3/L4 프록시
    TCP 프록싱, HTTP/1.1, HTTP/2, HTTP/3, gRPC 등을 위한 견고한 지원을 제공한다.
    소켓 수준에서 작동하여 모든 TCP 기반 프로토콜을 처리할 수 있다.
    SNI(Server Name Indication) 기반 라우팅을 지원한다.

  2. L7 프록시
    풍부한 라우팅 기능, 경로 기반 분할, 리트라이, 서킷 브레이킹 등을 지원한다.
    HTTP 헤더 조작, URL 재작성, 속도 제한 등의 고급 기능을 제공한다.
    gRPC를 포함한 다양한 프로토콜에 대한 심층 통합을 제공한다.

  3. 동적 구성
    xDS API라고 하는 동적 구성 API를 통해 런타임에 구성을 업데이트할 수 있다.
    제어 플레인과의 느슨한 결합을 통해 다양한 환경에서 유연하게 사용할 수 있다.
    핫 리스타트 기능으로 다운타임 없이 구성을 변경할 수 있다.

  4. 관찰성
    포괄적인 통계, 로깅, 분산 추적 기능을 제공한다.
    Prometheus, Grafana, Zipkin, Jaeger 등의 도구와 통합이 용이하다.
    상세한 모니터링 데이터를 통해 시스템 동작 및 성능에 대한 인사이트를 제공한다.

  5. 확장성
    필터 체인을 통한 확장 가능한 아키텍처를 가진다.
    WebAssembly(WASM) 필터를 통해 안전한 사용자 정의 확장을 지원한다.
    Lua 스크립팅을 통한 런타임 구성 조정이 가능하다.


environment 프로비저닝을 진행한다.

테라폼 코드 살펴보기!
main.tf

provider "aws" {
  region = local.region
}

locals {
  name   = "vpc-lattice"
  region = "us-west-2" # 이 부분을 ap-northeast-2로 수정

  domain = var.custom_domain_name

  tags = {
    Blueprint  = local.name
    GithubRepo = "github.com/aws-ia/terraform-aws-eks-blueprints"
  }
}
#-------------------------------
# Create Private Hosted Zone
#-------------------------------

resource "aws_route53_zone" "private_zone" {
  name = local.domain

  vpc {
    vpc_id = aws_vpc.example.id
  }

  #we will add vpc association in other terraform stack, prevent this one to revert this
  lifecycle {
    ignore_changes = [
      vpc,
    ]
  }

  force_destroy = true
  tags          = local.tags
}

#dummy VPC that will not be used, but needed to create private hosted zone
resource "aws_vpc" "example" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name = "Example VPC"
  }
}
  • Route 53 프라이빗 호스티드 존을 생성한다:

    • 도메인 이름은 local.domain 값을 사용한다.
    • 이 호스티드 존은 example VPC와 연결된다.
    • lifecycle 설정으로 향후 다른 테라폼 스택에서 VPC 연결을 변경해도 이 구성이 덮어쓰지 않도록 한다.
    • force_destroy = true는 리소스 삭제 시 연결된 레코드도 함께 삭제하도록 설정한다.
  • 예시용 VPC를 생성한다:

    • 주석에 따르면 이 VPC는 실제로 사용되지 않고, 단지 프라이빗 호스티드 존 생성을 위한 요구사항을 충족하기 위해 생성된다.
    • CIDR 블록은 "10.0.0.0/16"으로 설정된다.
################################################################################
# Create IAM role to talk to VPC Lattice services and get Certificate from Manager
################################################################################
data "aws_iam_policy_document" "eks_assume" {
  statement {
    effect = "Allow"
    principals {
      type        = "Service"
      identifiers = ["pods.eks.amazonaws.com"]
    }
    actions = ["sts:AssumeRole", "sts:TagSession"]
  }
}
resource "aws_iam_role" "vpc_lattice_role" {
  name               = "${local.name}-sigv4-client"
  description        = "IAM role for aws-sigv4-client VPC Lattice access"
  assume_role_policy = data.aws_iam_policy_document.eks_assume.json
}

resource "aws_iam_role_policy_attachment" "vpc_lattice_invoke_access" {
  role       = aws_iam_role.vpc_lattice_role.name
  policy_arn = "arn:aws:iam::aws:policy/VPCLatticeServicesInvokeAccess"
}

resource "aws_iam_role_policy_attachment" "private_ca_read_only" {
  role       = aws_iam_role.vpc_lattice_role.name
  policy_arn = "arn:aws:iam::aws:policy/AWSCertificateManagerPrivateCAReadOnly"
}
  • IAM 정책 문서를 정의한다:

    • EKS pod가 이 역할을 수임할 수 있도록 신뢰 관계를 설정한다.
    • pods.eks.amazonaws.com 서비스가 sts:AssumeRolests:TagSession 작업을 수행할 수 있도록 허용한다.
  • VPC Lattice 접근을 위한 IAM 역할을 생성한다:

    • 역할 이름은 vpc-lattice-sigv4-client로 설정된다.
    • 앞서 정의한 신뢰 정책을 연결한다.
  • 이 역할에 두 가지 관리형 정책을 연결한다:

    • VPCLatticeServicesInvokeAccess: VPC Lattice 서비스 호출 권한을 제공한다.
    • AWSCertificateManagerPrivateCAReadOnly: ACM Private CA에 대한 읽기 전용 권한을 제공한다.

pca.tf

#-------------------------------
# Associates a certificate with an AWS Certificate Manager Private Certificate Authority (ACM PCA Certificate Authority).
# An ACM PCA Certificate Authority is unable to issue certificates until it has a certificate associated with it.
# A root level ACM PCA Certificate Authority is able to self-sign its own root certificate.
#-------------------------------

# # https://docs.aws.amazon.com/acm-pca/latest/userguide/pca-rbp.html

resource "aws_acmpca_certificate_authority" "this" {
  enabled = true
  type    = "ROOT"

  certificate_authority_configuration {
    key_algorithm     = "RSA_4096"
    signing_algorithm = "SHA512WITHRSA"

    subject {
      common_name  = var.custom_domain_name
      organization = var.organization
    }
  }

  permanent_deletion_time_in_days = 7

  tags = local.tags
}

resource "aws_acmpca_certificate" "this" {
  certificate_authority_arn   = aws_acmpca_certificate_authority.this.arn
  certificate_signing_request = aws_acmpca_certificate_authority.this.certificate_signing_request
  signing_algorithm           = "SHA512WITHRSA"

  template_arn = "arn:aws:acm-pca:::template/RootCACertificate/V1"

  validity {
    type  = "YEARS"
    value = 10
  }
}

resource "aws_acmpca_certificate_authority_certificate" "this" {
  certificate_authority_arn = aws_acmpca_certificate_authority.this.arn

  certificate       = aws_acmpca_certificate.this.certificate
  certificate_chain = aws_acmpca_certificate.this.certificate_chain
}
#-------------------------------
# Create certificate in AWS Certificate Manager
#-------------------------------

resource "aws_acm_certificate" "private_domain_cert" {
  domain_name = var.custom_domain_name
  #validation_method = "DNS"

  subject_alternative_names = [
    "*.${var.custom_domain_name}"
  ]

  options {
    certificate_transparency_logging_preference = "DISABLED"
  }

  certificate_authority_arn = aws_acmpca_certificate_authority.this.arn

  tags = local.tags
}

VPC Lattice 서비스에서 사용할 프라이빗 CA와 인증서를 설정하는 과정이다. 프라이빗 CA를 사용하면 조직 내부에서만 신뢰되는 인증서를 발급할 수 있으며, 이는 내부 서비스 간의 암호화된 통신에 유용하다. 특히, 이 설정은 내부 전용 서비스에 대한 커스텀 도메인을 설정하고 보안 통신을 가능하게 한다.

terraform init
terraform apply --auto-approve

그 이후에 cluster도 마찬가지로 배포한다.

./deploy.sh cluster1

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

./deploy.sh cluster2

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

vpc 1, 2 두 개의 vpc가 만들어지게 된다.

eks-cluster1의 pod identity가 기본적으로 설정되어 있는데, iam의 권한을 받아서 private ca를 활용해서 https 프로토콜을 사용하게 하기 위해서이다.

[VPC Lattice]
VPC 콘솔 > PrivateLink and Lattice > Service networks > VPC Lattice Service network 콘솔로 이동

각 데모 애플리케이션으로 들어가는 타겟 그룹이 설정되어 있다.

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

kubectl --context eks-cluster1 \
  exec -ti -n apps deployments/demo-cluster1-v1 -c demo-cluster1-v1 \
  -- curl demo-cluster2.example.com

결과가 잘 나온다.

kubectl --context eks-cluster1 \
  exec -ti -n apps deployments/demo-cluster1-v1 -c demo-cluster1-v1 \
	-- curl demo-cluster1.example.com

권한 오류가 난다.
=> IAMAuthPolicy가 적용이 되어서 eks-cluster2로만 호출이 가능하기 때문

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"
        }
      }
    }
  ]
}

=> VPC Lattice Serivce를 invoke하는 액션 중에서 클러스터 명(eks-cluster-name)이 eks-cluster2 여야하고, 네임스페이스가 apps일 때에만 Invoke를 허용한다.

결과적으로 이 데모 애플리케이션 Pod가 IAMAuthPolicy의 규칙을 적용받고 있음을 확인할 수 있다.

이렇게 IAMAuthPolicy를 사용하면 멀티 클러스터 간에 각 애플리케이션에 대한 액세스 제어를 쉽게 구성할 수 있게 된다.

[Kyverno의 역할]

  • iptables 규칙은 애플리케이션에서 envoy 프록시로 트래픽을 라우팅한다.(소스 프로세스 gid가 0인 경우 규칙이 적용되지 않으므로 애플리케이션에 다른 gid를 제공합니다: runAsGroup: 1000).
  • envoy 프록시는 시작 시 Private CA 인증서를 검색하여 시작 스크립트를 통해 VPC lattice 서비스를 신뢰하도록 설치한다.
kubectl --context eks-cluster1 \
	exec -it deploy/demo-cluster1-v1 -c envoy-sigv4 -n apps \
	-- cat /usr/local/bin/launch_envoy.sh
#!/bin/sh

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0

cat /etc/envoy/envoy.yaml.in | envsubst \$AWS_REGION,\$JWT_AUDIENCE,\$JWT_JWKS,\$JWT_ISSUER,\$JWKS_HOST,\$APP_DOMAIN > /etc/envoy/envoy.yaml
aws acm-pca get-certificate-authority-certificate --certificate-authority-arn $CA_ARN --region $AWS_REGION --output text > /etc/pki/ca-trust/source/anchors/internal.pem
update-ca-trust extract

cat /etc/envoy/envoy.yaml
/usr/local/bin/envoy --base-id 1 -l trace -c /etc/envoy/envoy.yaml

launch_envoy.sh에서 활용하는 envoy.yaml.in 스크립트

static_resources:
  listeners:
  - name: http_connect
    address:
      socket_address:
        protocol: TCP
        address: 0.0.0.0
        port_value: 8080
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains:
              - "*"
              routes:
              - match:
                  prefix: '/'
                route:
                  cluster: outbound_proxy
          # Ignore traffic to /health and respond with a 200
          http_filters:
          - name: envoy.filters.http.dynamic_forward_proxy
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.dynamic_forward_proxy.v3.FilterConfig
              dns_cache_config:
                name: dynamic_forward_proxy_cache_config
                dns_lookup_family: V4_ONLY
                typed_dns_resolver_config:
                  name: envoy.network.dns_resolver.cares
                  typed_config:
                    "@type": type.googleapis.com/envoy.extensions.network.dns_resolver.cares.v3.CaresDnsResolverConfig
                    use_resolvers_as_fallback: true
                    resolvers:
                    - socket_address:
                        address: "127.0.0.1"
                        port_value: 53
                    dns_resolver_options:
                      use_tcp_for_dns_lookups: true
                      no_default_search_domain: true
          # SigV4 signing configuration
          - name: envoy.filters.http.aws_request_signing
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.aws_request_signing.v3.AwsRequestSigning
              service_name: vpc-lattice-svcs
              region: ${AWS_REGION}
              use_unsigned_payload: true
              match_excluded_headers:
              - prefix: x-envoy
              - prefix: x-forwarded
              - exact: x-amzn-trace-id
          - name: envoy.filters.http.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
  clusters:
  - name: outbound_proxy
    lb_policy: CLUSTER_PROVIDED
    cluster_type:
      name: envoy.clusters.dynamic_forward_proxy
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig
        dns_cache_config:
          name: dynamic_forward_proxy_cache_config
          dns_lookup_family: V4_ONLY
          typed_dns_resolver_config:
            name: envoy.network.dns_resolver.cares
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.network.dns_resolver.cares.v3.CaresDnsResolverConfig
              use_resolvers_as_fallback: true
              resolvers:
              - socket_address:
                  address: "127.0.0.1"
                  port_value: 53
              dns_resolver_options:
                use_tcp_for_dns_lookups: true
                no_default_search_domain: true
    transport_socket:
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
        common_tls_context:
          validation_context:
            trusted_ca:
              filename: /etc/ssl/certs/ca-bundle.crt

이 YAML 파일은 Envoy 프록시의 구성 파일로, AWS VPC Lattice 서비스와 통합하기 위한 설정을 포함한다. Envoy는 오픈소스 에지/서비스 프록시로, 이 구성은 특히 VPC Lattice 서비스로 요청을 전달하고 AWS SigV4 인증을 수행하도록 설정되어 있다.

  • 주요 구성 요소
  1. Listeners (리스너)
listeners:
- name: http_connect
  address:
    socket_address:
      protocol: TCP
      address: 0.0.0.0
      port_value: 8080
  • http_connect라는 이름의 리스너를 설정한다.
  • TCP 프로토콜을 사용하여 모든 네트워크 인터페이스(0.0.0.0)의 8080 포트에서 들어오는 연결을 수신한다.
  1. 필터 체인
filter_chains:
- filters:
  - name: envoy.filters.network.http_connection_manager
  • HTTP 연결 관리자 필터를 사용하여 들어오는 HTTP 요청을 처리한다.
  1. HTTP 라우팅 구성
route_config:
  name: local_route
  virtual_hosts:
  - name: local_service
    domains:
    - "*"
    routes:
    - match:
        prefix: '/'
      route:
        cluster: outbound_proxy
  • 모든 도메인("*")에 대한 요청을 처리한다.
  • 루트 경로(/)로 시작하는 모든 요청을 outbound_proxy 클러스터로 라우팅한다.
  1. HTTP 필터
    다음 필터들이 순차적으로 요청을 처리한다:

a. 동적 포워드 프록시 필터

- name: envoy.filters.http.dynamic_forward_proxy
  • 목적지 호스트에 따라 동적으로 업스트림 클러스터를 생성한다.
  • DNS 캐시 구성으로 V4 주소만 사용하도록 설정한다.
  • DNS 리졸버로 c-ares를 사용하며, 로컬호스트(127.0.0.1)의 53번 포트를 DNS 서버로 사용한다.
  • TCP를 사용한 DNS 조회와 기본 검색 도메인을 사용하지 않도록 설정한다.

b. AWS 요청 서명 필터

- name: envoy.filters.http.aws_request_signing
  • VPC Lattice 서비스(vpc-lattice-svcs)에 대한 AWS SigV4 인증을 수행한다.
  • 환경 변수에서 지정된 AWS 리전(${AWS_REGION})을 사용한다.
  • 서명에 페이로드를 포함하지 않는 옵션(use_unsigned_payload: true)을 사용한다.
  • 특정 헤더(x-envoy, x-forwarded, x-amzn-trace-id)는 서명 계산에서 제외한다.

c. 라우터 필터

- name: envoy.filters.http.router
  • 요청을 목적지 업스트림 클러스터로 라우팅하는 최종 필터이다.
  1. 클러스터 구성
clusters:
- name: outbound_proxy
  lb_policy: CLUSTER_PROVIDED
  cluster_type:
    name: envoy.clusters.dynamic_forward_proxy
  • outbound_proxy라는 이름의 클러스터를 정의한다.
  • 동적 포워드 프록시 클러스터 유형을 사용하여 요청의 호스트 헤더에 따라 동적으로 업스트림을 결정한다.
  • DNS 캐시 설정은 리스너의 동적 포워드 프록시 필터와 동일하다.
  1. TLS 구성
transport_socket:
  name: envoy.transport_sockets.tls
  typed_config:
    "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
    common_tls_context:
      validation_context:
        trusted_ca:
          filename: /etc/ssl/certs/ca-bundle.crt
  • 업스트림 서버와의 통신에 TLS를 사용한다.
  • 시스템의 CA 번들(/etc/ssl/certs/ca-bundle.crt)을 사용하여 서버 인증서를 검증한다.
  1. 8080 포트에서 HTTP 요청을 수신한다.
  2. 받은 요청을 동적으로 결정된 업스트림 서버로 전달한다.
  3. AWS VPC Lattice 서비스에 요청을 보낼 때 SigV4 인증을 적용한다.
  4. TLS를 사용하여 업스트림 서버와 통신한다.

[실습 리소스 정리]

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

./destroy.sh cluster2

./destroy.sh cluster1
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

나중에 추가로 도전해볼 것

profile
공블로그

0개의 댓글