cert-manager で let's encrypt (ACME) の証明書を LuaDNS を利用しつつ発行する

Let's Encrypt の証明書を発行するフローには ACME HTTP-01 と DNS-01 の2つがある。

HTTP-01 の場合、事前に 80 番ポートで対象となるドメインにファイルを設置する必要があり、またワイルドカード証明書に対応できない (と、思う)。

DNS-01 の場合は対象ドメインDNS の TXT レコードに特定の内容を設定する必要があるが、発行にあたって事前に HTTP 通信を行う必要がないし、ワイルドカード証明書も発行できる。

cert-managerk8s 上で TLS 証明書の取得や更新をするものであり、 ACME DNS-01 に対応している (たぶん HTTP-01 にも対応している)。

DNS の設定をおこなう必要があるが、各種 DNS プロバイダ にオフィシャルに (ビルトインで) 対応している、が、リストをみてもらえるとわかるとおり、有名どころはあるがその数は少ない。

さまざまな DNS プロバイダへの対応コードを cert-manager に組み込んでいくとメンテナンスやクオリティコントロールの面で課題があるので、 cert-managerWebhook Issuer という形で、外部から拡張可能にしているらしい。

野良を含め Webhook Issuer は https://github.com/topics/cert-manager-webhook にリストアップされている。 が、残念ながらわたしが利用している LuaDNS は存在しなかった。

未対応の DNS プロバイダに対応するためには https://github.com/cert-manager/webhook-example を参考に実装していけばよい。

以前 Traefik on k8s で let's encrypt のワイルドカード TLS 証明書を自動発行する - daily dayflower で書いたように、 Traefik はもともと LuaDNS に対応している。 どのようなコードで対応しているのかな、と思ったが、実際には GitHub - go-acme/lego: Let's Encrypt/ACME client and library written in Go ライブラリを利用しているようだ。

lego の LuaDNS むけ実装cert-manager の webhook example 実装 を照らし合わせてみてみたが、 (DNS-01 チャレンジを実装するという意味で) 似たような構造になっている。

これならそこまで難しくなさそうだぞと思い、 cert-manager webhookLuaDNS 向け実装を書き始めた……

が……

気づいてしまった。

LuaDNS 専用に書くより https://github.com/go-acme/lego のサポートしている DNS プロバイダを汎用的にサポートすることができるんじゃないか?

そもそもそういう実装がすでにあるんじゃないか?

と、思い、探してみました。すでにありました。

github.com

これで自力で開発する必要はなくなった (!) ので、ふつうにこれを使わせてもらうことにする。

(実際には ArgoCD での利用にちょっと問題があったので (あくまで Helm chart 部分だけだけど) fork してそれを使っている: https://github.com/yxwuxuanl/cert-manager-lego-webhook)

といっても、使い方は難しくはなく、 README にあるとおりにやればよい。

まず webhook を Helm でインストールする。

自分はいまは k8s cluster として MicroK8s を使っており、 cert-manager を addon として容易に追加できる。 この場合、 Helm install するときに指定する value としては certManager.namespacecert-manager、および certManager.serviceAccountNamecert-manager となる。

次に Issuer リソース を登録する (以下の例では ClusterIssuer を使っている)。

---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: luadns-issuer
spec:
  acme:
    privateKeySecretRef:
      name: luadns-issuer
    server: https://acme-v02.api.letsencrypt.org/directory
    email: EMAIL-ADDRESS
    solvers:
      - dns01:
          webhook:
            groupName: lego.dns-solver
            solverName: lego-solver
            config:
              provider: luadns
              envFrom:
                secret:
                  namespace: LUADNS-SECRET-NAMESPACE
                  name: LUADNS-SECRET

metadata.name (および spec.acme.privateKeySecretRef.name) は自由につけれる。

それ以外の部分は (おそらく) lego の LuaDNS プロバイダを利用するなら上記のような設定になると思う。

あとは一般的な cert-manager での証明書リソースの登録をすればよい。

---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  namespace: default
  name: example.com
spec:
  issuerRef:
    kind: ClusterIssuer
    name: luadns-issuer
  secretName: example.com-tls
  commonName: example.com
  dnsNames:
    - example.com
    - "*.example.com"

spec.issuerRef に上記で登録した Issuer を指定する。