폐쇄망에 사내 DNS 와 시간 서버 세우기
이 실습은 진짜 VM 에서 돕니다
우분투 24.04 VM 한 대입니다. 준비 단계가 네트워크 네임스페이스 client 를 만들어 두었습니다 — 같은 VM 안이지만 네트워크로는 따로인 "폐쇄망 안의 다른 서버" 이고, VM(10.203.0.1)과 veth 로 이어져 있습니다(10.203.0.2). 그 안에서 명령을 치려면 ip netns exec client <명령> 입니다. dnsmasq·chrony·dig 가 깔려 있습니다(dnsmasq 서비스는 포트 53 충돌로 실패한 채입니다 — 그 진단은 network-basics 코스에서 다룹니다). 채점은 바깥에서 VM 의 8899 포트로 들어오는 에이전트가 하므로 이미 맺은 연결을 막으면 채점이 끊깁니다.
목표
인터넷에 닿지 않는 망에 사내 DNS 와 시간 서버를 세우고, 다른 서버가 그것을 쓰게 한 뒤, 인계용 점검 스크립트로 끝낸다.
왜 중요한가
사내 미러는 이름으로 불러야 인증서와 맞고, 그 이름을 푸는 DNS 가 있어야 한다. 그런데 폐쇄망 DNS 가 모르는 이름을 바깥에 물으러 가면 매번 시간 초과를 기다린다. 사내 영역은 권한을 가지고 곧바로 답하게 만들어야 한다. 시간도 같다. 인터넷 시간 서버에 닿지 않는 서버들의 시계는 서로 멀어지고, 몇 분만 어긋나도 인증서 유효 기간 확인과 로그 대조가 깨진다. 폐쇄망에는 기준 시계 하나가 있어야 한다.
예상 50분이다. 세션이 끝나면 VM 이 사라지니 남기고 싶은 파일은 종료 전에 따로 보관한다.
단계
- 다시 돌려도 규칙이 한 벌만 남는
/root/infra/egress.sh로 바깥 송신을 막는다(체인AIRGAP-EGRESS, OUTPUT 에서 한 번). 루프백·이미 맺은 연결·사내 대역10.203.0.0/24는 살린다. 막기 전과 막은 뒤에curl -s -o /dev/null -w '%{http_code}' https://ubuntu.com을 재서/root/infra/egress-proof.txt에before=·after=로 적는다. /etc/dnsmasq.d/airgap.conf로 dnsmasq 가10.203.0.1에서만 듣고, 상류 없이,airgap.internal영역을 권한으로 답하게 한다. 이름표는/etc/airgap/hosts(registry·pypi·ntp세 이름 →10.203.0.1)에 두고addn-hosts로 읽는다. 서비스를 살리고 부팅 때도 뜨게 한다.client가 그 DNS 와 검색 도메인airgap.internal을 쓰게/etc/netns/client/resolv.conf를 쓴다.client에서 짧은 이름registry가 풀려야 한다./etc/airgap/hosts에nexus.airgap.internal→10.203.0.1을 더하고 dnsmasq 를 재시작하지 않고 반영한다. 반영 전후의 dnsmasq 주 프로세스 PID 를/root/infra/reload.txt에pid_before=·pid_after=로 적는다./etc/chrony/conf.d/airgap-server.conf로 chrony 가 사내 대역에 시간을 내주고, 상류가 없어도 층위 8 로 기준이 되게 한다.client에서 시계를 바꾸지 않고10.203.0.1에 시간을 물어 그 출력을/root/infra/ntp-query.txt에 저장한다.- 인계용 점검 스크립트
/root/infra/check.sh <네임스페이스>를 쓴다. 그 네임스페이스에서registry·pypi·ntp가 풀리고 시간 서버가 답하면 0, 아니면 0 이 아닌 값으로 끝난다.
참고
- 영역 권한:
local=/airgap.internal/· 상류 끊기:no-resolv· 이름표 파일:addn-hosts=<파일> - 확인:
dig @10.203.0.1 registry.airgap.internal +short, 없는 이름의 상태:dig @10.203.0.1 nope.airgap.internal | grep status - dnsmasq 에 SIGHUP:
systemctl reload dnsmasq또는kill -HUP <PID>· 주 PID:systemctl show -p MainPID --value dnsmasq - chrony 상태:
chronyc -n tracking, 클라이언트 목록:chronyc -n clients· 시계를 바꾸지 않는 질의:chronyd -Q '<server 줄>' - 흔한 실수 1:
local=없이no-resolv만 두기. 모르는 사내 이름에 '없음'(NXDOMAIN) 대신 '대답하지 않겠다'(REFUSED)가 나가, 클라이언트는 그 이름이 없다고 결론 내지 못하고 다음 서버를 찾습니다. - 흔한 실수 2:
addn-hosts를 고친 뒤 dnsmasq 를 재시작하기. 되긴 하지만 캐시와 질의 로그가 끊깁니다 — 이름표 파일은 SIGHUP 으로 다시 읽힙니다.
바깥 송신을 막아 폐쇄망 만들기
/root/infra/egress.sh 로 바깥 송신을 막고(체인 AIRGAP-EGRESS), 막기 전후의 https://ubuntu.com 상태 코드를 /root/infra/egress-proof.txt 에 before=·after= 로 적는다.
새 체인을 만들어 OUTPUT 맨 앞에서 그리로 보내면, 비우고 다시 채우는 방식으로 몇 번을 돌려도 같은 모양이 됩니다. 살릴 것(루프백, 이미 맺은 연결, 채점 에이전트, 사내 대역)을 먼저 RETURN 으로 적고 마지막에 막습니다.
상류 없는 사내 DNS
/etc/dnsmasq.d/airgap.conf 로 dnsmasq 가 10.203.0.1 에서만 듣고 상류 없이 airgap.internal 을 권한으로 답하게 하고, 이름표는 /etc/airgap/hosts 에 두어 읽게 한다. 서비스를 살리고 부팅 때도 뜨게 한다.
듣는 주소를 하나로 좁히는 두 줄, 상류를 끊는 한 줄, 영역을 로컬로 선언하는 한 줄, 이름표 파일을 읽는 한 줄이 필요합니다. 없는 사내 이름이 곧바로 '없음' 으로 답해지는지 dig 의 status 로 확인하세요.
다른 서버가 사내 DNS 를 쓰게
client 가 10.203.0.1 과 검색 도메인 airgap.internal 을 쓰게 /etc/netns/client/resolv.conf 를 쓴다.
ip netns exec 는 /etc/netns/<이름>/resolv.conf 가 있으면 그 네임스페이스 안에서 /etc/resolv.conf 자리에 끼워 줍니다. nameserver 와 search 두 줄이면 됩니다. 확인은 client 안에서 짧은 이름으로 dig +search.
재시작 없이 이름 더하기
/etc/airgap/hosts 에 nexus.airgap.internal → 10.203.0.1 을 더하고 dnsmasq 를 재시작하지 않고 반영한다. 반영 전후의 주 프로세스 PID 를 /root/infra/reload.txt 에 pid_before=·pid_after= 로 적는다.
dnsmasq 는 SIGHUP 을 받으면 캐시를 비우고 /etc/hosts 와 addn-hosts 파일을 다시 읽습니다(설정 파일 자체는 다시 읽지 않습니다). systemd 의 reload 가 무엇을 보내는지도 확인해 보세요.
상류 없는 사내 시간 서버
/etc/chrony/conf.d/airgap-server.conf 로 chrony 가 10.203.0.0/24 에 시간을 내주고, 상류가 없어도 층위 8 로 기준이 되게 한다.
chrony 는 기본으로 아무 클라이언트도 받지 않습니다. 받을 대역을 허락하는 지시자와, 상류 없이 자기 시계를 기준으로 내주는 지시자가 필요합니다. 우분투의 chrony.conf 는 conf.d 를 읽습니다. 바꾼 뒤 서비스를 다시 띄우고 tracking 의 Stratum 을 보세요.
다른 서버에서 시간 묻기
client 에서 시계를 바꾸지 않고 10.203.0.1 에 시간을 물어 출력을 /root/infra/ntp-query.txt 에 저장한다.
chronyd 에는 설정 파일 대신 명령줄 지시자로 한 번 묻고, 시계는 바꾸지 않고 차이만 찍고 끝나는 모드가 있습니다. 네임스페이스 안에서 돌리고, 몇 초 기다리도록 제한 시간을 주세요.
인계용 점검 스크립트
/root/infra/check.sh <네임스페이스> 를 쓴다. 그 네임스페이스에서 registry·pypi·ntp 가 풀리고 시간 서버가 답하면 0, 아니면 0 이 아닌 값으로 끝난다.
채점기는 이 스크립트를 client 와, 사내망에 이어지지 않은 빈 네임스페이스 두 곳에 돌립니다. 앞의 것은 0, 뒤의 것은 0 이 아니어야 합니다. dig 와 chronyd -Q 에 짧은 제한 시간을 주세요.