本記事について
本記事では、Kubernetes(GKE)でLet's Encryptを自動更新する方法について記載します。
Kubernetesのパッケージ「cert-manager」を用いて「DNS認証」によるチェックを行います。
以前にも「Kubernetes(GKE)でLet's Encryptを自動更新する方法」を書いたのですが、手順が変わっていたので、ワイルドカード証明書の取得方法と合わせて、書き直しました。
公式マニュアルを元に、自分がハマったところを中心にいくつか追記しています。
手順(cert-managerインストールまで)
Kubernetesを最新にする
1.12以前だと、作業に一手間必要なので、1.13以上にしておきます。
namespace「cert-manager」追加
kubectl create namespace cert-manager
# validation無効(マニュアルから転記)
kubectl label namespace cert-manager certmanager.k8s.io/disable-validation=true
cert-managerインストール
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v0.8.0/cert-manager.yaml
権限付与
kubectl create clusterrolebinding cluster-admin-binding \
--clusterrole=cluster-admin \
--user=$(gcloud config get-value core/account)
全体の流れ
以上でcert-managerのインストールが完了です。次の手順に進む前に、ざっくりと全体の流れを説明します。
cert-managerの仕組み
cert-managerは大きく「Issuer」と「Certificate」で構成されています。
「Certificate」は主にドメイン・証明書に関する設定が記載されており、「Issure」は証明書取得の手段やアカウントに関する設定が記載されています。
「Certificate」の証明書の取得を「Issuer」で実行し、「Certificate」で定義されているシークレットに保存することにより、証明書を利用できるようにします。
証明書利用の仕組み
上記で取得した証明書はシークレットとしてKubernetesに保存されます。
そして、そのシークレットをIngressから参照することにより証明書を利用します。
(Ingressを用いた証明書の利用方法については別記事「Kubernetes(GKE)でHTTPS通信する方法」にまとめました)
Let's Encrypt DNS認証の仕組み
Let's Encrypt DNS認証では、Let's Encryptは、DNSレコードに指定した値が書き込まれたかをチェックして、請求者がそのドメインの所有者かをチェックします。
そこで、cert-managerは、GCPのDNSレコードを編集できるサービスアカウントをIssuerと紐付けることによって、IssuerがDNSレコードを編集できるようにし、Let's Encryptからのチェックをパスできるようにします。
手順(残り)
GCPサービスアカウント作成
DNSレコードを編集できるサービスアカウントを作成します
- [GCP]-[IAMと管理]-[サービスアカウント]-[サービスアカウントを作成]で任意のアカウントを作成
- [GCP]-[IAMと管理]-[IAM]-[追加]で作成したアカウントを追加(役割を[DNS]-[DNS管理者]にする)
- [GCP]-[APIとサービス]-[認証情報]-[認証情報を作成]-[サービスアカウントキー]でキーJSONファイルを作成(サービスアカウントを選択してキータイプをJSONにしてキーファイルを保存)
cert-managerからキーファイルの内容を参照できるよう、Kubernetesのシークレットにキーファイルを登録します。
kubectl create secret generic <シークレット名> \
--from-file=key.json=<キーファイルパス> \
--namespace=cert-manager
cert-manager本体は、インストールの際に作ったnamespace「cert-manager」に作られるので、そこからアクセスできるよう、namespace「cert-manager」内にキーファイルを登録します。
Issuer作成
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
name: letsencrypt-issuer
namespace: default
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
# ステージの場合のURLは : https://acme-staging-v02.api.letsencrypt.org/directory
email: <Let's Encryptに登録するemail>
privateKeySecretRef:
name: letsencrypt-issuer
dns01:
providers:
- name: clouddns
clouddns:
serviceAccountSecretRef:
name: <DNSサービスアカウントのキーファイルのシークレット名>
key: key.json
project: <GCPプロジェクト名>
kubectl apply -f issuer.yaml
Certificate作成
apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
name: example-com-certificate
namespace: default
spec:
secretName: example-com-certificate # Ingressから参照するシークレット名
issuerRef:
name: letsencrypt-issuer # Issuer名
kind: ClusterIssuer
commonName: "*.example.com" # ドメイン名
dnsNames:
- example.com # CloudDNSのDNS名
acme:
config:
- dns01:
provider: clouddns # Issuerのprovider名
domains:
- "*.example.com" # ワイルドカード
- example.com # ドメイン名
kubectl apply -f certificate.yaml
確認
kubectl describe certificate,issuer,clusterissuer --all-namespaces
で状態をチェックできます。
うまくいくと、certificateの「Events」が下記のように表示されます。
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal OrderCreated 5m5s cert-manager Created Order resource …
Normal OrderComplete 5m3s cert-manager Order …
Normal CertIssued 5m3s cert-manager Certificate issued successfully
証明書取得は、namespace「cert-manager」内の「cert-manager」ポッドが行っているので、うまく行かないようならポッドのログを見て原因究明します。
ワイルドカード証明書について
通常証明書は、1つのURL(例えば「example.com」)に対して1つ発行されます。
一方、ワイルドカード証明書は、任意のサブドメイン(例えば「www.examble.com」「www1.example.com」…)に使える証明書になります。
cert-managerで取得した証明書は、任意のサブドメイン(「*.example.com」)とサブドメインなし(「example.com」)の両方に使えるので、
とりあえずワイルドカード証明書を取得しておけばいいかなと思います。
証明書の利用
Ingressのサンプルを記載します。
tlsのシークレットを、Certificateで設定したシークレット名にすることにより、IngressとCertificateの証明書を紐付けます。
(Ingressを用いた証明書の利用方法については別記事「Kubernetes(GKE)でHTTPS通信する方法」にまとめました)
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
annotations:
kubernetes.io/ingress.allow-http: "false"
kubernetes.io/ingress.global-static-ip-name: "<static ip名>"
spec:
tls:
- secretName: example-com-certificate
backend:
serviceName: nginx
servicePort: 80
補足説明
トライアルアンドエラーを繰り返していると、Let's Encryptの制限に引っかかることがあるので、はじめは本番ではなくステージングでテストした方がよいかと思います。
ステージングは「issuer.yaml」の「server」を「https://acme-staging-v02.api.letsencrypt.org/directory
」にするとなります。
参考情報
- https://qiita.com/apstndb/items/3a39a1e6acacbbc30765
- https://github.com/ahmetb/gke-letsencrypt
- https://cert-manager.readthedocs.io/en/latest/
- https://medium.com/google-cloud/kubernetes-w-lets-encrypt-cloud-dns-c888b2ff8c0e
- https://github.com/jetstack/cert-manager/issues/339