어떤 작업인가요?
내부 전용 API(/internal/**)를 외부 인터넷에서 호출할 수 없도록 하는 nginx 차단 규칙을, 운영 인스턴스에는 이미 수동 적용했고 코드에는 아직 반영되지 않은 상태입니다. 인스턴스가 재생성되면 유실되므로 modules/app_stack/scripts/nginx_setup.sh.tftpl 에 반영합니다.
배경
백업 실패 알림 API(POST /internal/alarms/db-backup)가 v2.6.1 로 prod 에 배포되면서, 이 경로가 외부 인터넷에 노출되었습니다.
서버의 SecurityConfiguration 은 /internal/** 을 permitAll() 로 두고 공유 토큰(internal-alarm.token)으로만 인증합니다. 즉 nginx 차단이 없으면 토큰 하나가 유일한 방어선입니다.
적용 전 외부에서 확인한 결과입니다.
POST https://api.solid-connection.com/internal/alarms/db-backup
→ 401 {"message":"요청을 인증할 수 없습니다."}
401 은 요청이 nginx 를 통과해 애플리케이션까지 도달했다는 뜻입니다.
DB EC2 는 API 서버의 app 포트(8080/9080)로 직접 요청하므로 nginx 를 거치지 않습니다. 따라서 외부 443 경로만 막으면 알림 기능에는 영향이 없습니다.
운영 인스턴스 반영 현황 (완료)
API EC2(i-016e57974be976a59)의 /etc/nginx/sites-available/solid-connection-server 에 아래 블록을 추가하고 nginx -t 통과 후 graceful reload 했습니다.
# 3차 차단: 내부 전용 API 는 VPC 내부에서 app 포트로 직접 호출하므로 외부 노출을 막는다
# DB EC2 의 백업 실패 알림은 8080/9080 직접 경로를 쓰므로 이 차단에 영향받지 않는다
location ^~ /internal {
return 444;
}
443 server 블록(server_name api.solid-connection.com) 안, dotfile 차단 블록과 location / 사이에 위치합니다.
설계 결정
| 항목 |
결정 |
이유 |
| 응답 |
return 444 |
기존 차단(IP 직접 접근, 확장자 스캔, dotfile)과 동일한 컨벤션. deny all(403)은 "경로는 있지만 금지" 를 알려주는데, 444 는 응답 없이 연결을 끊어 경로 존재 자체를 숨김 |
| 접두사 |
/internal (trailing slash 없음) |
^~ /internal/ 로 두면 /internal 이 매칭되지 않아 앱까지 도달함. 서버의 /internal/** 범위와 맞춤 |
| 위치 |
location / 앞 |
^~ 는 prefix priority match 라 정규식 location 보다 먼저 평가됨 |
검증 결과
외부 인터넷에서 차단됨 (000 = 응답 없이 연결 종료):
GET /internal → 000
GET /internal/ → 000
GET /internal/alarms/db-backup → 000
GET /internal/anything → 000
POST /internal/alarms/db-backup → 000
일반 경로는 그대로 앱으로 전달됨 (500 은 앱이 반환한 응답):
GET / → 500
GET /universities → 500
GET /actuator/health → 500
DB EC2 에서 직접 호출하는 알림 경로는 영향 없음:
health 9081 → {"status":"UP"}
알림 9080 → 401
되돌릴 필요가 있으면 /root/nginx-sc-before-internal-block.bak 에 적용 전 파일이 있습니다.
작업 내용
주의: 코드 반영만으로는 운영에 적용되지 않습니다
aws_instance.api_server 의 lifecycle.ignore_changes 에 user_data 와 user_data_base64 가 있고, cloud-init 의 scripts-user 는 once-per-instance 로 동작합니다. 따라서 nginx_setup.sh.tftpl 을 수정해도 plan 에 아무 변화가 나타나지 않고 실행 중인 인스턴스에도 반영되지 않습니다.
이 이슈의 목적은 인스턴스가 재생성되는 시점에 설정이 유지되도록 하는 것입니다. 운영 반영은 위와 같이 이미 수동으로 완료했습니다.
같은 성격의 괴리가 다른 곳에도 있습니다.
- 코드의
db_ec2_ami_id(ami-0501a03cd31b53e82)와 실제 인스턴스 AMI(ami-0d45c1f91adea31b8)
mysql_tuning.cnf (변경해도 반영되지 않음, binlog 설정이 MySQL 기본값에 의존)
런타임 설정을 배포 경로로 옮기는 작업은 별도 주제이며, 현재 튜닝 수요가 없어 보류한 상태입니다.
완료 조건
nginx_setup.sh.tftpl 에 차단 블록이 포함되어 있습니다.
- 새 인스턴스를 기동했을 때
/internal 접근이 외부에서 차단됩니다.
- DB EC2 의 백업 실패 알림이 정상 동작합니다.
Refs #66
어떤 작업인가요?
내부 전용 API(
/internal/**)를 외부 인터넷에서 호출할 수 없도록 하는 nginx 차단 규칙을, 운영 인스턴스에는 이미 수동 적용했고 코드에는 아직 반영되지 않은 상태입니다. 인스턴스가 재생성되면 유실되므로modules/app_stack/scripts/nginx_setup.sh.tftpl에 반영합니다.배경
백업 실패 알림 API(
POST /internal/alarms/db-backup)가v2.6.1로 prod 에 배포되면서, 이 경로가 외부 인터넷에 노출되었습니다.서버의
SecurityConfiguration은/internal/**을permitAll()로 두고 공유 토큰(internal-alarm.token)으로만 인증합니다. 즉 nginx 차단이 없으면 토큰 하나가 유일한 방어선입니다.적용 전 외부에서 확인한 결과입니다.
401 은 요청이 nginx 를 통과해 애플리케이션까지 도달했다는 뜻입니다.
DB EC2 는 API 서버의 app 포트(8080/9080)로 직접 요청하므로 nginx 를 거치지 않습니다. 따라서 외부 443 경로만 막으면 알림 기능에는 영향이 없습니다.
운영 인스턴스 반영 현황 (완료)
API EC2(
i-016e57974be976a59)의/etc/nginx/sites-available/solid-connection-server에 아래 블록을 추가하고nginx -t통과 후 graceful reload 했습니다.443server 블록(server_name api.solid-connection.com) 안, dotfile 차단 블록과location /사이에 위치합니다.설계 결정
return 444deny all(403)은 "경로는 있지만 금지" 를 알려주는데, 444 는 응답 없이 연결을 끊어 경로 존재 자체를 숨김/internal(trailing slash 없음)^~ /internal/로 두면/internal이 매칭되지 않아 앱까지 도달함. 서버의/internal/**범위와 맞춤location /앞^~는 prefix priority match 라 정규식 location 보다 먼저 평가됨검증 결과
외부 인터넷에서 차단됨 (
000= 응답 없이 연결 종료):일반 경로는 그대로 앱으로 전달됨 (500 은 앱이 반환한 응답):
DB EC2 에서 직접 호출하는 알림 경로는 영향 없음:
되돌릴 필요가 있으면
/root/nginx-sc-before-internal-block.bak에 적용 전 파일이 있습니다.작업 내용
modules/app_stack/scripts/nginx_setup.sh.tftpl의 443 server 블록에location ^~ /internal { return 444; }를 추가합니다.location /사이에 두고, 기존 차단 주석 스타일(1차/2차 차단)에 맞춰 설명을 남깁니다.terraform plan에서 인스턴스 교체가 발생하지 않는지 확인합니다.주의: 코드 반영만으로는 운영에 적용되지 않습니다
aws_instance.api_server의lifecycle.ignore_changes에user_data와user_data_base64가 있고, cloud-init 의scripts-user는 once-per-instance 로 동작합니다. 따라서nginx_setup.sh.tftpl을 수정해도 plan 에 아무 변화가 나타나지 않고 실행 중인 인스턴스에도 반영되지 않습니다.이 이슈의 목적은 인스턴스가 재생성되는 시점에 설정이 유지되도록 하는 것입니다. 운영 반영은 위와 같이 이미 수동으로 완료했습니다.
같은 성격의 괴리가 다른 곳에도 있습니다.
db_ec2_ami_id(ami-0501a03cd31b53e82)와 실제 인스턴스 AMI(ami-0d45c1f91adea31b8)mysql_tuning.cnf(변경해도 반영되지 않음, binlog 설정이 MySQL 기본값에 의존)런타임 설정을 배포 경로로 옮기는 작업은 별도 주제이며, 현재 튜닝 수요가 없어 보류한 상태입니다.
완료 조건
nginx_setup.sh.tftpl에 차단 블록이 포함되어 있습니다./internal접근이 외부에서 차단됩니다.Refs #66