route53で管理するドメインの証明書をcert-managerで管理しGKEで使用する

GCPでKubernetesを使用する場合、AWSと違いTLS証明書を発行してくれるサービスが存在しません。
有料の証明書を購入すれば良い話ではありますが、機能は同じなので無料でいきたいところです。
そこで、今回はLet's Encryptを利用したいと思います。

しかし、Let's Encryptは90日で証明書の期限が切れてしまい管理が大変なので、Kubernetesのアドオンであるcert-managerを使用したいと思います。

github.com

環境

  • GKE 1.9.7-gke.1
  • cert-manager v0.3.1
  • route53

Let's Encryptの認証方法

cert-managerではLet's EncryptのACMEプロトコルであるHTTP-01とDNS-01に対応しています。
ACMEプロトコルについての解説は他に譲りますが、HTTP-01だとhttpアクセスを受け入れるため、ingressとの関わりが生まれてしまいます。
できるだけシンプルに管理したいので、今回はDNS-01を使用します。

また、DNS-01だとDNSのTXT レコードを操作するため、DNSへのアクセス権を付与する必要があります。
DNSへアクセスできない場合はHTTP-01で行うしかありません。

HTTP-01のやり方はこの記事(英語)がわかりやすいです。

github.com

cert-managerのインストール

cert-managerはhelmでインストールします。

$ helm install --name cert-manager --namespace kube-system stable/cert-manager

その他のパラメーターなどの詳細はこちらで確認できます。

github.com

route53へアクセスするための設定

IAMの作成

DNS-01で認証するのでroute53に書き込みができるIAMを作成します。

公式ドキュメントにIAMのポリシーが書かれていますが、古くなっているのか執筆時(2018/06/28)では動きませんでした。
ですが、すでにこの事がissueで議論されており、動作するポリシーが書かれているのでそれを利用します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "route53:GetChange",
            "Resource": "arn:aws:route53:::change/*"
        },
        {
            "Effect": "Allow",
            "Action": "route53:ChangeResourceRecordSets",
            "Resource": "arn:aws:route53:::hostedzone/*"
        },
        {
            "Effect": "Allow",
            "Action": "route53:ListHostedZonesByName",
            "Resource": "*"
        }
    ]
}

このポリシーを適用したIAMユーザーの認証情報をダウンロードしておきます。

cert-managerが読み込むsecretの作成

cert-managerはAWSAccess Keyはyamlに生で書き込み、Secret KeyはKubernetesのsecretを経由して読み込みます。
そのため、まずはSecret Keyをsecretとして定義します。

$ echo -n 'youreSecretKey' | base64
apiVersion: v1
kind: Secret
metadata:
  name: prod-route53-credentials-secret
type: Opaque
data:
  secret-access-key: hogePiyoFaaaa==

base64エンコードしたsecretKeyをsecret-access-keyに入れます。

Issuerの作成

Issuerという名前の通り、Let's Encryptに発行を依頼するのに必要な情報を記述します。
ドメインの情報は、次に作成するCertificateで定義するのでそれ以外の情報をここで定義します。

apiVersion: certmanager.k8s.io/v1alpha1
kind: Issuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: hoge@hoge.com
    privateKeySecretRef:
      name: letsencrypt-prod
    dns01:
      providers:
        - name: prod-dns
          route53:
            accessKeyID: YOUREROUTE53ACCESSKEYID
            secretAccessKeySecretRef:
              name: prod-route53-credentials-secret
              key: secret-access-key

emailとaccessKeyIDを正しいものに書き換えます。

Certificateの作成

作成する証明書のドメイン情報を定義します。

apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
  name: sample-com
spec:
  secretName: hoge-tls
  issuerRef:
    name: letsencrypt-prod
  commonName: 'hoge.com'
  dnsNames:
    - hoge.com
  acme:
    config:
      - dns01:
          provider: prod-dns
        domains:
          - '*.hoge.com'
          - hoge.com

ドメインを正しいものに書き換えてください。
Certificateが存在するnamespaceにsecretNameで指定した名前でTLS証明書がsecretに加工された状態で作成されます。

証明書の作成

ここまでに作成したIssuerとCertificateをKubernetesに適用します。
そうするとcert-managerでの管理が始まり、証明書が作成されます。

作成状況はdescribeコマンドで確認できます。

$ kubectl describe certificate

...
Type     Reason                Message
----     ------                -------
...
Normal   CeritifcateIssued     Certificated issued successfully

このような出力になれば証明書の作成に成功しています。

この証明書はcert-managerによって管理され、失効まで30日を切ると更新されます。