はじめに
この記事は GRIPHONE Advent Calendar 2020 21日目の記事です。
こんにちは、SREの岩立です。
Let’s Encrypt使っていますか? 無料で容易にSSL証明書を発行できてとても便利なサービスでとても助かっています。ただ、Let’s Encryptには1週間に発行できる証明書は50個までという制限があります。こういったレート制限に引っかかるようになってしまい、ACMEに対応していて無制限に証明書を発行できるサービスを探していたところZeroSSLというサービスを見つけたため、今回はZeroSSLを用いてcert-managerで証明書を作成してみたいと思います。
ZeroSSLとは
ZeroSSLは、ざっくり言うとSSL証明書を発行してくれるサービスです。
特徴としては月$10払うと無制限で証明書が発行でき、かつACMEにも対応しているのでcert-managerなどから自動で発行することも出来ます。
今回自分たちはLet’s Encryptのレート制限に引っかかって代替のサービスを探していたため、ZeroSSLを試してみることにします。
実際に発行してみる
ZeroSSLのEAB Credentialを取得しSecretを作成する
まず、ACMEでの認証に必要なEAB CredentialをZeroSSLで発行します。
ログイン後のページのDeveloperタブからEAB Credentialの発行ができるので、発行されたEAB KIDとEAB HMAC Keyを控えます。
以下のコマンドで、EAB HMAC Keyをbase64デコードし、それを元にcert-managerで使用するSecretを作成します。(EAB HMAC Keyを実際のキーに置き換えてください。)
echo -n "EAB HMAC Key" | base64 -d > eab-key
kubectl -n cert-manager create secret generic zerossl-eab-key --from-file eab-key
Issuerを作成
externalAccountBindingを使用したIssuerの雛形はcert-managerのドキュメントを参照しました。
https://cert-manager.io/docs/configuration/acme/#external-account-bindings
Manifestの内容を軽く説明すると、spec.acme.serverがZeroSSLのACMEのエンドポイントになります。こちらのドキュメントに載っています。
https://zerossl.com/documentation/acme/
そして、spec.acme.externalAccountBindingでZeroSSLのEAB Credentialを使用して認証情報を設定します。
そして、最後にspec.solversですが、これはACMEで使用するChallengeの設定になります。今回はGCPを使っていることもありCloudDNSでDNS01 Challengeをすることにしたので、CloudDNSの認証情報を設定しています。そのため、CloudDNSでdns01を使用する場合はServiceAccountを発行してK8sのSecretを作成し、適宜置き換えてしてください。また、それ以外のChallengeを使用する場合はspec.solvers以下を修正してください。
apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
name: zerossl-dns01
spec:
acme:
server: https://acme.zerossl.com/v2/DV90
externalAccountBinding:
keyID: <EAB KIDを入力>
keySecretRef:
name: zerossl-eab-key
key: eab-key
keyAlgorithm: HS256
privateKeySecretRef:
name: zerossl-prod
solvers:
- dns01:
clouddns:
project: CloudDNSのZoneを置いているGCP Project ID
serviceAccountSecretRef:
key: CloudDNSのServiceAccountのSecretのKey
name: CloudDNSのServiceAccountのSecret名
IssuerのManifestが作成できたら、kubectlでapplyしてください。
Issuerが作成できたかどうかは、作成したclusterissuerリソースのStatusを確認してください。
StatusがTrueになっていて、MessageがThe ACME account was registered with the ACME serverになっていれば無事認証が通り、Issuerが作成できています。
kubectl get clusterissuer
NAME READY AGE
zerossl-dns01 True 8h
kubectl describe clusterissuer zerossl-dns01
(省略)
Status:
Message: The ACME account was registered with the ACME server
Reason: ACMEAccountRegistered
Status: True
Type: Ready
Certificateの作成
実際に動作確認用のCertificateを試しに発行してみます。
dnsNamesに発行したいドメインを書き、issuerRefに先ほど作成したIssuerを指定すれば終わりです。
また、今回ドメイン名はexample.localとして伏せていますのでご注意ください。
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
name: zerossl-test-example-local
spec:
dnsNames:
- zerossl.test.example.local
secretName: zerossl-test-example-local
issuerRef:
name: zerossl-dns01
kind: ClusterIssuer
CertificateのManifestも作成できたら、kubectlでapplyしてください。
こちらも作成できたかを確認するにはissuerと同様に作成したcertificateリソースのStatusを確認してください。
StatusがTrueになっていれば発行完了しています。数分待ってもReadyがTrueにならない場合はkubectl describeで詳細なStatusを確認してください。
kubectl get certificate
NAME READY SECRET AGE
zerossl-test-example-local True zerossl-test-example-local 8h
動作確認
最後に先ほど作成したCertificateを使ってnginxを立ててみたいと思います。
以下のコマンドでnginxのDeployment, Serviceを作成します。
kubectl create deploy nginx --image nginx --port 80
kubectl expose deploy nginx --port 80
最後にIngressを作成します。spec.tlsに先ほど作成したCertificateから生成されるSecretを設定します。
# ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: nginx
spec:
rules:
- http:
paths:
- path: /
backend:
serviceName: nginx
servicePort: 80
tls:
- secretName: zerossl-test-example-local
hosts:
- zerossl.test.example.local
そして、このIngressのManifestをapplyします。
kubectl apply -f ingress.yaml
そうしたら、以下のコマンドでingressのIPアドレスを調べます。(IPアドレスは伏せました)
$ kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
nginx * **.***.**.*** 80, 443 8h
IPアドレスを取得できたら、CloudDNSに証明書を取得しているドメインのAレコードに登録します。
そして、ブラウザからhttps://zerossl.test.example.local
にアクセスしてつながることを確認します。また証明書を見てZeroSSL発行のものであることが確認できるかと思います。
おわりに
今回はZeroSSLの証明書をcert-managerで発行する方法について書いてみました。
ZeroSSLがACMEに対応してくれているおかげでcert-managerを用いて自動でシュッと証明書を発行することが出来て幸せですね。
それでは!