사이드프로젝트/chan
VPC Endpoint 를 사용하여 private하게 Infra 개선하기
woong29
2022. 9. 16. 12:20
개요
VPC는 한 개만 생성하여 4개의 서비스를 모두 넣어도 충분했을 수도 있었습니다.하지만 Service 별로 VPC를 생성함으로써 보안적으로 리소스 간 허용을 최소화하고 네트워크를 간편하게 구성하기 위해서 서비스별로 별도로 생성을 해주었습니다.
- pivate 하게 vpc를 구성하여서 보안적으로 이점이 있습니다.
- 외부 네트워크가 아닌 Amazon내부의 네트워크를 통해서만 접근이 가능합니다.
- 외부 접근에 대해 private Link의 요금을 따라가기 때문에 업데이트가 많거나 외부 접근 트래픽이 많을 시에 비용적으로 이득을 볼수 있습니다.
- api gateway를 제외하고는 외부 접근이 불가능해집니다.
작업
- private와 isolate Type의 subnet만 생성 [public 생성 제외]
- nat gateway를 사용하지 않고 private link를 사용하여 필요한 외부 서비스 연결
- DB 및 데이터 관련 서비스는 link도 생성하지 못하게 isolate 서브넷에 할당
- 각 서비스간의 요청은 Enpoint Service를 이용하여 연결
CDK Source는 아래와 같이 작업하였습니다.
const vpc = new ec2.Vpc(this, 'vpc', {
vpcName: `${props.serviceName}-vpc`,
maxAzs: props.azs?? 3, //가용 영역 갯수
cidr: props.cidr, // 서비스별로 따로 받아오도록 변수로 설정 ex) '10.0.0.0/16'
natGateways: 0, //nat gateway를 사용하지 않고 외부와의 연결을 api gateway를 제외하고는 없애기 위해 설정
subnetConfiguration: [
//mask는 24면 2^8 - 5 = 251개씩 사용 가능
//외부와 차단된 subnet이 private만 선언
{ name: 'isolate', cidrMask: 24, subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
{ name: 'private', cidrMask: 24, subnetType: ec2.SubnetType.PRIVATE_WITH_NAT },
],
//Docker Image를 저장하는 ECR은 S3에 컨테이너 이미지 및 아티팩트를 저장하기 때문에 endpoint를 생성해주어야합니다.
gatewayEndpoints: {
S3: {
service: ec2.GatewayVpcEndpointAwsService.S3,
},
},
});
//해당 서비스에서 사용하는 aws 서비스에 대해서 endpoint를 등록 해주어야 한다.
const serviceList = [
{name:'ecr' , service:ec2.InterfaceVpcEndpointAwsService.ECR },
{name:'ecr-docker', service:ec2.InterfaceVpcEndpointAwsService.ECR_DOCKER },
{name:'ecr-agent' , service:ec2.InterfaceVpcEndpointAwsService.ECS_AGENT },
{name:'ecs-tel' , service:ec2.InterfaceVpcEndpointAwsService.ECS_TELEMETRY },
{name:'ecs' , service:ec2.InterfaceVpcEndpointAwsService.ECS },
]
serviceList.forEach( el =>
vpc.addInterfaceEndpoint(el.name, {
service: el.service
}));
//network loadbalancer 생성
const nlb = new elb.NetworkLoadBalancer(this, 'nlb', {
loadBalancerName: `${props.serviceName}-nlb`,
vpc,
crossZoneEnabled: false,
internetFacing: false,
});
//endpoint service 생성
const endpointService = new ec2.VpcEndpointService(this, 'endpointService', {
vpcEndpointServiceLoadBalancers: [ nlb ],
acceptanceRequired: false,
});
//endpoint dns를 컨테이너환경변수에 담아서 전달
const normalEnv = {
ENDPOINT_SELLER : dns[SERVICE.SELLER ],
ENDPOINT_LOGISTICS: dns[SERVICE.LOGISTICS],
};
//Ecs Setting
const service = new EcsConstructStack(this, `ecs`, {
serviceName: betaConfig.serviceName,
clusterName: `${betaConfig.serviceName}-cluster`,
dbKeyName: betaConfig.serviceName,
vpc,
loadbalancer: props.loadbalancer,
containerSecretEnv: secretEnv,
containerEnv: normalEnv,
ecrRepo: serviceRepo.ecrRepo,
containerPort: betaConfig.ContainerPort,
stackProps: {stackName : `${props.stackProps.stackName}-ecs`, env: props.stackProps.env},
});