0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ConoHa VPS の Kubernetes に cert-manager を導入して HTTPS 化した話

0
Posted at

はじめに

ConoHa VPS 上に構築した Kubernetes クラスターに Nginx Ingress Controller を導入した後、次のステップとして cert-manager + Let's Encrypt による TLS 証明書の自動取得(HTTPS 化) に挑戦しました。

ドキュメント通りに進めれば簡単なはずが、いくつかのハマりポイントがあったので、詰まった箇所と解決策も含めて記録します。


環境

項目 内容
インフラ ConoHa VPS
Kubernetes セルフホスト(kubeadm)
Ingress Controller ingress-nginx v1.12.1
FQDN xxx.xxx.xxx.xxx.nip.io(nip.io を利用)
cert-manager Helm でインストール

nip.io とは?
IPアドレスを含むホスト名を自動的にそのIPに解決してくれる無料のワイルドカードDNSサービスです。独自ドメインなしでFQDNが使えるため、検証環境に最適です。Let's Encrypt の証明書も取得可能です。


全体の流れ

Ingress に「HTTPS使いたい」と書くだけ
    ↓
cert-manager が Let's Encrypt に証明書を申請
    ↓
Let's Encrypt が HTTP-01 チャレンジでドメイン所有確認
    ↓
Nginx Ingress が確認用 URL に自動応答
    ↓
Let's Encrypt が証明書を発行
    ↓
cert-manager が Secret に TLS 証明書を保存・自動更新

Step 1:Helm のインストール

cert-manager は Helm でインストールするのが標準的です。

snap install helm --classic

注意: --classic オプションが必要です。省略するとエラーになります。snap の classic confinement はシステムへのアクセスが必要な開発ツールでは一般的な選択肢なので、helm では問題ありません。

snap を使いたくない場合は公式スクリプトでもインストールできます:

curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

インストール確認:

helm version

Step 2:cert-manager のインストール

helm repo add jetstack https://charts.jetstack.io
helm repo update

helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --set crds.enabled=true

Pod の起動確認:

kubectl get pods -n cert-manager
# NAME                                      READY   STATUS
# cert-manager-xxxx                         1/1     Running
# cert-manager-cainjector-xxxx              1/1     Running
# cert-manager-webhook-xxxx                 1/1     Running

3つの Pod がすべて Running になれば OK です。


Step 3:ClusterIssuer の作成

まずステージング環境でテストしてから本番に切り替えるのが必須の流れです。
本番 Let's Encrypt はレートリミット(週5回の失敗で制限)があるため、いきなり本番を使うのはリスクがあります。

ステージング用(テスト)

# clusterissuer-staging.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: your-email@example.com   # 自分のメールアドレスに変更
    privateKeySecretRef:
      name: letsencrypt-staging-key
    solvers:
    - http01:
        ingress:
          ingressClassName: nginx

本番用

# clusterissuer-prod.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: your-email@example.com   # 自分のメールアドレスに変更
    privateKeySecretRef:
      name: letsencrypt-prod-key
    solvers:
    - http01:
        ingress:
          ingressClassName: nginx
kubectl apply -f clusterissuer-staging.yaml
kubectl apply -f clusterissuer-prod.yaml

kubectl get clusterissuer
# NAME                   READY
# letsencrypt-staging    True
# letsencrypt-prod       True

Step 4:Ingress に TLS 設定を追加

既存の Ingress マニフェストに2点追加します。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    cert-manager.io/cluster-issuer: "letsencrypt-staging"  # ← 追加
spec:
  ingressClassName: nginx
  tls:                          # ← ブロックごと追加
  - hosts:
    - xxx.xxx.xxx.xxx.nip.io    # FQDNを指定
    secretName: my-app-tls
  rules:
  - host: xxx.xxx.xxx.xxx.nip.io
    http:
      paths:
      - backend:
          service:
            name: my-app-service
            port:
              number: 80
        path: /
        pathType: Prefix
kubectl apply -f ingress.yaml
kubectl get certificate -n default -w

⚠️ ハマりポイント:Admission Webhook が HTTP-01 チャレンジをブロックする

ここで大きな壁にぶつかりました。

症状

kubectl get challenge -n default
# STATE: pending のまま変わらない

kubectl describe challenge -n default
# Events:
#   Warning  PresentError  cert-manager-challenges
#   Error: admission webhook "validate.nginx.ingress.kubernetes.io" denied the request:
#   ingress contains invalid paths: path /.well-known/acme-challenge/xxxxx
#   cannot be used with pathType Exact

原因

cert-manager は HTTP-01 チャレンジのために一時的な Ingress を自動作成しますが、この Ingress の pathTypeExact になっています。Nginx Ingress Controller v1.12.1 の Admission Webhook がこの pathType: Exact/.well-known/acme-challenge/ パスに対して無効と判断してブロックしていました。

試したが効果がなかった対処

① ClusterIssuer に ingressTemplate を追加する

solvers:
- http01:
    ingress:
      ingressClassName: nginx
      ingressTemplate:
        metadata:
          annotations:
            nginx.ingress.kubernetes.io/use-regex: "true"

→ Webhook のバリデーションには効果なし

failurePolicy: Fail → Ignore に変更する

kubectl patch validatingwebhookconfiguration ingress-nginx-admission \
  --type='json' \
  -p='[{"op": "replace", "path": "/webhooks/0/failurePolicy", "value": "Ignore"}]'

Ignore に変更されたことは確認できたが、それでもブロックされ続けた
(Nginx Ingress Controller 自体のバリデーションも別途動作しているため)

✅ 解決策:ValidatingWebhookConfiguration を一時的に削除する

kubectl delete validatingwebhookconfiguration ingress-nginx-admission

Webhook を完全に削除することで、cert-manager がチャレンジ用 Ingress を作成できるようになりました。

クリーンアップして再挑戦:

kubectl delete certificate my-app-tls -n default
kubectl delete secret my-app-tls -n default 2>/dev/null; true
kubectl delete challenge --all -n default
kubectl delete ingress my-app-ingress -n default

# 再適用
kubectl apply -f ingress.yaml

# 監視
kubectl get challenge -n default -w
# STATE が pending → valid に変わればOK

Step 5:ステージング確認 → 本番証明書に切り替え

Challenge が valid になり、証明書が取得できたことを確認:

kubectl get certificate -n default
# NAME         READY   SECRET       AGE
# my-app-tls   True    my-app-tls   43s

READY: True を確認したら本番に切り替えます。

Ingress のアノテーションを変更:

cert-manager.io/cluster-issuer: "letsencrypt-prod"  # staging → prod
# ステージング証明書を削除して再取得
kubectl delete certificate my-app-tls -n default
kubectl delete secret my-app-tls -n default

kubectl apply -f ingress.yaml
kubectl get certificate -n default -w

Step 6:Webhook を復元

本番証明書の取得が完了したら、削除していた Webhook を復元します。

kubectl apply -f deploy.yaml

動作確認

ブラウザで https://your-fqdn.nip.io にアクセスして、アドレスバーに 🔒 が表示されれば HTTPS 化完了 です!


まとめ:ハマりポイントと対策

ハマりポイント 原因 解決策
helm コマンドが見つからない 未インストール snap install helm --classic
Challenge が pending のまま Nginx Ingress v1.12.1 の Webhook が pathType Exact を拒否 ValidatingWebhookConfiguration を一時削除
failurePolicy: Ignore が効かない Controller 自体にもバリデーションがある Webhook リソースごと削除が必要
古い Challenge が残って競合 リソースの削除漏れ certificate / secret / challenge / ingress を全削除してからやり直す

証明書の自動更新について

cert-manager は証明書の有効期限 30日前 に自動で更新してくれます。一度設定すれば、以後は何もしなくて OK です。


参考リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?