AMQP 0.9.1 Destination¶
Stream Keycloak events to AMQP 0.9.1 brokers.
| Property | Value |
|---|---|
destination.kind |
amqp-0.9.1 |
| Protocol | AMQP 0.9.1 |
Compatible Systems¶
| System | Notes |
|---|---|
| RabbitMQ | Primary target, all features supported |
| LavinMQ | Lightweight alternative, fully compatible |
| CloudAMQP | Managed RabbitMQ (supports TLS) |
| Amazon MQ for RabbitMQ | AWS managed (supports TLS) |
This destination uses AMQP 0.9.1 (RabbitMQ's native protocol). For AMQP 1 brokers like ActiveMQ Artemis or Azure Service Bus, see the AMQP 1 destination (kind=amqp-1).
Example Configurations¶
kete.routes.rabbitmq.destination.kind=amqp-0.9.1
kete.routes.rabbitmq.destination.host=rabbitmq.example.com
kete.routes.rabbitmq.destination.port=5672
kete.routes.rabbitmq.destination.username=keycloak
kete.routes.rabbitmq.destination.password=secret
kete.routes.rabbitmq.destination.virtual-host=/keycloak
kete.routes.rabbitmq.destination.exchange=keycloak-events
kete.routes.rabbitmq.destination.routing-key=events
kete.routes.lavinmq.destination.kind=amqp-0.9.1
kete.routes.lavinmq.destination.host=lavinmq.example.com
kete.routes.lavinmq.destination.port=5672
kete.routes.lavinmq.destination.username=keycloak
kete.routes.lavinmq.destination.password=secret
kete.routes.lavinmq.destination.exchange=keycloak-events
kete.routes.cloudamqp.destination.kind=amqp-0.9.1
kete.routes.cloudamqp.destination.host=your-instance.cloudamqp.com
kete.routes.cloudamqp.destination.port=5671
kete.routes.cloudamqp.destination.username=your-user
kete.routes.cloudamqp.destination.password=your-password
kete.routes.cloudamqp.destination.virtual-host=your-vhost
kete.routes.cloudamqp.destination.exchange=keycloak-events
kete.routes.cloudamqp.destination.tls.enabled=true
Features¶
- Full AMQP 0.9.1 protocol support
- Exchange and routing key configuration
- TLS/SSL support with mutual TLS (mTLS)
- Persistent and non-persistent delivery modes
- Message priority and TTL configuration
- Automatic reconnection and topology recovery
- Custom headers on messages
- Virtual host support
- Dynamic exchange and routing key (templating)
Configuration Properties¶
Required Properties¶
kete.routes.<NAME>.destination.kind=amqp-0.9.1
kete.routes.<NAME>.destination.host=<RABBITMQ_HOST>
kete.routes.<NAME>.destination.exchange=<EXCHANGE_NAME>
Basic Example¶
# Configure AMQP 0.9.1 destination
kete.routes.main-rabbitmq.destination.kind=amqp-0.9.1
kete.routes.main-rabbitmq.realm-matchers.realm=list:master
kete.routes.main-rabbitmq.event-matchers.filter=glob:*
# RabbitMQ-specific configuration
kete.routes.main-rabbitmq.destination.host=localhost
kete.routes.main-rabbitmq.destination.port=5672
kete.routes.main-rabbitmq.destination.username=guest
kete.routes.main-rabbitmq.destination.password=guest
kete.routes.main-rabbitmq.destination.exchange=keycloak-events
kete.routes.main-rabbitmq.destination.routing-key=events
All RabbitMQ Properties¶
| Property | Description | Default | Example |
|---|---|---|---|
host |
RabbitMQ server hostname (required) | - | rabbitmq.example.com |
exchange |
Exchange name, required (supports templating) | - | keycloak-${realmLowerCase} |
port |
RabbitMQ server port | 5672 |
5671 (AMQPS) |
username |
Authentication username | "" |
keycloak |
password |
Authentication password | "" |
secret123 |
virtual-host |
Virtual host | / |
/production |
routing-key |
Routing key (supports templating) | "" |
${eventTypeLowerCase} |
priority |
Message priority (0-9) | 4 |
7 |
delivery-mode |
Message durability: persistent or non-persistent |
persistent |
persistent |
time-to-live-seconds |
Message TTL in seconds (0 = never expires) | 0 |
60 |
connection-timeout-seconds |
Connection timeout in seconds | 10 |
30 |
handshake-timeout-seconds |
Handshake timeout in seconds | 10 |
5 |
channel-rpc-timeout-seconds |
Channel RPC timeout in seconds | 10 |
15 |
requested-heartbeat-seconds |
Heartbeat interval in seconds | 30 |
60 |
automatic-recovery-enabled |
Enable automatic connection recovery | true |
false |
network-recovery-interval-seconds |
Network recovery interval in seconds | 5 |
10 |
topology-recovery-enabled |
Enable topology recovery | Same as automatic-recovery-enabled |
true |
pool.min-idle |
1 |
Minimum idle connections in pool | 5 |
pool.max-idle |
10 |
Maximum idle connections in pool | 20 |
pool.max-total |
20 |
Maximum total connections in pool | 50 |
tls.* |
TLS/SSL configuration | - | See TLS & mTLS |
Custom Headers¶
Custom headers can be added to AMQP messages:
kete.routes.rabbitmq.destination.headers.X-Source=keycloak
kete.routes.rabbitmq.destination.headers.X-Environment=production
Headers are included in the AMQP message properties.
Dynamic Exchange/Routing Key (Templating)¶
The exchange and routing-key properties support template variables:
# Dynamic exchange per realm
kete.routes.rabbitmq.destination.exchange=keycloak-${realmLowerCase}
# Dynamic routing key per event type
kete.routes.rabbitmq.destination.routing-key=${eventTypeLowerCase}
# Combine both
kete.routes.rabbitmq.destination.exchange=keycloak-events
kete.routes.rabbitmq.destination.routing-key=${realmLowerCase}.${eventTypeLowerCase}
Available variables: ${realmLowerCase}, ${realmUpperCase}, ${eventTypeLowerCase}, ${eventTypeUpperCase}, ${kindLowerCase}, ${kindUpperCase}, ${resourceTypeLowerCase}, ${resourceTypeUpperCase}, ${operationTypeLowerCase}, ${operationTypeUpperCase}, ${resultLowerCase}, ${resultUpperCase}
Delivery Modes¶
| Mode | Description | Use Case |
|---|---|---|
persistent |
Messages survive broker restart | Audit logs, critical events |
non-persistent |
Messages lost on broker restart | High-throughput, non-critical events |
Configuration Examples¶
Production Configuration¶
kete.routes.prod.destination.host=rabbitmq-cluster.prod.internal
kete.routes.prod.destination.port=5672
kete.routes.prod.destination.username=keycloak-prod
kete.routes.prod.destination.password=secure-password
kete.routes.prod.destination.virtual-host=/production
kete.routes.prod.destination.exchange=keycloak-events
kete.routes.prod.destination.routing-key=events.production
TLS/SSL Configuration - File Path¶
kete.routes.secure.destination.host=rabbitmq-secure.example.com
kete.routes.secure.destination.port=5671
kete.routes.secure.destination.username=keycloak
kete.routes.secure.destination.password=secret
kete.routes.secure.destination.exchange=keycloak-events
kete.routes.secure.destination.tls.enabled=true
kete.routes.secure.destination.tls.trust-store.loader.kind=jks-file-path
kete.routes.secure.destination.tls.trust-store.loader.path=/opt/keycloak/certs/truststore.jks
kete.routes.secure.destination.tls.trust-store.password=truststorepass
# With client certificate authentication (mTLS)
kete.routes.secure-mutual.destination.host=rabbitmq-secure.example.com
kete.routes.secure-mutual.destination.port=5671
kete.routes.secure-mutual.destination.exchange=keycloak-events
kete.routes.secure-mutual.destination.tls.enabled=true
kete.routes.secure-mutual.destination.tls.key-store.loader.kind=pkcs12-file-path
kete.routes.secure-mutual.destination.tls.key-store.loader.path=/opt/keycloak/certs/client.p12
kete.routes.secure-mutual.destination.tls.key-store.password=keystorepass
kete.routes.secure-mutual.destination.tls.trust-store.loader.kind=jks-file-path
kete.routes.secure-mutual.destination.tls.trust-store.loader.path=/opt/keycloak/certs/truststore.jks
kete.routes.secure-mutual.destination.tls.trust-store.password=truststorepass
TLS/SSL Configuration - Base64 Encoded¶
kete.routes.secure-b64.destination.host=rabbitmq-secure.example.com
kete.routes.secure-b64.destination.port=5671
kete.routes.secure-b64.destination.username=keycloak
kete.routes.secure-b64.destination.password=secret
kete.routes.secure-b64.destination.exchange=keycloak-events
kete.routes.secure-b64.destination.tls.enabled=true
# Base64-encoded client certificate (PKCS12 keystore)
kete.routes.secure-b64.destination.tls.key-store.loader.kind=pkcs12-file-base64
kete.routes.secure-b64.destination.tls.key-store.loader.base64=MIIKegIBAzCCCj4GCSqGSIb3DQEHAaCCCi8EggorMII...
kete.routes.secure-b64.destination.tls.key-store.password=keystorepass
# Base64-encoded CA trust store (JKS)
kete.routes.secure-b64.destination.tls.trust-store.loader.kind=jks-file-base64
kete.routes.secure-b64.destination.tls.trust-store.loader.base64=/u3+7QAAAAIAAAABAAAA...
kete.routes.secure-b64.destination.tls.trust-store.password=truststorepass
Tip: Generate base64-encoded keystores:
# Linux/Mac
base64 -i client-keystore.p12 -o keystore-base64.txt
base64 -i truststore.jks -o truststore-base64.txt
# Windows PowerShell
[Convert]::ToBase64String([IO.File]::ReadAllBytes("client-keystore.p12")) | Out-File keystore-base64.txt
[Convert]::ToBase64String([IO.File]::ReadAllBytes("truststore.jks")) | Out-File truststore-base64.txt
Multi-VHost Setup¶
# Production vhost
kete.routes.prod-example.destination.host=rabbitmq
kete.routes.prod-example.destination.virtual-host=/production
kete.routes.prod-example.destination.exchange=events
# Development vhost
kete.routes.dev-example.destination.host=rabbitmq
kete.routes.dev-example.destination.virtual-host=/development
kete.routes.dev-example.destination.exchange=events
Exchange Patterns¶
Topic Exchange¶
Best for flexible routing based on event types:
Setup:
# Create topic exchange
rabbitmqadmin declare exchange name=keycloak-events type=topic
# Create queues
rabbitmqadmin declare queue name=all-events
rabbitmqadmin declare queue name=login-events
rabbitmqadmin declare queue name=admin-events
# Bind queues
rabbitmqadmin declare binding source=keycloak-events \
destination=all-events routing_key='#'
rabbitmqadmin declare binding source=keycloak-events \
destination=login-events routing_key='LOGIN*'
rabbitmqadmin declare binding source=keycloak-events \
destination=admin-events routing_key='*:*'
# Create topic exchange
rabbitmqadmin declare exchange name=keycloak-events type=topic
# Create queues
rabbitmqadmin declare queue name=all-events
rabbitmqadmin declare queue name=login-events
rabbitmqadmin declare queue name=admin-events
# Bind queues
rabbitmqadmin declare binding source=keycloak-events `
destination=all-events routing_key='#'
rabbitmqadmin declare binding source=keycloak-events `
destination=login-events routing_key='LOGIN*'
rabbitmqadmin declare binding source=keycloak-events `
destination=admin-events routing_key='*:*'
Configuration:
kete.routes.topic.destination.exchange=keycloak-events
kete.routes.topic.destination.routing-key=events
Direct Exchange¶
Best for simple point-to-point messaging:
Setup:
Configuration:
kete.routes.direct.destination.exchange=keycloak-events
kete.routes.direct.destination.routing-key=events
Fanout Exchange¶
Best for broadcasting to all consumers:
Setup:
# Create fanout exchange
rabbitmqadmin declare exchange name=keycloak-events type=fanout
# Create queues
rabbitmqadmin declare queue name=consumer1
rabbitmqadmin declare queue name=consumer2
# Bind queues (routing key ignored for fanout)
rabbitmqadmin declare binding source=keycloak-events destination=consumer1
rabbitmqadmin declare binding source=keycloak-events destination=consumer2
Configuration:
kete.routes.fanout.destination.exchange=keycloak-events
kete.routes.fanout.destination.routing-key= # Empty or anything
Headers Exchange¶
Route based on message headers. KETE sends the eventtype header which can be used for routing:
Setup:
# Create headers exchange
rabbitmqadmin declare exchange name=keycloak-events type=headers
# Create queues
rabbitmqadmin declare queue name=login-events
rabbitmqadmin declare queue name=logout-events
# Bind queues (match on eventtype header)
rabbitmqadmin declare binding source=keycloak-events \
destination=login-events \
arguments='{"x-match":"all","eventtype":"LOGIN"}'
rabbitmqadmin declare binding source=keycloak-events \
destination=logout-events \
arguments='{"x-match":"all","eventtype":"LOGOUT"}'
# Create headers exchange
rabbitmqadmin declare exchange name=keycloak-events type=headers
# Create queues
rabbitmqadmin declare queue name=login-events
rabbitmqadmin declare queue name=logout-events
# Bind queues (match on eventtype header)
rabbitmqadmin declare binding source=keycloak-events `
destination=login-events `
arguments='{"x-match":"all","eventtype":"LOGIN"}'
rabbitmqadmin declare binding source=keycloak-events `
destination=logout-events `
arguments='{"x-match":"all","eventtype":"LOGOUT"}'
Configuration:
kete.routes.headers.destination.exchange=keycloak-events
kete.routes.headers.destination.routing-key= # Ignored for headers
Tip: For routing admin vs user events, use separate KETE routes with different event matchers instead of headers exchange.
Configuration Examples¶
Example 1: Separate Exchanges by Event Category¶
# User authentication events (regex)
kete.routes.auth-events.destination.kind=amqp-0.9.1
kete.routes.auth-events.realm-matchers.realm=list:master
kete.routes.auth-events.event-matchers.pattern=regex:^LOG(IN|OUT)
kete.routes.auth-events.destination.host=rabbitmq
kete.routes.auth-events.destination.exchange=auth-events
kete.routes.auth-events.destination.routing-key=auth
# Admin events (admin event format: RESOURCETYPE_OPERATIONTYPE)
kete.routes.example-admin.destination.kind=amqp-0.9.1
kete.routes.example-admin.realm-matchers.realm=list:master
kete.routes.example-admin.event-matchers.filter=glob:*_*
kete.routes.example-admin.destination.host=rabbitmq
kete.routes.example-admin.destination.exchange=admin-events
kete.routes.example-admin.destination.routing-key=admin
Example 2: Per-Realm Routing¶
# Production realm
kete.routes.prod.destination.kind=amqp-0.9.1
kete.routes.prod.realm-matchers.realm=list:production
kete.routes.prod.event-matchers.filter=glob:*
kete.routes.prod.destination.host=rabbitmq
kete.routes.prod.destination.exchange=keycloak-events
kete.routes.prod.destination.routing-key=prod.events
# Staging realm
kete.routes.staging.destination.kind=amqp-0.9.1
kete.routes.staging.realm-matchers.realm=list:staging
kete.routes.staging.event-matchers.filter=glob:*
kete.routes.staging.destination.host=rabbitmq
kete.routes.staging.destination.exchange=keycloak-events
kete.routes.staging.destination.routing-key=staging.events
Example 3: High-Availability Setup¶
kete.routes.ha.destination.kind=amqp-0.9.1
kete.routes.ha.realm-matchers.realm=list:master
kete.routes.ha.event-matchers.filter=glob:*
kete.routes.ha.destination.host=rabbitmq-cluster.local
kete.routes.ha.destination.port=5672
kete.routes.ha.destination.username=keycloak
kete.routes.ha.destination.password=secret
kete.routes.ha.destination.virtual-host=/ha
kete.routes.ha.destination.exchange=keycloak-events-ha
kete.routes.ha.destination.routing-key=events
RabbitMQ HA Queue Setup: