legoのIIJ DNSプラットフォームサービスへの対応について

2022年06月17日 金曜日


【この記事を書いた人】
其田 学

元ネットワークエンジニア、今はDNSやらk8sやらを触りながらコードを書く日々を送ってます。

「legoのIIJ DNSプラットフォームサービスへの対応について」のイメージ

はじめに

先日、ACMEクライアントであるlegoが、IIJ DNSプラットフォームサービス(略称DPF)に対応しました。これにより、ACME対応の認証局で発行できる、ドメイン名認証のTLS証明書の発行が簡単に行えるようになりました。

 

legoのIIJ DNSプラットフォームサービスへの対応

旧DNSサービスである、DNSアウトソースサービスは、ACMEクライアントであるlegoに対応しておりました。legoを使うと、ドメイン名認証型のTLS証明書の発行が簡単に行えます。今回、後継サービスであるIIJ DNSプラットフォームサービスでも、legoのv4.7.0からDPF-APIを利用した dns-01 に対応しました。

ACMEは、TLS証明書を発行する仕組みで、発行するTLS証明書のドメイン名の利用権を申請者が保持しているかの検証をします。検証手段として、http-01 dns-01, tls-alpn-01の3種類が提供されています。主に使われているのは http-01とdns-01です。

なお、今回のlegoへの対応は、従来のDNSアウトソースサービスでそうだったのと同じく、IIJ DNSプラットフォームサービスとしての対応ではありません。利用、動作についてのお問い合わせはIIJのサポートセンターでは受け付けられません。ご利用は自己責任でお願いします。

 

利用方法

IIJ DNSプラットフォームサービスでAPIを利用するにはIIJ IDサービスとの連携の利用が必要です。IIJ IDサービスは、サービスオンラインからも契約可能です。(基本料金は無料です)IIJ IDサービスの契約を行い、IIJ IDサービスとの連携を実施すると、IIJ IDサービスのアクセストークンの発行画面から、アクセストークンを発行できるようになります。

legoで必要なscopeはdpf_read, dpf_writeの2種類になります。

 

 

発行するを押すとアクセストークンが表示されます。このアクセストークンを利用してlegoを実行することで、証明書が取得できます。

// version 4.7.0 or later
$ ./lego --version
lego version 4.7.0 darwin/amd64

// $ IIJ_DPF_API_TOKEN="アクセストークン" IIJ_DPF_DPM_SERVICE_CODE="IIJ マネージドDNSサービスのサービスコード" ./lego -m メールアドレス --dns iijdpf -d '*.ドメイン名' -d ドメイン名 run 
$ IIJ_DPF_API_TOKEN="アクセストークン" IIJ_DPF_DPM_SERVICE_CODE="IIJ マネージドDNSサービスのサービスコード" ./lego -m メールアドレス --dns iijdpf -d '*.iijtest-2017061600.org' -d iijtest-2017061600.org  run
2022/06/08 17:07:57 [INFO] [*.iijtest-2017061600.org, iijtest-2017061600.org] acme: Obtaining bundled SAN certificate
2022/06/08 17:07:59 [INFO] [*.iijtest-2017061600.org] AuthURL: https://acme-v02.api.letsencrypt.org/acme/authz-v3/117364146236
2022/06/08 17:07:59 [INFO] [iijtest-2017061600.org] AuthURL: https://acme-v02.api.letsencrypt.org/acme/authz-v3/117364146246
2022/06/08 17:07:59 [INFO] [*.iijtest-2017061600.org] acme: use dns-01 solver
2022/06/08 17:07:59 [INFO] [iijtest-2017061600.org] acme: Could not find solver for: tls-alpn-01
2022/06/08 17:07:59 [INFO] [iijtest-2017061600.org] acme: Could not find solver for: http-01
2022/06/08 17:07:59 [INFO] [iijtest-2017061600.org] acme: use dns-01 solver
2022/06/08 17:07:59 [INFO] [*.iijtest-2017061600.org] acme: Preparing to solve DNS-01
2022/06/08 17:08:11 [INFO] [iijtest-2017061600.org] acme: Preparing to solve DNS-01
2022/06/08 17:08:24 [INFO] [*.iijtest-2017061600.org] acme: Trying to solve DNS-01
2022/06/08 17:08:24 [INFO] [*.iijtest-2017061600.org] acme: Checking DNS record propagation using [1.1.1.1:53]
2022/06/08 17:08:29 [INFO] Wait for propagation [timeout: 11m0s, interval: 5s]
2022/06/08 17:08:34 [INFO] [*.iijtest-2017061600.org] The server validated our request
2022/06/08 17:08:34 [INFO] [iijtest-2017061600.org] acme: Trying to solve DNS-01
2022/06/08 17:08:34 [INFO] [iijtest-2017061600.org] acme: Checking DNS record propagation using [1.1.1.1:53]
2022/06/08 17:08:39 [INFO] Wait for propagation [timeout: 11m0s, interval: 5s]
2022/06/08 17:08:43 [INFO] [iijtest-2017061600.org] The server validated our request
2022/06/08 17:08:43 [INFO] [*.iijtest-2017061600.org] acme: Cleaning DNS-01 challenge
2022/06/08 17:08:55 [INFO] [iijtest-2017061600.org] acme: Cleaning DNS-01 challenge
2022/06/08 17:09:06 [INFO] [*.iijtest-2017061600.org, iijtest-2017061600.org] acme: Validations succeeded; requesting certificates
2022/06/08 17:09:08 [INFO] [*.iijtest-2017061600.org] Server responded with a certificate.
 
$ ./lego list
Found the following certs:
  Certificate Name: *.iijtest-2017061600.org
    Domains: *.iijtest-2017061600.org, iijtest-2017061600.org
    Expiry Date: 2022-09-06 07:09:06 +0000 UTC
    Certificate Path: /Users/manabu-s/.lego/certificates/_.iijtest-2017061600.org.crt

 

dns-01 では、_acme-challenge.${ドメイン名}のTXTレコードに認証情報を追加して、認証局側が確認しています。

 

ここで、変わった使い方を紹介します。

_acme-challenge.$(ドメイン名)にCNAMEレコードを追加し、別のゾーンに向ける方法です。

CNAMEが利用できることはRFCには明確には書かれておりませんが、Let’s Encryptでは利用可能とされています。

ターゲット名: acme-cname-test.iij-20170928-00.tokyo.jp (API非対応のゾーン)
 
// _acme-challengeが、API対応ゾーンにCNAMEで向いている
$ dig _acme-challenge.acme-cname-test.iij-20170928-00.tokyo.jp. +noall +ans
_acme-challenge.acme-cname-test.iij-20170928-00.tokyo.jp. 261 IN CNAME acme-cname-test.iijtest-2017061600.org.
 
// LEGO_EXPERIMENTAL_CNAME_SUPPORT="true" IIJ_DPF_API_TOKEN="アクセストークン" IIJ_DPF_DPM_SERVICE_CODE="CNAMEの正規名ゾーンのサービスコード" ./lego -m メールアドレス --dns iijdpf -d  ターゲット名 run
$ LEGO_EXPERIMENTAL_CNAME_SUPPORT="true" IIJ_DPF_API_TOKEN="****" IIJ_DPF_DPM_SERVICE_CODE="****" ./lego -m メールアドレス --dns iijdpf -d acme-cname-test.iij-20170928-00.tokyo.jp  run
2022/06/08 17:39:30 [INFO] [acme-cname-test.iij-20170928-00.tokyo.jp] acme: Obtaining bundled SAN certificate
2022/06/08 17:39:31 [INFO] [acme-cname-test.iij-20170928-00.tokyo.jp] AuthURL: https://acme-v02.api.letsencrypt.org/acme/authz-v3/117372082476
2022/06/08 17:39:31 [INFO] [acme-cname-test.iij-20170928-00.tokyo.jp] acme: Could not find solver for: tls-alpn-01
2022/06/08 17:39:31 [INFO] [acme-cname-test.iij-20170928-00.tokyo.jp] acme: Could not find solver for: http-01
2022/06/08 17:39:31 [INFO] [acme-cname-test.iij-20170928-00.tokyo.jp] acme: use dns-01 solver
2022/06/08 17:39:31 [INFO] [acme-cname-test.iij-20170928-00.tokyo.jp] acme: Preparing to solve DNS-01
2022/06/08 17:39:44 [INFO] [acme-cname-test.iij-20170928-00.tokyo.jp] acme: Trying to solve DNS-01
2022/06/08 17:39:44 [INFO] [acme-cname-test.iij-20170928-00.tokyo.jp] acme: Checking DNS record propagation using [1.1.1.1:53]
2022/06/08 17:39:49 [INFO] Wait for propagation [timeout: 11m0s, interval: 5s]
2022/06/08 17:39:56 [INFO] [acme-cname-test.iij-20170928-00.tokyo.jp] The server validated our request
2022/06/08 17:39:56 [INFO] [acme-cname-test.iij-20170928-00.tokyo.jp] acme: Cleaning DNS-01 challenge
2022/06/08 17:40:08 [INFO] [acme-cname-test.iij-20170928-00.tokyo.jp] acme: Validations succeeded; requesting certificates
2022/06/08 17:40:10 [INFO] [acme-cname-test.iij-20170928-00.tokyo.jp] Server responded with a certificate.
 
% ./lego list
Found the following certs:
  Certificate Name: *.iijtest-2017061600.org
    Domains: *.iijtest-2017061600.org, iijtest-2017061600.org
    Expiry Date: 2022-09-06 07:09:06 +0000 UTC
    Certificate Path: /Users/manabu-s/.lego/certificates/_.iijtest-2017061600.org.crt
 
  Certificate Name: acme-cname-test.iij-20170928-00.tokyo.jp
    Domains: acme-cname-test.iij-20170928-00.tokyo.jp
    Expiry Date: 2022-09-06 07:40:07 +0000 UTC
    Certificate Path: /Users/manabu-s/.lego/certificates/acme-cname-test.iij-20170928-00.tokyo.jp.crt

LEGO_EXPERIMENTAL_CNAME_SUPPORT=”true”を付与して実行すると、CNAMEの正規名に対する更新になります。この方法であれば、ゾーンがAPIに対応していなくても、APIに対応したゾーンにCNAMEの正規名を設定することで、証明書が発行できます。

また、ACMEに対応するには、レコードの読み書きが必要になります。この方法を利用して、ACMEに関するレコードを1ゾーンにまとめておき、lego用のアクセストークンの権限を、このゾーンだけに与え、最小の権限に止めることもできます。

これからのツールへの対応について

DNSを使ったツールというのはlego以外にも色々あります。例えば、IaC系のツールで言えば、ansibleであったりterraformなどです。最近ではkubernetesで、external-dnsを利用してServiceリソースを元にドメイン名を設定したいという要望もあります。

ただ、竹の子のように現れていくツールに全てに対応していくのは困難です。サービスに依存しないDNS共通のAPI仕様のようなものがあればいいのですが、現状は各社バラバラに開発が行われており、都度サービスに合わせてツールごとに開発が必要な状況です。

ご要望が多いツールを中心に対応していこうと考えておりますが、必ず実装されるとは限りません。便利なものを自作された方は公開していただけると、みなさん助かります。もし何かツールを作成し紹介しても良い場合はこちらからissueに作っていただけると助かります。DPF-APIの仕様はこちらで公開しており、今回使用したgolang用のDPFライブラリはこちらで公開されています。また、DPFのAPIはOpenAPI仕様に基づいて記述されていますので、他言語でも簡単にバイディングを作成できます

別のアプローチとしては、ほとんどのツールで利用可能な RFC2136(Dynamic Update)を利用しAPIを変換するというアプローチもあります。

ただ、この方法にも弱点があります。通常のRFC2136では、権威DNSサーバのメモリ上にあるゾーンの更新するため、すぐにレスポンスが帰ってくることが想定されており、クライアントのタイムアウト時間が非常に短いです。

これに対して、HTTPのAPIの場合は、タイムアウト時間は長めです。RFC2136のレスポンスを返す時にHTTPのAPIを待っていると、タイムアウトが発生する可能性があります。

  • IIJ DNSプラットフォームサービスのAPIは、レコードの追加とゾーン反映が分かれているためほぼ確実に発生します。

そのため、RFC2136でのリクエストをいったんキューに溜め、DNSの応答としては成功で返し、あとからAPIを実行するような動作になります。この場合もし、API実行に失敗した場合でも、ツール側は成功と思っているので、うまく動作しない可能性があります。legoのような、更新後にレコードの確認を行うツールに関しては、レコード確認でエラーが検知できるため、うまく動作します。弊社のSREチームではRFC2136変換を利用し、legoやcert-manager等を動作検証を行ったのちに使用しています。

 

宣伝・告知

IIJは6/24日に開催されるDNS Summer Day 2022にスポンサーとして参加します。スポンサーセッション中に遠隔でも直接エンジニアに質問できます。なお、参加には事前のお申し込みが必要になります。

其田 学

2022年06月17日 金曜日

元ネットワークエンジニア、今はDNSやらk8sやらを触りながらコードを書く日々を送ってます。

Related
関連記事