Published on

pulumi aws vpc endpoint 구성과 선택 기준

Authors
  • avatar
    Name
    Indo Yoon
    Twitter

Pulumi에서 AWS VPC 엔드포인트는 aws.ec2.VpcEndpoint 리소스 하나로 게이트웨이형과 인터페이스형을 모두 다룹니다. 먼저 서비스가 S3나 DynamoDB처럼 라우트 테이블 기반인지, 아니면 서브넷과 보안 그룹이 필요한 PrivateLink 기반인지 판단하는 것이 핵심이에요. 유형을 잘못 고르면 코드가 배포는 되지만 실제 트래픽이 프라이빗 경로로 흐르지 않기 때문에, 리소스 속성보다 서비스 연결 방식를 먼저 확인해야 해요.

한눈에 보기

VPC 엔드포인트는 인터넷 게이트웨이나 NAT 게이트웨이를 거치지 않고 AWS 서비스에 접근할 수 있게 해주는 진입점입니다. Pulumi 코드에서는 vpcEndpointType 값으로 유형이 갈리고, 같은 리소스 타입 안에서 필요한 인자만 달라져요.

게이트웨이 엔드포인트는 라우트 테이블에 대상 경로를 추가하는 방식이라 서브넷이나 보안 그룹을 직접 건드리지 않습니다. 반면 인터페이스 엔드포인트는 지정한 서브넷에 네트워크 인터페이스를 만들고 보안 그룹으로 접근을 제어해요. 그래서 인터페이스형은 서브넷 선택과 보안 그룹 규칙이 곧 보안 경계가 됩니다.

Pulumi 리소스 정의에서 자주 쓰는 인자는 다음과 같아요.

  • vpcId: 엔드포인트가 속할 VPC
  • serviceName: 리전별 서비스 이름
  • vpcEndpointType: Gateway 또는 Interface
  • routeTableIds: 게이트웨이형에서 사용
  • subnetIds, securityGroupIds: 인터페이스형에서 사용
  • privateDnsEnabled: 인터페이스형의 프라이빗 DNS 사용 여부
  • policy: 엔드포인트 정책 JSON

이 인자들은 서로 배타적인 조합이 있어요. 게이트웨이형에 subnetIds를 넣거나 인터페이스형에 routeTableIds를 넣으면 의도한 대로 동작하지 않습니다.

게이트웨이와 인터페이스 비교

항목게이트웨이 엔드포인트인터페이스 엔드포인트
대표 대상S3, DynamoDBECR, CloudWatch Logs, KMS, Systems Manager 등
연결 방식라우트 테이블에 경로 추가지정 서브넷에 네트워크 인터페이스 생성
서브넷 지정필요 없음필요함
보안 그룹적용되지 않음적용해야 함
프라이빗 DNS사용하지 않음서비스가 지원하면 사용 가능
Pulumi 핵심 인자routeTableIdssubnetIds, securityGroupIds, privateDnsEnabled
정책엔드포인트 정책으로 제어엔드포인트 정책으로 제어

표에서 볼 수 있듯이 두 유형은 같은 리소스로 선언되지만 운영 방식이 완전히 다릅니다. 게이트웨이형은 라우팅 문제로, 인터페이스형은 네트워크 인터페이스와 보안 그룹 문제로 장애가 나타나는 경우가 많아요.

단계별 구성 방법

1. 서비스 이름 확인하기

서비스 이름은 리전마다 형태가 조금씩 다르므로 코드에 하드코딩하기 전에 확인하는 편이 안전합니다. Pulumi에서는 데이터 소스로 서비스 정보를 조회할 수 있어요.

import * as aws from "@pulumi/aws";

const ecrApiService = aws.ec2.getVpcEndpointServiceOutput({
  service: "ecr.api",
});

조회한 결과에서 serviceName과 프라이빗 DNS 지원 여부를 확인한 뒤 리소스에 넘깁니다. 리전 코드를 문자열로 조립하는 방식은 오타에 취약하므로, 스택 설정값으로 리전을 주입하고 그 값으로 서비스 이름을 만드는 편이 관리하기 쉬워요.

2. VPC의 DNS 설정 확인하기

인터페이스 엔드포인트에서 프라이빗 DNS를 사용하려면 VPC 자체의 DNS 지원과 DNS 호스트 이름 설정이 켜져 있어야 합니다. Pulumi로 VPC를 함께 관리한다면 이 값을 명시적으로 지정해 두세요.

const vpc = new aws.ec2.Vpc("app-vpc", {
  cidrBlock: "10.0.0.0/16",
  enableDnsSupport: true,
  enableDnsHostnames: true,
});

이 설정이 꺼져 있으면 엔드포인트를 만들어도 기존 서비스 도메인이 프라이빗 주소로 해석되지 않습니다. 콘솔에서는 잘 보이는데 애플리케이션에서만 연결이 실패하는 전형적인 패턴이에요.

3. 게이트웨이 엔드포인트 선언하기

S3나 DynamoDB를 사설망에서 쓰려면 게이트웨이 엔드포인트를 만들고 사설 서브넷이 연결된 라우트 테이블을 지정합니다.

const s3Gateway = new aws.ec2.VpcEndpoint("s3-gateway", {
  vpcId: vpc.id,
  serviceName: "com.amazonaws.ap-northeast-2.s3",
  vpcEndpointType: "Gateway",
  routeTableIds: [privateRouteTable.id],
});

여기서 라우트 테이블을 빠뜨리면 엔드포인트는 생성되지만 경로가 잡히지 않아 트래픽이 그대로 NAT 게이트웨이로 나갑니다. 라우트 테이블이 여러 개라면 목록에 모두 넣어야 해요.

4. 인터페이스 엔드포인트와 보안 그룹 선언하기

인터페이스형은 서브넷과 보안 그룹을 함께 정의합니다. 보안 그룹은 VPC 대역에서 오는 HTTPS 트래픽을 허용하는 형태로 시작하는 경우가 많아요.

const endpointSg = new aws.ec2.SecurityGroup("endpoint-sg", {
  vpcId: vpc.id,
  ingress: [
    {
      fromPort: 443,
      toPort: 443,
      protocol: "tcp",
      cidrBlocks: [vpc.cidrBlock],
    },
  ],
  egress: [
    {
      fromPort: 0,
      toPort: 0,
      protocol: "-1",
      cidrBlocks: ["0.0.0.0/0"],
    },
  ],
});

const ecrApiEndpoint = new aws.ec2.VpcEndpoint("ecr-api", {
  vpcId: vpc.id,
  serviceName: "com.amazonaws.ap-northeast-2.ecr.api",
  vpcEndpointType: "Interface",
  privateDnsEnabled: true,
  subnetIds: privateSubnetIds,
  securityGroupIds: [endpointSg.id],
});

보안 그룹의 인바운드 규칙이 좁으면 애플리케이션은 타임아웃으로 실패합니다. 엔드포인트 보안 그룹은 서비스로 들어오는 트래픽을 제어하는 것이지, 애플리케이션 쪽 보안 그룹을 대신하지 않는다는 점도 기억해 두세요.

5. 엔드포인트 정책으로 범위 좁히기

엔드포인트 정책은 이 엔드포인트를 통해 어떤 리소스에 접근할 수 있는지 제한합니다. policy 인자에 JSON 문자열을 넘기면 되고, 생략하면 기본 동작을 따릅니다.

const logsEndpoint = new aws.ec2.VpcEndpoint("logs", {
  vpcId: vpc.id,
  serviceName: "com.amazonaws.ap-northeast-2.logs",
  vpcEndpointType: "Interface",
  privateDnsEnabled: true,
  subnetIds: privateSubnetIds,
  securityGroupIds: [endpointSg.id],
  policy: JSON.stringify({
    Version: "2012-10-17",
    Statement: [
      {
        Effect: "Allow",
        Principal: "*",
        Action: "logs:*",
        Resource: "*",
      },
    ],
  }),
});

정책을 너무 좁히면 배포 중에만 실패하고 런타임에는 정상처럼 보이는 혼란이 생길 수 있어요. 처음에는 넓게 시작하고, 실제 사용 패턴을 확인한 뒤 좁히는 순서가 안전합니다.

6. 출력값으로 연결 정보 남기기

나중에 다른 스택이나 애플리케이션 설정에서 참조할 수 있도록 엔드포인트 식별자와 DNS 이름을 출력으로 내보내 두면 편리합니다.

export const ecrEndpointDns = ecrApiEndpoint.dnsEntries;
export const s3EndpointId = s3Gateway.id;

상황별 선택 기준

사설망에서 AWS 서비스만 호출하면 되는 경우에는 게이트웨이 엔드포인트로 해결되는 대상이 많습니다. S3와 DynamoDB는 게이트웨이형을 지원하므로 라우트 테이블만 정리하면 되고, 보안 그룹을 추가로 관리할 필요가 없어요.

컨테이너 이미지를 사설 서브넷에서 받아야 하는 경우에는 ECR 관련 인터페이스 엔드포인트가 필요합니다. 이미지 레이어를 S3에서 받는 구조이므로 ECR API와 S3 게이트웨이를 함께 준비하는 조합이 자주 쓰입니다.

세션 관리나 파라미터 조회처럼 운영 도구를 사설망에서 쓰려면 Systems Manager 계열 인터페이스 엔드포인트를 검토하게 됩니다. 이때는 필요한 서비스가 여러 개로 나뉘어 있어 어떤 호출이 어떤 엔드포인트로 가는지 정리해 두는 것이 좋아요.

반대로 외부 SaaS나 온프레미스 시스템을 사설로 연결하려면 소비자 역할이 아니라 제공자 역할이 됩니다. 이때는 aws.ec2.VpcEndpointService로 엔드포인트 서비스를 만들고 네트워크 로드 밸런서를 연결하는 구조를 쓰게 되므로, 일반적인 엔드포인트 생성과는 코드 위치를 분리하는 편이 관리에 유리합니다.

주의할 점

첫째, vpcEndpointType은 생성 후 변경이 아니라 교체로 이어지는 속성입니다. 운영 중인 엔드포인트의 유형을 바꾸려면 리소스가 새로 만들어지므로, 사전에 pulumi preview로 교체 여부를 확인해야 해요.

둘째, 프라이빗 DNS를 켜면 해당 서비스의 공용 도메인이 VPC 안에서 사설 주소로 해석됩니다. 같은 VPC에서 공용 엔드포인트를 함께 쓰는 구성이 있다면 이름 해석이 달라지는 영향을 검토해야 합니다.

셋째, 게이트웨이 엔드포인트는 보안 그룹이 적용되지 않습니다. 접근을 제한하려면 엔드포인트 정책을 사용해야 하며, 보안 그룹 규칙만 확인하고 원인을 찾지 못하는 상황이 생길 수 있어요.

넷째, 인터페이스 엔드포인트는 가용 영역별로 네트워크 인터페이스를 만듭니다. 서브넷을 일부만 지정하면 그 가용 영역에만 경로가 생기므로, 장애 조치를 고려한다면 사설 서브넷을 고르게 포함하는 편이 좋습니다.

다섯째, 정책과 보안 그룹을 코드로 관리하면 변경 이력이 남지만, 콘솔에서 수동으로 바꾼 내용은 다음 배포에서 되돌아갑니다. 운영 중 임시 변경이 필요했다면 반드시 코드에 반영해 두세요.

자주 묻는 질문

게이트웨이 엔드포인트와 인터페이스 엔드포인트 중 무엇을 먼저 판단해야 하나요?

대상 서비스가 무엇인지부터 확인하는 것이 순서입니다. S3나 DynamoDB라면 게이트웨이형을 먼저 검토하고, 그 외 서비스라면 인터페이스형과 프라이빗 DNS 지원 여부를 확인하게 됩니다. 서비스 이름과 지원 유형은 AWS 공식 문서와 Pulumi 데이터 소스로 함께 대조할 수 있어요.

프라이빗 DNS를 켰는데 이름 해석이 되지 않으면 무엇을 확인해야 하나요?

VPC의 DNS 지원과 DNS 호스트 이름 설정이 켜져 있는지 먼저 봅니다. 다음으로 해당 서비스가 프라이빗 DNS를 지원하는지, 엔드포인트가 원하는 서브넷에 배치되었는지 확인하세요. 보안 그룹 문제라면 이름 해석이 아니라 연결 단계에서 실패하므로 증상 구분이 중요합니다.

엔드포인트 정책은 반드시 설정해야 하나요?

필수는 아니며 생략하면 기본 동작을 따릅니다. 다만 사설망에서 접근 가능한 리소스 범위를 좁히고 싶다면 정책을 명시하는 편이 좋아요. 정책을 적용한 뒤에는 배포 파이프라인과 런타임 호출이 모두 정상인지 함께 확인해야 합니다.

서브넷이나 라우트 테이블을 바꾸면 엔드포인트가 다시 만들어지나요?

인터페이스형에서 서브넷 목록을 바꾸는 것은 네트워크 인터페이스 재구성으로 이어질 수 있고, 유형 자체를 바꾸면 교체로 처리됩니다. 라우트 테이블 연결은 게이트웨이형에서 별도로 조정되는 부분이라 변경 전후로 라우팅을 확인하는 습관이 필요해요. 어떤 속성이 교체를 유발하는지는 pulumi preview 결과로 확인하는 것이 가장 확실합니다.

출처

VPC 엔드포인트를 코드로 관리하다 보면 자연스럽게 스택 구성과 배포 순서를 정리하는 일이 함께 따라옵니다. 스택 분리와 참조 방식은 Pulumi 공식 문서의 스택 개념 글(https://www.pulumi.com/docs/iac/concepts/stacks/)을 함께 읽어 두면 네트워크 리소스와 애플리케이션 리소스를 나눠 운영할 때 도움이 됩니다.