2. 배치 원칙을 역으로 추적한 기록
1번에서 만든 서버들(Web/App/DB)에 아직 네트워크가 없다는 가정에서 시작. 이번엔 "왜 이렇게 배치해야 하는가"를 순서대로 배우는 대신, 뚫리는 경로를 하나씩 막아가는 관점으로 기록해봤다.
관찰 1 — 다 열어두면 무슨 일이 생기는가
Web, App, DB 세 서버 모두에 공인 IP를 부여하고 인터넷에 바로 연결.
💥 결과: 하루 만에 DB의 3306 포트로 전 세계에서 로그인 시도가 유입됨. 특정 대상을 노린 공격이 아니라, 열린 포트를 찾아다니는 자동 스캐너에 그냥 걸린 것.
🛠 교훈: 공인 IP = 전 인터넷에 대한 접근 허용. DB나 App처럼 외부와 직접 통신할 이유가 없는 서버까지 같은 방식으로 열어둔 게 문제. 통신 필요 여부에 따라 서버를 나눠 배치해야 한다는 최소 권한(Least Privilege) 원칙, 그리고 이를 위한 네트워크 분리(Segmentation) 개념을 확인.
관찰 2 — 반대로 다 잠그면?
이번엔 정반대로, 2005년식 사내 데이터센터를 가정해 웹 서버·사내 업무 서버·DB·관리자 PC를 전부 사설 IP로 내부망에 몰아넣음.
💥 결과: 안전해졌지만 외부 고객이 웹 서버에 접속 자체를 못 함. 서비스 목적을 상실.
🛠 교훈: 전부 개방/전부 폐쇄 둘 다 답이 아님. DMZ(외부 노출이 필요한 서버만 모아두는 완충 구역)를 인터넷과 내부망 사이에 둬야 함. DMZ ↔ 내부망, DMZ ↔ 인터넷 경계마다 Firewall이 트래픽을 통제하고, 물리 장비는 VLAN으로 논리 분리.
관찰 3 — 경계는 만들었는데 나가는 길이 없음
웹 서버는 DMZ, DB는 내부망으로 재배치 완료. 그런데 DB가 OS 패치를 받아야 하는데 내부망이라 인터넷에 나갈 수가 없음.
💥 결과: 보안은 지켰는데 운영(패치, 업데이트)이 마비됨.
🛠 교훈: NAT을 도입. 내부망 서버가 먼저 요청을 보낼 때(Outbound)만 공인 IP로 변환해서 내보내고, 그 요청에 대한 응답만 다시 들여보냄. 요청한 적 없는 트래픽(순수 Inbound)은 여전히 차단 — NAT의 연결 상태 테이블이 "누가 먼저 요청했는지"를 기억하기 때문.
여기서 짚고 넘어간 오해: "NAT이 있으면 외부에서도 DB에 접속되는 거 아니냐" → 아니다. Outbound(내부가 먼저 나가는 것)와 Inbound(외부가 먼저 들어오는 것)는 완전히 다른 방향의 문제이고, NAT은 전자만 허용한다.
관찰 4 — 관리 편의가 만든 구멍
관리자가 재택에서 내부 서버를 관리해야 하는 상황. 급한 대로 방화벽에서 DB의 SSH 포트를 외부로 열어버림.
💥 결과: 며칠 뒤 알 수 없는 로그인 시도 수천 건. 사실상 관찰 1과 동일한 실수 — "관리자용"이라는 목적과 무관하게, 열린 포트는 누구나 두드릴 수 있음.
🛠 교훈: Bastion Host 도입. 내부 서버 각각에 포트를 열지 않고, 관리 접속 전용 서버 한 대만 경계에 세워 그곳으로만 진입시킴. 노출 지점을 하나로 좁혀서 그 지점에만 강력한 접근 통제(허용 IP 제한, 키 인증 = ACL)를 집중.
온프레미스 최종 구조
flowchart LR
Internet((인터넷)) --> FW1[Firewall/Router]
FW1 --> DMZ[DMZ]
DMZ --> Web[Web 서버]
FW1 --> Bastion[Bastion Host]
Bastion --> FW2[Firewall]
FW2 --> Internal[내부망]
Internal --> DB[(DB 서버)]
Internal --> Biz[사내 업무 서버]
Internal -->|NAT 경유 Outbound만| FW1
Admin[관리자 재택] -->|SSH, 22, 지정 IP만| Bastion관찰 5 — 온프레미스를 클라우드로 옮기니 새 함정이 나옴
AWS로 이관 완료: Web은 Public Subnet, App·DB는 Private Subnet. 그런데 공격자가 웹 서버 취약점으로 권한을 탈취하자, Web에서 DB로 그대로 접속이 됨.
💥 결과: Private Subnet에 뒀는데 왜 뚫리는지 처음엔 의아했음.
🛠 교훈: Private Subnet은 "외부→내부" 방향만 차단할 뿐, "내부→내부" 이동(East-West Traffic)은 애초에 다루는 영역이 아님. Subnet 배치는 위치의 문제고, 지금 필요한 건 "누가 누구에게 접속 가능한가"를 정하는 인스턴스 단위 규칙 — Security Group.
관찰 6 — "내부니까 믿는다"는 가정이 깨지는 지점
Security Group을 붙이긴 했는데 처음엔 "내부망끼리는 전부 허용"으로 대충 설정. 여전히 Web → DB 접속이 가능.
💥 결과: 관찰 5와 같은 문제가 반복됨.
🛠 교훈: 계층별로 정확히 필요한 통신만 명시적으로 허용해야 함(Web→App, App→DB만 열고 Web→DB는 아예 규칙을 만들지 않음). IP를 일일이 등록하는 대신 "어느 Security Group에 속했는가"로 규칙을 연결하는 Security Group Chaining을 적용하면 서버가 늘어나도 규칙을 다시 안 써도 됨. "내부니까 안전하다"는 가정 자체를 버리고 매 접속을 검증하는 게 Zero Trust.
AWS 최종 구조
flowchart TB
Internet((인터넷)) --> IGW[Internet Gateway]
IGW --> PubSubnet[Public Subnet]
PubSubnet --> Web[Web 서버]
PubSubnet --> NGW[NAT Gateway]
NGW --> PrivSubnet[Private Subnet]
PrivSubnet --> App[App 서버]
PrivSubnet --> DB[(DB 서버)]
Admin[관리자] -->|SSM, 인바운드 포트 없음| SSM[SSM 경유 접속]
SSM --> PrivSubnet
Web -->|8080만| App
App -->|3306/5432만| DB제출
1. 온프레미스 네트워크 설계도 (관찰 2 ~ 4)
인터넷 → Firewall/Router → DMZ(Web 서버) / Bastion Host → Firewall → 내부망(DB, 사내 업무 서버). 내부망 서버는 NAT을 통해서만 외부로 나갈 수 있고(Outbound 한정), 관리자는 Bastion Host를 거쳐야만 내부망에 진입 가능. (위 mermaid 다이어그램 참고)
2. 온프레미스 ↔ AWS 대응 정리 (관찰 5)
온프레미스 개념 | AWS 서비스 |
사내 네트워크 전체 | VPC |
Network Segment | Subnet |
Routing Table | Route Table |
DMZ | Public Subnet |
Internal Network | Private Subnet |
Internet Router | Internet Gateway (IGW) |
NAT | NAT Gateway |
Firewall Rule (서버 단위) | Security Group |
Firewall Rule (서브넷 단위) | NACL |
3. AWS 네트워크 설계도와 각 서버의 Public/Private 배치 근거
- Web 서버 → Public Subnet: 사용자가 직접 접속해야 서비스가 성립하므로, 외부 노출이 서비스의 필수 조건
- App 서버 → Private Subnet: Web을 거쳐서만 요청을 받으면 되고, 외부에서 직접 접속할 이유가 없음(관찰 1의 교훈 재적용)
- DB 서버 → Private Subnet: App을 거쳐서만 데이터를 주고받으면 되며, 절대 인터넷에서 직접 도달 가능해서는 안 됨(관찰 1에서 실제로 뚫렸던 지점)
- 배치 위치와 별개로, Private Subnet은 East-West 이동까지는 못 막으므로(관찰 5) Security Group으로 인스턴스 단위 통제를 반드시 추가
4. 접근 제어 정리 (관찰 5 ~ 6): 누가 / 누구에게 / 어떤 Port로 / 왜
출발지 | 목적지 | 허용 Port | 왜 |
Internet | Web | 80 / 443 | 사용자 요청 수신 목적 외엔 불필요 |
Web | App | 8080(예시) | Web이 App 로직을 호출하는 용도로만 필요, 그 이상은 불필요 |
App | DB | 3306 / 5432(예시) | App만 DB 조회·저장 수행, 다른 경로는 불필요 |
Web | DB | 차단 (규칙 없음) | Web이 DB에 직접 접속할 이유가 원천적으로 없음 — 관찰 5·6에서 실제로 뚫렸던 구멍 |
관리자 | Bastion / SSM | 22(SSH) 또는 SSM, 지정 IP만 | 관리 접속 경로를 단일 지점으로 강제해 노출 면적 최소화 |
Bastion | 내부 서버(App/DB) | 22 / SSM | Bastion을 거친 접속만 내부망 진입 허용 |
총평: 이번 조사에서 반복적으로 나타난 패턴은, "위치를 옮기는 것"(DMZ 분리, Public/Private 분리)과 "누가 접속 가능한지를 규칙으로 정하는 것"(Firewall, Security Group)이 서로 다른 계층의 방어라는 점이었다. 위치만 옮기고 규칙을 세밀화하지 않으면(관찰 5, 6) 언제든 같은 방식으로 뚫린다는 걸 온프레미스와 AWS 양쪽에서 동일하게 확인했다.


