소개
애플리케이션의 인스턴스가 실행 중이고 퍼블릭 주소가 있어도 접근할 수 없는 경우가 있습니다. Terraform으로 누락된 경로와 범위를 좁게 제한한 보안 그룹 규칙을 정의한 다음, 허용되는 연결과 차단되는 연결을 모두 테스트합니다.
Terraform 리소스 참조, VPC, 서브넷, 인터넷 경로, 보안 그룹을 이해하고 있어야 합니다. 이 독립적인 환경에는 대상 애플리케이션, 별도로 정상 작동하는 참조 애플리케이션, 준비된 Terraform 입력값이 제공됩니다. 여러분은 새로 추가하는 연결 리소스만 관리합니다.
관련 자격증 시험 항목
| 자격증 | 시험 과제 | 실습 내용 |
|---|---|---|
| Solutions Architect – Associate (SAA-C03) | Task 1.2 | 인터넷 게이트웨이를 통해 VPC 서브넷을 연결하고 출발지와 포트로 애플리케이션의 네트워크 접근을 제한합니다. |
실습 개요

인터넷 경로 구성하기
이 단계에서는 애플리케이션 VPC에 인터넷 게이트웨이를 연결하고 해당 서브넷에 라우팅 테이블을 명시적으로 연결합니다.
Terminal과 AWS View를 여세요. 애플리케이션 네트워크와 참조 네트워크는 독립적입니다. application-server는 서브넷에서 인스턴스 시작 시 퍼블릭 IP를 할당하므로 이미 퍼블릭 주소가 있습니다. 퍼블릭 주소만으로 인터넷 경로나 인바운드 권한이 생성되지는 않습니다.
AWS View에서 application-server, User · 198.51.100.10, Application · 8081을 선택한 다음 Send request를 클릭하세요. Blocked가 표시되어야 합니다. 같은 클라이언트와 애플리케이션 포트로 reference-server를 선택하여 다시 요청을 보내고 참조 애플리케이션이 응답하는지 확인합니다. 실습 내내 이 참조 애플리케이션이 정상 작동하도록 유지하세요.
준비된 작업 디렉터리로 이동합니다.
cd /home/labex/project/application-access
제공된 terraform.tfvars.json에는 이 새로운 환경의 VPC, 서브넷, 보안 그룹 ID가 담겨 있습니다. Terraform은 이 입력값을 자동으로 불러옵니다. 해당 변수를 사용하기 전에 내용을 읽어 보세요.
cat terraform.tfvars.json
준비된 프로바이더 구성은 이 과정의 환경을 선택합니다. 이전 VM에서 ID를 복사하거나 개인 자격 증명을 입력할 필요는 없습니다. 나중에 확인할 수 있도록 제공된 대상 인스턴스 ID를 저장하고 표시합니다. $(...)는 명령 출력을 캡처하고, --output text는 ID를 일반 텍스트로 반환합니다.
TARGET_ID=$(aws ec2 \
describe-instances \
--filters Name=tag:Name,Values=application-server Name=instance-state-name,Values=running \
--query 'Reservations[0].Instances[0].InstanceId' \
--output text)
echo "$TARGET_ID"
인터넷 게이트웨이는 VPC에 연결됩니다. 라우팅 테이블은 목적지로 향하는 트래픽을 해당 게이트웨이로 보내고, 서브넷 연결은 어느 테이블이 서브넷을 제어할지 선택합니다. 명시적인 연결이 없으면 서브넷은 VPC의 기본 라우팅 테이블을 사용합니다. 제공된 기본 테이블은 변경하지 마세요. 목적지 0.0.0.0/0은 더 구체적인 경로가 없는 IPv4 주소와 일치하며, 보안 그룹을 통과할 권한을 부여하지는 않습니다.
routing.tf를 생성합니다. 따옴표를 사용한 heredoc은 HCL을 그대로 씁니다. 리소스 참조는 경로를 해당 테이블과 게이트웨이에 연결하고, 서브넷 연결을 같은 테이블에 연결합니다.
cat > routing.tf <<'HCL'
resource "aws_internet_gateway" "application" {
vpc_id = var.vpc_id
}
resource "aws_route_table" "application" {
vpc_id = var.vpc_id
}
resource "aws_route" "internet" {
route_table_id = aws_route_table.application.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.application.id
}
resource "aws_route_table_association" "application" {
subnet_id = var.subnet_id
route_table_id = aws_route_table.application.id
}
output "route_table_id" {
value = aws_route_table.application.id
}
output "subnet_id" {
value = var.subnet_id
}
HCL
구성을 초기화하고 형식을 정리한 뒤 유효성을 검사합니다.
terraform init
terraform fmt
terraform validate
init에서 Incomplete lock file information for providers가 출력되면 다른 플랫폼의 체크섬에 관한 메시지입니다. 준비된 이 VM은 linux_amd64를 사용합니다. 초기화와 유효성 검사가 성공하면 계속 진행하세요.
추가할 네 리소스인 게이트웨이, 테이블, 경로, 연결을 검토합니다. 제공된 인스턴스와 참조 네트워크가 교체하거나 삭제할 리소스로 나타나서는 안 됩니다.
terraform plan
적용하고 확인 요청이 나오면 yes를 입력합니다.
terraform apply
새 테이블 ID와 제공된 서브넷 ID를 저장하고 표시합니다.
TABLE_ID=$(terraform output -raw route_table_id)
echo "$TABLE_ID"
SUBNET_ID=$(terraform output -raw subnet_id)
echo "$SUBNET_ID"
라우팅 테이블을 독립적으로 조회합니다. 기본 목적지, igw-... 게이트웨이, 해당 서브넷 ID와의 연결을 찾으세요. VPC의 로컬 경로도 유지됩니다.
aws ec2 \
describe-route-tables \
--route-table-ids "$TABLE_ID" \
--query 'RouteTables[].{Routes:Routes[].{Destination:DestinationCidrBlock,Gateway:GatewayId},Subnets:Associations[].SubnetId}'
제공된 서브넷의 퍼블릭 IP 할당 설정을 확인합니다.
aws ec2 \
describe-subnets \
--subnet-ids "$SUBNET_ID" \
--query 'Subnets[].{CIDR:CidrBlock,PublicIPOnLaunch:MapPublicIpOnLaunch}'
PublicIPOnLaunch는 true입니다. 이 설정은 새로 시작하는 인스턴스에 적용됩니다. 설정을 변경한다고 기존 인스턴스에 주소가 소급 할당되지는 않습니다. 이제 AWS View에는 실제 게이트웨이와 적용되는 라우팅 테이블이 표시됩니다. 애플리케이션에 User/8081 요청을 다시 보내세요. 아직 허용하는 인바운드 규칙이 없으므로 여전히 Blocked입니다.
의도한 클라이언트 허용 및 경계 테스트하기
이 단계에서는 User 클라이언트가 애플리케이션 포트에 접근하도록 허용하고, 다른 클라이언트와 다른 포트는 계속 차단되는지 확인합니다.
보안 그룹은 인스턴스의 네트워크 인터페이스에 연결되는 상태 기반 네트워크 경계입니다. 라우팅이 경로를 제공해도 어떤 수신 연결을 허용할지는 여전히 보안 그룹이 결정합니다. 제공된 애플리케이션 그룹에는 현재 인바운드 규칙이 없습니다.
해당 그룹에 독립적인 인바운드 규칙 리소스 하나를 생성합니다. cidr_ipv4 = "198.51.100.10/32"는 User 클라이언트의 단일 IPv4 주소를 선택합니다. 시작 및 끝 포트를 모두 8081로 설정하면 애플리케이션 리스너만 허용됩니다. 참조 애플리케이션은 자체 보안 그룹을 사용합니다.
cat > access.tf <<'HCL'
resource "aws_vpc_security_group_ingress_rule" "application" {
security_group_id = var.security_group_id
ip_protocol = "tcp"
from_port = 8081
to_port = 8081
cidr_ipv4 = "198.51.100.10/32"
}
output "security_group_id" {
value = var.security_group_id
}
HCL
형식을 정리하고 유효성을 검사한 다음 계획을 검토합니다. 인바운드 규칙 하나만 추가되며 인스턴스 교체는 없어야 합니다.
terraform fmt
terraform validate
terraform plan
규칙을 적용하고 yes로 확인합니다.
terraform apply
기존 그룹 ID를 저장하고 표시한 다음 실제 인바운드 권한을 읽습니다.
GROUP_ID=$(terraform output -raw security_group_id)
echo "$GROUP_ID"
aws ec2 \
describe-security-groups \
--group-ids "$GROUP_ID" \
--query 'SecurityGroups[].{Group:GroupId,Ingress:IpPermissions}'
권한에는 198.51.100.10/32에서 TCP 포트 8081로의 접근이 명시되어야 합니다. Terraform이 수렴했는지 확인합니다.
terraform plan
No changes.가 표시되어야 합니다. 이제 AWS View에서 매번 application-server를 선택하여 세 가지 테스트를 모두 수행하세요.
User · 198.51.100.10과 Application · 8081을 선택합니다. Send request를 클릭하세요. Connected · 200과 Application network connected 메시지가 표시되어야 합니다.
출발지를 Unrelated · 198.51.100.20으로 바꾸고 포트 8081을 유지한 채 다시 요청을 보냅니다. Blocked가 표시되어야 합니다.
User 출발지로 돌아가 SSH · 22를 선택하고 다시 요청을 보냅니다. Blocked가 표시되어야 합니다. 애플리케이션 요청이 성공했다고 해서 게스트의 별도 SSH 리스너에 접근할 권한이 부여되지는 않습니다.
결과에는 실제 출발지, 대상 인스턴스, 포트가 표시됩니다. Request service unavailable은 환경 오류이며 의도한 네트워크 거부의 증거가 아닙니다. 규칙을 0.0.0.0/0으로 넓히지 마세요. 그렇게 하면 관련 없는 클라이언트에도 같은 애플리케이션 리스너가 노출됩니다.
AWS 프로바이더 인바운드 규칙 문서는 이 리소스의 필드를 설명합니다. CLI, Terraform 매핑, 실제 요청 결과가 서로 일치해야 합니다.
연결 리소스 삭제 및 애플리케이션 보존하기
이 단계에서는 Terraform으로 관리하는 연결 리소스만 삭제하고 제공된 애플리케이션이 온전히 유지되는지 확인합니다.
이 작업 디렉터리는 인터넷 게이트웨이, 라우팅 테이블, 기본 경로, 서브넷 연결, 인바운드 규칙의 다섯 리소스를 소유합니다. VPC, 서브넷, 기본 라우팅 테이블, 대상 인스턴스, 참조 애플리케이션은 독립적으로 제공되었습니다. 이들은 이 상태의 관리 범위 밖에 있으므로 유지해야 합니다.
삭제 계획을 검토합니다.
terraform plan -destroy
삭제할 리소스가 다섯 개여야 합니다. 그런 다음 삭제를 실행하고 yes를 입력합니다.
terraform destroy
상태에 관리 중인 리소스 주소가 없는지 확인합니다.
terraform state list
제공된 대상은 여전히 같은 ID로 실행 중이어야 합니다.
aws ec2 \
describe-instances \
--instance-ids "$TARGET_ID" \
--query 'Reservations[].Instances[].{ID:InstanceId,State:State.Name,Subnet:SubnetId}'
AWS View에서 대상에 User/8081 요청을 다시 보냅니다. 연결 리소스를 삭제했으므로 Blocked가 표시되어야 합니다. 그런 다음 reference-server, User, 포트 8081을 선택하고 요청을 보냅니다. 참조 애플리케이션은 여전히 Connected · 200과 Reference application을 반환해야 합니다.
HCL 파일은 검토할 수 있도록 남아 있습니다. 나중에 일반 계획을 실행하면 삭제된 리소스를 다시 생성하자고 제안합니다. terraform destroy 후 구성이 남아 있는 것은 정상입니다.
요약
Terraform 참조를 사용하여 인터넷 게이트웨이를 연결하고, 기본 경로를 정의하며, 라우팅 테이블을 애플리케이션 서브넷에 연결했습니다. 그런 다음 범위를 제한한 인바운드 규칙 하나를 추가하고, 실제 출발지 및 포트 경계를 테스트하고, 수렴을 확인한 뒤, 제공된 애플리케이션을 보존하면서 자신의 연결 리소스만 삭제했습니다.



