title: Manage Ingress Certificates With Cert Manager

This tutorial will detail how to secure ingress using cert-manager.

Prerequisites

In this guide, we assume that your APISIX is installed with ssl enabled, which is not enabled by default in the Helm Chart. To enable it, you need to set gateway.tls.enabled=true during installation.

For example, you could install APISIX and APISIX ingress controller by running:

helm install apisix apisix/apisix --set gateway.type=NodePort --set ingress-controller.enabled=true --set gateway.tls.enabled=true --set ingress-controller.config.apisix.serviceNamespace=default

Assume that the SSL port is 9443.

Create Issuer

For testing purposes, we will use a simple CA issuer. All required files can be found here.

To create a CA issuer, use the following commands:

kubectl apply -f ./cert-manager/ca.yaml
kubectl apply -f ./cert-manager/issuer.yaml

If the cert-manager is working correctly, we should be able to see the Ready status by running:

kubectl get issuer

It should output:

NAME        READY   AGE
ca-issuer   True    50s

Create Test Certificate

To ensure that cert-manager is working properly, we can create a test Certificate resource.

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: demo-cert
spec:
  dnsNames:
    - example.com
  issuerRef:
    kind: Issuer
    name: ca-issuer
  secretName: example-cert
  usages:
    - digital signature
    - key encipherment

Like Issuer, we could see its readiness status by running:

kubectl get certificate

It should output:

NAME        READY   SECRET        AGE
demo-cert   True    example.com   50s

Check the secrets by running:

kubectl get secret

It should output:

NAME          TYPE                DATA   AGE
example.com   kubernetes.io/tls   3      2m20s

This means that our cert-manager is working properly.

Create Test Service

We use kennethreitz/httpbin as the service image.

Deploy it by running:

kubectl run httpbin --image kennethreitz/httpbin --expose --port 80

Secure Ingress

The cert-manager supports several ways to secure ingress. The easiest way is to use annotations.

By using annotations, we don't need to manage Certificate CRD manually.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: httpserver-ingress
  annotations:
    # add an annotation indicating the issuer to use.
    cert-manager.io/issuer: "ca-issuer"
spec:
  # apisix-ingress-controller is only interested in Ingress
  # resources with the matched ingressClass name, in our case,
  # it's apisix.
  ingressClassName: apisix
  tls:
    - hosts:
        - local.httpbin.org # placing a host in the TLS config will determine what ends up in the cert's subjectAltNames
      secretName: ingress-cert-manager-tls # cert-manager will store the created certificate in this secret.
  rules:
  - host: local.httpbin.org
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: httpbin
            port:
              number: 80

The annotation cert-manager.io/issuer tells cert-manager which issuer should be used. The Issuer must be in the same namespace as the Ingress resource. Please read Securing Ingress Resources for more details.

We should now be able to see the certificate and secret resource created by cert-manager:

kubectl get certificate
kubectl get secret

It should output:

NAME                       READY   SECRET                     AGE
ingress-cert-manager-tls   True    ingress-cert-manager-tls   2m

NAME                       TYPE                DATA   AGE
ingress-cert-manager-tls   kubernetes.io/tls   3      3m

Test

Run curl command in a APISIX pod to see if the Ingress and TLS configuration works.

kubectl -n <APISIX_NAMESPACE> exec -it <APISIX_POD_NAME> -- curl --resolve 'local.httpbin.org:9443:127.0.0.1' "https://local.httpbin.org:9443/ip" -k

It should output:

{
  "origin": "127.0.0.1"
}