2
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

GKE+freenom+Let'sEncrypt+cert-managerでTLS証明書を自動更新する

Last updated at Posted at 2019-05-08

今まで検証環境はロードバランサーの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で好きなドメインを取得します。

190424-0002-2.png

ドメインはtk,ml,ga,cf,gqを選ぶことができます、好きなドメインを取得してください。
サイトが重いですが、無料なのでしょうがないと諦めます

190424-0005-2.png

一旦ドメインの発行だけを行いたいのでForward this domain toは適当に入力し

Periodは12ヶ月を選択しContinueを押します。
この後個人情報の入力などありますが、これでドメインが取得できました。

Cloud DNSにドメイン登録する

取得したドメインをCloudDNSに登録します

190507-0009.png

ゾーン名はDNS-01チャレンジで使うのでわかりやすい名前を設定してください
DNS名は先ほどfreenomで取得したドメインを入れます。

190507-0001-2.png

登録するとこのようになります、NameServerがわかったので、FreenomのNameServerに登録します

freenomのNameServersにGCPのNameServerを登録する

190507-0003.png

Cloud DNSに表示されているNameServerを入力します。

GCPで静的なグローバルIPを取得する

GCPに戻り、静的なグローバルUPを取得します。

190507-0010.png

名前は自分のわかりやすい名前を設定してください、ここのIPに設定した名前は後ほど使います

190507-0011-2.png

このような形でグローバルIPが割り当てられます。
静的なはIPはインスタンスと紐づいていない場合は従量課金が発生します。

Cloud DNSにAレコードを登録して反映を待つ

サブドメインのAレコードに先ほどのIPを紐づけます

190507-0002-3.png

今回は2つIPを取得していますが、特に意味はありません
develop.[domain]でサブドメインにAレコードを発行します

反映までしばらく時間がかかります、digなりドメイン検索するなりして作成したサブドメインがAレコードで登録したIPに向くのを待ちます

ServiceをNodePortに変更する

もともとロードバランサーの発行したIPで接続していたのですが、Ingressからの接続に変更するため、
NodePortに変更します。

service.yaml
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を変更してください
190507-0012-2.png

applyし、GKEのサービスで確認すると10...**:80のようにNodePortになっているのがわかります

Ingressを設定する

ingress.yaml
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を作成する

cert-manager-issuer.yaml
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
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検証を行う

cert-manager-cert.yaml
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を追加する

ingress.yaml
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接続ができるはずです!

190507-0008-2.png

色々な記事を参考にさせてもらいながらどうにか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

2
5
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
2
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?