Skip to content
Kong Docs are moving soon! Our docs are migrating to a new home. You'll be automatically redirected to the new site in the future. In the meantime, view this page on the new site!
Kong Logo | Kong Docs Logo
  • Docs
    • Explore the API Specs
      View all API Specs View all API Specs View all API Specs arrow image
    • Documentation
      API Specs
      Kong Gateway
      Lightweight, fast, and flexible cloud-native API gateway
      Kong Konnect
      Single platform for SaaS end-to-end connectivity
      Kong AI Gateway
      Multi-LLM AI Gateway for GenAI infrastructure
      Kong Mesh
      Enterprise service mesh based on Kuma and Envoy
      decK
      Helps manage Kong’s configuration in a declarative fashion
      Kong Ingress Controller
      Works inside a Kubernetes cluster and configures Kong to proxy traffic
      Kong Gateway Operator
      Manage your Kong deployments on Kubernetes using YAML Manifests
      Insomnia
      Collaborative API development platform
  • Plugin Hub
    • Explore the Plugin Hub
      View all plugins View all plugins View all plugins arrow image
    • Functionality View all View all arrow image
      View all plugins
      AI's icon
      AI
      Govern, secure, and control AI traffic with multi-LLM AI Gateway plugins
      Authentication's icon
      Authentication
      Protect your services with an authentication layer
      Security's icon
      Security
      Protect your services with additional security layer
      Traffic Control's icon
      Traffic Control
      Manage, throttle and restrict inbound and outbound API traffic
      Serverless's icon
      Serverless
      Invoke serverless functions in combination with other plugins
      Analytics & Monitoring's icon
      Analytics & Monitoring
      Visualize, inspect and monitor APIs and microservices traffic
      Transformations's icon
      Transformations
      Transform request and responses on the fly on Kong
      Logging's icon
      Logging
      Log request and response data using the best transport for your infrastructure
  • Support
  • Community
  • Kong Academy
Get a Demo Start Free Trial
Kong Ingress Controller
2.6.x
  • Home icon
  • Kong Ingress Controller
  • Guides
  • Using cert-manager for automated TLS certificate
github-edit-pageEdit this page
report-issueReport an issue
  • Kong Gateway
  • Kong Konnect
  • Kong Mesh
  • Kong AI Gateway
  • Plugin Hub
  • decK
  • Kong Ingress Controller
  • Kong Gateway Operator
  • Insomnia
  • Kuma

  • Docs contribution guidelines
  • unreleased
  • 3.4.x (latest) (LTS)
  • 3.3.x
  • 3.2.x
  • 3.1.x
  • 3.0.x
  • 2.12.x (LTS)
  • 2.11.x
  • 2.10.x
  • 2.9.x
  • 2.8.x
  • 2.7.x
  • 2.6.x
  • 2.5.x (LTS)
  • Introduction
    • FAQ
    • Version Support Policy
    • Stages of Software Availability
    • Changelog
  • Concepts
    • Architecture
    • Custom Resources
    • Deployment Methods
    • Kong for Kubernetes with Kong Gateway Enterprise
    • High-Availability and Scaling
    • Resource Classes
    • Security
    • Ingress Resource API Versions
    • Gateway API
  • Deployment
    • Kong Ingress on Minikube
    • Kong for Kubernetes
    • Kong Enterprise for Kubernetes (DB-less)
    • Kong Enterprise for Kubernetes (DB-backed)
    • Kong Ingress on AKS
    • Kong Ingress on EKS
    • Kong Ingress on GKE
    • Admission Controller
    • Installing Gateway APIs
  • Guides
    • Getting Started with KIC
    • Upgrading from previous versions
    • Upgrading to Kong 3.x
    • Using Kong Gateway Enterprise
    • Getting Started using Istio
    • Using Custom Resources
      • Using the Kong(Cluster)Plugin Resource
      • Using the KongIngress Resource
      • Using KongConsumer and Credential Resources
      • Using the TCPIngress Resource
      • Using the UDPIngress Resource
    • Using the ACL and JWT Plugins
    • Using cert-manager with Kong
    • Configuring a Fallback Service
    • Using an External Service
    • Configuring HTTPS Redirects for Services
    • Using Redis for Rate Limiting
    • Integrate KIC with Prometheus/Grafana
    • Configuring Circuit-Breaker and Health-Checking
    • Setting up a Custom Plugin
    • Using Ingress with gRPC
    • Setting up Upstream mTLS
    • Exposing a TCP-based Service
    • Exposing a UDP-based Service
    • Using the mTLS Auth Plugin
    • Using the OpenID Connect Plugin
    • Rewriting Hosts and Paths
    • Preserving Client IP Address
    • Using Gateway API
    • Using Kong with Knative
  • References
    • KIC Annotations
    • CLI Arguments
    • Custom Resource Definitions
    • Plugin Compatibility
    • Version Compatibility
    • Troubleshooting
    • Prometheus Metrics
    • Feature Gates
    • Gateway API Support
    • File Permissions Reference
enterprise-switcher-icon Switch to OSS
On this pageOn this page
  • Before you begin
  • Deploy the Kong Ingress Controller
  • Set up cert-manager
  • Set up your application
  • Set up DNS
  • Expose your application to the Internet
  • Request TLS Certificate from Let’s Encrypt
  • Test HTTPS
You are browsing documentation for an older version. See the latest documentation here.

Using cert-manager for automated TLS certificate

This guide will walk through steps to set up the Kong Ingress Controller with cert-manager to automate certificate management using Let’s Encrypt. Any ACME-based CA can be used in-place of Let’s Encrypt as well.

Before you begin

You will need the following:

  • Kubernetes cluster that can provision an IP address that is routable from the Internet. If you don’t have one, you can use GKE or any managed Kubernetes cloud offering.
  • A domain name for which you control the DNS records. This is necessary so that Let’s Encrypt can verify the ownership of the domain and issue a certificate. In the current guide, we use example.com, please replace this with a domain you control.

This tutorial was written using Google Kubernetes Engine.

Deploy the Kong Ingress Controller

You can deploy the Kong Ingress Controller using kubectl or Helm:

kubectl
Helm Charts
$ kubectl create -f https://raw.githubusercontent.com/Kong/kubernetes-ingress-controller/v2.6.0/deploy/single/all-in-one-dbless.yaml
helm repo add kong https://charts.konghq.com
helm repo update
helm install kong kong/ingress -n kong --create-namespace

The results should look like this:

kubectl
Helm Charts
   namespace/kong created
   customresourcedefinition.apiextensions.k8s.io/kongplugins.configuration.konghq.com created
   customresourcedefinition.apiextensions.k8s.io/kongconsumers.configuration.konghq.com created
   customresourcedefinition.apiextensions.k8s.io/kongcredentials.configuration.konghq.com created
   customresourcedefinition.apiextensions.k8s.io/kongingresses.configuration.konghq.com created
   serviceaccount/kong-serviceaccount created
   clusterrole.rbac.authorization.k8s.io/kong-ingress-clusterrole created
   clusterrolebinding.rbac.authorization.k8s.io/kong-ingress-clusterrole-nisa-binding created
   service/kong-proxy created
   service/kong-validation-webhook created
   deployment.apps/ingress-kong created
   deployment.apps/proxy-kong created
   ingressclass.networking.k8s.io/kong created
NAME: kong
LAST DEPLOYED: Tue Oct  3 15:12:38 2023
NAMESPACE: kong
STATUS: deployed
REVISION: 1
TEST SUITE: None

Note: this process could take up to five minutes the first time.

Set up cert-manager

Please follow cert-manager’s documentation on how to install cert-manager onto your cluster.

Once installed, verify all the components are running using:

kubectl get all -n cert-manager
NAME                                           READY   STATUS    RESTARTS   AGE
pod/cert-manager-86478c5ff-mkhb9               1/1     Running   0          23m
pod/cert-manager-cainjector-65dbccb8b6-6dnjl   1/1     Running   0          23m
pod/cert-manager-webhook-78f9d55fdf-5wcnp      1/1     Running   0          23m

NAME                           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/cert-manager-webhook   ClusterIP   10.63.240.251   <none>        443/TCP   23m

NAME                                      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/cert-manager              1         1         1            1           23m
deployment.apps/cert-manager-cainjector   1         1         1            1           23m
deployment.apps/cert-manager-webhook      1         1         1            1           23m

NAME                                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/cert-manager-86478c5ff               1         1         1       23m
replicaset.apps/cert-manager-cainjector-65dbccb8b6   1         1         1       23m
replicaset.apps/cert-manager-webhook-78f9d55fdf      1         1         1       23m

Set up your application

Any HTTP-based application can be used, for the purpose of the demo, install the following echo server:

$ kubectl apply -f https://bit.ly/echo-service
service/echo created
deployment.apps/echo created

Set up DNS

Get the IP address of the load balancer for Kong:

$ kubectl get service -n kong kong-proxy
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)                      AGE
kong-proxy   LoadBalancer   10.63.250.199   35.233.170.67   80:31929/TCP,443:31408/TCP   58d

To get only the IP address:

$ kubectl get -o jsonpath="{.status.loadBalancer.ingress[0].ip}" service -n kong kong-proxy
35.233.170.67

Please note that the IP address in your case will be different.

Next, set up a DNS records to resolve proxy.example.com to the above IP address:

$ dig +short proxy.example.com
35.233.170.67

Next, set up a CNAME DNS record to resolve demo.example.com to proxy.example.com.

$ dig +short demo.example.com
proxy.example.com.
35.233.170.67

Expose your application to the Internet

Setup an Ingress rule to expose the application:

$ echo "
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: demo-example-com
spec:
  ingressClassName: kong
  rules:
  - host: demo.example.com
    http:
      paths:
      - path: /
        pathType: ImplementationSpecific
        backend:
          service:
            name: echo
            port:
              number: 80
" | kubectl apply -f -
ingress.extensions/demo-example-com created

Access your application:

$ curl -I demo.example.com
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Connection: keep-alive
Date: Fri, 21 Jun 2019 21:14:45 GMT
Server: echoserver
X-Kong-Upstream-Latency: 1
X-Kong-Proxy-Latency: 1
Via: kong/3.1.1

Request TLS Certificate from Let’s Encrypt

First, set up a ClusterIssuer for cert-manager:

$ echo "apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    email: user@example.com #please change this/this is an optional, but recommended setting
    privateKeySecretRef:
      name: letsencrypt-prod
    server: https://acme-v02.api.letsencrypt.org/directory
    solvers:
    - http01:
        ingress:
          podTemplate:
             metadata:
               annotations:
                 sidecar.istio.io/inject: 'false'  # If using Istio, disable sidecar injection
               labels:
                 kuma.io/sidecar-injection: 'false'   # If ingress is running in Kuma/Kong Mesh, disable sidecar injection
          class: kong" | kubectl apply -f -
clusterissuer.cert-manager.io/letsencrypt-prod configured

Note: If you run into issues configuring this, be sure that the group (cert-manager.io) and version (v1) match those in the output of kubectl describe crd clusterissuer.

This tells cert-manager which CA authority to use to issue the certificate.

Next, update your Ingress resource to provision a certificate and then use it:

$ echo '
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: demo-example-com
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: kong
  tls:
  - secretName: demo-example-com
    hosts:
    - demo.example.com
  rules:
  - host: demo.example.com
    http:
      paths:
      - path: /
        pathType: ImplementationSpecific
        backend:
          service:
            name: echo
            port:
              number: 80
' | kubectl apply -f -
ingress.extensions/demo-example-com configured

Things to note here:

  • certmanager.k8s.io/cluster-issuer is set to letsencrypt-prod, directing cert-manager to use Let’s Encrypt’s production server to provision a TLS certificate.
  • tls section of the Ingress directs the Kong Ingress Controller to use the secret demo-example-com to encrypt the traffic for demo.example.com. This secret will be created by cert-manager.

Once you update the Ingress resource, cert-manager will start provisioning the certificate and in sometime the certificate will be available for use.

You can track the progress of certificate issuance:

$ kubectl describe certificate demo-example-com
Name:         demo-example-com
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  certmanager.k8s.io/v1
Kind:         Certificate
Metadata:
  Creation Timestamp:  2019-06-21T20:41:54Z
  Generation:          1
  Owner References:
    API Version:           networking.k8s.io/v1
    Block Owner Deletion:  true
    Controller:            true
    Kind:                  Ingress
    Name:                  demo-example-com
    UID:                   261d15d3-9464-11e9-9965-42010a8a01ad
  Resource Version:        19561898
  Self Link:               /apis/certmanager.k8s.io/v1/namespaces/default/certificates/demo-example-com
  UID:                     014d3f1d-9465-11e9-9965-42010a8a01ad
Spec:
  Acme:
    Config:
      Domains:
        demo.example.com
      Http 01:
  Dns Names:
    demo.example.com
  Issuer Ref:
    Kind:       ClusterIssuer
    Name:       letsencrypt-prod
  Secret Name:  demo-example-com
Status:
  Conditions:
    Last Transition Time:  2019-06-21T20:42:20Z
    Message:               Certificate is up to date and has not expired
    Reason:                Ready
    Status:                True
    Type:                  Ready
  Not After:               2019-09-19T19:42:19Z
Events:
  Type    Reason              Age   From          Message
  ----    ------              ----  ----          -------
  Normal  Generated           53m   cert-manager  Generated new private key
  Normal  GenerateSelfSigned  53m   cert-manager  Generated temporary self signed certificate
  Normal  OrderCreated        53m   cert-manager  Created Order resource "demo-example-com-3811625818"
  Normal  OrderComplete       53m   cert-manager  Order "demo-example-com-3811625818" completed successfully
  Normal  CertIssued          53m   cert-manager  Certificate issued successfully

Test HTTPS

Once all is in place, you can use HTTPS:

$ curl -v https://demo.example.com
* Rebuilt URL to: https://demo.example.com/
*   Trying 35.233.170.67...
* TCP_NODELAY set
* Connected to demo.example.com (35.233.170.67) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/cert.pem
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: CN=demo.example.com
*  start date: Jun 21 19:42:19 2019 GMT
*  expire date: Sep 19 19:42:19 2019 GMT
*  subjectAltName: host "demo.example.com" matched cert's "demo.example.com"
*  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
*  SSL certificate verify ok.
> GET / HTTP/1.1
> Host: demo.example.com
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/plain; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Date: Fri, 21 Jun 2019 21:37:43 GMT
< Server: echoserver
< X-Kong-Upstream-Latency: 1
< X-Kong-Proxy-Latency: 1
< Via: kong/3.1.1
<


Hostname: echo-d778ffcd8-52ddj

Pod Information:
  node name: gke-harry-k8s-dev-default-pool-bb23a167-9w4t
  pod name: echo-d778ffcd8-52ddj
  pod namespace: default
  pod IP:10.60.2.246

Server values:
  server_version=nginx: 1.12.2 - lua: 10010

Request Information:
  client_address=10.60.2.239
  method=GET
  real path=/
  query=
  request_version=1.1
  request_scheme=http
  request_uri=http://demo.example.com:8080/

Request Headers:
  accept=*/*
  connection=keep-alive
  host=demo.example.com
  user-agent=curl/7.54.0
  x-forwarded-for=10.138.0.6
  x-forwarded-host=demo.example.com
  x-forwarded-port=8443
  x-forwarded-proto=https
  x-real-ip=10.138.0.6

Request Body:
  -no body in request-

Et voilà ! You’ve secured your API with HTTPS with the Kong Ingress Controller and cert-manager.

Thank you for your feedback.
Was this page useful?
Too much on your plate? close cta icon
More features, less infrastructure with Kong Konnect. 1M requests per month for free.
Try it for Free
  • Kong
    Powering the API world

    Increase developer productivity, security, and performance at scale with the unified platform for API management, service mesh, and ingress controller.

    • Products
      • Kong Konnect
      • Kong Gateway Enterprise
      • Kong Gateway
      • Kong Mesh
      • Kong Ingress Controller
      • Kong Insomnia
      • Product Updates
      • Get Started
    • Documentation
      • Kong Konnect Docs
      • Kong Gateway Docs
      • Kong Mesh Docs
      • Kong Insomnia Docs
      • Kong Konnect Plugin Hub
    • Open Source
      • Kong Gateway
      • Kuma
      • Insomnia
      • Kong Community
    • Company
      • About Kong
      • Customers
      • Careers
      • Press
      • Events
      • Contact
  • Terms• Privacy• Trust and Compliance
© Kong Inc. 2025