June 28, 2022 By Takeyuki Nakajo 9 min read

How do I configure a TLS certificate with a custom domain in a Kubernetes cluster so that I can access an application with the custom domain?

The short answer is defining a DNS alias for your custom domain, creating a secret with a TLS certificate of the custom domain and defining an Ingress resource that uses the custom domain to route incoming network traffic to the service of your application. 

In this article, I will demonstrate the detailed steps for how to configure a TLS certificate with a custom domain in a Kubernetes cluster so that you can clearly understand how to set it up on your IBM Cloud Kubernetes Service cluster.


  1. Register a custom domain.
  2. Define a DNS alias for your custom domain by specifying the IBM-provided domain.
  3. Create a secret in the namespace to use TLS termination where your application exists.
  4. Define an Ingress resource that uses your custom domain to route incoming network traffic to the service of your application.

Step 1: Register a custom domain

Register your custom domain with any Domain Name Service (DNS) provider or IBM Cloud Classic Infrastructure Domain Name Service. If you don’t have a custom domain yet, you can register a domain here

I am going to use my custom domain tnexample.com in the IBM Cloud Domain Name Registration service:

Step 2. Define an alias for your custom domain

Define an alias for the custom domain by specifying the IBM-provided Ingress subdomain as a Canonical Name record (CNAME) in DNS:

  1. Verify the Ingress Subdomain host for your cluster:
    $ export YOURAPIKEY=********
    $ export REGION=au-syd
    $ export RESOURCEGROUP=default
    $ export CLUSTERID=cajdfrcs0idhc1uip6n0 
    $ ibmcloud login -r $REGION -g $RESOURCEGROUP -apikey $YOURAPIKEY
    $ ibmcloud ks cluster ls
    Name              ID                     State    Created      Workers   Location   Version                 Resource Group Name   Provider   
    mycluster-tn      cajdfrcs0idhc1uip6n0   normal   1 week ago   1         Sydney     1.22.10_1553            default               classic   
    $ ibmcloud ks cluster get --cluster $CLUSTERID  | grep Ingress
    Ingress Subdomain:              mycluster-tn-5be51ad3139a99d89cdf8f97c78ef71c-0000.au-syd.containers.appdomain.cloud
  2. From the dashboard in the IBM Cloud console, click the Menu icon and select Classic Infrastructure to get to the Classic Infrastructure landing page.
  3. In the Classic Infrastructure navigation, select Network > DNS > Forward Zones.
  4. Select the domain tnexample.com.
  5. In Add New Record section, select Resource Type: CNAME, type Host: *,  Resource Type: CNAME and Points To: mycluster-tn-5be51ad3139a99d89cdf8f97c78ef71c-0000.au-syd.containers.appdomain.cloud. Note: You need add . at the end of the Ingress Subdomain host:
  6. Confirm if the DNS works by using the commands nslookup and ping. You see the custom domain URL can be reached via the custom domain:
    % nslookup app.tnexample.com
    Non-authoritative answer:
    app.tnexample.com        canonical name = mycluster-tn-5be51ad3139a99d89cdf8f97c78ef71c-0000.au-syd.containers.appdomain.cloud.
    Name:        mycluster-tn-5be51ad3139a99d89cdf8f97c78ef71c-0000.au-syd.containers.appdomain.cloud
    $ ping app.tnexample.com
    PING mycluster-tn-5be51ad3139a99d89cdf8f97c78ef71c-0000.au-syd.containers.appdomain.cloud ( 56 data bytes
    64 bytes from icmp_seq=0 ttl=54 time=114.156 ms
    64 bytes from icmp_seq=1 ttl=54 time=23.914 ms
    64 bytes from icmp_seq=2 ttl=54 time=24.528 ms
    --- mycluster-tn-5be51ad3139a99d89cdf8f97c78ef71c-0000.au-syd.containers.appdomain.cloud ping statistics ---
    3 packets transmitted, 3 packets received, 0.0% packet loss
    round-trip min/avg/max/stddev = 23.914/54.199/114.156/42.397 ms

    Alternatively, You can use IBM Cloud Internet Services (CIS), which offers capabilities to enhance your workflow — security, reliability and performance, including DNS management. See more details here.

Step 3. Create a secret in the namespace to use TLS termination

Create a secret in the namespace to use TLS termination where your apps exist that contains your own TLS certificate. 

Granting service access to classic infrastructure

If you manage domains by using the classic infrastructure DNS service, you must grant service access to its DNS service so that IBM Cloud Secrets Manager can validate the ownership of your domains. You’ll need your classic infrastructure account credentials before you can grant access. To obtain your classic infrastructure username and API key, you can use the Access (IAM) section of the console.

  1. In the console, go to Manage > Access (IAM) > Users, then select the user’s name.
  2. In the VPN password section, copy the Username value. In most cases, your classic infrastructure username is your <account_id>_<email_address> or IBM<number>:
  3. In the API keys section, create a classic infrastructure API key or find your existing key.
  4. Click the Actions icon > Details to copy the API key value:
  5. Assign your user permissions to manage DNS in the account. For more information about managing classic infrastructure access, see Classic infrastructure permissions:
    • Click the Classic infrastructure tab to manage your classic infrastructure permissions.
    • In the Services section, ensure that the Manage DNS permission is selected.

Adding DNS provider configurations to your Secrets Manager instance

  1. In the console, click the Menu icon > Resource List.
  2. From the list of services, select your instance of Secrets Manager (or create a Secret Manager instance).
  3. On the Secrets engines page, click the Public certificates tab.
  4. In the DNS providers table, click Add:
  5. Enter name and Select the DNS provider: IBM Cloud classic infrastructure and click Next:
  6. Enter the classic infrastructure username and API key and click Add:
  7. You should see the DNS provider configuration added:

Connecting third-party certificate authorities

Connect to a third-party certificate authority by adding a configuration to your instance with IBM Cloud Secrets Manager. A certificate authority (CA) is the entity that signs and issues your TLS certificates. By adding a CA configuration, you can specify the authority that you want to use when you order public certificates through Secrets Manager.

Creating a Let’s Encrypt ACME account

Secrets Manager uses the Automatic Certificate Management Environment (ACME) protocol. The ACME protocol makes it possible to automatically obtain browser trusted certificates from a certificate authority without human intervention.

Create an account by using the ACME account creation tool. Once you create the account, keep the Account information (json file) and the Private key (pem file) in a safe place:

$ chmod +x acme-account-creation-tool
$ ./acme-account-creation-tool -e tnakajo@au1.ibm.com -o my-letsencrypt -d letsencrypt-prod
INFO[2022-04-18T14:07:19+10:00] Registering a new account with the CA        
INFO[2022-04-18T14:07:20+10:00] Account information written to file : my-letsencrypt-account-info.json 
INFO[2022-04-18T14:07:20+10:00] Private key written to file : my-letsencrypt-private-key.pem 

Adding a certificate authority configuration

Add certificate authority configurations to your service instance by using the Secrets Manager UI:

  1. In the console, click the Menu icon > Resource List.
  2. From the list of services, select your instance of Secrets Manager.
  3. On the Secrets engines page, click the Public certificates tab.
  4. In the Certificate authorities table, click Add.
  5. Enter name and select Let’s Encrypt for the Certificate authority:
  6. Add the private key file in PEM format that’s associated with your ACME account:
  7. Click Add. You should see the certificate authority configured.

Ordering public certificates from third parties

You can also order a certificate by using Secrets Manager. When you order a certificate, domain validation takes place to verify the ownership of your selected domains. This process can take a few minutes to complete.

  1. In the console, click the Menu icon > Resource List.
  2. From the list of services, select your instance of Secrets Manager.
  3. In the Secrets table, click Add:
  4. From the list of secret types, click the TLS certificates tile:
  5. Click the Order a public certificate tile:
  6. Enter the details of your certificate:
    • Add a name and description to easily identify your certificate.
    • Select a certificate authority configuration: LetEncrypt.
    • Select a DNS provider configuration: ClassicInfraDNS.
    • Add the domains to include in your request: *.tnexample.com.
    • Click Order:
  7. After you submit your certificate details, Secrets Manager sends your request to the selected certificate authority.
  8. After a certificate is issued, you can check the issuance details of your certificate by clicking the Actions icon > View details:
  9. Copy the certificate CRN value:

Creating a secret in the cluster

  1. Make sure the Secrets Manager instance is registered as an Ingress instance in the cluster:
    $ ibmcloud ks ingress instance ls --cluster $CLUSTERID
    Name                                Type              Is Default   Status    CRN   
    secretsmanager-tn                   secrets-manager   true         created   crn:v1:bluemix:public:secrets-manager:us-south:a/bde92b81610817c89a6b7b3f8e8813f8:64353325-db92-4433-86dd-a2855bb634fb::
  2. Create a secret with the certificate. I have a sample hello-world service running in the cluster. Refer to this blog post to use this sample:
    $ ibmcloud ks cluster config --cluster $CLUSTERID
    $ export NAMESPACE=project-a
    $ export DEPLOYMENT=hello-world-deployment
    $ export APPIMAGE=us.icr.io/tn_namespace/hello-world:1
    $ export SERVICENAME=hello-world-svc
    $ export SERVICEPORT=8080
    $ kubectl create deployment $DEPLOYMENT --image=$APPIMAGE --namespace $NAMESPACE
    deployment.apps/hello-world-deployment created
    $ kubectl expose deploy $DEPLOYMENT --name $SERVICENAME--port $SERVICEPORT --namespace $NAMESPACE
    service/hello-world-svc exposed
    $ kubectl get service --namespace $NAMESPACE
    NAME                  TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
    hello-world-svc            ClusterIP    <none>        8080/TCP         13s
  3. Set CERTCRN as I copied the certificate CRN value in the previous step:
    $ export CERTCRN=crn:v1:bluemix:public:secrets-manager:us-south:a/bde92b81610817c89a6b7b3f8e8813f8:64353325-db92-4433-86dd-a2855bb634fb:secret:9a935e61-1a5c-8888-4d27-3fbd7dbe2e48
    $ export SECRETNAME=custom-cert-tnexample
  4. Run the command to create a secret:
    $ ibmcloud ks ingress secret create --cluster $CLUSTERID --name $SECRETNAME --cert-crn $CERTCRN --namespace $NAMESPACE --type TLS
  5. Verify the secret:
    $ ibmcloud ks ingress secret ls --cluster $CLUSTERID
    Name                                                 Namespace        CRN                                                                                                                                                                  Expires On                 Domain                                                                                 Status    Type   
    custom-cert-tnexample                                project-a        crn:v1:bluemix:public:secrets-manager:us-south:a/bde92b81610817c89a6b7b3f8e8813f8:64353325-db92-4433-86dd-a2855bb634fb:secret:9a935e61-1a5c-8888-4d27-3fbd7dbe2e48   2022-09-13T05:29:02+0000   *.tnexample.com                                                                        created   TLS   
    $ kubectl get secret -n $NAMESPACE
    NAME                    TYPE                                  DATA   AGE
    custom-cert-tnexample   kubernetes.io/tls                     2      27s

4. Define an Ingress resource that uses your custom domain to route incoming network traffic to the service

Create an Ingress resource to define the routing rules that use your custom domain to route traffic to your application.

  1. Create an Ingress with the custom domain host and the custom domain secret. The following is an example configuration for the Ingress resource (hello-world-ingress.yaml):
    apiVersion: networking.k8s.io/v1
    kind: Ingress
      name: hello-world-ingress
        kubernetes.io/ingress.class: "public-iks-k8s-nginx"
      - hosts:
        - app.example.com
        secretName: custom-cert-tnexample
      - host: app.tnexample.com
          - path: /
            pathType: Prefix
                name: hello-world-svc
                  number: 8080
  2. Apply the ingress configuration:
    $ kubectl apply -f hello-world-ingress.yaml
    ingress.networking.k8s.io/hello-world-ingress created
  3. Verify by accessing your app with the Ingress subdomain and the path https://CUSTOM-DOMAIN-HOST/APP-PATH, and you should see the HTTPS connection is established with the valid custom domain certificate:
    % curl https://app.tnexample.com -v
    *   Trying
    * Connected to app.tnexample.com ( port 443 (#0)
    * ALPN, offering h2
    * ALPN, offering http/1.1
    * successfully set certificate verify locations:
    *  CAfile: /etc/ssl/cert.pem
    *  CApath: none
    * (304) (OUT), TLS handshake, Client hello (1):
    * (304) (IN), TLS handshake, Server hello (2):
    * (304) (IN), TLS handshake, Unknown (8):
    * (304) (IN), TLS handshake, Certificate (11):
    * (304) (IN), TLS handshake, CERT verify (15):
    * (304) (IN), TLS handshake, Finished (20):
    * (304) (OUT), TLS handshake, Finished (20):
    * SSL connection using TLSv1.3 / AEAD-AES256-GCM-SHA384
    * ALPN, server accepted to use h2
    * Server certificate:
    *  subject: CN=*.tnexample.com
    *  start date: Jun 15 05:29:03 2022 GMT
    *  expire date: Sep 13 05:29:02 2022 GMT
    *  subjectAltName: host "app.tnexample.com" matched cert's "*.tnexample.com"
    *  issuer: C=US; O=Let's Encrypt; CN=R3
    *  SSL certificate verify ok.
    * Using HTTP2, server supports multiplexing
    * Connection state changed (HTTP/2 confirmed)
    * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
    * Using Stream ID: 1 (easy handle 0x152811400)
    > GET / HTTP/2
    > Host: app.tnexample.com
    > user-agent: curl/7.79.1
    > accept: */*
    < HTTP/2 200 
    < content-type: text/html; charset=utf-8
    < content-length: 99
    < x-powered-by: Express
    < etag: W/"63-YG5NFOcPJdtrKh8AoAwX12ItC28"
    < strict-transport-security: max-age=15724800; includeSubDomains
    Hello world from hello-world-deployment-69c5c5cd86-pvdll! Your app is up and running in a cluster!
    * Connection #0 to host app.tnexample.com left intact

Learn more

I hope that you now understand how you can configure a TLS certificate with a custom domain in a Kubernetes cluster so that you can access an application with the custom domain. If you want to learn more, the following links will help:

Was this article helpful?

More from Cloud

The history of the central processing unit (CPU)

10 min read - The central processing unit (CPU) is the computer’s brain. It handles the assignment and processing of tasks, in addition to functions that make a computer run. There’s no way to overstate the importance of the CPU to computing. Virtually all computer systems contain, at the least, some type of basic CPU. Regardless of whether they’re used in personal computers (PCs), laptops, tablets, smartphones or even in supercomputers whose output is so strong it must be measured in floating-point operations per…

A clear path to value: Overcome challenges on your FinOps journey 

3 min read - In recent years, cloud adoption services have accelerated, with companies increasingly moving from traditional on-premises hosting to public cloud solutions. However, the rise of hybrid and multi-cloud patterns has led to challenges in optimizing value and controlling cloud expenditure, resulting in a shift from capital to operational expenses.   According to a Gartner report, cloud operational expenses are expected to surpass traditional IT spending, reflecting the ongoing transformation in expenditure patterns by 2025. FinOps is an evolving cloud financial management discipline…

IBM Power8 end of service: What are my options?

3 min read - IBM Power8® generation of IBM Power Systems was introduced ten years ago and it is now time to retire that generation. The end-of-service (EoS) support for the entire IBM Power8 server line is scheduled for this year, commencing in March 2024 and concluding in October 2024. EoS dates vary by model: 31 March 2024: maintenance expires for Power Systems S812LC, S822, S822L, 822LC, 824 and 824L. 31 May 2024: maintenance expires for Power Systems S812L, S814 and 822LC. 31 October…

IBM Newsletters

Get our newsletters and topic updates that deliver the latest thought leadership and insights on emerging trends.
Subscribe now More newsletters