はじめに
固定IPを持つサーバーでSSL/TLS証明書を自動的に管理することは、セキュリティを保ちながら運用の手間を減らすための重要なステップです。 現在、SSL/TLS証明書の有効期間は、短縮される傾向にあります。一度手動で設定して放置できるようなことは今後少なくなるでしょう。そこで、短縮された期限に合わせ、本記事では、Kubernetes環境におけるcert-managerを使用して、固定IPサーバーのSSL/TLS証明書を自動的に発行し、管理する方法を詳しく解説します。
ディレクトリ構成
まず、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-manager
とcertificate
で分けています。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
- v●.●.●:
https://github.com/cert-manager/cert-manager/releases から最新バージョンを調べ、置き換えください。
./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/dev
とoverlays/prod
です。 - privateKeySecretRef.name: 任意の名前
- solvers:
dns01
とhttp01
があります。ざっくり違いは以下になります。
特徴 | DNS-01 | HTTP-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-manager
のcluster-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
問題があれば、以下の順番で、原因を探索します。
- clusterissuerリソースの詳細情報の確認
kubectl get clusterissuer -o wide
kubectl describe clusterissuer <Issuer name> -n certificate
- CertificateRequestの詳細
kubectl get CertificateRequest -n certificate
kubectl describe CertificateRequest -n certificate
- 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
はポッド名を調べて、指定せずにポッドの詳細を確認できるので、非常に便利な書き方です。他でも参考になる書き方かなと思います。
- 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を用いた構造的なマニフェスト管理により、環境ごとの差分管理を簡素化。