웹/클라우드/인프라로 돌아가기
웹/클라우드/인프라신윤섭·2026년 9월 21일

CIDR 읽는 법, 슬래시 뒤 숫자가 문을 얼마나 여는지 정한다

공유

코드는 리뷰하면서 인프라 설정은 그냥 승인한다

Claude Code한테 이렇게 시킨다. "DB 서버는 사무실에서만 접속되게 막아줘." 에이전트가 Terraform 파일을 열더니 한 줄을 고쳐놓는다.

cidr_blocks = ["10.0.0.0/8"]

설명도 그럴듯하다. 사설 대역이라 외부에서는 못 들어온다고 한다. 승인을 누른다. 사실 /8이 무슨 뜻인지는 모른다.

바이브 코딩을 하다 보면 이 장면이 반복된다. 파이썬 코드는 한 줄씩 읽으면서, 인프라 설정에 박힌 숫자는 읽지 않고 넘어간다. 읽을 줄 모르기 때문이다. 그런데 방화벽 규칙에서 이 숫자는 함수 이름이나 변수명보다 훨씬 무겁다. 슬래시 뒤 숫자 하나가 "나 혼자"와 "전 세계 43억"을 가른다.

다행히 읽는 규칙 자체는 십 분이면 익힌다.

슬래시 뒤 숫자는 앞에서부터 몇 칸을 고정할지 정한다

먼저 IP 주소가 어떻게 생겼는지부터. 192.168.0.1처럼 점으로 나뉜 숫자 네 덩어리다. 각 덩어리는 0부터 255까지 들어간다. 사람 눈에는 네 덩어리지만, 컴퓨터는 이걸 켜거나 끄는 칸 32개로 본다. 한 덩어리가 칸 8개, 네 덩어리니까 8 곱하기 4로 32개다.

이 칸의 원래 이름이 비트다. 앞으로 AWS 콘솔이나 에이전트 설명에서 "24비트"라는 말을 보면 이 칸 24개를 가리킨다고 보면 된다. 슬래시 뒤에 붙는 숫자도 정식 명칭이 있는데, 프리픽스 길이라고 부른다. 글에서는 계속 "칸"이라고 쓰겠지만, 밖에서 만나는 이름은 이 둘이다.

CIDR은 IP 주소에 슬래시와 숫자를 붙인 표기법이다. 10.0.0.0/8에서 뒤에 붙은 8은 앞에서부터 여덟 칸을 고정한다는 뜻이다. 고정된 칸은 반드시 그 값이어야 하고, 나머지 칸은 뭐가 들어와도 된다.

전화번호를 떠올리면 감이 온다. "02로 시작하는 번호"라고 하면 앞 두 자리만 고정하고 뒷자리는 아무 숫자나 허용하는 것이다. 여기에 "02-1234로 시작하는 번호"라고 조건을 붙이면 고정하는 자리가 늘어나고, 해당되는 번호는 확 줄어든다. 고정 자리를 하나도 안 두면 세상 모든 번호가 걸린다.

비유는 딱 여기까지만 가져가면 된다. 전화번호 한 자리에는 0부터 9까지 열 가지가 들어가지만, IP 주소의 한 칸에는 켜짐과 꺼짐 두 가지만 들어간다. 그래서 자유로운 자리가 하나 늘 때 전화번호는 10배가 되지만 IP 주소는 2배가 된다. 이 2배가 뒤에 나오는 계산의 전부다.

정리하면 고정하는 칸이 많을수록 좁고, 적을수록 넓다.

  • 203.0.113.42/32 : 서른두 칸 전부 고정. 딱 그 주소 하나다.
  • 192.168.0.0/16 : 앞 열여섯 칸, 그러니까 앞 두 덩어리인 192.168까지 고정. 뒤 두 덩어리는 자유라 192.168.0.0부터 192.168.255.255까지 전부 해당된다.
  • 0.0.0.0/0 : 고정하는 칸이 하나도 없다. 인터넷에 존재하는 모든 IPv4 주소다.

그러니까 숫자가 클수록 좁고, 작을수록 넓다. 직관과 반대라서 처음엔 자꾸 헷갈린다. /8은 작아 보이지만 1,600만 개가 넘고, /32는 커 보이지만 주소 하나다.

숫자 8이 줄면 범위는 256배가 된다

정확한 개수는 공식 하나로 나온다. 32에서 슬래시 뒤 숫자를 뺀 만큼이 자유로운 칸 수이고, 칸 하나가 두 배씩 불어난다.

표기자유로운 칸주소 개수어느 정도인가
/320칸1특정 서버 한 대
/284칸16아주 작은 묶음
/248칸256마지막 덩어리 전부
/2012칸4,096서브넷 하나 정도
/1616칸65,536뒤 두 덩어리 전부
/1220칸1,048,576백만 개
/824칸16,777,216첫 덩어리만 맞으면 통과
/032칸4,294,967,296전 세계

외울 건 두 개다. 숫자가 1 줄면 두 배, 8 줄면 256배. 그래서 /24/16은 겉보기엔 한 글자 차이인데 실제로는 256배 차이가 난다. 에이전트가 /24라고 써야 할 자리에 /16을 써놓으면, 256개 허용할 자리에 65,536개를 허용한 것이다. diff 화면에서는 문자 두 개 바뀐 것으로 보인다.

앞에서 본 10.0.0.0/8도 다시 보자. 사설 대역이라는 설명은 맞다. 다만 그 대역의 크기가 1,677만 개다. "사무실에서만"이라고 시킨 결과치고는 넓다. 회사가 쓰는 사설 IP가 10.3.x.x 한 덩어리라면 10.3.0.0/16으로 줄여야 요청한 의도에 가깝다.

CIDR 프리픽스 길이에 따른 허용 범위 비교
CIDR 프리픽스 길이에 따른 허용 범위 비교

172.16.0.0/12는 왜 172.31까지인가

/8, /16, /24는 점 위치와 딱 맞아떨어져서 눈으로 읽힌다. 고정되는 칸이 각각 첫 덩어리, 두 덩어리, 세 덩어리까지니까 그냥 덩어리 단위로 끊으면 된다.

문제는 /12 같은 숫자다. 점 사이를 가로질러 끊기 때문에 눈으로 안 읽힌다. 그리고 하필 자주 쓰이는 사설 대역 하나가 /12다.

172.16.0.0/12를 풀어보자. 앞 열두 칸을 고정한다는 뜻인데, 첫 덩어리 172가 여덟 칸을 쓰니 두 번째 덩어리에서 네 칸이 더 필요하다. 두 번째 덩어리의 여덟 칸 중 앞 네 칸은 고정, 뒤 네 칸은 자유가 된다. 칸 하나가 두 가지이므로 자유로운 네 칸은 16가지다. 그래서 두 번째 덩어리는 16에서 시작해 16가지, 즉 16부터 31까지 전부 포함된다.

결론은 172.16.0.0부터 172.31.255.255까지다. 172.16.x.x만 해당된다고 읽으면 틀린다.

172.16.0.0/12의 비트 분해와 실제 주소 범위
172.16.0.0/12의 비트 분해와 실제 주소 범위

여기서 실무 사고가 난다. 에이전트한테 "내부망으로 못 나가게 막아줘"라고 시키면 사설 대역 차단 목록을 만들어준다. RFC 1918이 정한 사설 대역은 세 개뿐이다.

대역실제 범위개수
10.0.0.0/810.0.0.0 ~ 10.255.255.25516,777,216
172.16.0.0/12172.16.0.0 ~ 172.31.255.2551,048,576
192.168.0.0/16192.168.0.0 ~ 192.168.255.25565,536

이걸 손으로 옮겨 적다가 172.16.0.0/16으로 잘못 쓰면, 막히는 건 172.16.x.x 6만여 개뿐이고 172.17부터 172.31까지는 그대로 뚫린다. 하필 AWS가 계정마다 자동으로 만들어주는 기본 VPC의 대역이 172.31.0.0/16이다. AWS 공식 문서에 "기본 VPC는 /16 크기의 172.31.0.0/16을 쓰고, 가용 영역마다 /20 서브넷을 만든다"고 적혀 있다. VPC를 따로 만들지 않고 콘솔에서 바로 EC2를 띄웠다면 그 서버는 기본 VPC 안에 있고, 사설 주소도 172.31.로 시작한다. 사설 대역을 막았다고 생각했는데 정작 자기 옆자리 서버만 안 막힌 상황이 된다.

차단 목록에 넣을 대역은 세 개가 아니라 다섯 개다

사설 대역 세 개만 막으면 구멍이 남는다. 두 개를 더해야 한다.

하나는 169.254.169.254다. EC2 안에서 이 주소로 요청하면 인스턴스 메타데이터가 나오고, IAM 역할에 딸린 임시 자격증명도 여기서 나온다. 이 주소는 169.254.0.0/16이라는 링크로컬 대역에 속한다. AWS는 네트워크 장비 단에서 이 목적지로 가는 패킷을 버리라고 권고한다.

다른 하나는 127.0.0.0/8, 흔히 localhost라고 부르는 루프백 대역이다. 사설 대역 세 개 어디에도 속하지 않는다. 127.0.0.110.0.0.0/8에도, 172.16.0.0/12에도, 192.168.0.0/16에도 안 들어간다. 그래서 세 개만 막아두면 http://127.0.0.1:6379 같은 주소는 그대로 통과한다. 서버 자기 자신에서 도는 관리 포트를 노리는 가장 흔한 경로다.

목록으로 쓸 때는 이 다섯 줄을 통째로 쓰면 된다.

10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
169.254.0.0/16
127.0.0.0/8

에이전트가 써준 설정에서 눈여겨볼 숫자 네 개

0.0.0.0/0. 전 세계 전부다. 웹 서버의 80번과 443번 포트라면 이게 맞다. 그 외의 포트, 특히 22번(SSH)이나 5432번(PostgreSQL), 6379번(Redis) 옆에 이 표기가 붙어 있으면 둘 중 하나로 바꾼다. 접속할 곳이 고정 IP 한 군데면 그 주소에 /32를 붙여 넣고, 접속하는 쪽이 같은 VPC 안의 서버라면 CIDR 대신 그 서버의 보안 그룹 ID를 소스로 지정한다(뒤에서 다시 다룬다).

집 공인 IP를 /24로 넣은 경우. "내 IP만 허용해줘"라고 시켰는데 1.2.3.4/24가 들어왔다면, 허용된 건 한 개가 아니라 1.2.3.0부터 1.2.3.255까지 256개다. 주소 뒤에 .4가 붙어 있어서 그 한 대만 가리키는 것처럼 보이지만, 슬래시 뒤 숫자가 24인 이상 마지막 덩어리는 통째로 자유다. 통신사는 한 블록을 여러 가입자에게 나눠 쓰는 경우가 많으니, 같은 대역을 받은 남의 집 회선에서도 문이 열린다. 한 대만 허용할 생각이면 /32를 쓴다.

0.0.0.0/1128.0.0.0/1 두 줄. 각각 반쪽씩이라 좁아 보이는데, 앞 칸 하나가 0인 주소 전부와 1인 주소 전부니까 둘을 합치면 정확히 전체 IPv4가 된다. 0.0.0.0/0 한 줄과 결과가 같다. 원래는 기존 기본 경로와 충돌하지 않으면서 모든 트래픽을 특정 경로로 보내려 할 때 VPN 설정에서 쓰는 방식이다. 방화벽 허용목록에 이게 두 줄로 들어와 있다면 사실상 전면 개방인데, 규칙을 한 줄씩 훑는 것만으로는 눈에 안 띈다. 다음 섹션의 마지막 명령이 이런 경우를 잡아낸다.

IPv4만 막고 ::/0이 열려 있는 경우. ::/0은 IPv6 쪽의 0.0.0.0/0이다. 인바운드 규칙에서 IPv4는 사무실 IP로 좁혀놓고 IPv6는 ::/0으로 열어둔 설정이 꽤 나온다. 서버에 IPv6 주소가 붙어 있다면 그쪽 문은 그냥 열려 있는 셈이다.

눈으로 읽지 말고 검산한다

암산하다 틀릴 바에는 한 줄 돌려보는 게 빠르다. 파이썬에 ipaddress가 기본으로 들어 있어서 따로 설치할 게 없다.

범위와 개수를 확인한다.

python3 -c "import ipaddress as i; n=i.ip_network('172.16.0.0/12'); print(n[0], n[-1], n.num_addresses)"
172.16.0.0 172.31.255.255 1048576

특정 주소가 그 안에 드는지 본다.

python3 -c "import ipaddress as i; print(i.ip_address('172.31.5.10') in i.ip_network('172.16.0.0/12'))"
True

앞에서 본 1.2.3.4/24도 넣어보면 무슨 일이 벌어지는지 바로 보인다. ip_networkstrict=False를 주면 고정되지 않은 뒷칸을 0으로 밀어버리고 대역을 정규화한다.

python3 -c "import ipaddress as i; n=i.ip_network('1.2.3.4/24', strict=False); print(n, n[0], n[-1], n.num_addresses)"
1.2.3.0/24 1.2.3.0 1.2.3.255 256

.4가 사라지고 1.2.3.0/24가 됐다. 방화벽이 읽는 것도 이쪽이다. 내 주소 한 개를 적었다고 생각했는데 실제로 허용된 건 256개라는 사실이 출력 한 줄로 드러난다. strict=False를 빼면 파이썬이 아예 ValueError: 1.2.3.4/24 has host bits set을 내면서 "뒷칸에 값이 남아 있다"고 알려준다.

규칙이 여러 줄로 쪼개져 있을 때는 한꺼번에 접어본다. collapse_addresses는 이어붙일 수 있는 대역을 합쳐서 가장 짧은 형태로 돌려준다.

python3 -c "import ipaddress as i; print(list(i.collapse_addresses([i.ip_network('0.0.0.0/1'), i.ip_network('128.0.0.0/1')])))"
[IPv4Network('0.0.0.0/0')]

한 줄씩 볼 때는 반쪽으로 보이던 두 규칙이 접고 나니 0.0.0.0/0이다. 허용목록 전체를 이 함수에 넣어보면, 여러 줄로 흩어놓은 전면 개방이 한 줄로 정리돼 나온다.

AWS 보안 그룹을 쓴다면 방법이 하나 더 있다. 소스 칸에 CIDR 대신 다른 보안 그룹의 ID를 넣는 것이다. "이 보안 그룹이 붙은 서버에서 오는 접속만 허용"이라는 뜻이 되므로, 서버가 재시작돼 사설 IP가 바뀌어도 규칙을 고칠 필요가 없다. 대역을 넓게 잡고 싶은 유혹 자체가 사라진다. 다만 같은 VPC이거나 같은 리전에서 피어링된 VPC일 때만 동작하고, 리전이 다르면 CIDR을 써야 한다.

정리

슬래시 뒤 숫자는 앞에서부터 몇 칸을 고정할지를 정한다. 고정이 많을수록 좁고, 적을수록 넓다. /32는 주소 하나, /0은 전부다. 1이 줄면 두 배, 8이 줄면 256배로 불어난다.

점 경계와 안 맞는 /12 같은 표기는 눈으로 읽으면 틀린다. 172.16.0.0/12172.16이 아니라 172.31까지이고, AWS 기본 VPC가 쓰는 172.31.0.0/16이 바로 그 끝자락에 있다. 내부망을 막을 생각이라면 사설 대역 세 개로는 모자라고, 링크로컬과 루프백까지 다섯 줄이 필요하다.

에이전트는 동작하는 설정을 잘 써준다. 다만 "동작한다"와 "필요한 만큼만 열었다"는 다른 기준이고, 후자를 판정하려면 사람이 숫자를 읽어야 한다. 읽는 규칙은 두 개뿐이고, 헷갈리는 자리는 python3 -c 한 줄에 물어보면 된다.

YS

신윤섭

데이너스 대표 | AI 교육 & AX 컨설팅

90개 이상의 AI/AX 교육 과정을 설계하고, 50여 교육·협업 기관에서 강의했습니다. 강남세브란스, 삼성전자, 현대자동차 등 다양한 조직의 AI 역량 강화를 지원하고 있습니다.

AI 교육이 필요하신가요?

조직에 맞는 맞춤형 AI/AX 교육 프로그램을 설계해드립니다. 커리큘럼 상담부터 시작해보세요.

같은 주제의 다른 글