今まで検証環境はロードバランサーのIP直で接続していたのですが、
アプリと組み込むにあたり、httpsであることがもとめられてきました。
今回はドメインはfreenomで無料で取得しLet's EncryptでTLS証明書を発行してhttps化するところまでの備忘録を残しておきたいと思います。
やらないといけないことは以下です。少し長いですが一個づつやっていきたいと思います。
- freenomでフリードメインの取得
- Cloud DNSにドメイン登録する
- freenomのNameServersにGCPのNameServerを登録する
- GCPで静的なグローバルIPを取得する
- Cloud DNSにAレコードを登録して反映を待つ
- ServiceをNodePortに変更する
- Ingressを設定する
ここでまででhttp接続ができます
- tillerサービスアカウントを作成する
- helmの初期化する
- cert-managerをインストール
- cert-managerIAMを作成する
- cert-managerIAMにdnsのロールを追加する
- cert-managerIAMの接続JSON発行する
- 作成されたJSONをシークレットを登録する
- Let's EncryptへのDNS検証するためIssuerを作成する
- Certを作成しDNS検証を行う
- Ingressにtls設定をする
freenomでフリードメインの取得
freenomのドメイン取得については無料のドメインを取得するこちらの記事が非常に丁寧に記載してくれていますので内容は省略しております
freenomで好きなドメインを取得します。
ドメインはtk,ml,ga,cf,gqを選ぶことができます、好きなドメインを取得してください。
サイトが重いですが、無料なのでしょうがないと諦めます
一旦ドメインの発行だけを行いたいのでForward this domain toは適当に入力し
Periodは12ヶ月を選択しContinueを押します。
この後個人情報の入力などありますが、これでドメインが取得できました。
Cloud DNSにドメイン登録する
取得したドメインをCloudDNSに登録します
ゾーン名はDNS-01チャレンジで使うのでわかりやすい名前を設定してください
DNS名は先ほどfreenomで取得したドメインを入れます。
登録するとこのようになります、NameServerがわかったので、FreenomのNameServerに登録します
freenomのNameServersにGCPのNameServerを登録する
Cloud DNSに表示されているNameServerを入力します。
GCPで静的なグローバルIPを取得する
GCPに戻り、静的なグローバルUPを取得します。
名前は自分のわかりやすい名前を設定してください、ここのIPに設定した名前は後ほど使います
このような形でグローバルIPが割り当てられます。
静的なはIPはインスタンスと紐づいていない場合は従量課金が発生します。
Cloud DNSにAレコードを登録して反映を待つ
サブドメインのAレコードに先ほどのIPを紐づけます
今回は2つIPを取得していますが、特に意味はありません
develop.[domain]でサブドメインにAレコードを発行します
反映までしばらく時間がかかります、digなりドメイン検索するなりして作成したサブドメインがAレコードで登録したIPに向くのを待ちます
ServiceをNodePortに変更する
もともとロードバランサーの発行したIPで接続していたのですが、Ingressからの接続に変更するため、
NodePortに変更します。
apiVersion: v1
kind: Service
metadata:
name: api-service-dev
spec:
selector:
app: web-server-dev
ports:
- name: http
protocol: "TCP"
port: 80
targetPort: 80
type: "NodePort"
nginxは80でListenしているのでtargetPortは80です、もしも8080など別のポートで接続したい場合はnginxのconfを変更してください
applyし、GKEのサービスで確認すると10...**:80のようにNodePortになっているのがわかります
Ingressを設定する
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: api-service-dev-ingress
annotations:
kubernetes.io/ingress.global-static-ip-name: [IPに設定した名前]
kubernetes.io/ingress.class: "gce"
spec:
rules:
- host: develop.[ドメイン].tk
http:
paths:
- path: /*
backend:
serviceName: api-service-dev
servicePort: 80
serviceNameは先ほどのServiceの名前です。
Ingressの反映は10分ほどかかります、しばらくして取得したドメインでhttp接続できれば成功です。
tillerサービスアカウントを作成する
$ kubectl create serviceaccount tiller --namespace kube-system
serviceaccount "tiller" created
$ kubectl create clusterrolebinding tiller --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
clusterrolebinding "tiller" created
作成したtillerアカウントにcluster-admin権限を付与します
helmの初期化する
helmは別途インストールしてください
$ helm init --upgrade --service-account tiller
$HELM_HOME has been configured at /Users/raharu/.helm.
Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster.
Please note: by default, Tiller is deployed with an insecure 'allow unauthenticated users' policy.
To prevent this, run `helm init` with the --tiller-tls-verify flag.
For more information on securing your installation see: https://docs.helm.sh/using_helm/#securing-your-helm-installation
Happy Helming!
cert-managerをインストール
helmでcert-managerをインストールします。v0.6をインストールしようとするとCRDsを先にインストールしてくださいと言われるので、今回はv0.5.2を使用します。
$ helm install stable/cert-manager --name cert-manager --namespace kube-system --version v0.5.2
NAME: cert-manager
LAST DEPLOYED: Tue May 7 14:51:38 2019
NAMESPACE: kube-system
STATUS: DEPLOYED
~skio
https://cert-manager.readthedocs.io/en/latest/reference/ingress-shim.html
cert-managerIAMにdnsのロールを追加する
cert-managerのIAMアカウントを作成し、dnsの変更権限を付与します
$ gcloud iam service-accounts create cert-manager --display-name "cert-manager"
Created service account [cert-manager].
$ gcloud projects add-iam-policy-binding [プロジェクトID] --member serviceAccount:cert-manager@[プロジェクトID].iam.gserviceaccount.com --role roles/dns.admin
Updated IAM policy for project [プロジェクトID].
bindings:
~skip
- members:
- serviceAccount:cert-manager@[プロジェクトID].iam.gserviceaccount.com
role: roles/dns.admin
~skip
プロジェクトIDは自分のIDに変更してください
cert-managerIAMの接続JSON発行する
$ gcloud iam service-accounts keys create cert-manager-key.json --iam-account cert-manager@[プロジェクトID].iam.gserviceaccount.com
これでcert-manager-key.jsonが出来上がります
作成されたJSONをシークレットを登録する
$ kubectl create secret generic clouddns-service-account --from-file=cert-manager-key.json=cert-manager-key.json
Let's EncryptへのDNS検証するためIssuerを作成する
apiVersion: certmanager.k8s.io/v1alpha1
kind: Issuer
metadata:
name: letsencrypt-prod
spec:
acme:
# The ACME server URL
# 検証用URL
server: https://acme-staging-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: [メールアドレス]
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prod
# Enable the HTTP-01 challenge provider
http01: {}
# ACME dns-01 provider configurations
dns01:
# Here we define a list of DNS-01 providers that can solve DNS challenges
providers:
- name: prod-dns
clouddns:
# A secretKeyRef to a the google cloud json service account
serviceAccountSecretRef:
name: clouddns-service-account
key: cert-manager-key.json
# The project in which to update the DNS zone
project: [プロジェクトID]
Issuerは一旦検証用のURLで作成します。
projectは自分のプロジェクトIDに変更してください
$ kubectl apply -f cert-manager-issuer.yaml
範囲したら確認します。
$ kubectl describe issuer
Name: letsencrypt-prod
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"certmanager.k8s.io/v1alpha1","kind":"Issuer","metadata":{"annotations":{},"name":"letsencrypt-prod","namespace":"default"},"spec":{"acme...
API Version: certmanager.k8s.io/v1alpha1
Kind: Issuer
Metadata:
Creation Timestamp: 2019-05-07T08:46:53Z
Generation: 1
Resource Version: 20432444
Self Link: /apis/certmanager.k8s.io/v1alpha1/namespaces/default/issuers/letsencrypt-prod
UID: *********-******-*******-*****
Spec:
Acme:
Dns 01:
Providers:
Clouddns:
Project: [プロジェクトID]
Service Account Secret Ref:
Key: cert-manager-key.json
Name: clouddns-service-account
Name: prod-dns
Email: [メールアドレス]
Http 01:
Private Key Secret Ref:
Key:
Name: letsencrypt-prod
Server: https://acme-staging-v02.api.letsencrypt.org/directory
Status:
Acme:
Uri: https://acme-staging-v02.api.letsencrypt.org/acme/acct/9150475
Conditions:
Last Transition Time: 2019-05-07T08:47:00Z
Message: The ACME account was registered with the ACME server
Reason: ACMEAccountRegistered
Status: True
Type: Ready
Events: <none>
StatusにエラーがなくTypeがReadyになっていれば問題ありません。
一度Issuerを削除して本番用URLにします。
$ kubectl delete -f cert-manager-issuer.yaml
apiVersion: certmanager.k8s.io/v1alpha1
kind: Issuer
metadata:
name: letsencrypt-prod
spec:
acme:
# The ACME server URL
#server: https://acme-staging-v02.api.letsencrypt.org/directory
#本番用URLに変更
server: https://acme-v02.api.letsencrypt.org/directory
再度反映します
$ kubectl apply -f cert-manager-issuer.yaml
Certを作成しDNS検証を行う
apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
name: [名前は適宜変更]
namespace: default
spec:
secretName: cert-manager-tls
issuerRef:
name: letsencrypt-prod
commonName: *****.tk
dnsNames:
- develop.*****.tk
acme:
config:
- dns01:
provider: prod-dns
domains:
- develop.*****.tk
ドメインは自分のドメインをいれてください
$ kubectl apply -f cert-manager-cert.yaml
反映して確認を行います。
$ kubectl describe cert
Name: [名前は先ほど指定した名前]
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"certmanager.k8s.io/v1alpha1","kind":"Certificate","metadata":{"annotations":{},"name":"*********","namespace":"default"},"spec":{"acm...
API Version: certmanager.k8s.io/v1alpha1
Kind: Certificate
Metadata:
Creation Timestamp: 2019-05-07T09:06:29Z
Generation: 1
Resource Version: 20435693
Self Link: /apis/certmanager.k8s.io/v1alpha1/namespaces/default/certificates/*********
UID: *******-*******-*******-******
Spec:
Acme:
Config:
Dns 01:
Provider: prod-dns
Domains:
develop.*****.tk
Common Name: *****.tk
Dns Names:
develop.*****.tk
Issuer Ref:
Name: letsencrypt-prod
Secret Name: cert-manager-tls
Status:
Acme:
Order:
URL: https://acme-v02.api.letsencrypt.org/acme/order/*********/********
Conditions:
Last Transition Time: 2019-05-07T09:10:25Z
Message: Certificate issued successfully
Reason: CertIssued
Status: True
Type: Ready
Last Transition Time: <nil>
Message: Order validated
Reason: OrderValidated
Status: False
Type: ValidateFailed
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CreateOrder 12m cert-manager Created new ACME order, attempting validation...
Normal DomainVerified 9m cert-manager Domain "*****.tk" verified with "dns-01" validation
Normal DomainVerified 8m cert-manager Domain "develop.******.tk" verified with "dns-01" validation
Normal IssueCert 8m cert-manager Issuing certificate...
Normal CertObtained 8m cert-manager Obtained certificate from ACME server
Normal CertIssued 8m cert-manager Certificate issued successfully
しばらく待っていると検証が完了しCertificate issued successfullyとなります。
これで、cert-manager-tlsという名前のシークレットが作成されているはずです。
$ kubectl get secret
NAME TYPE DATA AGE
cert-manager-tls kubernetes.io/tls 2 15h
Ingressにtlsを追加する
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: api-service-dev-ingress
annotations:
kubernetes.io/ingress.global-static-ip-name: [IPに設定した名前]
kubernetes.io/ingress.class: "gce"
spec:
tls:
- hosts:
- develop.******.tk
secretName: cert-manager-tls
rules:
- host: develop.[ドメイン].tk
http:
paths:
- path: /*
backend:
serviceName: api-service-dev
servicePort: 80
しばらく待っているとHTTPS接続ができるはずです!
色々な記事を参考にさせてもらいながらどうにかTLS証明書を発行&自動更新まで作成することができました。
GAEのようにプロジェクトドメインを自動で発行してくれると尚楽なのですが、今後のGCPの発展に期待します。
また本来本番運用はLet's Encryptではなく有料証明書を発行して行うのが良いかとおもいますが、GAEの証明書もLet's Encryptとなっている今なにを選択するのかはお任せいたします。
また本記事は自分の備忘録に記載しております、同じようなことをこれから行う方の一助になれば幸いです。
ご意見、マサカリなどお待ちしております。
参考記事
https://qiita.com/atotto/items/9b626505cc1a56919bc2
https://qiita.com/apstndb/items/2fef0a80d4510516cb1f
https://torumakabe.github.io/post/aks_tls_autorenewal/
https://qiita.com/hali/items/ee71bc318233bad32d81
https://github.com/helm/charts/issues/10869