Related Documentation
TL;DR

Create a Secret containing a CA Certificate and pass the ID of the certificate to an mTLS plugin configuration.

Prerequisites

If you don’t have a Konnect account, you can get started quickly with our onboarding wizard.

  1. The following Konnect items are required to complete this tutorial:
    • Personal access token (PAT): Create a new personal access token by opening the Konnect PAT page and selecting Generate Token.
  2. Set the personal access token as an environment variable:

    export KONNECT_TOKEN='YOUR KONNECT TOKEN'
    
  1. Install the Gateway API CRDs before installing Kong Ingress Controller.

    kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/standard-install.yaml
    
  2. Create a Gateway and GatewayClass instance to use.

echo "
apiVersion: v1
kind: Namespace
metadata:
  name: kong
---
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: kong
  annotations:
    konghq.com/gatewayclass-unmanaged: 'true'

spec:
  controllerName: konghq.com/kic-gateway-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: kong
spec:
  gatewayClassName: kong
  listeners:
  - name: proxy
    port: 80
    protocol: HTTP
    allowedRoutes:
      namespaces:
         from: All
" | kubectl apply -n kong -f -

Use the Konnect API to create a new CLUSTER_TYPE_K8S_INGRESS_CONTROLLER Control Plane:

CONTROL_PLANE_DETAILS=$(curl -X POST "https://us.api.konghq.com/v2/control-planes" \
     -H "Authorization: Bearer $KONNECT_TOKEN" \
     --json '{
       "name": "My KIC CP",
       "cluster_type": "CLUSTER_TYPE_K8S_INGRESS_CONTROLLER"
     }')

We’ll need the id and telemetry_endpoint for the values.yaml file later. Save them as environment variables:

CONTROL_PLANE_ID=$(echo $CONTROL_PLANE_DETAILS | jq -r .id)
CONTROL_PLANE_TELEMETRY=$(echo $CONTROL_PLANE_DETAILS | jq -r '.config.telemetry_endpoint | sub("https://";"")')

Create mTLS certificates

Kong Ingress Controller talks to Konnect over a connected secured with TLS certificates.

Generate a new certificate using openssl:

openssl req -new -x509 -nodes -newkey rsa:2048 -subj "/CN=kongdp/C=US" -keyout ./tls.key -out ./tls.crt

The certificate needs to be a single line string to send it to the Konnect API with curl. Use awk to format the certificate:

export CERT=$(awk 'NF {sub(/\r/, ""); printf "%s\\n",$0;}' tls.crt);

Next, upload the certificate to Konnect:

curl -X POST "https://us.api.konghq.com/v2/control-planes/$CONTROL_PLANE_ID/dp-client-certificates" \
     -H "Authorization: Bearer $KONNECT_TOKEN" \
     --json '{
       "cert": "'$CERT'"
     }'

Finally, store the certificate in a Kubernetes secret so that Kong Ingress Controller can read it:

kubectl create namespace kong -o yaml --dry-run=client | kubectl apply -f -
kubectl create secret tls konnect-client-tls -n kong --cert=./tls.crt --key=./tls.key
  1. Add the Kong Helm charts:

    helm repo add kong https://charts.konghq.com
    helm repo update
    
  2. Create a values.yaml file:

    cat <<EOF > values.yaml
    controller:
      ingressController:
        image:
          tag: "3.4"
        env:
          feature_gates: "FillIDs=true"
        konnect:
          license:
            enabled: true
          enabled: true
          controlPlaneID: "$CONTROL_PLANE_ID"
          tlsClientCertSecretName: konnect-client-tls
          apiHostname: "us.kic.api.konghq.com"
    gateway:
      image:
        repository: kong/kong-gateway
      env:
        konnect_mode: 'on'
        vitals: "off"
        cluster_mtls: pki
        cluster_telemetry_endpoint: "$CONTROL_PLANE_TELEMETRY:443"
        cluster_telemetry_server_name: "$CONTROL_PLANE_TELEMETRY"
        cluster_cert: /etc/secrets/konnect-client-tls/tls.crt
        cluster_cert_key: /etc/secrets/konnect-client-tls/tls.key
        lua_ssl_trusted_certificate: system
        proxy_access_log: "off"
        dns_stale_ttl: "3600"
      secretVolumes:
         - konnect-client-tls
    EOF
    
  3. Install Kong Ingress Controller using Helm:

    helm install kong kong/ingress -n kong --create-namespace --values ./values.yaml
    
  4. Set $PROXY_IP as an environment variable for future commands:

    export PROXY_IP=$(kubectl get svc --namespace kong kong-gateway-proxy -o jsonpath='{range .status.loadBalancer.ingress[0]}{@.ip}{@.hostname}{end}')
    echo $PROXY_IP
    
  1. Add the Kong Helm charts:

    helm repo add kong https://charts.konghq.com
    helm repo update
    
  2. Create a file named license.json containing your Kong Gateway Enterprise license and store it in a Kubernetes secret:

    kubectl create namespace kong --dry-run=client -o yaml | kubectl apply -f -
    kubectl create secret generic kong-enterprise-license --from-file=license=./license.json -n kong
    
  3. Create a values.yaml file:

    cat <<EOF > values.yaml
    gateway:
      image:
        repository: kong/kong-gateway
      env:
        LICENSE_DATA:
          valueFrom:
            secretKeyRef:
              name: kong-enterprise-license
              key: license
    EOF
    
  4. Install Kong Ingress Controller using Helm:

    helm install kong kong/ingress -n kong --create-namespace --values ./values.yaml
    
  5. Set $PROXY_IP as an environment variable for future commands:

    export PROXY_IP=$(kubectl get svc --namespace kong kong-gateway-proxy -o jsonpath='{range .status.loadBalancer.ingress[0]}{@.ip}{@.hostname}{end}')
    echo $PROXY_IP
    

This how-to requires some Kubernetes services to be available in your cluster. These services will be used by the resources created in this how-to.

kubectl apply -f https://developer.konghq.com/manifests/kic/echo-service.yaml -n kong

This how-to also requires 1 pre-configured route:

About mTLS

Mutual TLS (mTLS) is a way to secure connectivity using certificates. Kong Gateway can look for a certificate in incoming requests and reject the request if the public key presented does not match the private key stored in Kong Gateway.

Generate a CA certificate

To use the mtls-auth plugin you need a CA certificate. If you don’t have one, generate a new certificate using openssl:

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365 -nodes \
-subj "/C=US/ST=California/L=San Francisco/O=Kong/OU=Org/CN=www.example.com"

Add the Certificate to Kong Gateway

CA Certificates in Kong Gateway are provisioned by creating a Secret or ConfigMap resource in Kubernetes.

Resources holding CA certificates must have the following properties:

  • The konghq.com/ca-cert: "true" label applied
  • A cert or ca.crt data property which contains a valid CA certificate in PEM format
  • A kubernetes.io/ingress.class annotation whose value matches the value of the controller’s --ingress-class argument. By default, that value is kong.
  • An id data property which contains a random UUID

Each CA Certificate that you create needs a unique ID. Any random UUID should suffice here, and it doesn’t have a security implication. You can use uuidgen (Linux, macOS) or New-Guid (Windows) to generate an ID.

CERT_ID=$(uuidgen | tr "[:upper:]" "[:lower:]")
kubectl create secret -n kong generic my-ca-cert --from-literal=id=$CERT_ID --from-file=cert=./cert.pem
kubectl label secret -n kong my-ca-cert 'konghq.com/ca-cert=true'
kubectl annotate secret -n kong my-ca-cert 'kubernetes.io/ingress.class=kong'

Configure the mtls-auth plugin

The mtls-auth plugin requires a CA Certificate ID that will be used to validate the Certificate in the incoming request. In this example we disable revocation checks, but you should enable checks in a production setting.

echo "
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: mtls-auth
  namespace: kong
  annotations:
    kubernetes.io/ingress.class: kong
config:
  ca_certificates:
  - '$CERT_ID'
  skip_consumer_lookup: true
  revocation_check_mode: SKIP
plugin: mtls-auth
" | kubectl apply -f -

Next, apply the KongPlugin resource by annotating the service resource:

kubectl annotate -n kong service echo konghq.com/plugins=mtls-auth

Validate your configuration

At this point, Kong Gateway will reject requests that do not contain a client certificate.

  1. Send a request to check Kong Gateway prompts for a client certificate:

     curl "$PROXY_IP/echo"
    

    You should see the following response:

     No required TLS certificate was sent
    
     curl "$PROXY_IP/echo"
    

    You should see the following response:

     No required TLS certificate was sent
    

    As you can see, Kong Gateway is restricting the request because it doesn’t have the necessary authentication information.

    Two things to note here:

    • -k is used because Kong Gateway is set up to serve a self-signed certificate by default. For full mutual authentication in production use cases, you must configure Kong Gateway to serve a Certificate that is signed by a trusted CA.
    • For some deployments $PROXY_IP might contain a port that points to http port of Kong Gateway. In others, it might contain a DNS name instead of an IP address. If needed, update the command to send an https request to the https port of Kong Gateway or the load balancer in front of it.
  2. Use the key and Certificate to authenticate against Kong Gateway and use the Service:

     curl -k --key key.pem --cert cert.pem "https://$PROXY_IP/echo"
    
     curl -k --key key.pem --cert cert.pem "https://$PROXY_IP/echo"
    

    The results should look like this:

     HTTP/2 200
     content-type: text/plain; charset=UTF-8
     server: echoserver
     x-kong-upstream-latency: 1
     x-kong-proxy-latency: 1
     via: kong/x.y.z
    

Cleanup

kubectl delete -n kong -f https://developer.konghq.com/manifests/kic/echo-service.yaml
helm uninstall kong -n kong
Something wrong?

Help us make these docs great!

Kong Developer docs are open source. If you find these useful and want to make them better, contribute today!
OSZAR »