cert-managerを使った固定IPサーバーのSSL/TLS証明書自動化の実践ガイド
2024-12-11
Post Image

はじめに

固定IPを持つサーバーでSSL/TLS証明書を自動的に管理することは、セキュリティを保ちながら運用の手間を減らすための重要なステップです。 現在、SSL/TLS証明書の有効期間は、短縮される傾向にあります。一度手動で設定して放置できるようなことは今後少なくなるでしょう。そこで、短縮された期限に合わせ、本記事では、Kubernetes環境におけるcert-managerを使用して、固定IPサーバーのSSL/TLS証明書を自動的に発行し、管理する方法を詳しく解説します。

※cert-manager

ディレクトリ構成

まず、k3sのマニフェスト作成は、Kustomizeで行っており、構成は以下のようにしています。
個人開発のような小規模環境であれば、Kustomizeは学習コストも低く、自身の理解につながりやすいのでオススメです。
参考: https://notes.midnightstops.com/posts/15/

tree -L 3 ./projects > directory_structure.txtで出力したディレクトリ構成を示します。

./projects
├── base
│   ├── base
│   │   └── kustomization.yaml
│   ├── certificate
│   │   ├── kustomization.yaml
│   │   └── namespace.yaml
│   └── cert-manager
│       └── kustomization.yaml
└── overlays
    ├── dev
    │   ├── 01_configMap
    │   ├── 02_settings
    │   ├── certificate
    │   └── cert-manager
    └── prod
        ├── 01_configMap
        ├── 02_settings
        ├── base
        ├── certificate
        │ 	└── notes-midnightstops-com-certificate.yaml
        └── cert-manager
        	   ├── cluster-issuer_letsencrypt.yaml
        	   └── kustomization.yaml

管理の観点から、namespaceをcert-managercertificateで分けています。
cert-managerでSSL/TLS証明書の自動取得を管理し、certificateでSSL/TLS証明書を作成する、ドメイン名を指定するイメージです。ドメイン名はアプリの追加に伴い、追加していくと思いますので、このような構成が個人的に良いといきつきました。
ここで、作成したSSL/TLS証明書、つまりsecretを各アプリのnamespace間で共有する必要がでてきます。
その、secretを異なるnamespace間で共有するための設定として、baseディレクトリにて、ポッドをたてます。

異なるネームスペース間でのリソースの自動同期

マニフェスト詳細

projects/base/base/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - https://raw.githubusercontent.com/mittwald/kubernetes-replicator/master/deploy/rbac.yaml
  - https://raw.githubusercontent.com/mittwald/kubernetes-replicator/master/deploy/deployment.yaml

projects/overlays/prod/base/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - ../../../base/base

上記のマニフェストファイルを作成し、デプロイします。

kubectl apply -k ./projects/overlays/prod/base

これにより、複製対象のリソース名を保持しつつ同期が可能になります。
リソースのマニフェストにおけるアノテーションの例は以下になります。

annotations:
  reflector.v1.k8s.emberstack.com/reflection-allowed: "true"
  reflector.v1.k8s.emberstack.com/reflect-to-namespace: "namespace1,namespace2"

SSL/TLS証明書の自動取得設定

マニフェスト詳細

./projects/base/cert-manager/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - https://github.com/cert-manager/cert-manager/releases/download/v●.●.●/cert-manager.yaml

./projects/overlays/prod/cert-manager/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - ../../../base/cert-manager
  # Let's encrypt
  - ./cluster-issuer_letsencrypt.yaml

./projects/overlays/prod/cert-manager/cluster-issuer_letsencrypt.yaml

---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: <Issuer name>
  namespace: cert-manager
spec:
  acme:
    email: [email protected]
    # The ACME server URL
    # server: https://acme-staging-v02.api.letsencrypt.org/directory
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: <secret-name>
    solvers:
    ### HTTP01
    - http01:
        ingress:
          class: traefik
  • metadata.name: 任意の名前
  • spec.acme.email: [email protected]:
    Let's Encryptで取得する場合、必須ではありません。あれば、期限が近づくとメール連絡が来るはずです。
  • spec.acme.server: ステージング環境と本番環境でURLが異なります。Let's Encryptの取得回数には制限がありますので、ステージング環境で構築できることを確認してから、本番環境にすると良いと思います。そのためのoverlays/devoverlays/prodです。
  • privateKeySecretRef.name: 任意の名前
  • solvers: dns01http01があります。ざっくり違いは以下になります。
特徴DNS-01HTTP-01
利用用途ワイルドカード証明書対応単一ドメイン証明書
認証方式DNSレコードにTXTを追加特定のHTTPエンドポイントにトークン配置
ポート要件不要80番ポート(HTTP)が必要
利便性DNS編集が必要簡単に設定可能
制約DNS反映時間がかかる場合があるサーバーが外部からアクセス可能である必要

ワイルドカード証明書にもメリットはあるのですが、設定はhttp01に比べ煩雑になります。

  • solvers.http01.ingress.class: ingress classを指定してください。nginxであれば、nginxになります。

デプロイ

kubectl apply -k ./projects/overlays/prod/cert-manager

ここまでで、SSL/TLS証明書の自動取得環境は整いました。
次に、SSL/TLS証明書を取得するドメイン名の設定を行います。

certificateの設定

マニュフェストの詳細

./projects/base/certificate/namespace.yaml

apiVersion: v1
kind: Namespace
metadata:
  name: certificate

./projects/base/certificate/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - ./namespace.yaml

./projects/overlays/prod/certificate/notes-midnightstops-com-certificate.yaml

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  # certificaterequest name
  name: <certificate name>
  namespace: certificate
spec:
  secretName: <tls secret name>
  privateKey:
    rotationPolicy: Always
  issuerRef:
    name: <Issuer name>
    kind: ClusterIssuer
  secretTemplate:
    annotations:
      replicator.v1.mittwald.de/replication-allowed: "true"
      replicator.v1.mittwald.de/replication-allowed-namespaces: "namespace1,namespace2"
      replicator.v1.mittwald.de/replicate-to: "namespace1,namespace2"
  dnsNames:
  - "sub.example.com"
  duration: 720h
  renewBefore: 240h
  
  • metadata.name:
    任意の名前

  • spec.secretName:
    任意の名前(tls secret name)をつけますが、ここで指定したsecet nameが他のネームスペースでも共有されます。

  • spec. issuerRef.name:
    cert-managercluster-issuer_letsencrypt.yamlで指定したIssuer nameに合わせます。

  • secretTemplate.annotations:
    シークレット情報を他のネームスペースで共有するために必要な設定です。

  • replicator.v1.mittwald.de/replication-allowed-namespaces:

  • replicator.v1.mittwald.de/replicate-to:
    に共有先のネームスペースを指定することで、シークレット情報が同期されます。
    つまり、cert-managerで自動更新されたSSL/TLS証明書が他のアプリでも更新されることになります。

  • spec.duration:
    SSL/TLS証明書の期限

  • spec.renewBefore:
    durationから起算して、どのくらい前にSSL/TLS証明書を更新するか

デプロイ

kubectl apply -f ./projects/overlays/prod/certificate/notes-midnightstops-com-certificate.yaml
でデプロイします。

デプロイの確認

Certificateリソースの確認

kubectl get certificates -n certificate

出力のReadyの項目がTrueになれば、SSL/TLS証明書は作成され、今後自動更新されます。
Falseの場合は、以下のコマンドで、Certificateリソースの詳細情報を確認します。

kubectl describe certificate <certificate name> -n certificate

問題があれば、以下の順番で、原因を探索します。

  1. clusterissuerリソースの詳細情報の確認
kubectl get clusterissuer -o wide
kubectl describe clusterissuer <Issuer name> -n certificate
  1. CertificateRequestの詳細
kubectl get CertificateRequest -n certificate
kubectl describe CertificateRequest -n certificate
  1. orderリソースの詳細情報
kubectl get order -n certificate
kubectl describe order $(kubectl get order -n certificate -o name | head -n 1 | cut -d'/' -f 2) -n certificate

$(kubectl get order -n certificate -o name | head -n 1 | cut -d'/' -f 2はポッド名を調べて、指定せずにポッドの詳細を確認できるので、非常に便利な書き方です。他でも参考になる書き方かなと思います。

  1. challengeリソースの詳細情報
kubectl get challenge --all-namespaces
kubectl describe challenge $(kubectl get challenge -n certificate -o name | head -n 1 | cut -d'/' -f 2) -n certificate

このような手順で、エラー原因を探索していきます。

結論

本記事では、固定IPを持つKubernetes環境でのSSL/TLS証明書の自動管理について、cert-managerを活用した実践的な方法を解説しました。この設定により、SSL/TLS証明書の有効期限の短縮に対応し、セキュリティと運用効率を両立させることが可能です。

主なポイント:

  • cert-managerの導入により、SSL/TLS証明書の自動取得・更新が可能となる。
  • ネームスペース間でのシークレット共有機能を活用して、異なるアプリケーション間で証明書を効率的に利用。
  • Kustomizeを用いた構造的なマニフェスト管理により、環境ごとの差分管理を簡素化。
cert-managerを使った固定IPサーバーのSSL/TLS証明書自動化の実践ガイド
https://notes.midnightstops.com/posts/10/
作者
Author
公開日
2024-12-11