Kubernetes

cert-manager + Let's Encrypt を使って無料でTSL/SSL証明書を自動管理する

はじめに

WEBサイトを公開しようとすると、セキュリティの観点からHTTPSでの公開は必須となります。HTTPSを行うためにはSSL/TLS証明書が必要となりますが、お名前.comなどのサービスを利用すると証明書の発行にお金がかかってしまいます。

本ブログは無料のSSL/TLS証明書発行サービスであるLet’s Encryptと、KubernetesのツールであるCert-managerを組み合わせてHTTPS公開を行っています。

この2つを組み合わせることで、Kubernetesクラスタ内でHTTPS通信に必要な証明書を完全自動化する手法として紹介します。

Cert-managerとは?

cert-managerは、Kubernetes上でSSL/TLS証明書を自動的に取得・更新・管理するためのツールです。これによって証明書運用が簡単になります。

公式ドキュメント https://cert-manager.io/docs/

Let’s Encryptとは?

米国の非営利団体であるISRGにより運営され、90日間有効なDV証明書を無料で自動発行してくれる認証局です。WebサイトのHTTPS化を行う事ができます。

https://letsencrypt.org/ja/

仕組み

1. Certificate リソース作成

2. cert-manager が検知

3. CertificateRequest 作成

4. Let's Encrypt に証明書発行リクエスト (ACME プロトコル)

5. ドメイン所有確認 (Challenge)
   ├─ HTTP-01: Webサーバー経由で確認
   └─ DNS-01: DNS レコード経由で確認

6. Let's Encrypt が証明書発行

7. cert-manager が Secret に保存

8. Ingress が Secret を参照して TLS 有効化

この仕組みによって、一度設定すればあとは何もしなくても証明書が自動的に更新され続けます。

利用するまでの手順

1. cert-managerのインストール

# インストール
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.2/cert-manager.yaml

# インストール確認
kubectl get pods -n cert-manager

以下のような感じで cert-manager のPodが生成されます。

$ kubectl get pods -n cert-manager
NAME                                      READY   STATUS    RESTARTS   AGE
cert-manager-79559475b4-r8bdm             1/1     Running   0          29d
cert-manager-cainjector-966fc8fbc-gmk85   1/1     Running   0          29d
cert-manager-webhook-854cf5f458-7knns     1/1     Running   0          29d

2. ClusterIssuer の作成

ClusterIssuer は Let’s Encrypt から証明書を取得するための設定です。クラスター全体で共有されます。

cat <<'EOF' | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    # Let's Encrypt の本番サーバー
    server: https://acme-v02.api.letsencrypt.org/directory
    # 証明書の期限切れ通知を受け取るメールアドレス
    email: your-email@example.com
    # ACME アカウントの秘密鍵を保存する Secret
    privateKeySecretRef:
      name: letsencrypt-prod
    # HTTP-01 チャレンジの設定
    solvers:
    - http01:
        ingress:
          ingressClassName: traefik
EOF

確認

# 確認
kubectl get clusterissuer

# 出力例
NAME                  READY   AGE
letsencrypt-prod      True    29d

3. Ingress での証明書設定

Ingress リソースにアノテーションを追加するだけで、cert-manager が自動的に証明書を取得します。

単一ドメインの場合

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app
  namespace: default
  annotations:
    # cert-manager に証明書を取得させる
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: traefik
  tls:
    - hosts:
        - app.example.com
      # 証明書を保存する Secret 名
      secretName: my-app-tls
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: my-app
                port:
                  number: 80

複数ドメインの場合

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: blog
  namespace: default
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: traefik
  tls:
    - hosts:
        - blog.example.com
        - example.com
      secretName: blog-tls
  rules:
    - host: blog.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: blog
                port:
                  number: 80
    - host: example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: blog
                port:
                  number: 80

証明書発行の流れ

1. Ingress 作成

2. cert-manager が Ingress を検知

3. Certificate リソースを自動作成

4. CertificateRequest を作成

5. Order を作成(Let's Encrypt への注文)

6. Challenge を作成(HTTP-01 検証)

7. 一時的な Ingress/Pod を作成
   (/.well-known/acme-challenge/xxx に応答)

8. Let's Encrypt が検証

9. 証明書発行

10. Secret に保存(tls.crt, tls.key)

4. 証明書の確認コマンド

  • Certificate リソースの状態の確認
$ kubectl get certificate -A

私の運用環境では以下のようになっています。

# kubectl get certificate -A

NAMESPACE   NAME                       READY   SECRET                     AGE
argocd      argocd-cert                True    argocd-tls                 29d
default     blog-tls                   True    blog-tls                   29d
default     n8n-tls                    True    n8n-tls                    28d
  • 発行中の Challenge 確認
kubectl get challenges -A

証明書発行中は Challenge リソースが表示されます。発行完了後は削除されます。

  • Certificate の詳細
kubectl describe certificate blog-tls -n default
  • 証明書更新タイミングの確認
kubectl describe certificate <certificate name> -n default | grep -E "(Not After|Renewal Time)"

まとめ

cert-managerによる証明書取得・利用の流れを簡単に紹介しました。 割と手軽に無料でHTTPS運用ができるのと、証明書運用の勉強になると思いました。

「HTTPS化したいけど証明書管理が面倒」と思っている方は、ぜひcert-manager + Let’s Encryptを試してみてください。