Configuring HTTPS with cert-manager and Google Cloud DNS

You can use cert-manager with Knative to automatically provision TLS certificates from Let’s Encrypt and use Google Cloud DNS to handle HTTPS requests and validate DNS challenges.

The following guide demonstrates how you can setup Knative to handle secure HTTPS requests on Google Cloud Platform, specifically using cert-manager for TLS certificates and Google Cloud DNS as the DNS provider.

Learn more about using TLS certificates in Knative:

Before you begin

You must meet the following prerequisites to configure Knative with cert-manager and Cloud DNS:

Creating a service account and using a Kubernetes secret

To allow cert-manager to access and update the DNS record, you must create a service account in GCP, add the key in a Kubernetes secret, and then add that secret to your Knative cluster.

Note that several example names are used in the following commands, for example secret or file names, which can all be changed to your liking.

  1. Create a service account in GCP with dns.admin project role by running the following commands, where <your-project-id> is the ID of your GCP project:

    1. # Set this to your GCP project ID
    2. export PROJECT_ID=<your-project-id>
    3. # Name of the service account you want to create.
    4. export CLOUD_DNS_SA=cert-manager-cloud-dns-admin
    5. gcloud --project $PROJECT_ID iam service-accounts \
    6. create $CLOUD_DNS_SA \
    7. --display-name "Service Account to support ACME DNS-01 challenge."
    8. # Fully-qualified service account name also has project-id information.
    9. export CLOUD_DNS_SA=$CLOUD_DNS_SA@$PROJECT_ID.iam.gserviceaccount.com
    10. # Bind the role dns.admin to this service account, so it can be used to support
    11. # the ACME DNS01 challenge.
    12. gcloud projects add-iam-policy-binding $PROJECT_ID \
    13. --member serviceAccount:$CLOUD_DNS_SA \
    14. --role roles/dns.admin
  2. Download the service account key by running the following commands:

    1. # Make a temporary directory to store key
    2. KEY_DIRECTORY=`mktemp -d`
    3. # Download the secret key file for your service account.
    4. gcloud iam service-accounts keys create $KEY_DIRECTORY/cloud-dns-key.json \
    5. --iam-account=$CLOUD_DNS_SA
  3. Create a Kubernetes secret and then add that secret to your Knative cluster by running the following commands:

    1. # Upload that as a secret in your Kubernetes cluster.
    2. kubectl create secret --namespace cert-manager generic cloud-dns-key \
    3. --from-file=key.json=$KEY_DIRECTORY/cloud-dns-key.json
    4. # Delete the local secret
    5. rm -rf $KEY_DIRECTORY

Adding your service account to cert-manager

Create a ClusterIssuer configuration file to define how cert-manager obtains TLS certificates and how the requests are validated with Cloud DNS.

  1. Run the following command to create the ClusterIssuer configuration. The following creates the letsencrypt-issuer ClusterIssuer, that includes your Let’s Encrypt account info, DNS-01 challenge type, and Cloud DNS provider info, including your cert-manager-cloud-dns-admin service account.

    1. kubectl apply --filename - <<EOF
    2. apiVersion: cert-manager.io/v1alpha2
    3. kind: ClusterIssuer
    4. metadata:
    5. name: letsencrypt-issuer
    6. spec:
    7. acme:
    8. server: https://acme-v02.api.letsencrypt.org/directory
    9. # This will register an issuer with LetsEncrypt. Replace
    10. # with your admin email address.
    11. email: myemail@gmail.com
    12. privateKeySecretRef:
    13. # Set privateKeySecretRef to any unused secret name.
    14. name: letsencrypt-issuer
    15. solvers:
    16. - dns01:
    17. clouddns:
    18. # Set this to your GCP project-id
    19. project: $PROJECT_ID
    20. # Set this to the secret that we publish our service account key
    21. # in the previous step.
    22. serviceAccountSecretRef:
    23. name: cloud-dns-key
    24. key: key.json
    25. EOF
  2. Ensure that letsencrypt-issuer is created successfully by running the following command:

    1. kubectl get clusterissuer --namespace cert-manager letsencrypt-issuer --output yaml

    Result: The Status.Conditions should include Ready=True. For example:

    1. status:
    2. acme:
    3. uri: https://acme-v02.api.letsencrypt.org/acme/acct/40759665
    4. conditions:
    5. - lastTransitionTime: 2018-08-23T01:44:54Z
    6. message: The ACME account was registered with the ACME server
    7. reason: ACMEAccountRegistered
    8. status: "True"
    9. type: Ready

Add letsencrypt-issuer to your ingress secret to configure your certificate

To configure how Knative uses your TLS certificates, you create a Certificate to add letsencrypt-issuer to the istio-ingressgateway-certs secret.

Note that istio-ingressgateway-certs will be overridden if the secret already exists.

  1. Run the following commands to create the my-certificate Certificate, where <your-domain.com> is your domain:

    1. # Change this value to the domain you want to use.
    2. export DOMAIN=<your-domain.com>
    3. kubectl apply --filename - <<EOF
    4. apiVersion: cert-manager.io/v1alpha2
    5. kind: Certificate
    6. metadata:
    7. name: my-certificate
    8. namespace: istio-system
    9. spec:
    10. secretName: istio-ingressgateway-certs
    11. issuerRef:
    12. name: letsencrypt-issuer
    13. kind: ClusterIssuer
    14. dnsNames:
    15. - "*.default.$DOMAIN"
    16. - "*.other-namespace.$DOMAIN"
    17. EOF
  2. Ensure that my-certificate is created successfully by running the following command:

    1. kubectl get certificate --namespace istio-system my-certificate --output yaml

    Result: The Status.Conditions should include Ready=True. For example:

    1. status:
    2. acme:
    3. order:
    4. url: https://acme-v02.api.letsencrypt.org/acme/order/40759665/45358362
    5. conditions:
    6. - lastTransitionTime: 2018-08-23T02:28:44Z
    7. message: Certificate issued successfully
    8. reason: CertIssued
    9. status: "True"
    10. type: Ready

Note: If Status.Conditions is Ready=False, that indicates a failure to obtain a certificate, which should be explained in the accompanying error message.

Configuring the Knative ingress gateway

To configure the knative-ingress-gateway to use the TLS certificate that you created, append the tls: section to the end of your HTTPS port configuration.

Run the following commands to configure Knative to use HTTPS connections and send a 301 redirect response for all HTTP requests:

  1. kubectl apply --filename - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: Gateway
  4. metadata:
  5. name: knative-ingress-gateway
  6. namespace: knative-serving
  7. spec:
  8. selector:
  9. istio: ingressgateway
  10. servers:
  11. - port:
  12. number: 80
  13. name: http
  14. protocol: HTTP
  15. hosts:
  16. - "*"
  17. tls:
  18. # Sends 301 redirect for all http requests.
  19. # Omit to allow http and https.
  20. httpsRedirect: true
  21. - port:
  22. number: 443
  23. name: https
  24. protocol: HTTPS
  25. hosts:
  26. - "*"
  27. tls:
  28. mode: SIMPLE
  29. privateKey: /etc/istio/ingressgateway-certs/tls.key
  30. serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
  31. EOF

Congratulations, you can now access your Knative services with secure HTTPS connections. Your Knative cluster is configured to use cert-manager to manually obtain TLS certificates but see the following section about automating that process.

Configure Knative for automatic certificate provisioning

You can update your Knative configuration to automatically obtain and renew TLS certificates before they expire. To learn more about automatic certificates, see Enabling automatic TLS certificate provisioning.