Freenomの無料ドメインでcert-managerを使って、GKEのIngressをHTTPS(TLS)対応する
本記事
本記事ではGKE上でホストしているアプリケーションサーバーのが使っているIngressに対してHTTPS対応をしたいと思います。
背景としては、実はハッカソン用で開発をしていたのですが決済プラットフォームを使うためHTTPSに対応しなければなりませんでした。
しかし、ドメインにかけるお金は学生にはないので、無料で取得できるFreenom
で使ってやってみようと思います。
Freecomで無料ドメインを取得する
Freecomでは、数ヶ月程度の短い間なら無料でドメインを取得することができます。 ここで注意点ですが、FreeDomainと書いていても、Freeな期間はドメイン毎に決まっていて、1年間無料のものもあれば3ヶ月だけ無料のものもあるので、購入する前は注意してください。
無料ドメインが取得できれば、以下のようにリソースネームを設定します。
ここには以下のようにIngressのADDRESS
を入力します。
kubectl get ingress NAME HOSTS ADDRESS PORTS AGE frontend * 73.231.43.45 80 5d
ここでのIngressの設定は以下のようになっています。
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: frontend labels: app.kubernetes.io/name: frontend annotations: kubernetes.io/ingress.global-static-ip-name: frontend-ip spec: rules: - http: paths: - path: /* backend: serviceName: frontend servicePort: 3000
このときは簡単にファンアウト(出力を増やす)できるようにしています。例えば以下のようにすることができます。
以下のように簡単にファンアウトできて
121.31.164.232 -> / fan service1:80 / out service2:80
ドメインをとっても
example.com -> 121.31.164.232 -> / fan service1:80 / out service2:80
することができます。
Cert Managerを使って証明書を管理する
cert-manager
とはKubernetesのアドオンでLet`s Encryptによって証明書をプロビジョニング、更新をするものです。
同じようで機能でkube-lego
がありましたが、cert-maneger
はこの新しいバージョンになります。
Helmを使ってCert Managerをインストール
$ helm install \ --name https \ --namespace kube-system \ stable/cert-manager
すると以下のようにDeploymentができます。
$ kubectl get pods --namespace=kube-system https-cert-manager-6ffc878445-986qf 1/1 Running 0 7s
Deploymentだけでなく、以下のようにいくつかできています。
==> v1/ServiceAccount NAME AGE https-cert-manager 1s ==> v1beta1/ClusterRole https-cert-manager 1s ==> v1beta1/ClusterRoleBinding https-cert-manager 1s
Let`s Encryptの認証用ファイルを作成
以下のようにcusterIssuer.yaml
を作成します。
apiVersion: certmanager.k8s.io/v1alpha1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: XXXXXXXX@gmail.com // 自分のメールアドレス privateKeySecretRef: name: letsencrypt-prod // Certのために使うために名前をつける http01: {}
そしてkubectl apply
します。
kubectl apply -f issuer.yaml -n kube-system
証明書のためのファイルを作成
以下のようにcert.yaml
を作成します。
apiVersion: certmanager.k8s.io/v1alpha1 kind: Certificate metadata: name: oaiso-tk namespace: default spec: secretName: oaiso-tk-tls issuerRef: name: letsencrypt-prod commonName: oaiso.tk // Domainの名前 dnsNames: - oaiso.tk acme: config: - http01: ingress: frontend // Ingressの名前 domains: - oaiso.tk // Domainの名前
今回はACMEプロトコルのhttp01 challenge
を使います。
ACMEとは証明書発行のプロトコルで
http01 challenge
: Let`s EncryptからTokenをつけとって特定のパスに入れて認証されてドメインを確認する方法dns01 challenge
: Token受け取ってTXT
レコードにTokenをつけてドメインを確認する方法
の二つの種類があります。
ここまでを確認してみます。
kubectl get issuer -n kube-system kubectl get cert
Ingress
を見てみると以下のように挿入されています。
これはcert
をデプロイしてから数分後に作られるのですぐに設定されていなくても安心して少し待ってみてください。
- host: oaiso.tk http: paths: - backend: serviceName: cm-acme-http-solver-jhzv7 servicePort: 8089 path: /.well-known/acme-challenge/lJeUWf5GOboGTFtsukxSaZpXNC_qyQkGulvTHpkly8k
lJeUWf5GOboGTFtsukxSaZpXNC_qyQkGulvTHpkly8k
がTokenであり、これによってhttp01 challenge
をすることができるようになるというわけです。
もちろん、バックエンドには
$ kubectl get svc cm-acme-http-solver-jhzv7 NodePort 10.31.250.77 <none> 8089:32100/TCP 49m $ kubectl get pods cm-acme-http-solver-9b9nj 1/1 Running 0 49m
があるからこそ実現できます。これらはDeployment
はcert
を削除することで消すことができます。
Certの進捗確認はcert
リソースタイプを見てみるといいです。
$ kubectl describe cert oaiso-tk ... Normal CreateOrder 9m cert-manager Created new ACME order, attempting validation... Normal DomainVerified 2m cert-manager Domain "oaiso.tk" verified with "http-01" validation Normal IssueCert 1m cert-manager Issuing certificate... Normal CertObtained 1m cert-manager Obtained certificate from ACME server Normal CertIssued 1m cert-manager Certificate issued successfully
これで取得できていることがわかります。
cert-manager
のログをみると様子がわかります。
Ingressで証明書を使用する
以下のようにspec.tls
を追加します。
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: frontend labels: app.kubernetes.io/name: frontend annotations: kubernetes.io/ingress.global-static-ip-name: frontend-ip spec: tls: - secretName: oaiso-tk-tls hosts: - oaiso.tk rules: - http: paths: - path: /* backend: serviceName: frontend servicePort: 5000
そしてUPDATE
します。
$ kubectl apply -f ingress.yaml
そして進捗を確認します。
$ kubectl describe ing frondend ... Normal Service 1m (x141 over 1h) loadbalancer-controller no user specified default backend, using system default Normal UPDATE 37s (x149 over 1h) nginx-ingress-controller Ingress default/frontend
OpenSSLコマンドで証明書を確認する
以下のコマンドをドメイン名に対して使うことによって証明書を取得できているかどうか確認することができます。
openssl s_client -connect oaiso.tk:443 CONNECTED(00000006) depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 verify error:num=20:unable to get local issuer certificate verify return:0 --- Certificate chain 0 s:/CN=oaiso.tk i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3 1 s:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3 i:/O=Digital Signature Trust Co./CN=DST Root CA X3 --- Server certificate -----BEGIN CERTIFICATE----- MIIF+zCCBOOgAwIBAgISAw5/coR89bnHT1nLudtsywtKMA0GCSqGSIb3DQEBCwUA MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODEwMjkxMTMyMTdaFw0x OTAxMjcxMTMyMTdaMBMxETAPBgNVBAMTCG9haXNvLnRrMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAox8hhYK/5Pg1J0f+qnSNCAtJ6s7OaNqJJ+4cMqsU uaVCMFjx7fxaXn2O7gm9KKTIYYbFp0//EJMKHbaR7oxyWrdCF98oAWfaDFunR1MP 5CjeZgrgiHTk7QeU4hO+m9IGXdvoZtdeNnaVhnk8MP9l/h5rm7D9c5OWuB1pqqSe rWWq3IPApd2ql/J891FMEUETy/8bJYFYRVUL2cUB/CkT5+YKcj7paqPQ16sujG0Q /LihXCPnGRrKnyNqK3FZzExWIDgJu5z0m/9ib8MfKMgrg3nXs71wjv5UsJkvRgp5 UQbLLnmGanPAO+ceiN3Rneg3Ws3hnaEa74nyAsOu4DQGEwIDAQABo4IDEDCCAwww DgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAM BgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTnElbPxcgLsOg0dht0E/qyFyXdqDAfBgNV HSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEFBQcBAQRjMGEwLgYI KwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5jcnlwdC5vcmcwLwYI KwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5vcmcvMBMG A1UdEQQMMAqCCG9haXNvLnRrMIH+BgNVHSAEgfYwgfMwCAYGZ4EMAQIBMIHmBgsr BgEEAYLfEwEBATCB1jAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5sZXRzZW5jcnlw dC5vcmcwgasGCCsGAQUFBwICMIGeDIGbVGhpcyBDZXJ0aWZpY2F0ZSBtYXkgb25s eSBiZSByZWxpZWQgdXBvbiBieSBSZWx5aW5nIFBhcnRpZXMgYW5kIG9ubHkgaW4g YWNjb3JkYW5jZSB3aXRoIHRoZSBDZXJ0aWZpY2F0ZSBQb2xpY3kgZm91bmQgYXQg aHR0cHM6Ly9sZXRzZW5jcnlwdC5vcmcvcmVwb3NpdG9yeS8wggEEBgorBgEEAdZ5 AgQCBIH1BIHyAPAAdgBvU3asMfAxGdiZAKRRFf93FRwR2QLBACkGjbIImjfZEwAA AWa/z308AAAEAwBHMEUCIGji06/WBgHj84tTKJ0DVKOmnEB29mUGjy0zuVW3n4dA AiEAxM0HhDfeKkZbeY53+zETToF8AEPEwKqvB96C59uWdnIAdgApPFGWVMg5Zbqq UPxYB9S3b79Yeily3KTDDPTlRUf0eAAAAWa/z30JAAAEAwBHMEUCIHynBttOOg4/ 6C4qtrrptZ198CUH9TCRXTWz9YETLu8nAiEA/o67eXNHba3+NZb7GvTf1pyw/3k4 S+iyK8Wy2MQQd5IwDQYJKoZIhvcNAQELBQADggEBAJsM9AvC7o+qzrFBTw5ZAhK/ 4+F9plHykrwGeICkYcmN1kG0Hjnqud8VYnH7TGoN477anAyqDUAxb57QxWn3Osbp uK1hkKCWd1XB/g8i17YUA98iGGCVt2r8AM2qLaTRgnfjknWUDOlf9R7c2keqPCpA ghWNVB5BaoNoqPyNOrzF80ziD/0p4i7BZjSoLsTGIpk4+H7YOFLF+khXuXlxviak cOCIFINmt7o4Gi/k37JVGlkrl2s/tKklD6dN3aqCfBeni7YoGrLwuBFLTUgHH6PA yekN/xcHwwZ85/cDNl+Nq7iIPdLF6cf6OSE2S1E3jTd5ULCMkSLb3fGN1GLZXiY= -----END CERTIFICATE----- subject=/CN=oaiso.tk issuer=/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3 --- No client certificate CA names sent --- SSL handshake has read 3417 bytes and written 444 bytes --- New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256 Server public key is 2048 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE No ALPN negotiated SSL-Session: Protocol : TLSv1.2 Cipher : ECDHE-RSA-AES128-GCM-SHA256 Session-ID: 9A4F4B51894315CE19C148A3B5071EB05713DF6C7A4615BD8F5EAC41B9AE6A88 Session-ID-ctx: Master-Key: FDBB6D4AA680ED5219EA449E17C1A49F789D5772FAFF69FC49670DBB30D89EB24BA3AB1AB2BBBB346EA8371625B61D2C TLS session ticket lifetime hint: 100800 (seconds) TLS session ticket: 0000 - 00 3c a8 dd 25 de 46 b4-98 61 b6 0a ec d9 5f da .<..%.F..a...._. 0010 - e6 d9 ac e7 30 f4 df 45-f0 48 9c eb e1 e1 ed 0f ....0..E.H...... 0020 - 11 5c 2e e9 1f 89 39 d3-f8 d5 e4 d9 c0 5a dc 61 .\....9......Z.a 0030 - 7f ed df f3 c1 ad 63 c3-fd 8c bd 1d 6c a0 6b d1 ......c.....l.k.
HTTPをはじく
以下のようにingress
にmetadata.annotation[]
に追加するとhttp
をはじくことができます。
... metadata: name: frontend annotations: kubernetes.io/ingress.global-static-ip-name: oaiso-frontend kubernetes.io/ingress.allow-http: "false" ...
ポイント
helm
で簡単に対応することができる- 必ずする必要がないが
spec.tls
なしで開始して、cert
をapply
してspec.tls
を足す方がわかりやすい。 kubectl apply -f cert.yaml
してからも時間がかかるし、ingress
が更新されても時間がかかるので、時間を使う- 無料ドメインでいくらでも対応できる
http://IPアドレス
は使うことができないexample.com
がHTTPS対応してもhoge.example.com
がHTTPS対応できるわけではない- Let`s Encryptの証明書が取れないときは、一度コンポーネントを削除して見るのもいい、特にsecretそのもの
Named Base Virtual Hostion
Vitual Hostingとは
バーチャルホストは、一台のサーバーで同じIPアドレスを使って仮想的に複数のドメインを運用するサーバー技術の一種です。ドメイン数を上回るサーバーを用意したくないときに使用する
ものです。IPアドレスの節約効果やサーバー機器を減らすことで運用コストの削減などのメリットがありますが、障害のリスクや負荷が集中するなどデメリットもあります。
実用的に使ってみる
今まではいかのように
以下のようにVirtual Hostionを実際に使うならば
example.com --| |-> example.com service1:80 | 178.91.123.132 | example2.com --| |-> another.example.com service1:80
これからは一つだけと同じなので、説明をしません。