Kubernetes環境のWebサイトでLet’s Encryptの証明書を利用してHTTPS化します。
証明書は90日で失効してしまうためcert-managerを利用して証明書更新を自動化します。
※長くなるため、前編・後編に分けています。
- ingressControllerの導入
- cert-managerで証明書更新の自動化 ★ここ
Let’s Encryptとは
無償で利用可能なSSL/TSL証明書を発行してくれる認証局です。
Webサーバとドメインが正しいことを検証できれば証明書の発行ができます。
証明書発行にはHTTPとDNSの2種類あり、HTTPの場合TCP80番ポートを解放する必要があります。
DNSサーバのTXTレコードにAPIトークンを登録することで証明書の発行が可能で、TCP80番ポートがブロックされていても利用可能です。
今回は簡単なHTTPでの証明書発行を利用します。
cert-managerとは
証明書の自動更新を行うツールです。
Let’s Encryptの証明書をACMEプロトコルで自動更新します。
cert-managerのリソースについて
- ClusterIssuer … 発行先や発行者情報を定義します。(メールアドレスや問い合わせ先など)
- Certificate … 発行者のDN情報を定義します。
- Secret … 証明書を管理します。
- Order … チャレンジ要求を作成します。
- Challenge … ACME Issuerに証明書要求をします。
cert-managerの導入
環境
名前 | バージョン |
---|---|
CentOS-Stream-9 | |
kubelet | v1.26.2 |
kubeadm | v1.26.2 |
containerd | v1.6.16 |
calico | v3.25 |
metallb | v0.13.9 |
cert-manager | v1.12.0 |
cert-managerのデプロイ
cert-managerをデプロイします。
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.12.0/cert-manager.yaml
3つのPodがRunningになれば正常です。
[user001@k8s-mas01~]# kubectl get pod -n cert-manager
NAME READY STATUS RESTARTS AGE
cert-manager-66d976bfd7-vfhr4 1/1 Running 13 (13h ago) 16d
cert-manager-cainjector-66b9cf5bd6-mbjml 1/1 Running 13 (13h ago) 16d
cert-manager-webhook-7b46c97bd9-nmn8f 1/1 Running 13 (14h ago) 16d
Issuer作成
lets-encrypt-issuer.yamlで作成します。
ネームスペースを跨いで証明書を適用できるように ClusterIssuer で作成しました。
Let’sEncryptの証明書はレート制限(https://letsencrypt.org/ja/docs/rate-limits/)があり、1時間に5回までしか失敗できません。検証失敗すると数日間ブロックされますので気になる方はステージング環境を利用してください。ステージング環境の証明書は認証局に(STAGING)と表示されます。ステージング環境を利用した後、本番用に切り替える場合はSecretを削除してから再発行ください。
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: lets-encrypt-issuer
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory #本番用
#server: https://acme-staging-v02.api.letsencrypt.org/directory #検証用
email: '<your-mail-address>' #メールアドレスを入力
privateKeySecretRef:
name: example-client-letsencrypt #
solvers:
- http01:
ingress:
class: nginx
Issuerを適用します。
kubectl apply -f lets-encrypt-issuer.yaml
kubectl describe clusterissuer で状態を確認します。
READY ステータスが Trueになれば利用可能です。
[user001@k8s-mas01~]# kubectl get clusterissuer
NAME READY AGE
clusterissuer.cert-manager.io/lets-encrypt-issuer True 2m
Ingress作成
lets-encrypt-ingress.yaml で作成します。
tlsを設定することでcertificateが自動で作成されます。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ing
annotations:
cert-manager.io/cluster-issuer: lets-encrypt-issuer # ClusterIssuerを設定
acme.cert-manager.io/http01-edit-in-place: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- example.com # ドメイン記載
secretName: example-letsencrypt-cert # cert-managerが格納するsecret名
rules:
- host: example.com # ドメイン記載
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: www-app-service
port:
number: 80
Ingressを適用します。
kubectl apply -f lets-encrypt-ingress.yaml
kubectl get clusterissuer,cert,cr,order,challenge,secret,ingress で一通りの状態を確認します。
ingressにIPアドレスが付与されるまで数分かかります。
[user001@k8s-mas01~]# kubectl get clusterissuer,cert,cr,order,challenge,secret,ingress --all-namespaces -o wide
NAME READY STATUS AGE
clusterissuer.cert-manager.io/lets-encrypt-issuer True The ACME account was registered with the ACME server 39s
NAMESPACE NAME READY SECRET ISSUER STATUS AGE
default certificate.cert-manager.io/example-letsencrypt-cert True example-letsencrypt-cert lets-encrypt-issuer Certificate is up to date and has not expired 16s
NAMESPACE NAME APPROVED DENIED READY ISSUER REQUESTOR STATUS AGE
default certificaterequest.cert-manager.io/example-letsencrypt-cert-1 True True lets-encrypt-issuer system:serviceaccount:cert-manager:cert-manager Certificate fetched from issuer successfully 16s
NAMESPACE NAME STATE ISSUER REASON AGE
default order.acme.cert-manager.io/example-letsencrypt-cert-1-2496073388 valid lets-encrypt-issuer 16s
NAMESPACE NAME TYPE DATA AGE
cert-manager secret/cert-manager-webhook-ca Opaque 3 46m
cert-manager secret/example-client-letsencrypt Opaque 1 39s
ingress-nginx secret/ingress-nginx-admission Opaque 3 42m
NAMESPACE NAME CLASS HOSTS ADDRESS PORTS AGE
default ingress.networking.k8s.io/example-ing nginx example.com 172.16.200.1 80, 443 16s
Test用Podを作成
nginx-test.yaml で作成します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: www-app
labels:
app: www-app
spec:
replicas: 3
selector:
matchLabels:
app: www-app
template:
metadata:
labels:
app: www-app
spec:
containers:
- name: web-container
image: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: www-app-service
labels:
app: www-app-service
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: www-app
type: NodePort
externalTrafficPolicy: Local
Nginxをデプロイします。
kubectl apply -f nginx-test.yaml
WebサイトにHTTPSで接続できれば成功です。
HTTPSにできない場合
下記コマンドでどこで詰まっているか調査していきます。
kubectl get ev
kubectl get clusterissuer,cert,cr,order,challenge,secret,ingress
さらに詳細を確認したい場合は kubectl describe [resource] [resource名] で確認できます。
successfullyになっていれば証明書が発行されているはずです。
[user001@k8s-mas01~]# kubectl describe order example-letsencrypt-cert-h474n-2496073388
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Created 4m11s cert-manager Created Challenge resource "example-letsencrypt-cert-h474n-2496073388-454293563" for domain "example.com"
Normal Complete 3m45s cert-manager Order completed successfully
最後に
参考サイトに記載しておりますが、先人の方々が詳細に説明されておりますので、情報が足りない方はそちらを参照してください。
また近いうちにDNSでの検証を記事にしたいと思います。