학습 목표

시나리오

실습 1의 네트워크에서 프라이빗 서브넷의 워크로드가 Amazon S3와 AWS Systems Manager를 호출합니다. 요구는 이렇습니다.

아키텍처 개요

게이트웨이 엔드포인트와 인터페이스 엔드포인트 비교
항목 게이트웨이 엔드포인트 인터페이스 엔드포인트(PrivateLink)
구현 위치 라우팅 테이블의 경로 서브넷 안의 네트워크 인터페이스
대상 서비스 Amazon S3, Amazon DynamoDB 대부분의 AWS 서비스와 PrivateLink 서비스
보안 그룹 연결하지 않는다 연결한다
DNS 공용 이름 그대로, 경로만 바뀐다 프라이빗 DNS로 공용 이름을 가로챌 수 있다
온프레미스에서 사용 직접 불가 가능
접근 제어 엔드포인트 정책 엔드포인트 정책 + 보안 그룹

요구를 나누면 이렇게 배정됩니다 — Amazon S3는 게이트웨이 엔드포인트, Systems Manager는 인터페이스 엔드포인트입니다.

구성 단계

1 · 사용 가능한 엔드포인트 서비스 확인

list-services.sh — 리전에서 제공되는 엔드포인트 서비스와 유형
aws ec2 describe-vpc-endpoint-services \
  --query 'ServiceDetails[?ServiceType[0].ServiceType==`Gateway`].ServiceName' \
  --output table

aws ec2 describe-vpc-endpoint-services \
  --query 'ServiceDetails[?contains(ServiceName, `ssm`)].[ServiceName, ServiceType[0].ServiceType, PrivateDnsName]' \
  --output table

서비스 이름은 com.amazonaws.<리전>.<서비스> 형태입니다. 게이트웨이 유형으로 제공되는 것은 Amazon S3와 Amazon DynamoDB뿐이라는 사실을 위 첫 번째 명령의 출력으로 직접 확인할 수 있습니다.

2 · S3 게이트웨이 엔드포인트

create-gateway-endpoint.sh — 프라이빗 라우팅 테이블에 경로 추가 (ID와 리전은 예시입니다)
VPC_ID=vpc-0123456789abcdef0
REGION=ap-northeast-2

# 경로를 추가할 프라이빗 라우팅 테이블을 확인합니다.
aws ec2 describe-route-tables \
  --filters Name=vpc-id,Values="$VPC_ID" \
  --query 'RouteTables[].[RouteTableId,Tags[?Key==`Name`].Value|[0]]' \
  --output table

ENDPOINT_ID=$(aws ec2 create-vpc-endpoint \
  --vpc-id "$VPC_ID" \
  --vpc-endpoint-type Gateway \
  --service-name "com.amazonaws.$REGION.s3" \
  --route-table-ids rtb-0private0000000a rtb-0private0000000b \
  --query 'VpcEndpoint.VpcEndpointId' --output text)

echo "$ENDPOINT_ID"

3 · 엔드포인트 정책으로 범위 제한

엔드포인트 정책은 이 엔드포인트를 통해 무엇을 할 수 있는지를 정합니다. 기본값은 전체 허용이므로, 요구 3(지정 버킷만)을 만족시키려면 좁혀야 합니다.

endpoint-policy.json — 지정한 버킷에만 접근 허용 (버킷 이름은 예시입니다)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowSpecificBucketsOnly",
      "Effect": "Allow",
      "Principal": "*",
      "Action": ["s3:GetObject", "s3:PutObject", "s3:ListBucket"],
      "Resource": [
        "arn:aws:s3:::example-lab10-data",
        "arn:aws:s3:::example-lab10-data/*"
      ]
    }
  ]
}
apply-endpoint-policy.sh — 정책 적용
aws ec2 modify-vpc-endpoint \
  --vpc-endpoint-id "$ENDPOINT_ID" \
  --policy-document file://endpoint-policy.json

4 · 버킷 쪽에서 경로를 강제

반대 방향의 통제도 가능합니다. 버킷 정책에 특정 엔드포인트를 지나지 않은 요청은 거부하는 조건을 넣으면, 인터넷 경유 접근 자체가 막힙니다.

bucket-policy.json — 지정 엔드포인트 경유만 허용 (ID는 예시입니다)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyUnlessThroughVpcEndpoint",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::example-lab10-data",
        "arn:aws:s3:::example-lab10-data/*"
      ],
      "Condition": {
        "StringNotEquals": {
          "aws:SourceVpce": "vpce-0123456789abcdef0"
        }
      }
    }
  ]
}

5 · 인터페이스 엔드포인트

create-interface-endpoint.sh — Systems Manager용 인터페이스 엔드포인트
aws ec2 create-vpc-endpoint \
  --vpc-id "$VPC_ID" \
  --vpc-endpoint-type Interface \
  --service-name "com.amazonaws.$REGION.ssm" \
  --subnet-ids subnet-0prv00000000000a subnet-0prv00000000000b \
  --security-group-ids sg-0vpce00000000000 \
  --private-dns-enabled \
  --query 'VpcEndpoint.[VpcEndpointId,State]' --output table

--private-dns-enabled가 요구 4(코드 무변경)의 핵심입니다. 이 옵션을 켜면 공용 서비스 이름이 VPC 안에서 엔드포인트의 사설 IP로 해석되므로, 애플리케이션은 평소와 같은 엔드포인트를 호출하면 됩니다.

검증 방법

라우팅 테이블이 실제로 바뀌었는가

verify-routes.sh — 접두사 목록 경로가 추가되었는지 확인
aws ec2 describe-route-tables \
  --route-table-ids rtb-0private0000000a \
  --query 'RouteTables[0].Routes[].[DestinationCidrBlock,DestinationPrefixListId,GatewayId,NatGatewayId]' \
  --output table

게이트웨이 엔드포인트를 만들면 DestinationPrefixListId가 채워진 경로가 새로 나타나고 대상이 vpce-로 시작합니다. 이것이 게이트웨이 엔드포인트가 "라우팅 테이블에 구현된다"는 말의 실체입니다.

verify-endpoints.sh — 엔드포인트 상태와 인터페이스 확인
aws ec2 describe-vpc-endpoints \
  --filters Name=vpc-id,Values="$VPC_ID" \
  --query 'VpcEndpoints[].[VpcEndpointId,VpcEndpointType,ServiceName,State,PrivateDnsEnabled]' \
  --output table

# 인터페이스 엔드포인트가 만든 네트워크 인터페이스를 확인합니다.
aws ec2 describe-vpc-endpoints \
  --vpc-endpoint-ids vpce-0interface00000 \
  --query 'VpcEndpoints[0].[NetworkInterfaceIds, SubnetIds, DnsEntries[].DnsName]' \
  --output json
검증 항목과 통과 기준
항목 통과 기준
라우팅 테이블 접두사 목록 경로의 대상이 vpce-다
인터페이스 엔드포인트 서브넷마다 네트워크 인터페이스가 생겼다
S3 접근 프라이빗 서브넷 인스턴스에서 지정 버킷 접근이 성공한다
범위 제한 정책에 없는 다른 버킷 접근이 거부된다
NAT 처리량 S3 트래픽이 NAT 지표에서 사라진다
test-from-instance.sh — 프라이빗 서브넷 인스턴스 안에서 실행
# 허용된 버킷 — 성공해야 합니다.
aws s3 ls s3://example-lab10-data/

# 정책 범위 밖 버킷 — 거부되어야 합니다.
aws s3 ls s3://example-other-bucket/

비용 고려

엔드포인트 도입이 바꾸는 항목
항목 변화
NAT 게이트웨이 처리량 줄어든다 — S3 트래픽이 더 이상 지나지 않는다
게이트웨이 엔드포인트 라우팅 경로로 동작한다. 별도의 가동 자원이 생기지 않는다
인터페이스 엔드포인트 가용 영역마다 인터페이스와 처리량이 항목이 된다
가용 영역 간 전송 엔드포인트를 가용 영역마다 두면 경계를 넘는 트래픽이 줄어든다

판단 기준은 단순합니다. S3와 DynamoDB는 게이트웨이 엔드포인트를 거의 항상 만드는 편이 낫습니다. 인터페이스 엔드포인트는 그 서비스로 가는 트래픽이 충분히 클 때 유리하며, 트래픽이 적으면 엔드포인트 항목이 NAT 절감분보다 클 수 있습니다.

프로덕션 고려사항

정리 — 리소스 삭제

cleanup.sh — 엔드포인트 삭제와 경로 원복 확인
aws ec2 delete-vpc-endpoints \
  --vpc-endpoint-ids vpce-0gateway000000 vpce-0interface00000

# 게이트웨이 엔드포인트를 지우면 라우팅 테이블의 접두사 목록 경로도 사라집니다.
aws ec2 describe-route-tables \
  --route-table-ids rtb-0private0000000a \
  --query 'RouteTables[0].Routes[].[DestinationCidrBlock,DestinationPrefixListId,GatewayId]' \
  --output table

# 버킷 정책에 엔드포인트 조건을 넣었다면 함께 제거합니다.
aws s3api delete-bucket-policy --bucket example-lab10-data

자주 하는 실수

자주 나오는 실수와 증상
실수 증상 고치는 법
게이트웨이 엔드포인트를 만들고 라우팅 테이블을 지정하지 않음 경로가 추가되지 않아 여전히 NAT로 나간다 --route-table-ids에 프라이빗 라우팅 테이블을 전부 넣는다
인터페이스 엔드포인트에 보안 그룹 허용 없음 호출이 시간 초과된다 워크로드에서 엔드포인트로 향하는 HTTPS를 허용한다
VPC의 DNS 설정이 꺼져 있음 프라이빗 DNS가 동작하지 않는다 DNS 확인과 DNS 호스트 이름을 켠다
엔드포인트 정책을 기본값으로 방치 이 경로로 모든 버킷에 접근할 수 있다 필요한 리소스로 정책을 좁힌다
버킷 정책 조건을 범위 확인 없이 적용 콘솔과 운영 도구까지 막힌다 접근 주체 목록을 먼저 만들고 예외를 함께 넣는다
온프레미스에서 게이트웨이 엔드포인트 사용 시도 경로가 성립하지 않는다 인터페이스 엔드포인트를 쓴다
엔드포인트를 한 가용 영역에만 가용 영역 장애 시 호출이 끊긴다 가용 영역마다 서브넷을 지정한다

이어서 볼 곳

공식 문서 출처