Ansible: CoreDNSの設定

## 概要
Ansibleを使ってCoreDNSを設定します。
インベントリには各サーバのIPアドレスとホスト名の対応関係が記載されているので、まずはその値を`/etc/hosts`に書き出します。
その後、CoreDNSのhostsプラグインを使って参照します。


## プレイブックとテンプレート
プレイブックとテンプレートは次の通りです。
CoreDNSの最新バイナリをGitHubリリースから取得しています。
GitHubから最新リリースのバイナリURLを取得する方法は、[GitHubリリースからPythonパッケージをインストールする](https://qiita.com/jkawamoto/items/f60c84145f105c227b97)を参照してください。
変数`arch`はamd64やarm64といったCPUアーキテクチャ名です。
使用可能なアーキテクチャは、[CoreDNSのリリースページ](https://github.com/coredns/coredns/releases)を参照してください。

```yaml
- hosts: dns_servers
  become: true 
  gather_facts: false
  tasks:
    - name: Update /etc/hosts with inventory information
      ansible.builtin.lineinfile:
        path: /etc/hosts
        line: "{{ item.value.ansible_host }} {{ item.key }}"
      loop: "{{ lookup('dict', hostvars) }}"

    - name: Find the latest version of CoreDNS
      ansible.builtin.uri:
        url: "https://api.github.com/repos/coredns/coredns/releases/latest" 
      register: coredns_release_info

    - name: Download the latest version
      ansible.builtin.get_url:
        url: "{{ item.url }}"
        headers:
          Accept: application/octet-stream
        dest: "/tmp/{{ item.name }}"
        mode: "0644"
      loop: "{{ coredns_release_info.json | community.general.json_query(_query) }}"
      vars:
        _query: "assets[?ends_with(name, linux_{{ arch }}.tgz )].{name: name, url: url }"
      register: coredns_package_files

    - name: Copy the downloaded binary
      ansible.builtin.unarchive:
        src: "{{ item.dest }}"
        dest: /usr/local/bin/
        owner: root
        group: root
        mode: "0755"
        remote_src: true
      loop: "{{ coredns_package_files.results }}"
      notify:
        - coredns is updated

    - name: Ensure /etc/coredns exists
      ansible.builtin.file:
        path: /etc/coredns
        state: directory
        mode: "0755"

    - name: Upload a configuration file
      ansible.builtin.template:
        src: Corefile.j2
        dest: /etc/coredns/Corefile
        mode: "0644"
      notify:
        - configuration is updated

    - name: Upload an unit file
      ansible.builtin.template:
        src: coredns.service.j2 
        dest: /etc/systemd/system/coredns.service 
        mode: "0644"
      notify:
        - unit file is updated

  handlers:
    - name: Reload systemd daemon
      ansible.builtin.systemd:
        daemon_reload: true
      listen:
        - unit file is updated

    - name: Restart CoreDNS
      ansible.builtin.systemd:
        name: coredns
        state: restarted
      listen:
        - unit file is updated
        - coredns is updated
        - configuration is updated

  post_tasks:
    - name: Ensure CoreDNS is enabled
      ansible.builtin.systemd:
        name: coredns
        state: started
        enabled: true
```

systemd用ユニットファイルのテンプレートです。
特に変数を参照してはいませんが、一応テンプレート扱いにしています。

```jinja:templates/coredns.service.j2
[Unit]
Description=CoreDNS
Wants=network-online.target
After=network-online.target

[Service]
ExecStart=/usr/local/bin/coredns -logtostderr -conf /etc/coredns/Corefile
Type=simple

[Install]
WantedBy=multi-user.target
```

Corefileのテンプレートです。移譲先にCloudflareのパブリックDNSを設定しました。

```jinja:templates/Corefile.j2
. {
    forward . tls://1.1.1.2 tls://1.0.0.2 {
        tls_servername security.cloudflare-dns.com
        health_check 5s
    }
    cache
    errors
    log
}

{{ my_domain }} {
    hosts {
        fallthrough
    }
    errors
    log
}
```

## 参考
- [Use DNS over TLS with Cloudflare 1.1.1.1 for Families](https://pratikpc.medium.com/use-dns-over-tls-with-cloudflare-1-1-1-1-for-families-b332a1d1a1a9)
- [パブリックDNSまとめ(ざっくり)](https://qiita.com/h_tyokinuhata/items/1684ab0b2f039f1c64eb)