Welcome to new things

[Technical] [Electronic work] [Gadget] [Game] memo writing

How to automatically renew Let's Encrypt on Kubernetes (GKE) (wildcard certificate)

It was convenient to use "cert-manager" + DNS authentication to automatically update Let's Encrypt on Kubernetes (GKE) without processing on the service side.

I wrote Introductory note before, but the procedure had changed, so I rewrote it with how to get a wildcard certificate.

Based on the official manual, I have added some additional information, mainly where I got stuck.

Procedure (up to cert-manager installation)

Bring Kubernetes up to date

If it is 1.12 or earlier, the work requires a lot of work, so it should be 1.13 or higher.

Added namespace "cert-manager

kubectl create namespace cert-manager

# Validation invalidation (transcribed from manual)
kubectl label namespace cert-manager certmanager.k8s.io/disable-validation=true

install

kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v0.8.0/cert-manager.yaml

empowerment

kubectl create clusterrolebinding cluster-admin-binding \
  --clusterrole=cluster-admin \
  --user=$(gcloud config get-value core/account)

Overall flow

This completes the installation of cert-manager. Before proceeding to the next step, we will briefly describe the entire process.

How cert-manager works

The cert-manager consists largely of "Issuer" and "Certificate".

Certificate" mainly describes settings related to domains and certificates, and "Issue" describes settings related to the means of obtaining certificates and accounts.

The certificate is made available by executing the acquisition of the certificate in "Issuer" and storing it in the secret defined in "Certificate".

Difference between Issure and ClusterIssure

There are two types of "Issure": "Issure" and "ClusterIssure.

Issue" is an "Issue" associated with a namespace, and the certificate is valid only for the namespace in which the "Issue" is located.

ClusterIssure" on the other hand is an "Issure" tied to a cluster, and the certificate is valid in all namespaces.

Mechanism of Certificate Usage

The certificate obtained above is stored in Kubernetes as a secret. The certificate is then used by referencing the secret from Ingress. (The method of using certificates with Ingress is described in another article "How to communicate HTTPS with Kubernetes (GKE) (Ingress version)")

How Let's Encrypt DNS Authentication Works

In Let's Encrypt DNS authentication, Let's Encrypt checks if the claimant is the owner of the domain by checking if the specified value was written to the DNS record. Therefore, cert-manager allows the Issuer to edit DNS records by associating a service account with the Issuer that can edit GCP's DNS records, allowing the Issuer to pass the check from Let's Encrypt.

Procedure (remaining)

GCP Service Account Creation

Create a service account that allows you to edit DNS records

  1. Create any account by [GCP]-[IAM and Administration]-[Service Account]-[Create Service Account
  2. Add the account created in [GCP]-[IAM and Administration]-[IAM]-[Add] (with the role [DNS]-[DNS Admin])
  3. [GCP]-[APIs and Services]-[Authentication Information]-[Create Authentication Information]-[Service Account Key] to create a key JSON file (select service account and save key file with key type as JSON)

Register the key file in Kubernetes secret so that the contents of the key file can be referenced by cert-manager.

kubectl create secret generic <シークレット名> \
    --from-file=key.json=<キーファイルパス> \
    --namespace=cert-manager

The cert-manager itself will be created in the namespace "cert-manager" created during installation, so register the key file in the namespace "cert-manager" so that it can be accessed from there.

Issuer made

issuer.yaml

apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
  name: letsencrypt-issuer-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    # ステージの場合のURLは : https://acme-staging-v02.api.letsencrypt.org/directory
    email: <Let's Encryptに登録するemail>
    privateKeySecretRef:
      name: letsencrypt-issuer-prod
    dns01:
      providers:
        - name: clouddns
          clouddns:
            serviceAccountSecretRef:
              name: <DNSサービスアカウントのキーファイルのシークレット名>
              key: key.json
            project: <GCPプロジェクト名>
kubectl apply -f issuer.yaml

Certificate作成

certificate.yaml

apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
  name: letsencrypt-certificate-prod
spec:
  secretName: letsencrypt-tls-secret-prod    # Ingressから参照するシークレット名
  issuerRef:
    name: letsencrypt-issuer-prod  # Issuer名
    kind: ClusterIssuer
  commonName: "*.example.com"  # ドメイン名
  dnsNames:
  - example.com  # CloudDNSのDNS名
  acme:
    config:
    - dns01:
        provider: clouddns  # Issuerのprovider名
      domains:
      - example.com  # ドメイン名
      - "*.example.com"  # ワイルドカード
kubectl apply -f certificate.yaml

confirmation

kubectl describe certificate,issuer,clusterissuer --all-namespaces

You can check the status at

If all goes well, the certificate's "Events" will appear as shown below.

Events:
  Type    Reason         Age   From          Message
  ----    ------         ----  ----          -------
  Normal  OrderCreated   5m5s  cert-manager  Created Order resource …
  Normal  OrderComplete  5m3s  cert-manager  Order …
  Normal  CertIssued     5m3s  cert-manager  Certificate issued successfully

The "cert-manager" pod in the "cert-manager" namespace is responsible for obtaining certificates, so if it does not work, check the pod's logs to determine the cause.

About Wildcard Certificates

Normally one certificate is issued for one URL.

Wildcard certificates, on the other hand, can be used for any subdomain.

Since the certificate obtained with cert-manager can be used for both arbitrary subdomains ("*.example.com") and no subdomain ("example.com"), I think it would be a good idea to get a wildcard certificate for now.

Certificate Usage

A sample of Ingress is described below. By setting the secret of tls to the secret name set in Certificate, the certificate of Ingress and Certificate are linked. (How to use Certificate with Ingress is described in another article "How to communicate HTTPS with Kubernetes (GKE) (Ingress version)")

ingress.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress
  annotations:
    kubernetes.io/ingress.allow-http: "false"
    kubernetes.io/ingress.global-static-ip-name: "<static ip名>"
spec:
  tls:
  - secretName: letsencrypt-tls-secret-prod
  backend:
    serviceName: nginx
    servicePort: 80

supplementary explanation

If you keep repeating trial and error, you may get stuck on Let's Encrypt Limitations, It is better to test in staging rather than in production at first.

Staging is done by setting "server" in "issuer.yaml" to "https://acme-staging-v02.api.letsencrypt.org/directory".

reference information

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com