GKEのSSL証明書を使ってGCP/GAEの証明書を更新する

  • このエントリーをはてなブックマークに追加

GKEでLet’s Encryptを使ってSSL証明書の自動更新をしています。それとは別に、GKEのIngressとして作成していないロードバランサやGAEにもSSL証明書を使用しています。

GAEは証明書の自動更新をしてくれますが、ワイルドカード証明書には対応していません。

私が作っている環境はワイルドカード証明書を利用しているので、GKEで自動更新設定しているSSL証明書をGCP/GAEにも適用してみます。

GKEでSSL証明書の自動更新の設定をする

こっちは本題ではないので、かなり簡潔に書きます。HTTPではなくDNS01で行います。また、cert-managerは0.3以上じゃないとワイルドカード証明書に対応していません。

HELM INSTALL
curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get> get_helm.sh
chmod 700 get_helm.sh
./get_helm.sh
HELM UPDATE(既にインストール済みの場合はUpdateする)
helm init --upgrade

$HELM_HOME has been configured at /Users/tamtam180/.helm.

Tiller (the Helm server-side component) has been upgraded to the current version.
Happy Helming!
RBAC設定
kubectl create serviceaccount tiller --namespace kube-system
kubectl create clusterrolebinding tiller --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
Install Tiller
helm init --upgrade --service-account tiller
cert-manager
git clone https://github.com/kubernetes/charts
cd charts
helm install --set image.tag=v0.3.2 --name cert-manager --namespace kube-system stable/cert-manager
cert-managerがCloudDNSを操作できるようにする
GCLOUD_PROJECT=my-sample-project
gcloud iam service-accounts create cert-manager --display-name "cert-manager"
gcloud projects add-iam-policy-binding ${GCLOUD_PROJECT} --member serviceAccount:cert-manager@${GCLOUD_PROJECT}.iam.gserviceaccount.com --role roles/dns.admin
service accountのkeyを作る
gcloud iam service-accounts keys create cert-manager-key.json --iam-account cert-manager@${GCLOUD_PROJECT}.iam.gserviceaccount.com
service accountをsecretに登録する
kubectl create secret generic clouddns-service-account --from-file=cert-manager-key.json=cert-manager-key.json --namespace=kube-system

ClusterIssuerを作る

clusterissuer.yaml
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@example.com # FIXME
privateKeySecretRef:
name: letsencrypt-prod
dns01:
providers:
- name: prod-dns
clouddns:
serviceAccountSecretRef:
name: clouddns-service-account
key: cert-manager-key.json
project: my-sample-project # FIXME
kubectl apply -f clusterissuer.yaml

Certificateを作る

ドメイン名はCloudDNSに登録している自分のドメインを指定します。
namespaceにdevを指定していますが、そこも自分の環境に合わせて調整してください。(私の場合はワイルドカード証明書を使っている関係で、dev環境やstaging環境に別のドメインを使っているため、環境ごとにnamesapceを分けています)

certificate.yaml
apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
name: example-com-tls
namespace: dev
spec:
secretName: example-com-tls
commonName: example.com
dnsNames:
- "example.com"
- "*.example.com"
acme:
config:
- dns01:
provider: prod-dns
domains:
- "example.com"
- "*.example.com"
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
kubectl apply -f certificate.yaml

GKEのSSL証明書をGAEに設定する

GAEは既存の証明書をupdateコマンドで一発で更新できます。

gcloud app ssl-certificates list 2>/dev/nullで証明書の一覧が取得できます。

GAEの証明書のExpire時間を計算する
CERT_ID=xxxxx # 目的のIDにしてね
T=$(LANG=C date --date $(gcloud app ssl-certificates describe ${CERT_ID} | grep expireTime | sed -e "s/'//g" | cut -d " " -f 2) +'%s')
expr \( $T - $(date +'%s') \) / 86400

こんな感じで今の証明書があと何日で期限切れになるのか計算できます。cert-managerでは30日前に自動更新するようになっているので、30日とか25日あたりを閾値にすると良いと思います。

GAEの証明書を更新する

# 秘密鍵を取得する
kubectl get secret example-com-tls -o json --namespace=dev | jq -r '.data["tls.key"]' | base64 --decode > /tmp/tls.key
# 証明書を取得する
kubectl get secret example-com-tls -o json --namespace=dev | jq -r '.data["tls.crt"]' | base64 --decode > /tmp/tls.crt

証明書の有効期限が延長済みであることを確認するには、次のコマンドで証明書の有効期限を見れば良いです。

# 有効期限の表示
cat /tmp/tls.crt | openssl x509 -noout -enddate
notAfter=Oct 29 08:40:28 2018 GMT

# UNIX時間でほしい場合
date --date "$(cat /tmp/tls.crt | openssl x509 -noout -enddate | cut -d'=' -f2)" +"%s"
CERT_ID=xxxx
gcloud app ssl-certificates update "${CERT_ID}" \
--display-name "*.example.com lets" \ # GAEに登録するSSL証明書の名前。日付とか入れると良いかも
--certificate "/tmp/tls.crt" \
--private-key "/tmp/tls.key"

ロードバランサの証明書を更新する

※GKE(k8s)のIngressとして作成したロードバランサは、cert-managerで勝手に更新されます。そうではない野良のロードバランサが対象です。

GCP管理の証明書を一覧する
# この結果にはGKEで作成したものも含まれています
gcloud compute ssl-certificates list

残念ながらGAEのようなupdateコマンドがありません。
手順はSSL証明書を作成し、target-https-proxiesにその作成した証明書を設定します。

SSL証明書の更新
CERT_NAME="star-dev-example-com-$(date +'%Y-%m-%d')"
gcloud compute ssl-certificates create "${CERT_NAME}" \
--certificate "/tmp/tls.crt" \
--private-key "/tmp/tls.key"

TARGET_PROXY="star-example-com-target-proxy-2"
gcloud compute target-https-proxies update "${TARGET_PROXY}" \
--ssl-certificates "${CERT_NAME}"

これでGKEの環境で証明書を自動更新しつつ、ほかの環境にも展開できるようになりました。実運用はk8sのcronjobを定義して↑の内容をよしなに処理するスクリプトを作れば良いと思います。