Authenticate Kong Event Gateway connections to Kafka using AWS IAM

TL;DR

Create a backend cluster with authentication.type: sasl_aws_iam and sasl_aws_iam.type: default_provider_chain to authenticate with the AWS SDK’s default credentials provider chain, or assume_role to authenticate by assuming an IAM role.

Prerequisites

Install kafkactl. You’ll need it to interact with Kafka clusters.

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'

You need an Amazon MSK cluster with IAM access control enabled, reachable from your Event Gateway data plane, and the bootstrap broker addresses for its IAM listener (port 9098 by default).

Event Gateway authenticates to Amazon MSK using the AWS SDK’s default credentials provider chain, so the Event Gateway data plane host needs AWS credentials available through one of the standard mechanisms, for example environment variables, a shared credentials file, or an EC2/ECS/EKS instance role.

The credentials (or a role they can assume) need the MSK IAM actions required to connect and describe the cluster, such as kafka-cluster:Connect and kafka-cluster:DescribeCluster. They also need the relevant kafka-cluster:*Topic* permissions for the topic resources.

In this guide you’ll configure Event Gateway to connect to an Amazon MSK cluster using AWS Identity and Access Management (IAM) credentials.

 
flowchart LR
    C[Kafka Client]
    subgraph EG [" Event Gateway "]
        VC[aws-iam virtual cluster]
    end
    subgraph K [Amazon MSK]
        L["IAM :9098"]
    end
    C -->|anonymous| VC
    VC -->|AWS IAM| L

  

Create an Event Gateway control plane and data plane

For the purposes of tutorial, we assume you have an IAM user with permissions needed to access the cluster as described in the prerequisites and an access key (AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY). Adjust this to fit your production deployment. If you’re running on EC2, for example, KEG handles calling IMDS to get credentials.

Run the quickstart script to provision a local data plane and configure your environment:

curl -Ls https://get.konghq.com/event-gateway | bash -s -- -k $KONNECT_TOKEN -e AWS_ACCESS_KEY_ID=... -e AWS_SECRET_ACCESS_KEY=... -N kafka_event_gateway

Copy the exported variable into your terminal:

export EVENT_GATEWAY_ID=your-gateway-id

This quickstart script is meant for demo purposes only, therefore it runs locally with most default parameters and a small number of exposed ports. If you want to run Kong Gateway as a part of a production-ready platform, set up your control plane and data planes through the Konnect UI, or using Terraform.

Unlike the local Docker Compose examples for mTLS and SASL/PLAIN, this guide connects to a real Amazon MSK cluster. Make sure the host running the Event Gateway data plane can reach your MSK cluster’s bootstrap brokers, for example through VPC peering, a VPN, or by running the data plane inside the same VPC.

Configure kafkactl

Create a kafkactl.yaml config file with a context for the AWS IAM virtual cluster:

cat <<EOF > kafkactl.yaml
contexts:
  aws-iam-vc:
    brokers:
      - localhost:19092
EOF

Clients only ever authenticate anonymously to this virtual cluster. AWS IAM is used solely by Event Gateway itself, when it connects to the backend cluster on the client’s behalf.

Create the backend cluster

Export the bootstrap broker addresses for your MSK cluster’s IAM listener:

export MSK_BOOTSTRAP_SERVERS="b-1.example.abc123.c2.kafka.us-east-1.amazonaws.com:9098,b-2.example.abc123.c2.kafka.us-east-1.amazonaws.com:9098,b-3.example.abc123.c2.kafka.us-east-1.amazonaws.com:9098"

Build the request body for a backend cluster using sasl_aws_iam authentication with the default AWS credentials provider chain:

jq -n --arg brokers "$MSK_BOOTSTRAP_SERVERS" \
  '{
    "name": "msk_backend_cluster",
    "bootstrap_servers": ($brokers | split(",")),
    "authentication": {
      "type": "sasl_aws_iam",
      "sasl_aws_iam": {"type": "default_provider_chain"}
    },
    "insecure_allow_anonymous_virtual_cluster_auth": true,
    "tls": {"enabled": true}
  }' > msk_backend_cluster.json

Then, create the backend cluster:

MSK_BACKEND_CLUSTER_ID=$(curl -X POST "https://us.api.konghq.com/v1/event-gateways/$EVENT_GATEWAY_ID/backend-clusters" \
     --no-progress-meter --fail-with-body  \
     -H "Authorization: Bearer $KONNECT_TOKEN" \
     --json "$(cat msk_backend_cluster.json)" | jq -r ".id"
)

default_provider_chain tells Event Gateway to resolve AWS credentials the same way the AWS CLI and SDKs do.

Assume an IAM role instead

If you need Event Gateway to assume a role before connecting, for example to access an MSK cluster in another AWS account, use sasl_aws_iam.type: assume_role instead:

{
  "authentication": {
    "type": "sasl_aws_iam",
    "sasl_aws_iam": {
      "type": "assume_role",
      "assume_role": {
        "arn": "arn:aws:iam::123456789012:role/example-role",
        "session_name": "event-gateway-session"
      }
    }
  }
}

Event Gateway first resolves base credentials from the default provider chain, then uses them to assume the role at arn. The role’s trust policy must allow the base credentials to assume it. session_name is optional and becomes part of the assumed role session’s ARN.

Create a virtual cluster

Create a virtual cluster with anonymous authentication:

MSK_VC_ID=$(curl -X POST "https://us.api.konghq.com/v1/event-gateways/$EVENT_GATEWAY_ID/virtual-clusters" \
     --no-progress-meter --fail-with-body  \
     -H "Authorization: Bearer $KONNECT_TOKEN" \
     --json '{
       "name": "aws_iam_vc",
       "destination": {
         "id": "'$MSK_BACKEND_CLUSTER_ID'"
       },
       "dns_label": "aws-iam-vc",
       "authentication": [
         {
           "type": "anonymous"
         }
       ],
       "acl_mode": "passthrough"
     }' | jq -r ".id"
)

Create a listener

Run the following command to create a new listener:

MSK_LISTENER_ID=$(curl -X POST "https://us.api.konghq.com/v1/event-gateways/$EVENT_GATEWAY_ID/listeners" \
     --no-progress-meter --fail-with-body  \
     -H "Authorization: Bearer $KONNECT_TOKEN" \
     --json '{
       "name": "aws_iam_listener",
       "addresses": [
         "0.0.0.0"
       ],
       "ports": [
         "19092-19105"
       ]
     }' | jq -r ".id"
)

Create a listener policy

Add a Forward to Virtual Cluster policy, which will forward requests based on a defined mapping to our virtual cluster:

curl -X POST "https://us.api.konghq.com/v1/event-gateways/$EVENT_GATEWAY_ID/listeners/$MSK_LISTENER_ID/policies" \
     --no-progress-meter --fail-with-body  \
     -H "Authorization: Bearer $KONNECT_TOKEN" \
     --json '{
       "type": "forward_to_virtual_cluster",
       "name": "forward_to_aws_iam_vc",
       "config": {
         "type": "port_mapping",
         "advertised_host": "localhost",
         "destination": {
           "id": "'$MSK_VC_ID'"
         }
       }
     }'

Validate

Ensure there’s at least one topic on your MSK cluster. Then list the topics through the aws-iam-vc virtual cluster:

kafkactl -C kafkactl.yaml --context aws-iam-vc list topics

If Event Gateway authenticated to Amazon MSK using AWS IAM and forwarded the metadata request, you will see the topic listed:

TOPIC                    PARTITIONS     REPLICATION FACTOR
test-topic               1              1

Cleanup

When you’re done experimenting with this example, clean up the resources:

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

  2. Stop and remove the containers:

    docker-compose down

This will stop all services and remove the containers, but preserve your configuration files for future use.

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!