GKEで組んだクラスタへのHTTPS接続を試みる
GKEではGAEやAWSのロードバランサーのようにボタンポチーでHTTPS対応!みたいにはいかないようなのでメモ。
単純に実現しようとすると cert-manager でLet's Encryptの証明書を取得するのが最も手っ取り早そうなので、これを試してみることにします。
ちなみに 公式ドキュメント まんまなのでこっちを見たほうが早いと思います。
Helmのインストール
HelmはKubernetesのパッケージマネージャーです。
Macなら brew install kubernetes-helm
で入る。
スクリプト叩くだけでもいい。詳しくは こちら。
サービスアカウントの作成
サービスアカウントを作る
$ kubectl create serviceaccount tiller --namespace=kube-system
作成したサービスアカウントに権限をつける
$ kubectl create clusterrolebinding tiller-admin --serviceaccount=kube-system:tiller --clusterrole=cluster-admin
この例では管理者権限を付与してますが本番環境で使うときはしっかり権限のハンドリングをしておいたほうが良さそうです。参考
Tillerのインストール
サービスアカウントを渡してhelmをイニシャライズします。
これでKubernetesクラスタにTillerが立ちます。
Tillerはhelmのクライアントから送られてくる情報を元にうまいことk8sのAPIを叩いてくれるいい奴です。
$ helm init --service-account=tiller
nginx-ingressを立てる
$ helm install stable/nginx-ingress
これで各クラウドベンダのロードバランサーも立ちます。お金がかかります。しばらくすると外部IPが生えます。
外部IPにドメインを紐付ける
DNSの設定を行う。
アプリケーションのデプロイ
アプリケーションのServiceを立てておく。
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: exmaple-ingress annotations: kubernetes.io/ingress.class: "nginx" # certmanager.k8s.io/issuer: "letsencrypt-staging" # certmanager.k8s.io/acme-challenge-type: http01 spec: tls: - hosts: - example.example.com secretName: example-tls rules: - host: example.example.com # ドメイン名 http: paths: - path: / backend: serviceName: example-service # アプリケーションのService名 servicePort: 80
これを適当なファイル(今回はingress.yml
)に保存して
$ kubectl apply -f ingress.yml
ここまでで外部からの通信が可能になる。
cert-managerのインストール
$ kubectl apply -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.6/deploy/manifests/00-crds.yaml
Issuer の登録
Let's Encryptには証明書の取得制限があります。
基本的に気にしなくてもいいレベルの制限ですが、同じドメインの証明書の取得は一週間に5度までです。
作り直したりする過程で制限に入っても困るのでstagingで試してからにします。
なお、DNS-01方式はだるそうだったので、HTTP-01方式でドメインの認証を行います。
apiVersion: certmanager.k8s.io/v1alpha1 kind: Issuer metadata: name: letsencrypt-staging spec: acme: # The ACME server URL server: https://acme-staging-v02.api.letsencrypt.org/directory # Email address used for ACME registration email: user@example.com # Name of a secret used to store the ACME account private key privateKeySecretRef: name: letsencrypt-staging # Enable the HTTP-01 challenge provider http01: {}
$ kubectl apply -f staging-issuer.yaml
本番用のIssuerも作成しておく。
apiVersion: certmanager.k8s.io/v1alpha1 kind: Issuer metadata: name: letsencrypt-prod spec: acme: # The ACME server URL server: https://acme-v02.api.letsencrypt.org/directory # Email address used for ACME registration email: user@example.com # Name of a secret used to store the ACME account private key privateKeySecretRef: name: letsencrypt-prod # Enable the HTTP-01 challenge provider http01: {}
$ kubectl apply -f production-issuer.yaml
再度ingress.ymlを開いてコメントアウトを外した後にapplyする。
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: exmaple-ingress annotations: kubernetes.io/ingress.class: "nginx" certmanager.k8s.io/issuer: "letsencrypt-staging" certmanager.k8s.io/acme-challenge-type: http01 spec: tls: - hosts: - example.example.com secretName: example-tls rules: - host: example.example.com http: paths: - path: / backend: serviceName: example-service servicePort: 80
$ kubectl apply -f ingress.yml
applyすることでOrderが動いてLet's Encryptに対してリクエストが飛びます。
証明書の発行状態は kubectl describe certificate example-tls
で表示されるEventから見れる。
完了していた場合はSecretが作成されている。
$ kubectl describe secret example-tls
で確認できる。
問題なければIssuerを本番のものに切り替える。
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: exmaple-ingress annotations: kubernetes.io/ingress.class: "nginx" certmanager.k8s.io/issuer: "letsencrypt-prod" # changed certmanager.k8s.io/acme-challenge-type: http01 spec: tls: - hosts: - example.example.com secretName: example-tls rules: - host: example.example.com http: paths: - path: / backend: serviceName: example-service servicePort: 80
$ kubectl apply -f ingress.yml
Issuerを変更した後に、Secretを削除することで変更後のIssuerで証明書を取得します。
$ kubectl delete secret example-tls
ちょっとだけ時間がかかる。 状態はOrderから見れる。
$ kubectl get order NAME AGE example-tls-2000613234 2h
$ kubectl describe order example-tls-2000613234
以上でHTTPS接続が確認できた。
Helmとか知ってればあんまり手間じゃないのかもしれないけど結構面倒くさかったです…