Go, Vantage point
가까운 곳을 걷지 않고 서는 먼 곳을 갈 수 없다.
Github | https://github.com/overnew/
Blog | https://everenew.tistory.com/
티스토리 뷰
최종 완성 DNS image 바로 실행하기
docker run -d --name dns-server -p 53:53/udp --restart=always everenew/dns-jin:latest
https://hub.docker.com/repository/docker/everenew/dns-jin
아래에서는 글은 위의 이미지를 만들기 위한 세팅 방법과 연결 테스트 정보를 담았다.
DNS 이미지 실행
docker run -d --name dns-server -p 53:53/udp --restart=always sameersbn/bind:latest
ubuntu에 bind9 이 설치된 이미지이다.
UDP 53번 포트는 DNS 프로토콜이 동작하는 포트이므로 이를 노출시키자.
단 실행 시에, 포트 오류가 발생하는데, 53번 포트가 이미 사용 중이라 실행이 안 되는 상황이다.
systemd-resolved
netstat -lntup 명령어로 확인해보면 53번 포트는 systemd-resolved가 LISTEN 중이다.
Listen 상태인 프로그램은 다른 장치나 프로그램이 해당 포트로 연결을 시도할 때, 연결을 받아들일 준비가 되어있는 것이다.
기본적으로 nano /etc/resolv.conf에서 세팅이 없다면, nameserver가 127.0.0.53으로 설정되어 있다.
이 Local address 127.0.0.53:53은 systemd-resolved가 사용 중인 것으로 확인된다.
/run/systemd/resolve/ 를 확인해보면, 실제 사용할 dns server 주소가 존재한다.
이 systemd-resolved가 DNS 쿼리를 날리고, 수신하는 주체가 되는 데몬이다.
실행 중인 systemd-resolved를 중지시키자.
systemctl stop systemd-resolved
더 이상 53 UDP port를 사용 중인 프로세스가 없다.
이제 다운로드한 dns-server image를 실행하자.
DNS server container 세팅
docker exec -it dns-server /bin/bash
로 dns 서버 접속
Nano 편집기 설치를 위해
apt-get update
apt-get install nano
nano /etc/default/named
-4로 ipv4만 사용
Hostname -I 로 container의 IP를 확인
nano / etc/bind/named.conf.options #기본 옵션설정
acl "trusted" { #option 위에
any; # 모든 IP 허용
};
#option 안에
//listen-on-v6 { any; }; # disable bind on IPv6
recursion yes; # enables resursive queries
allow-recursion { trusted; }; # allows recursive queries from "trusted" - referred to ACL
listen-on { 172.17.0.2; }; # ns1 IP address
allow-transfer { none; }; # disable zone transfers by default
nano /etc/bind/named.conf.local # Zone 명시
zone "team1.com" {
type master;
file "/etc/bind/zones/db.team1.com"; # zone file path
};
영역 데이터 베이스를 만들어 주자.
mkdir -p /etc/bind/zones/
cp /etc/bind/db.local /etc/bind/zones/db.team1.com #기본 파일 복사
nano /etc/bind/zones/db.team1.com #Zone record 설정
$TTL 604800
@ IN SOA root.team1.com. root.team1.com. (
2022013101 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
; Name servers
@ IN NS root.team1.com.
; Define hosts in the domain
root.team1.com. IN A 192.168.137.1
apache.team1.com. IN A 192.168.137.1
nginx.team1.com. IN A 192.168.137.124
named-checkconf 로 구문 오류 확인
어떠한 출력도 없다면 오류가 없다.
named-checkzone team1.com /etc/bind/zones/db.team1.com
OK 확인.
이후 service named restart로 프로세스 재시작
재시작 시, 접속이 끊기므로 다시 접속하자.
Nameserver 주소 설정
Container의 nameserver를 확인해 보면, 자기 자신을 가리키고 있다.
nano /etc/resolv.conf
nameserver 172.17.0.2 만 남겨주자.
이후 container를 나가고 ubuntu server의 nameserver를 변경한다.
nano /etc/resolv.conf
nameserver 127.0.0.1
자기 자신으로 설정하면, 자기 자신의 53번 포트로 dns 쿼리가 나간다.
이 53번 포트가 container의 53번 포트와 연결되어 있으므로 dns 컨테이너에게 쿼리가 된다.
또는 nameserver 172.17.0.2로 설정해서 컨테이너에게 직접 쿼리 할 수도 있다.
이제 nslookup을 하면 172.17.0.2로 정상적으로 쿼리가 된다.
NAT 포트포워딩 및 실습 목표 해설
DNS는 자신이 쓰기 위한 것이 아니라 외부에서 DNS 서비스를 사용하기 위함이다.
이 실습의 목표 두대의 PC를 연결하여 서로의 Ubuntu server가 DNS 를 사용해 서로의 Web server container에 접속하는 것이다. 이때 두 대의 PC가 연결되기 위해서 같은 공유기의 wifi를 사용하면 되지만, 네트워크 보안 관련으로 서로의 연결이 차단될 수 있다.
-p로 설정하는 port에 따라 VM의 특정 포트의 트래픽이 이동한다.
우리는 dns container 실행 시, -p 53:53/udp 옵션을 주었기 때문에, VM의 UDP 53번 port로 오는 트래픽이 container로 이동하게 된다.
웹서버 container를 실행한다면, -p (원하는 포트):80 옵션으로 VM의 특정 포트의 트래픽의 web server container로 전달할 수 있다.
우리는 두 PC를 공유기를 사용하기보다는 노트북의 핫스팟 기능을 사용해서 같은 네트워크로 만들어주자.
핫스팟을 설정한 노트북(192.168.137.1)이 해당 네트워크(192.168.137.0/24)의 게이트웨이의 역할도 하게 된다.
192.168.137.1의 53 UPD 연결은 VM NAT의 53 UDP 포트로 연결하자.
이제 상대 VM의 nameserver를 192.168.137.1로 바꾸어 주면, 아래와 같은 Flow로 DNS 요청이 전달된다.
192.168.137.1:53 (핫스팟 PC) -> 10.0.2.15:53 (ubuntu VM) -> 172.17.0.2:53 (DNS Container)
정상적으로 DNS 쿼리가 수행된다.
DNS를 이용한 Web server 접속을 위해 8080포트를 nginx 컨테이너의 80번과 매칭해 실행시킨다.
sudo docker run -d -p 8080:80 nginx
포트포워딩으로 192.168.137.1:8080 tcp port를 10.0.2.15:8080으로 연결하였으므로, 아래와 같은 Flow로 HTTP 요청이 전달된다.
192.168.137.1:8080 (root.team1.com:8080) -> 10.0.2.15:8080 (ubuntu VM) -> 172.17.0.3:80 (Nginx Container)
상대 PC(192.168.137.124)의 VM NAT 포트포워딩을 동일하게 진행하면, 상대의 webserver에 접속할 수 있다.
Ubnutu server DNS(in PC1)와 Container DNS(in PC2) 동시 사용
이제 Ubnutu server에는 main DN 주소를
Container DNS에는 sub DN 주소를 넣어서, 자신에게 없는 DN이라면 서로에게 질의해서 데이터를 가져오는 방식을 구현해 보자.
이때 사용하는 것이 forwarders옵션이다.
Forwarders 세팅
nano /etc/bind/named.conf.options #기본 옵션설정
DNS 서버에서 forwarders 옵션은 서버가 리졸브를 위해 다른 DNS 서버에 질의를 전달하는 방법을 지정한다. 이 옵션을 사용하면 DNS 서버가 직접 인터넷상의 루트 DNS 서버 등을 쿼리 하는 대신 특정 다른 DNS 서버(예: ISP가 제공하는 DNS 서버)에게 질의를 전달할 수 있다.
즉, 자신의 레코드에 존재하지 않는 데이터는 forwarder에 명시한 DNS sever 주소로 질의하게 된다.
하지만 내부에서 사용하는 DNS인데, 자신에게 없는 레코드를 외부의 DNS 서버를 사용하도록 만들진 않는다.
보통은 forwarder에 설정되는 DNS 서버는 캐시 서버이다.
이러한 포워더 세팅을 위해 DNSSEC 기능을 OFF 시키자.
DNSSEC(DNS Security Extensions)
DNSSEC(DNS Security Extensions)은 DNS 데이터 대상의 "데이터 위조-변조 공격"을 방지하기 위한 인터넷 표준기술이다.
DNS 데이터의 위조-변조 가능성을 원천적으로 차단하기 위해, DNSSEC은 공개키 암호화방식(Public Key Cryptography)의 전자서명 기술을 DNS 체계에 도입 적용하였다. 공개키 암호화방식의 전자서명 메커니즘은 금융권 등에서 널리 사용하는 공인인증서가 사용하고 있는 기술이다.
이 기술을 활용해 피싱과 파밍 공격으로부터 DNS를 신뢰할 수 있게 만든다.
dnssec-validation 값은 디폴트로 yes로 설정되어 있다.
따라서 forwarder서버에게 DNSSEC 활성화 ZONE의 reply을 검증하려고 시도한다.
options {
dnssec-enable yes;
dnssec-validation yes; # enable DNSSEC validation
};
(default value is dnssec-validation yes;)
이 옵션을 사용하면 복잡한 키설정이 필요하므로, 비활성화시켜주어야 forwarder 서버로 쿼리를 제대로 받아올 수 있다.
nano /etc/bind/named.conf.options #서로의 설정파일에서 dnssec 비활성화
dnssec-validation no;
이제 forwarder로 받아온 데이터는 Non-authoritative answer로 표현된다.
이는 신뢰하지 못할 수 있는 IP이므로 주의가 필요함을 의미한다.
Ubuntu server DNS 설정법
이전에 정리해 둔 게시글을 참조하자.
https://everenew.tistory.com/348
각각의 zone 설정 법
Ubnutu의 DNS와 Conatianer의 DNS가 같은 Zone 데이터를 가지고 있다면, 해당 Zone 데이터에 없는 DN은 forwarder에게 질의하지 않고 찾을 수 없다고 반환한다.
(서로 babo.com에 대한 데이터를 가지고 있기 때문에, 자신의 Zone에서 데이터를 찾아보고 없다면 찾을 수 없다는 메시지를 보낸다.)
따라서 적어도 zone의 이름은 다르게 사용해야 식별이 가능해진다.
예를 들어 메인이 되는 쪽은 babo.com을 사용하고
zone "babo.com" {
type master;
file "/etc/bind/zones/db.babo.com"; # zone file path
};
Sub가 되는 쪽은 sub.babo.com을 사용하게 한다.
zone "sub.babo.com" {
type master;
file "/etc/bind/zones/db.sub.babo.com"; # zone file path
};
여기까지의 진행을 마친 container의 이미지를 docker hub에 업로드해두었다.
아래 명령어로 실행가능 하다.
docker run -d --name dns-server -p 53:53/udp --restart=always everenew/dns-jin:latest
https://hub.docker.com/repository/docker/everenew/dns-jin
다른 PC의 VM내의 DNS container를 서로 사용하기
노트북 두대를 핫스팟으로 연결하자.
이때 서로 간의 통신을 하려면 공용 네트워크 방화벽을 꺼주어야 한다.
Docker hub 이미지 활용하기
위에서 사용한 이미지를 그대로 사용해 주면 편리하다.
docker run -d --name dns-server -p 53:53/udp --restart=always everenew/dns-jin
이제 각 container에 들어가자.
docker exec -it dns-server /bin/bash
forwarder설정에서 서로의 PC ip를 가리키도록 변경한다.
nano /etc/bind/named.conf.options
superbaboy.com DNS setting
한쪽의 DNS Container가 superbaboy.com zone을 명시한다.
nano /etc/bind/named.conf.local
zone "superbaboy.com" {
type master;
file "/etc/bind/zones/db.superbaboy.com"; # zone file path
};
mkdir -p /etc/bind/zones/
cp /etc/bind/db.local /etc/bind/zones/db.superbaboy.com
nano /etc/bind/zones/db.superbaboy.com
$TTL 604800
@ IN SOA superbaboy.com. root.superbaboy.com. (
2022013101 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
; Name servers
@ IN NS superbaboy.com.
; Define hosts in the domain
superbaboy.com. IN A 192.168.137.1
cafe1.superbaboy.com. IN A 192.168.137.1
named-checkconf 로 구문 오류 확인
named-checkzone superbaboy.com /etc/bind/zones/db.superbaboy.com
service named restart #설정 후 재시작
nano /etc/resolv.conf #DNS 주소 변경
sub.superbaboy.com DNS setting
다른 쪽의 DNS Container가 sub.superbaboy.com zone을 명시한다.
nano /etc/bind/named.conf.local
zone "sub.superbaboy.com" {
type master;
file "/etc/bind/zones/db.sub.superbaboy.com"; # zone file path
};
mkdir -p /etc/bind/zones/
cp /etc/bind/db.local /etc/bind/zones/db.sub.superbaboy.com
nano /etc/bind/zones/db.sub.superbaboy.com
$TTL 604800
@ IN SOA sub.superbaboy.com. root.sub.superbaboy.com. (
2022013101 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
; Name servers
@ IN NS sub.superbaboy.com.
; Define hosts in the domain
sub.superbaboy.com. IN A 192.168.137.178
cafe2.superbaboy.com. IN A 192.168.137.178 # sub.가 아니기 때문에 질의가 안됨.
cafe2.sub.superbaboy.com. IN A 192.168.137.178
named-checkconf
named-checkzone superbaboy.com /etc/bind/zones/db.sub.superbaboy.com
cafe2.superbaboy.com. 가 Zone을 벗어났다는 구문이 출력된다. (sub. superbaboy에 속하지 않게 만들었기 때문. 질의해 보면 질의가 안된다.)
service named restart #세팅 후 재시작
NAT 세팅
서로에게 DNS 질의가 갈 수 있도록 세팅
결과
자신의 zone에서 찾을 수 없는 DN은 forwarder 서버로부터 가져온다.
Zone을 벗어난 cafe2.superbaboy.com. 는 찾아오지 못한다.
따라서 Zone 설정에서는 두 DNS가 같은 Zone을 사용해서 서로에게 받아오는 구성은 할 수 없다.
이러한 설정을 하려면 master – slave로 서로 간의 zone 파일을 동기화하거나, sub.처럼 sub Zone을 나누어 구현할 필요가 있다.
또는 Glue record라는 기능을 사용할 수 있다.
'개발 > Docker' 카테고리의 다른 글
Docker container storage (docker run -v), 볼륨과 마운트 차이 (0) | 2024.02.28 |
---|---|
Docker Hub에 Docker Image 업로드하기 (0) | 2024.02.28 |
[Virtual Box] Ubuntu에 Jenkins container 올리고 접속하기 (0) | 2024.02.28 |
Docker exec와 attach의 차이 (docker run) (0) | 2024.02.21 |
[Github Actions] 여러 Docker image 빌드하고 ECR로 업로드 하기 (0) | 2023.08.18 |