PowerDNSのAPIを使ってレコードを追加してみる

前回作成した、PowerDNS Authoritative Serverのdocker環境を使ってレコード情報を登録してみます。

レコードを追加する方法としては、以下の方法があります。

  • ビルトインのAPI経由で更新
  • nsupdateコマンド経由で更新
  • 直接SQLでDBに書き込んで更新

このうち、今回は ビルトインのAPI経由で更新 をやってみます。

参考情報

公式のドキュメントを参考に見ていきます。 https://doc.powerdns.com/authoritative/http-api/index.html

認証する

設定ファイル api-key に設定されている値を、リクエストヘッダに設定します。

curl -H 'X-API-Key: changeme' http://localhost:8081/api/v1/servers

zone情報を登録する

/servers/{server_id}/zones に向けてPOSTリクエストを送ります。 https://doc.powerdns.com/authoritative/http-api/zone.html#post--servers-server_id-zones

server_idは権威サーバーの場合は常にlocalhostを設定します。

簡単にRubyでクライアントを作成し実行してみます。

module Powerdns
  class Client
    def initialize(url, api_key)
      @connection = Faraday.new(
        url: url,
        headers: {
          'X-API-Key' => api_key,
        }
      )
    end

    def create_zone(zone_name)
      params = {
        "kind": "Master",
        "name": zone_name,
        "rrsets": [{
          "name": zone_name,
          "ttl": 3600,
          "type": "SOA",
          "records": [{
            "content": "dns1.example.jp. admin.example.com. 2020010101 900 600 6048000 300",
            "disabled": false
          }],
        }]
      }

      response = @connection.post do |request|
        request.url("/api/v1/servers/localhost/zones")
        request.headers['Content-Type'] = 'application/json'
        request.body = params.to_json
      end

      response
    end
  end
end

実行

client = Powerdns::Client.new(
      'http://localhost:8081',
      'api-key',
    )
client.create_zone("example.com.")

結果

201が返ってきた

{"account"=>"", "api_rectify"=>false, "dnssec"=>false, "edited_serial"=>2021010201, "id"=>"example.com.", "kind"=>"Master", "last_check"=>0, "master_tsig_key_ids"=>[], "masters"=>[], "name"=>"example.com.", "notified_serial"=>0, "nsec3narrow"=>false, "nsec3param"=>"", "rrsets"=>[{"comments"=>[], "name"=>"example.com.", "records"=>[{"content"=>"dns1.example.jp. admin.example.com. 2021010201 900 600 6048000 300", "disabled"=>false}], "ttl"=>3600, "type"=>"SOA"}], "serial"=>2021010201, "slave_tsig_key_ids"=>[], "soa_edit"=>"", "soa_edit_api"=>"DEFAULT", "url"=>"/api/v1/servers/localhost/zones/example.com."}

レコードを追加する

レコード追加用のエンドポイントはなく、zoneのエンドポイントに対しPATCHメソッドで更新する形のようです。

/servers/{server_id}/zones/{zone_id}

https://doc.powerdns.com/authoritative/http-api/zone.html#patch--servers-server_id-zones-zone_id

レコード追加用のメソッドを追加して実行してみます。

def add_records(name, type, ttl, content)
  params = {
    "rrsets": [
      {
        name: name,
        type: type,
        ttl: ttl,
        changetype: "REPLACE",
        comments: [],
        records: [
          {
            content: content,
            disabled: false
          }
        ],
      }
    ]
  }

  response = @connection.patch do |request|
    request.url("/api/v1/servers/localhost/zones/example.com.")
    request.headers['Content-Type'] = 'application/json'
    request.body = params.to_json
  end

  response
end

実行

client = Powerdns::Client.new(
      'http://localhost:8081',
      'api-key',
    )
client.add_records(
  "www.example.com.",
  "A",
  "300",
  "127.0.0.1",
)

結果

204が返ってきた

レスポンスボディはなし

問い合せをしてみる

Aレコードが登録されていることが確認できました。

dig +norec @localhost -p 1053 www.example.com ANY
;; Truncated, retrying in TCP mode.

; <<>> DiG 9.10.6 <<>> +norec @localhost -p 1053 www.example.com ANY
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28977
;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;www.example.com.               IN      ANY

;; ANSWER SECTION:
www.example.com.        300     IN      A       127.0.0.1

;; Query time: 5 msec
;; SERVER: ::1#1053(::1)
;; WHEN: Sat Jan 02 16:13:19 JST 2021
;; MSG SIZE  rcvd: 60

まとめ

PowerDNSのAPIを軽く触ってみましたが、シンプルでRESTfulなAPIなので使いやすかった印象でした。 細かい設定などは、別途引き続き見ていこうと思います。