こんにちは。今回はタイトルにもあるように、K3sで動作する Traefik Ingress の証明書発行を cert-manager で自動化します。
証明書の発行にはお馴染みの Let’s Encrypt くんにやってもらいます。また、今回は Cloudflare の DNS-01 Challenge を使用します。
環境
Name
Version
K3s
v1.30.6+k3s1 (1829eaae)
cert-manager
v1.16.1
OS
Ubuntu 24.04.1 LTS
K3s のインストール
K3s のインストールについては、公式ドキュメントもしくはその他の記事が丁寧に説明されているので、ここでの説明は省略し、コマンドだけ紹介します。
1
2
$ sudo apt install wireguard
$ curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC = "server" sh -s - --flannel-backend wireguard-native
なぜ cert-manager を使うのか
Docker では以下のような Traefik Conifg を反映させることで、自動証明書発行ができます。
1
2
3
4
5
6
7
8
certificatesResolvers :
cloudflare :
acme :
dnsChallenge :
provider : cloudflare
email : [email protected]
storage : /letsencrypt/acme.json
keyType : EC384
そのため、「cert-manager なんか使わなくとも Traefik 単体で証明書発行できるんじゃないの?」と思いましたが、どうやら負荷分散や高可用性のためにKubernetes向けにはサポートされていないようでした。(Enterprise の方はされているらしい)
つまり、上記の Traefik Config をそのままコピペして移行することはできないようです。
余談ですが、K3s に付属する Traefik の設定は HelmChartConfig リソースを定義した以下のようなマニフェストを Apply するだけで変更されます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion : helm.cattle.io/v1
kind : HelmChartConfig
metadata :
name : traefik
namespace : kube-system
spec :
valuesContent : |-
certificatesResolvers:
cloudflare:
acme:
dnsChallenge:
provider: cloudflare
email: [email protected]
storage: /letsencrypt/acme.json
keyType: EC384
上記のことから、Traefik 単体での証明書発行は行わず、今回は cert-manager を使って証明書発行します。
cert-manager のインストール
cert-manager のインストールは kubectl apply コマンドでやる方法と、helm からやる方法などがありますが、今回は kubectl apply でやりました。
1
$ kubectl apply - f https : // github . com / cert - manager / cert - manager / releases / download / v1 . 16.1 / cert - manager . yaml
詳細は以下のドキュメントから確認してください。
Issue / Cluster Issuer を作成する
Issuers, and ClusterIssuers, are Kubernetes resources that represent certificate authorities (CAs) that are able to generate signed certificates by honoring certificate signing requests.
Issuer と Cluster Issuer は Ingress から証明書発行のリクエストを送信したときに、その処理を担ってくれる Kubernetes リソースです。
今回は DNS-01 チャレンジを Cloudflare に対して実行する ACME の Cluster Issuer を作成します。
Cloudflare プロバイダーを使用するためには、 API Token をSecret リソースとして登録しておきましょう。
ここで使用する API Token の Scope は以下のような状態である必要があります。
ゾーンリソースについては、特定のゾーンでも問題ありません。
1
2
3
4
5
6
7
8
apiVersion : v1
kind : Secret
metadata :
name : cloudflare-api-token-secret
namespace : cert-manager
type : Opaque
stringData :
api-token : <API_TOKEN>
以下は Let’s Encryptサーバーを対象とした Cluster Issuer リソースです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion : cert-manager.io/v1
kind : ClusterIssuer
metadata :
name : letsencrypt
spec :
acme :
email : [email protected]
server : https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef :
name : letsencrypt-issuer-account-key
solvers :
- dns01 :
cloudflare :
apiTokenSecretRef :
name : cloudflare-api-token-secret
key : api-token
おまけにステージング用の Cluster Issuer リソースを作成しておくと良いでしょう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion : cert-manager.io/v1
kind : ClusterIssuer
metadata :
name : letsencrypt-staging
spec :
acme :
email : [email protected]
server : https://acme-staging-v02.api.letsencrypt.org/directory
privateKeySecretRef :
name : example-issuer-account-key
solvers :
- dns01 :
cloudflare :
apiTokenSecretRef :
name : cloudflare-api-token-secret
key : api-token
Ingress から証明書発行を要求する
Ingress リソースの annotations から cert-manager.io/cluster-issuer: letsencrypt
と書くことで指定された Issuer が証明書発行要求を行います。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion : networking.k8s.io/v1
kind : Ingress
metadata :
name : sample-ingress
labels :
name : sample-ingress
annotations :
ingress.kubernetes.io/ssl-redirect : "true"
cert-manager.io/cluster-issuer : letsencrypt
spec :
tls :
- hosts :
- sample.example.com
secretName : sample-tls-secret
rules :
- host : sample.example.com
http :
paths :
- pathType : Prefix
path : "/"
backend :
service :
name : sample
port :
number : 80
証明書発行状態の確認
証明書が発行されているかどうかは、以下のコマンドで確認することができます。
READY が True になっていると使用可能な状態になっています。Trueになるまでには数分から数十分かかることがあるので少し待ちましょう。
1
2
3
$ kubectl get cert -A
NAMESPACE NAME READY SECRET AGE
default sample-tls-secret True sample-tls-secret 13h
いつまで経っても True にならない場合は、cert-manager の pod のログを見て確認しましょう。
1
2
$ kubectl get pod -n cert-manager
$ kubectl logs -f -n cert-manager pod/cert-manager-6796d554c5-fsjmn
おわりに
かなりお手軽に証明書発行できてよかったです。