Configure HTTP logging over mTLS

Deployment Platform
Minimum Version
Kong Gateway - 3.15
TL;DR

To send HTTP logs to a log server over mTLS, store the client certificate and private key as a Certificate entity in Kong Gateway and configure the HTTP Log plugin’s client_certificate parameter to reference that entity by ID. Start Kong Gateway with KONG_LUA_SSL_TRUSTED_CERTIFICATE pointing to the CA that signed the log server’s certificate.

Prerequisites

To complete this tutorial, install decK. We recommend keeping decK up to date with the latest version (1.64.0).

decK is a CLI tool for managing Kong Gateway declaratively with state files. This guide uses deck gateway apply, which directly applies entity configuration to your Gateway instance.

You can check your current decK version with deck version.

Generate certificates

This guide uses three certificates:

  • A CA certificate, used to sign the log server and client certificates
  • A log server certificate, presented by the log server during the TLS handshake
  • A client certificate, presented by Kong Gateway to the log server
  1. Create a working directory and change into it:

    mkdir -p ~/http-log-mtls/certs && cd ~/http-log-mtls/certs
  2. Generate a CA certificate:

    openssl req -new -x509 -nodes -days 365 \
      -subj '/CN=my-ca' \
      -keyout ca.key \
      -out ca.crt
  3. Generate a log server certificate signed by the CA. The subjectAltName must match the hostname that Kong Gateway uses to reach the log server. In this guide, the log server runs as a Docker container on the same network as Kong Gateway under the hostname logserver:

    openssl genrsa -out logserver.key 2048
    
    openssl req -new -key logserver.key -out logserver.csr \
      -subj "/CN=logserver"
    
    cat > logserver.ext <<EOF
    authorityKeyIdentifier=keyid,issuer
    basicConstraints=CA:FALSE
    keyUsage = digitalSignature, keyEncipherment
    extendedKeyUsage = serverAuth
    subjectAltName = DNS:logserver
    EOF
    
    openssl x509 -req \
      -in logserver.csr \
      -CA ca.crt -CAkey ca.key -CAcreateserial \
      -out logserver.crt -days 365 -sha256 -extfile logserver.ext
  4. Generate a client certificate for Kong Gateway:

    openssl genrsa -out client.key 2048
    
    openssl req -new -key client.key -out client.csr \
      -subj "/CN=kong-client"
    
    openssl x509 -req \
      -in client.csr \
      -CA ca.crt -CAkey ca.key -CAcreateserial \
      -out client.crt -days 365 -sha256

Start Kong Gateway

The HTTP Log plugin verifies the log server’s TLS certificate against a trusted CA. Pass the CA certificate to Kong Gateway at startup so Kong Gateway can validate the log server’s certificate during the mTLS handshake.

  1. Export your credentials:

    export KONG_LICENSE_DATA='LICENSE-CONTENTS-GO-HERE'
    export KONNECT_TOKEN='YOUR_KONNECT_PAT'
  2. Start Kong Gateway using the quickstart script, mounting the CA certificate and configuring it as a trusted CA:

    curl -Ls https://get.konghq.com/quickstart | bash -s -- \
      -e KONG_LICENSE_DATA \
      -v "$(pwd)/ca.crt:/etc/ssl/certs/ca.crt" \
      -e KONG_LUA_SSL_TRUSTED_CERTIFICATE="/etc/ssl/certs/ca.crt, system"
    curl -Ls https://get.konghq.com/quickstart | bash -s -- -k $KONNECT_TOKEN \
      -v "$(pwd)/ca.crt:/etc/ssl/certs/ca.crt" \
      -e KONG_LUA_SSL_TRUSTED_CERTIFICATE="/etc/ssl/certs/ca.crt, system" \
      --deck-output

    This mounts ca.crt into the container and tells Kong Gateway to trust it for outbound TLS connections. When Kong Gateway is ready, you’ll see:

    Kong Gateway Ready

    Copy and paste the printed environment variable exports into your terminal to configure your session.

Start the log server

For this tutorial, we’re using an Nginx log server, and configuring it to require a client certificate from any connecting client.

  1. Create a directory for the log server and copy the certificates into it:

    mkdir -p ~/http-log-mtls/logserver
    cp ~/http-log-mtls/certs/logserver.crt ~/http-log-mtls/logserver/
    cp ~/http-log-mtls/certs/logserver.key ~/http-log-mtls/logserver/
    cp ~/http-log-mtls/certs/ca.crt ~/http-log-mtls/logserver/
  2. Create a configuration file for Nginx named nginx.conf:

    cat <<'EOF' > ~/http-log-mtls/logserver/nginx.conf
    worker_processes auto;
    events {
      worker_connections 1024;
    }
    
    http {
      default_type application/json;
    
      log_format ingestion_format escape=json '$time_iso8601 | $remote_addr | $request_body';
    
      server {
        listen 443 ssl;
        server_name logserver;
    
        ssl_certificate     /etc/ssl/certs/logserver.crt;
        ssl_certificate_key /etc/ssl/certs/logserver.key;
        ssl_client_certificate /etc/ssl/certs/ca.crt;
        ssl_verify_client on;
    
        location /health {
          access_log off;
          return 200 '{"status":"ok"}';
          add_header Content-Type application/json;
        }
    
        location /v1/logs {
          limit_except POST {
            deny all;
         }
    
          client_body_in_single_buffer on;
          client_body_buffer_size 2m;
    
          proxy_pass http://127.0.0.1:65534 ;
          error_page 502 = @log_and_respond;
        }
    
        location @log_and_respond {
          access_log /var/log/nginx/ingested_logs.log ingestion_format;
          return 202 '{"status":"accepted"}';
          default_type application/json;
        }
      }
    }
    EOF
  3. Create the Dockerfile:

    cat <<'EOF' > ~/http-log-mtls/logserver/Dockerfile
    FROM nginx:latest
    COPY logserver.crt /etc/ssl/certs/logserver.crt
    COPY logserver.key /etc/ssl/certs/logserver.key
    COPY ca.crt        /etc/ssl/certs/ca.crt
    COPY nginx.conf    /etc/nginx/nginx.conf
    EXPOSE 443
    CMD ["nginx", "-g", "daemon off;"]
    EOF
  4. Build and start the log server on the same Docker network as Kong Gateway:

    cd ~/http-log-mtls/logserver
    docker build -t logserver .
    docker run -d --name logserver --net kong-quickstart-net -p 9443:443 logserver
  5. Verify that the log server accepts a valid client certificate:

    curl -s --cacert ~/http-log-mtls/certs/ca.crt \
      --cert ~/http-log-mtls/certs/client.crt \
      --key ~/http-log-mtls/certs/client.key \
      --resolve logserver:9443:127.0.0.1 \
      https://logserver:9443/health

    You should receive:

    {"status":"ok"}

Add the client certificate to Kong Gateway

Store the client certificate and private key as a Certificate entity so the HTTP Log plugin can reference it by ID.

Add the Certificate and export its ID:

export DECK_CLIENT_CERT_ID=$(curl -s -X POST http://localhost:8001/certificates \
  --data-urlencode "cert=$(cat ~/http-log-mtls/certs/client.crt)" \
  --data-urlencode "key=$(cat ~/http-log-mtls/certs/client.key)" | jq -r .id)
echo "Client Certificate ID: $DECK_CLIENT_CERT_ID"

Create Service and Route

Configure an example-service and an example-route:

echo '
_format_version: "3.0"
services:
  - name: example-service
    url: https://httpbin.konghq.com
    routes:
    - name: example-route
      paths:
      - "/anything"
' | deck gateway apply -

Configure the HTTP Log plugin

Enable the HTTP Log plugin on the Route and reference the Certificate entity:

echo '
_format_version: "3.0"
plugins:
  - name: http-log
    route: example-route
    config:
      http_endpoint: https://logserver/v1/logs
      ssl_verify: true
      client_certificate:
        id: "${{ env "DECK_CLIENT_CERT_ID" }}"
      method: POST
      timeout: 10000
' | deck gateway apply -

In this configuration:

  • http_endpoint: The HTTPS URL of the log server. In this example, Kong Gateway resolves the hostname logserver over the shared Docker network.
  • ssl_verify: When true, Kong Gateway verifies the log server’s certificate against the CA configured in KONG_LUA_SSL_TRUSTED_CERTIFICATE.
  • client_certificate: References the Certificate entity containing the client certificate and private key that Kong Gateway presents to the log server.

Validate the flow

Send a request through Kong Gateway:

curl -k -i "https://$KONNECT_PROXY_URL/anything" \
     --no-progress-meter --fail-with-body 
curl -k -i "https://localhost:8443/anything" \
     --no-progress-meter --fail-with-body 

You should get an HTTP 200 response.

Check the log server to confirm that it received the log entry:

docker exec logserver tail -n 5 /var/log/nginx/ingested_logs.log

You should see a JSON log entry containing the request data.

Cleanup

Stop and remove the log server container, then delete the working directory:

docker stop logserver && docker rm logserver
rm -rf ~/http-log-mtls

If you created a new control plane and want to conserve your free trial credits or avoid unnecessary charges, delete the new control plane used in this tutorial.

curl -Ls https://get.konghq.com/quickstart | bash -s -- -d

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!