LoginSignup
13
10

More than 5 years have passed since last update.

Google Container Engine上でLet's Encryptによる証明書を自動更新する(kube-lego)

Last updated at Posted at 2016-12-28

背景

GKE上でLet's Encrypt(certbot)によるhttps化をするには、いくつか課題があります。
特に自動更新は厄介です。

本記事ではkube-legoを用いて、証明書の自動更新に対応する構成を記載します。
これを用いると、サービス側のファイルや設定をほぼいじらずにhttps化できます(ついでにhttp2も)。

なお、節約のためLet's Encryptで無料の証明書を取っていますが、これが複雑さの原因です。
証明書を買っている方は設定のみ行えば良いので、この記事の内容は一部しか役立ちません。
お金の力は偉大です。

前提

上記記事の手順を踏んでいると仮定します。
なお、独自ドメイン周りは本記事の手順の後半で再度いじることになる可能性が高いです。

できること

  • Let's Encryptで証明書の無料&自動更新

全体像

ingressでL7ロードバランサーを設定し、Let's Encrypt認証と通常のアクセスを振り分けます。
nginxを挟むの手順に従っている場合は)通常のアクセスではnginxを挟み、httpであればhttpsにリダイレクトします。

Let's Encryptの認証処理や一部設定は、kube-legoが行います。
kube-legoはアプリケーションとはnamespaceから区切り、独立したサービスとして立てます。

手順

(オプション)http->httpsのリダイレクト

2016年の現状、GCEのL7ロードバランサーではリダイレクトができません。
そのため、nginxを挟んで処理してね!とドキュメントに書かれています。

http->httpsのリダイレクトを行う場合は、nginxを挟むに沿って設定を行ってください。

Service typeの変更

serviceのタイプはLoadBalancerとして設定していましたが、これをNodePortにします。
これにより、サービスにロードバランサーを割り当てず、こちらで設定ができます。

apiVersion: v1
kind: Service
metadata:
  name: yourservice
  labels:
    app: yourservice
spec:
  type: NodePort
  ports:
    - name: http
      port: 80
  selector:
    app: yourservice

上記で設定後kubectl get svcで見てみると、EXTERNAL IP<nodes>となっています。

ingressの設定

GCPなので某ゲームが真っ先に浮かびますが、一般的な名詞(入場権とか)として使われているようです。
これは、L7ロードバランサーの設定をするもので、サービスへのアクセスルールを設定することができます。
公式ドキュメントに分かりやすいアスキーアートがあります。

ingressの設定は以下のようになります。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: yourservice
  namespace: default
  annotations:
    kubernetes.io/tls-acme: "true"
    kubernetes.io/ingress.class: "gce"
spec:
  tls:
  - hosts:
    - yourhost.jp
    secretName: yourservice-tls
  rules:
  - host: yourhost.jp
    http:
      paths:
      - path: /*
        backend:
          serviceName: yourservice
          servicePort: 80

これは以下の処理を行っています。

  • TLSターミネーション
    • yourservice-tlsという名前のkubernetesのsecretを取り出します
    • ここには.crtなどが入っています
  • アクセスの割り振り
    • ここでは/*(要はデフォルト)のみを設定しています
    • Let's Encryptの/.well-known/...はどうするの?となりますが、kube-legoが作ってくれます

ingressを使うと、自動でL7ロードバランサーが割り当てられます。
詳細はGoogle HTTP(S) Load Balancer

applyすると、kubectl get ingでステータスが確認できます。

kube-legoを立てる

kube-legoによるGCEのサンプルが用意されているので、この手順通りに進めます。

まずはkube-lego用のnamespaceを作ります。

apiVersion: v1
kind: Namespace
metadata:
  name: kube-lego

次に、configMapを設定します。
ここでLet's Encryptのサーバーを指定しますが、まずはテスト用のAPIから取得し、上手く行ってから本番のAPIに切り替えましょう。
Staging Environment

なお、本番APIにconfigMapを切り替えた際は、kube-lego周りのsecretを一旦削除しないと正しく取得をしてくれないので要注意です。

apiVersion: v1
metadata:
  name: kube-lego
  namespace: kube-lego
data:
  lego.email: "your@mail.address"
  lego.url: "https://acme-staging.api.letsencrypt.org/directory"
kind: ConfigMap

最後に、サービスのdeploymentです。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: kube-lego
  namespace: kube-lego
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: kube-lego
    spec:
      containers:
      - name: kube-lego
        image: jetstack/kube-lego:0.1.3
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
        env:
        - name: LEGO_EMAIL
          valueFrom:
            configMapKeyRef:
              name: kube-lego
              key: lego.email
        - name: LEGO_URL
          valueFrom:
            configMapKeyRef:
              name: kube-lego
              key: lego.url
        - name: LEGO_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: LEGO_POD_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        readinessProbe:
          httpGet:
            path: /healthz
            port: 8080
          initialDelaySeconds: 5
          timeoutSeconds: 1

jetstack/kube-legoをポート8080で立て、各種値をconfigMapから拾ったり設定したりしています。
特に他サービスに依存しないため、書き換える必要はありません。

確認

kube-legoの確認

kubectl describe ingで詳細を見てみると、
/.well-known/acme-challenge/* kube-lego-gce:8080 (<none>)というものが追加されています。
無事アクセスが分かれてくれそうですね。

追加した時点から、kube-legoは認証の確認を行っています。
kubectl --namespace=kube-lego get podでポッドIDを確認し、
kubectl --namespace=kube-lego log <pod-id>
でログを見てみましょう。

上手く行っていない場合は原因がログに出ているので対処します。

成功すると、以下のようなログが出ています。
msg="creating new secret" context=secret name=yourservice-tls namespace=default
kube-legoがyourservice-tlsというsecretに設定をしてくれた模様です。

msg="cert expires in 90.0 days, no renewal needed"
というログも出ており、期限に近づくと改めて認証を行い、証明書を取得してくれます。

サービスの確認

最後に、取得したドメインにhttpsでアクセスしてみます。
ページが見つからないと言われたりする場合は、ingressで割り振られた新しいIPにドメインが正しく紐付いているか確認してください。

  • ingressを一旦削除
  • Cloud DNSの設定、IPを確認
  • IPで正しくアクセスできるか確認
  • Static IPを解放してやり直す
  • などなど...

正しくアクセスできると、「この接続は信頼されていません...」というメッセージが出てくるかと思います。
これはテスト用のLet's Encrypt APIを使ったためです。

configMapを本番用のAPI URL(https://acme-v01.api.letsencrypt.org/directory)に書き換え、applyをします。

kubectl delete secret yourservice-tls
kubectl --namespace=kube-lego delete secret --all
kubectl --namespace=kube-lego delete pod --all

を行い、secretの削除&podの再起動をしてすぐさま再取得をしてもらいます。

証明書が発行され、サービスに警告無しでhttpsアクセスできたら成功です!:tada:

13
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
10