Configuring Knative and CertManager for Google Cloud DNS
These instructions assume you have already setup a Knative cluster and installed cert-manager into your cluster. For more information, see using an SSL certificate. They also assume you have already set up your managed zone with Cloud DNS as part of configuring the domain to map to your IP address.
To automate the generation of a certificate with cert-manager and LetsEncrypt,
we will use a
DNS01 challenge type, which requires the domain owner to add a
TXT record to their zone to prove ownership. Other challenge types are not
currently supported by Knative.
Creating a Cloud DNS service account
To add the TXT record, configure Knative with a service account that can be used by cert-manager to create and update the DNS record.
To begin, create a new service account with the project role
# Set this to your GCP project ID export PROJECT_ID=<your-project-id> # Name of the service account you want to create. export CLOUD_DNS_SA=cert-manager-cloud-dns-admin gcloud --project $PROJECT_ID iam service-accounts \ create $CLOUD_DNS_SA \ --display-name "Service Account to support ACME DNS-01 challenge." # Fully-qualified service account name also has project-id information. export CLOUD_DNS_SA=$CLOUD_DNS_SA@$PROJECT_ID.iam.gserviceaccount.com # Bind the role dns.admin to this service account, so it can be used to support # the ACME DNS01 challenge. gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:$CLOUD_DNS_SA \ --role roles/dns.admin # Download the secret key file for your service account. gcloud iam service-accounts keys create ~/key.json \ --iam-account=$CLOUD_DNS_SA
After obtaining the service account secret, publish it to your cluster. This
command uses the secret name
cloud-dns-key, but you can choose a different
# Upload that as a secret in your Kubernetes cluster. kubectl create secret --namespace cert-manager generic cloud-dns-key \ --from-file=key.json=$HOME/key.json # Delete the local secret rm ~/key.json
Configuring CertManager to use your DNS admin service account
Next, configure cert-manager to request new certificates and verify the challenges using DNS.
Specifying a certificate issuer
This example configures cert-manager to use LetsEncrypt, but you can use any certificate provider that supports the ACME protocol.
This example uses the
dns01 challenge type, which will enable certificate
generation and wildcard certificates.
kubectl apply --filename - <<EOF apiVersion: certmanager.k8s.io/v1alpha1 kind: ClusterIssuer metadata: name: letsencrypt-issuer namespace: cert-manager spec: acme: server: https://acme-v02.api.letsencrypt.org/directory # This will register an issuer with LetsEncrypt. Replace # with your admin email address. email: firstname.lastname@example.org privateKeySecretRef: # Set privateKeySecretRef to any unused secret name. name: letsencrypt-issuer dns01: providers: - name: cloud-dns-provider clouddns: # Set this to your GCP project-id project: $PROJECT_ID # Set this to the secret that we publish our service account key # in the previous step. serviceAccountSecretRef: name: cloud-dns-key key: key.json EOF
To check if your ClusterIssuer is valid, enter:
kubectl get clusterissuer --namespace cert-manager letsencrypt-issuer --output yaml
Then confirm that its conditions have
Ready=True. For example:
status: acme: uri: https://acme-v02.api.letsencrypt.org/acme/acct/40759665 conditions: - lastTransitionTime: 2018-08-23T01:44:54Z message: The ACME account was registered with the ACME server reason: ACMEAccountRegistered status: "True" type: Ready
Specifying the certificate
Next, configure which certificate issuer to use and which secret you will
publish the certificate into. Use the Secret
following steps will overwrite this Secret if it already exists.
# Change this value to the domain you want to use. export DOMAIN=your-domain.com kubectl apply --filename - <<EOF apiVersion: certmanager.k8s.io/v1alpha1 kind: Certificate metadata: name: my-certificate # Istio certs secret lives in the istio-system namespace, and # a cert-manager Certificate is namespace-scoped. namespace: istio-system spec: # Reference to the Istio default cert secret. secretName: istio-ingressgateway-certs acme: config: # Each certificate could rely on different ACME challenge # solver. In this example we are using one provider for all # the domains. - dns01: provider: cloud-dns-provider domains: # Since certificate wildcards only allow one level, we will # need to one for every namespace that Knative is used in. # We don't need to use wildcard here, fully-qualified domains # will work fine too. - "*.default.$DOMAIN" - "*.other-namespace.$DOMAIN" # The certificate common name, use one from your domains. commonName: "*.default.$DOMAIN" dnsNames: # Provide same list as `domains` section. - "*.default.$DOMAIN" - "*.other-namespace.$DOMAIN" # Reference to the ClusterIssuer we created in the previous step. issuerRef: kind: ClusterIssuer name: letsencrypt-issuer EOF
To check that your certificate setting is valid, enter:
kubectl get certificate --namespace istio-system my-certificate --output yaml
Verify that its
Ready=True. For example:
status: acme: order: url: https://acme-v02.api.letsencrypt.org/acme/order/40759665/45358362 conditions: - lastTransitionTime: 2018-08-23T02:28:44Z message: Certificate issued successfully reason: CertIssued status: "True" type: Ready
A condition with
Ready=False is a failure to obtain certificate, and such
condition usually has an error message to indicate the reason of failure.
Configuring the gateway
In the last step, configure the
knative-shared-gateway if using Knative Serving 0.2.x or prior version) to use
the certificate that is generated and stored automatically by cert-manager.
The key edit here is adding the
tls: section to the end of the HTTPS port
kubectl apply --filename - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: knative-ingress-gateway namespace: knative-serving spec: selector: knative: ingressgateway servers: - port: number: 80 name: http protocol: HTTP hosts: - "*" - port: number: 443 name: https protocol: HTTPS hosts: - "*" tls: httpsRedirect: true # sends 301 redirect for http requests. mode: SIMPLE privateKey: /etc/istio/ingressgateway-certs/tls.key serverCertificate: /etc/istio/ingressgateway-certs/tls.crt EOF
Now you can access your services via HTTPS; cert-manager will keep your certificates up-to-date, replacing them before the certificate expires.