3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Docker+DNS入門 その2:Unboundを用いたキャッシュDNSサーバ構築

Last updated at Posted at 2022-09-18

本記事はDocker+DNS入門 その1:CoreDNSを用いた権威DNSサーバ構築の続きの記事になります.

今回はローカルのdocker環境にUnboundによるキャッシュDNSサーバを構築し,前回の記事で構築した2つの権威DNSサーバへの反復問い合わせを実現します.

対象者

  • DNSの基礎的な知識はあるが,実装したことがない方

実行環境

システムの全体像

Docker環境に3つのDNSサーバを構築します.
2つの権威DNSサーバがそれぞれ管理するドメインに対して,自前のキャッシュDNSサーバが名前解決を行います.
権威DNSサーバ1はexample.orgのドメインを管理し,そのサブドメイン"home".example.orgの管理を権威DNSサーバ2が委譲します.
前回の記事 Docker+DNS入門 その1:CoreDNSを用いた権威DNSサーバ構築でCoreDNSを用いて権威DNSサーバを構築しました.
今回はキャッシュDNSサーバを構築します.

用意するファイル

本記事では前回の記事で用意したファイルに,full_resolver配下を追加します.

$ tree -a dns_test/
dns_test/
├── compose.yml
├── .env
├── example_auth
│   ├── Corefile
│   └── zone
│       └── db.example.org
├── home_example_auth
│   ├── Corefile
│   └── zone
│       └── db.home.example.org
└── full_resolver
    ├── Dockerfile
    └── server.conf

Unboundの設定

  1. Dockerfileを作成

    ./full_resolver/Dockerfile
    
    FROM ubuntu:22.04
    
    # Install unbound
    RUN set -x \
       && apt-get update && apt-get install -y --no-install-recommends \
       unbound=1.13.1-1ubuntu5.3 \
       curl \
       ca-certificates \
       && apt-get clean \
       && rm -r /var/lib/apt/lists/*
    
    RUN curl -o /etc/unbound/root.hints -LO https://www.internic.net/domain/named.cache
    RUN chown -R unbound:unbound /etc/unbound
    
    # unbound-anchor: DNSSEC検証のためのルートトラストアンカーの設置と更新
    RUN unbound-anchor -4 -a "/var/lib/unbound/root.key" ; ls -al /var/lib/unbound/root.key
    
    # unbound-checkconf: unboundの設定のエラーを検査
    RUN unbound-checkconf
    
    • set -xによってその後に実行したコマンド自体を標準出力します.
      • これによって,&&で複数コマンドをまとめて実行したときの状況が見やすくなります.
    • RUN curl ~によってルートヒント (ルートDNSサーバのIPアドレスが記載されているファイル) をダウンロードし,docker内に配置します.
    • RUN chown -R unbound:unbound /etc/unboundによって,所有者をunboundに変更し,ルートヒントを読み込めるようにします.
    • unbound-anchorによってDNSSEC検証に必要なルートトラストアンカー (root.key) を取得します.
      • 本記事ではDNSSECを利用しないため,機能的には不要ですが,unbound-checkconfでroot.keyがないと怒られるので取得しておきます.(DNSSECは次回の記事で実装します.)
      • オプション
        • -4: トラストアンカーを提供するサーバにアクセスする際に,ipv4を利用します.dockerはデフォルトだとipv6通信ができないため.
        • -a "/var/lib/unbound/root.key": root.keyを生成するパスを指定します.
    • unbound-checkconfによって,unboundの設定に誤りがないか検査します.

    unbound-anchorの注意点

    ただし,このままではunbound-anchorによってroot.keyが生成されているにも関わらず,Dockerfile上ではエラー扱いになります.(Unbound 1.16.2)
    そこで,unbound-anchorの後に; ls -al /var/lib/unbound/root.keyを加えます.
    これにより,unbound-anchorの実行結果にかかわらずlsコマンドを呼び出し,root.keyが存在すれば正常とみなして,Dockerfileをエラー終了させないようにします.

  2. unboundの設定ファイル (server.conf) を作成

    ./full_resolver/server.conf
    server:
        verbosity: 4
        do-daemonize: no
        do-ip6: no
        do-ip4: yes
        root-hints: root.hints
    
        # module-config: "validator" or "iterator"
        module-config: "iterator" 
    
        # trust-anchor
        auto-trust-anchor-file: "/var/lib/unbound/root.key"
    
        # access-control
        access-control: 0.0.0.0/0 refuse
        access-control: 127.0.0.0/8 allow_snoop
        access-control: 172.19.0.0/16 allow_snoop
    
        # interface
        interface: 0.0.0.0
    
        # stub-zone
        stub-zone:
            name: "example.org"
            stub-addr: 172.19.0.21
        stub-zone:
            name: "0.19.172.in-addr.arpa."
            stub-addr: 172.19.0.21
    
    • root.hints:でDockerfileでダウンロードしたルートヒントを指定します.
    • module-config:で"iterator"を指定することで,DNSSECを無効にします.
    • auto-trust-anchor-file:でDockerfileでダウンロードしたトラストアンカーを指定します.
    • access-contorl:でこのサーバにアクセス可能なクライアントのIPアドレスの範囲(ここではプライベートIP)を指定します.
    • interface:でunboundがリクエストを受け付ける(リッスンする)インターフェースのIPアドレスを指定します.
      • デフォルトではlocalhost (172.0.0.1) ですが,外部と通信するので,任意のインターフェース (0.0.0.0) で受け付けます.
    • stub-zone:によって,あるゾーンに対応する権威DNSサーバを設定します.
      • ゾーン名をname:,その権威DNSサーバのIPアドレスをstub-addr:で指定します.

dockerの設定

  • compose.ymlを作成
    • 前回の記事からfull_resolver:の部分を追加しています.
    • これを実行することで,前回の記事で構築した2つの権威DNSサーバと,今回構築するキャッシュDNSサーバが起動します.
    ./compose.yml
    services:
        example_auth:
            image: coredns/coredns:1.11.1
            container_name: example_auth
            restart: on-failure
            volumes:
                - './example_auth:/etc/coredns'
            networks:
                dns_test:
                    ipv4_address: $ipv4_example_auth
            command: -conf /etc/coredns/Corefile -dns.port $dns_port
        home_example_auth:
            image: coredns/coredns:1.11.1
            container_name: home_example_auth
            restart: on-failure
            volumes:
                - './home_example_auth:/etc/coredns'
            networks:
                dns_test:
                    ipv4_address: $ipv4_home_example_auth
            command: -conf /etc/coredns/Corefile -dns.port $dns_port
        full_resolver:
            container_name: full_resolver
            build:
                context: './full_resolver'
                dockerfile: Dockerfile
            restart: on-failure
            volumes:
                - '/etc/unbound'
                - './full_resolver:/etc/unbound/unbound.conf.d'
            networks:
                dns_test:
                    ipv4_address: $ipv4_full_resolver
            command: /usr/sbin/unbound
    networks:
        dns_test:
            external: true
    
  • compose.yml内の変数は./.envに記述
    ./.env
    dns_port=53
    ipv4_full_resolver=172.19.0.11
    ipv4_example_auth=172.19.0.21
    ipv4_home_example_auth=172.19.0.31
    

動作確認

権威DNSサーバの起動

compose.ymlがあるディレクトリでdocker compose upを実行します.

Ubuntu-22.04 (WSL2)
~/dns_test$ docker compose up
[+] Running 3/0
 ✔ Container home_example_auth  Cre...                               0.0s 
 ✔ Container full_resolver      Created                              0.0s 
 ✔ Container example_auth       Created                              0.0s 
Attaching to example_auth, full_resolver, home_example_auth
full_resolver      | [1704280672] unbound[1:0] debug: creating udp4 socket 0.0.0.0 53
full_resolver      | [1704280672] unbound[1:0] debug: creating tcp4 socket 0.0.0.0 53
full_resolver      | [1704280672] unbound[1:0] debug: creating tcp4 socket 127.0.0.1 8953
full_resolver      | [1704280672] unbound[1:0] debug: setup SSL certificates
full_resolver      | [1704280672] unbound[1:0] debug: switching log to syslog
example_auth       | example.org.:53
example_auth       | [INFO] plugin/reload: Running configuration SHA512 = ~~~
example_auth       | CoreDNS-1.11.1
example_auth       | linux/amd64, go1.20.7, ae2bbc2
home_example_auth  | home.example.org.:53
home_example_auth  | [INFO] plugin/reload: Running configuration SHA512 = ~~~
home_example_auth  | CoreDNS-1.11.1
home_example_auth  | linux/amd64, go1.20.7, ae2bbc2

キャッシュDNSサーバによる名前解決

  • 構築したキャッシュDNSサーバに対して,WSL2から再帰問い合わせを行います.
  • まず権威DNSサーバ1 (example.orgサーバ) の内容を問い合わせ,名前解決できていることを確認します.
    権威DNSサーバの内容は前回の記事と同じです.
    Ubuntu-22.04 (WSL2)
    $ dig +nocookie @172.19.0.11 ns1.example.org
    
    ; <<>> DiG 9.18.18-0ubuntu0.22.04.1-Ubuntu <<>> +nocookie @172.19.0.11 ns1.example.org
    ; (1 server found)
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34321
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
    
    ;; OPT PSEUDOSECTION:
    ; EDNS: version: 0, flags:; udp: 1232
    ;; QUESTION SECTION:
    ;ns1.example.org.               IN      A
    
    ;; ANSWER SECTION:
    ns1.example.org.        86400   IN      A       172.19.0.21
    
    ;; Query time: 0 msec
    ;; SERVER: 172.19.0.11#53(172.19.0.11) (UDP)
    ;; WHEN: ~~~
    ;; MSG SIZE  rcvd: 60
    
  • 同様に権威DNSサーバ2 (home.example.orgサーバ) の内容を問い合わせ,名前解決できていることを確認します.
    Ubuntu-22.04 (WSL2)
    $ dig +nocookie @172.19.0.11 www.home.example.org
    
    ; <<>> DiG 9.18.18-0ubuntu0.22.04.1-Ubuntu <<>> +nocookie @172.19.0.11 www.home.example.org
    ; (1 server found)
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18139
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
    
    ;; OPT PSEUDOSECTION:
    ; EDNS: version: 0, flags:; udp: 1232
    ;; QUESTION SECTION:
    ;www.home.example.org.          IN      A
    
    ;; ANSWER SECTION:
    www.home.example.org.   86400   IN      A       172.19.0.33
    
    ;; Query time: 0 msec
    ;; SERVER: 172.19.0.11#53(172.19.0.11) (UDP)
    ;; WHEN: ~~~
    ;; MSG SIZE  rcvd: 65
    
    この結果から,再帰問い合わせが機能していることが分かります.
    Unboundの設定(server.conf)で,example.orgドメインのstub-zoneを権威DNSサーバ1としているため,www.home.example.orgの問い合わせはまず権威DNSサーバ1へ送られます. そのあと,権威DNSサーバ1から権威DNSサーバ2への委譲され,名前解決されています.

次回の話

これまでの権威DNSサーバ,キャッシュDNSサーバの構築では,簡単のためDNSSEC機能を無効化していました.
しかし,実際にはDNSSEC機能を無効にすると,キャッシュDNSサーバの問い合わせに対して,偽装された回答が送られてもそれを受け入れてしまいます (DNSキャッシュポイズニング).
次回の記事では,これまで構築してきたDNSサーバにDNSSEC機能を実装します.

3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?