Google Domains が事業売却されるという話から約半年、重い腰をあげてついに我が家のドメインも Cloudflare に移行対応しました。 半年も経てば Cloudflare への移行手順は多くの記事で紹介されているので、今回は Cloudflare 移行に伴って発生した自宅ラボで使っている cert-manager の移行対応を記録しておきます。
なぜドメイン移行先を Cloudflare にしたのか
このブログでも使っている nnstt1.dev
というドメインは Google Domains で購入していましたが、ネームサーバーを設定してレコードの管理自体は Azure DNS でおこなっていました。
Azure DNS で管理しているなら Azure 自体でドメインを購入すればいいじゃないかと思ったのですが、Azure でドメインを購入するサービスの App Service ドメインでは com、net、co.uk、org、nl、in、biz、org.uk、co.in のトップレベルドメイン (TLD) しか対応していなかったため、.dev ドメインは別のサービスを利用するしかありませんでした。 (そもそも Google Domains にしたのも Azure が .dev に対応してなかったからなのに、今回も移行できないか確認してしまったという…)
というわけで他のドメインサービスを探すことになったのですが、おネームドットコムは論外ということ以外は特にこだわりはありませんでした。 半年前でもそうでしたが、やっぱり Cloudflare が移行先として人気のようで、右にならえで自分も Cloudflare に移行することにしました。
移行自体はすんなり完了したのと、レコード自体の管理も Terraform を使うようにしました。
cert-manager の対応
自宅ラボの Kubernetes クラスタでは証明書管理のための cert-manager を使っています。 クラスタで(自宅内に閉じて)公開しているサービスの証明書を Let’s Encrypt で発行していますが、そのためにはドメインの検証が必要になります。 検証の方法は 2 つあって、Let’s Encrypt から対象ドメインを使っているサービスにアクセスする HTTP Validation と、DNS に指定の TXT レコードを作成する DNS Validation があります。
自宅ラボのサービスが外部公開していないため、ドメインの検証は DNS Valication になり、前項で述べた通りレコードの管理は Azure DNS を使っているため、cert-manger の DNS Validation の設定も Azure DNS を対象としたものにしていました。
今回 Cloudflare に移行したとしても Azure DNS を使うようにネームサーバーを設定すれば cert-manager の対応もいらなかったのですが、Cloudflare のネームサーバーは無料プランでは変更できない仕様だったため、泣く泣く Azure DNS を手放してドメイン周りは Cloudflare に統一することにしました。
そういう背景もあり、cert-mangaer の DNS Validation で Cloudflare 対応が必要になったというわけです。
Cloudflare API トークン
cert-manager で Cloudflare に検証用レコードを追加するには Cloudflare の API トークンを利用します。 Cloudflare のダッシュボードから対象ドメインの概要ページを開き、右下の[API トークンを取得] というリンクから API トークンを発行・取得できます。 API トークンに付与する権限はテンプレートの「ゾーン DNS を編集する」を選びました。
この API トークンを cert-manager で利用するには Kubernetes の Secret リソースを作成して Pod から参照させます。 Secret リソースに直接 API トークンを書いてもいいのですが、我が家の Kubernetes クラスタでは HashiCorp Vault を使ってシークレット管理をしているため、API トークンを Vault に書き込んで Vault Secrets Operator を使って Secret リソースに同期させます。
次の Vault Secrets Operator で使用するカスタムリソースをデプロイしました。
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultConnection
metadata:
name: vaultconnection
namespace: cert-manager
spec:
address: http://vault.vault.svc.cluster.local:8200
skipTLSVerify: true
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
name: vaultauth
namespace: cert-manager
spec:
vaultConnectionRef: vaultconnection
method: kubernetes
mount: kubernetes
kubernetes:
role: cert-manager
serviceAccount: cert-manager
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
name: cloudflare-api-token
namespace: cert-manager
spec:
vaultAuthRef: vaultauth
mount: secret
path: cloudflare
type: kv-v2
refreshAfter: 5s
rolloutRestartTargets:
- kind: Deployment
name: cert-manager
destination:
name: cloudflare-api-token
create: true
VaultConnection で Vault クラスタを指定し、VaultAuth で Vault への認証方法を指定しています。 API トークンは Vault の KV v2 というシークレットエンジンに格納したため、VaultStaticSecret というリソースに API トークンの格納パスや、どの Secret リソースに同期させるか、どの Deployment をロールアウトするか、といった構成を記述しています。
もともと Azure DNS を使っていた際は Vault の「動的シークレット (Dynamic Secrets)」という機能を使って Azure にアクセスする認証情報を動的に作成していたのですが、その設定も不要になりました。 ちなみに、Vault に API トークンを追加したときのコマンドはこちら。
$ vault secrets enable -path=secret kv-v2
$ vault kv put secret/cloudflare api-token=<API トークン>
このシークレットを参照するための権限をポリシーに追加。
path "secret/data/cloudflare" {
capabilities = [ "read" ]
}
cert-manager Issuer/ClusterIssuer
Cloudflare にレコードを追加するための API トークンも準備できたので、cert-manager が Cloudflare を使って DNS Validation できるようにマニフェストを書き換えます。 もともと次のようなマニフェストを使って、Azure DNS ゾーンに TXT レコードを追加していました。
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
email: hoge@example.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: issuer-account-key
solvers:
- dns01:
azureDNS:
clientID: 00000000-0000-0000-0000-000000000000
clientSecretSecretRef:
name: azure-service-principal
key: client_secret
subscriptionID: 00000000-0000-0000-0000-000000000000
tenantID: 00000000-0000-0000-0000-000000000000
resourceGroupName: home-lab
hostedZoneName: nnstt1.dev
environment: AzurePublicCloud
このマニフェストの spec.acme.solvers.dns01
を azureDNS
から cloudflare
に書き換えます。
Azure DNS の場合はテナント ID だったりリソースグループ名だったりを指定する必要があったのですが、Cloudflare では API トークンを格納した Secret リソースを指定するだけでよいです。
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
email: hoge@example.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: issuer-account-key
solvers:
- dns01:
cloudflare:
apiTokenSecretRef:
name: cloudflare-api-token
key: api-token
とてもスッキリしましたね! 最後はこのマニフェストをデプロイするだけで、Cloudflare を使って cert-manager の DNS Validation が動いて証明書を発行してもらえるようになります。