We are committed to provide service 24 X 7

Deals, Shopping, Training, Tools

53
1.743.648,50

Cart

Quantity 20,00
Quantity 116,00
Quantity 18,00

Learn how to – Use Let’s Encrypt SSL Certificates on OpenShift 4.x Ingress / Routes

Learn how to – Use Let’s Encrypt SSL Certificates on OpenShift 4.x Ingress / Routes.

In Red Hat OpenShift Container Platform, Certificates are used to encrypt communications to the applications exposed using Routes/Ingress as well as Web Console access. When deploying OpenShift Container Platform, the installer will automatically generate self-signed certificates which are configured for cluster use without any further customizations. While using self-signed certificates, you’ll often see security warnings about unknown certificates in most web browsers when accessing the Web Console or any application exposed via HTTPS.

It is recommended to use proper certificates, signed by a known CA to encrypt the API endpoints and applications exposed on routes. Let’s Encrypt is one viable option towards getting secure Certificates for free, the beauty of open source!. I’m running an OpenShift 4.8 cluster in my Lab environment. In OpenShift 4.x, the process of updating or changing self-signed certificates generated and the time of cluster setup has been simplified and is reasonably straightforward.

In this article we walk you through the process of getting Let’s Encrypt SSL Certificates and using it in an OpenShift 4.x cluster. The main requirements for this setup are:

  • A running OpenShift / OKD 4.x Cluster
  • API endpoint URL (Example – api.ocp4.example.com)
  • Ingress Controller Wildcard Domain (Example – apps.ocp4.example.com)
  • Access to OpenShift Cluster with oc as admin user

Step 1: Install git on Bastion machine

We need git to pull acme.sh project source from Github.

Install git and openssl on your Bastion machine by using the commands shared below:

# CentOS / Fedora
sudo yum -y install git openssl openssl-devel socat

# UBuntu / Debian
sudo apt update
sudo apt install git openssl socat

Step 1: Download acme.sh Project Code

We’ll use the acme.sh client tool to request for Let’s Encrypt certificates on our Bastion machine. The ACME protocol client is written purely in Shell (Unix shell) language with no dependencies on python. It has support for SAN and wildcard certificates. In fact, we will request Wildcard Let’s Encrypt certificates for our Ingress Controller Wildcard Domain.

Clone the acme.sh GitHub repository.

cd ~/
git clone https://github.com/acmesh-official/acme.sh.git

Change your current working directory to acme.sh:

cd acme.sh

Step 3: Configure DNS API / CNAME on your DNS Provider

Since we will be requesting for a Wildcard certificate, there is a need to get your DNS API credentials for automated certificates generation with acme.sh.

If your DNS provider supports API access, we can use that API to automatically issue the certs.

Below is a list of supported DNS Providers with proper documentation:

Using DNS API credentials

Check all currently supported dns providers by acme.sh project in the link below:

Cloudflare configurations

Since my domain is hosted in Cloudflare and its Domain API offers two methods to automatically issue certificates.

  1. Using the global API key
  2. Using cloudflare api token

I will use the first method.

Login to cloudflare and select the domain used by OpenShift cluster.

Under API sections copy and save your Zone ID and Account ID information.

Click on “Get your API token link to generate API authentication token. On the next screen use “Create Token” link.

Fill API Token generation information:

  • Use “Edit Zone DNS” template
  • Select the options as shown in the screenshot. On Zone Resources select specific OpenShift Domain.

Hit the “Create Token” button to generate the token.

Copy token generated to a safe place. The curl commands printed can be used to test if the token is working.

Using DNS Alias Mode

Suppose your DNS provider doesn’t provide API access, you can use the DNS alias mode of generation:

When working with DNS Alias Mode and standard DNS zone file format, (like ISC BIND or NSD), the setting looks like this:

_acme-challenge.example.com	IN	CNAME	_acme-challenge.aliasDomainForValidationOnly.com.

Where:

  • example.com is the primary domain which doesn’t have API access
  • aliasDomainForValidationOnly is another domain which has a supported DNS API

Issuing certificate when using DNS Alias Mode:

acme.sh --issue  
  -d  example.com --challenge-alias aliasDomainForValidationOnly.com --dns dns_cf

Step 4: Generate Let’s Encrypt Certificates using acme.sh

Save the variables in DNS API configurations file:

# For CLoudflare
$ vim dnsapi/dns_cf.sh
CF_Token="xxxx"
CF_Account_ID="yyyy"
CF_Zone_ID="zzzz"

If you don’t want to save the API credentials on a file, export command can be used to effect only in the current session:

export CF_Token="xxxx"
export CF_Account_ID="yyyy"
export CF_Zone_ID="zzzz"

Requesting Let’s Encrypt Certificates

Make sure you’re logged in to Red Hat OpenShift Cluster as a user with cluster administrator permissions

$ oc whoami
system:admin

Obtain OpenShift API Endpoint fully qualified domain name and set to variable OCP_API_DOMAIN:

export OCP_API_DOMAIN=$(oc whoami --show-server | cut -f 2 -d ':' | cut -f 3 -d '/' | sed 's/-api././')
echo $OCP_API_DOMAIN

Obtain OpenShift configured Wildcard Domain and save in a variable OCP_WILDCARD_DOMAIN:

export OCP_WILDCARD_DOMAIN=$(oc get ingresscontroller default -n openshift-ingress-operator -o jsonpath='{.status.domain}')
echo $OCP_WILDCARD_DOMAIN

Create a directory where generated certificates will be saved:

export CERTDIR=$HOME/openshift_certificates
mkdir -p ${CERTDIR}

Register account with acme while replacing your_email_address@example.com with your email address.

$ ~/acme.sh/acme.sh --register-account -m your_email_address@example.com
[Fri Aug 20 15:08:18 UTC 2021] No EAB credentials found for ZeroSSL, let's get one
[Fri Aug 20 15:08:19 UTC 2021] Registering account: https://acme.zerossl.com/v2/DV90
[Fri Aug 20 15:08:20 UTC 2021] Registered
[Fri Aug 20 15:08:20 UTC 2021] ACCOUNT_THUMBPRINT='zPovRxBENz8E2uu1MgimKIQo2wsDKo1lxtZsXD6rl9Q'

Next step is generating Let’s Encrypt SSL certificates:

${HOME}/acme.sh/acme.sh --issue --dns dns_cf -d ${OCP_API_DOMAIN} -d *.${OCP_WILDCARD_DOMAIN} --debug

Here is the output from my command generation.

[Fri Aug 20 15:07:28 UTC 2021] Using CA: https://acme.zerossl.com/v2/DV90
[Fri Aug 20 15:07:28 UTC 2021] Create account key ok.
[Fri Aug 20 15:07:28 UTC 2021] No EAB credentials found for ZeroSSL, let's get one
[Fri Aug 20 15:07:28 UTC 2021] acme.sh is using ZeroSSL as default CA now.
[Fri Aug 20 15:07:28 UTC 2021] Please update your account with an email address first.
[Fri Aug 20 15:07:28 UTC 2021] acme.sh --register-account -m my@example.com
[Fri Aug 20 15:07:28 UTC 2021] See: https://github.com/acmesh-official/acme.sh/wiki/ZeroSSL.com-CA
[Fri Aug 20 15:07:28 UTC 2021] Please add '--debug' or '--log' to check more details.
[Fri Aug 20 15:07:28 UTC 2021] See: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh
debian@debian-bullseye-01:~$ ${HOME}/acme.sh/acme.sh --install --accountemail myemail@gmail.com
[Fri Aug 20 15:07:45 UTC 2021] Installing to /home/debian/.acme.sh
cp: -r not specified; omitting directory 'acme.sh'
[Fri Aug 20 15:07:45 UTC 2021] Install failed, can not copy acme.sh
debian@debian-bullseye-01:~$ ${HOME}/acme.sh/acme.sh --register-account -m myemail@gmail.com
debian@debian-bullseye-01:~$ ${HOME}/acme.sh/acme.sh --register-account -m myeamil@gmail.com
[Fri Aug 20 15:08:18 UTC 2021] No EAB credentials found for ZeroSSL, let's get one
[Fri Aug 20 15:08:19 UTC 2021] Registering account: https://acme.zerossl.com/v2/DV90
[Fri Aug 20 15:08:20 UTC 2021] Registered
[Fri Aug 20 15:08:20 UTC 2021] ACCOUNT_THUMBPRINT='zPovRxBENz8E2uu1MgimKIQo2wsDKo1lxtZsXD6rl9Q'
debian@debian-bullseye-01:~$ ${HOME}/acme.sh/acme.sh  --issue --dns dns_cf --ocsp-must-staple --keylength 4096 -d api.ocp4.example.com -d '*.apps.ocp4.example.com'
[Fri Aug 20 15:09:19 UTC 2021] Using CA: https://acme.zerossl.com/v2/DV90
[Fri Aug 20 15:09:19 UTC 2021] Creating domain key
[Fri Aug 20 15:09:20 UTC 2021] The domain key is here: /home/debian/.acme.sh/api.ocp4.example.com/api.ocp4.example.com.key
[Fri Aug 20 15:09:20 UTC 2021] Multi domain='DNS:api.ocp4.example.com,DNS:*.apps.ocp4.example.com'
[Fri Aug 20 15:09:21 UTC 2021] Getting domain auth token for each domain
[Fri Aug 20 15:09:24 UTC 2021] Getting webroot for domain='api.ocp4.example.com'
[Fri Aug 20 15:09:24 UTC 2021] Getting webroot for domain='*.apps.ocp4.example.com'
[Fri Aug 20 15:09:24 UTC 2021] Adding txt value: oo99OcEtcMb8grxu2JQP5ZnewwDWRi-A0RmuWhMWgA8 for domain:  _acme-challenge.api.ocp4.example.com
[Fri Aug 20 15:09:26 UTC 2021] Adding record
[Fri Aug 20 15:09:27 UTC 2021] Added, OK
[Fri Aug 20 15:09:27 UTC 2021] The txt record is added: Success.
[Fri Aug 20 15:09:27 UTC 2021] Adding txt value: GKGuROuRJoetS8aNbxvwTFAYzL3CDkj_ZTE5IrpqYsI for domain:  _acme-challenge.apps.ocp4.example.com
[Fri Aug 20 15:09:29 UTC 2021] Adding record
[Fri Aug 20 15:09:30 UTC 2021] Added, OK
[Fri Aug 20 15:09:30 UTC 2021] The txt record is added: Success.
[Fri Aug 20 15:09:30 UTC 2021] Let's check each DNS record now. Sleep 20 seconds first.
[Fri Aug 20 15:09:51 UTC 2021] You can use '--dnssleep' to disable public dns checks.
[Fri Aug 20 15:09:51 UTC 2021] See: https://github.com/acmesh-official/acme.sh/wiki/dnscheck
[Fri Aug 20 15:09:51 UTC 2021] Checking api.ocp4.example.com for _acme-challenge.api.ocp4.example.com
[Fri Aug 20 15:09:51 UTC 2021] Domain api.ocp4.example.com '_acme-challenge.api.ocp4.example.com' success.
[Fri Aug 20 15:09:51 UTC 2021] Checking apps.ocp4.example.com for _acme-challenge.apps.ocp4.example.com
[Fri Aug 20 15:09:52 UTC 2021] Domain apps.ocp4.example.com '_acme-challenge.apps.ocp4.example.com' success.
[Fri Aug 20 15:09:52 UTC 2021] All success, let's return
[Fri Aug 20 15:09:52 UTC 2021] Verifying: api.ocp4.example.com
[Fri Aug 20 15:09:52 UTC 2021] Processing, The CA is processing your order, please just wait. (1/30)
[Fri Aug 20 15:09:55 UTC 2021] Success
[Fri Aug 20 15:09:55 UTC 2021] Verifying: *.apps.ocp4.example.com
[Fri Aug 20 15:09:55 UTC 2021] Processing, The CA is processing your order, please just wait. (1/30)
[Fri Aug 20 15:09:58 UTC 2021] Success
[Fri Aug 20 15:09:58 UTC 2021] Removing DNS records.
[Fri Aug 20 15:09:58 UTC 2021] Removing txt: oo99OcEtcMb8grxu2JQP5ZnewwDWRi-A0RmuWhMWgA8 for domain: _acme-challenge.api.ocp4.example.com
[Fri Aug 20 15:10:02 UTC 2021] Removed: Success
[Fri Aug 20 15:10:02 UTC 2021] Removing txt: GKGuROuRJoetS8aNbxvwTFAYzL3CDkj_ZTE5IrpqYsI for domain: _acme-challenge.apps.ocp4.example.com
[Fri Aug 20 15:10:05 UTC 2021] Removed: Success
[Fri Aug 20 15:10:05 UTC 2021] Verify finished, start to sign.
[Fri Aug 20 15:10:05 UTC 2021] Lets finalize the order.
[Fri Aug 20 15:10:05 UTC 2021] Le_OrderFinalize='https://acme.zerossl.com/v2/DV90/order/d7mmBjsYkrrP6ccyi7Q7_w/finalize'
[Fri Aug 20 15:10:06 UTC 2021] Order status is processing, lets sleep and retry.
[Fri Aug 20 15:10:06 UTC 2021] Retry after: 15
[Fri Aug 20 15:10:22 UTC 2021] Polling order status: https://acme.zerossl.com/v2/DV90/order/d7mmBjsYkrrP6ccyi7Q7_w
[Fri Aug 20 15:10:23 UTC 2021] Downloading cert.
[Fri Aug 20 15:10:23 UTC 2021] Le_LinkCert='https://acme.zerossl.com/v2/DV90/cert/d5CJh8QMzGOPRzgJKfL8Nw'
[Fri Aug 20 15:10:24 UTC 2021] Cert success.
-----BEGIN CERTIFICATE-----
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
OV4=
-----END CERTIFICATE-----
[Fri Aug 20 15:10:24 UTC 2021] Your cert is in: /home/debian/.acme.sh/api.ocp4.example.com/api.ocp4.example.com.cer
[Fri Aug 20 15:10:24 UTC 2021] Your cert key is in: /home/debian/.acme.sh/api.ocp4.example.com/api.ocp4.example.com.key
[Fri Aug 20 15:10:24 UTC 2021] The intermediate CA cert is in: /home/debian/.acme.sh/api.ocp4.example.com/ca.cer
[Fri Aug 20 15:10:24 UTC 2021] And the full chain certs is there: /home/debian/.acme.sh/api.ocp4.example.com/fullchain.cer

Let’s save the certs in the directory we created.

${HOME}/acme.sh/acme.sh --install-cert -d ${OCP_API_DOMAIN} -d *.${OCP_WILDCARD_DOMAIN} --cert-file ${CERTDIR}/cert.pem --key-file ${CERTDIR}/key.pem --fullchain-file ${CERTDIR}/fullchain.pem --ca-file ${CERTDIR}/ca.cer

Command execution output if successful.

[Fri Aug 20 15:18:11 UTC 2021] Installing cert to: /home/debian/openshift_certificates/cert.pem
[Fri Aug 20 15:18:11 UTC 2021] Installing CA to: /home/debian/openshift_certificates/ca.cer
[Fri Aug 20 15:18:11 UTC 2021] Installing key to: /home/debian/openshift_certificates/key.pem
[Fri Aug 20 15:18:11 UTC 2021] Installing full chain to: /home/debian/openshift_certificates/fullchain.pem

Step 5: Install Let’s Encrypt Certificates to OpenShift Ingress Controller

OpenShift Ingress Controller consumes certificates stored in a secret object. The secret should be created in the openshift-ingress namespace.

Create a secret in the openshift-ingress project:

oc -n openshift-ingress create secret tls router-certs --cert=${CERTDIR}/fullchain.pem --key=${CERTDIR}/key.pem 

Secret creation output:

secret/router-certs created

Thereafter we update the Custom Resource for the ingress controller located in the openshift-ingress-operator project and named default:

$ oc get ingresscontroller -n openshift-ingress-operator
NAME      AGE
default   2d6h

Update the custom resource by running the command below:

oc -n openshift-ingress-operator patch ingresscontroller default  --type=merge --patch='{"spec": { "defaultCertificate": { "name": "router-certs" }}}'

Command expected output:

ingresscontroller.operator.openshift.io/default patched

Router pods in the openshift-ingress should be restarted automatically in a short while:

$ oc get pods -n openshift-ingress
NAME                              READY   STATUS    RESTARTS   AGE
router-default-7b7d5bb68f-4lzft   1/1     Running   0          2m11s
router-default-7b7d5bb68f-x44lb   1/1     Running   0          2m49s

We now have generated Let’s Encrypt SSL certificates applied on the Ingress router. The certificates also used by the applications exposed using the default route and Red Hat OpenShift Cluster Web Console and other services such as the Monitoring stack.

Step 6: Installing Certificates to the Red Hat OpenShift API Endpoint (Optional)

You can also apply the certificates in API Endpoint. Personally I didn’t perform this step!.

The OpenShift API Server also expects the certificates in a Secret. We should create the certificates secret in the openshift-config project.

$ oc get secret -n openshift-config
NAME                                      TYPE                                  DATA   AGE
builder-dockercfg-nxjhg                   kubernetes.io/dockercfg               1      2d6h
builder-token-mc5fj                       kubernetes.io/service-account-token   4      2d6h
builder-token-wd9nc                       kubernetes.io/service-account-token   4      2d6h
default-dockercfg-t7h6m                   kubernetes.io/dockercfg               1      2d6h
default-token-4vsjs                       kubernetes.io/service-account-token   4      2d6h
default-token-gsmt9                       kubernetes.io/service-account-token   4      2d6h
deployer-dockercfg-hmfmz                  kubernetes.io/dockercfg               1      2d6h
deployer-token-b9t58                      kubernetes.io/service-account-token   4      2d6h
deployer-token-khbdh                      kubernetes.io/service-account-token   4      2d6h
etcd-client                               kubernetes.io/tls                     2      2d6h
etcd-metric-client                        kubernetes.io/tls                     2      2d6h
etcd-metric-signer                        kubernetes.io/tls                     2      2d6h
etcd-signer                               kubernetes.io/tls                     2      2d6h
initial-service-account-private-key       Opaque                                1      2d6h
pull-secret                               kubernetes.io/dockerconfigjson        1      2d6h
webhook-authentication-integrated-oauth   Opaque                                1      2d6h

Create a secret named api-certs

oc -n openshift-config create secret tls api-certs --cert=${CERTDIR}/fullchain.pem --key=${CERTDIR}/key.pem 

Confirm that the secret is created successfully:

secret/api-certs created

Run the command below to apply the certs on API endpoint

oc patch apiserver cluster --type merge --patch="{"spec"": {""servingCerts"": {""namedCertificates"": [ { ""names"": [  ""$OCP_API_DOMAIN""  ]

53
1.743.648,50

Cart

Quantity 20,00
Quantity 116,00
Quantity 18,00