Getting Started
Enable the KubeMQ AWS connector, point a standard AWS SDK at port 4566, and run an SQS send-and-receive round-trip in minutes — no LocalStack, no KubeMQ SDK.
Get a message flowing through the KubeMQ AWS connector in minutes. You enable the connector, point a standard AWS SDK at the connector's endpoint, create an SQS queue, send a message, and receive it back — all over the genuine AWS SQS wire protocol, with no LocalStack and no KubeMQ SDK. The only change versus a real-AWS app is the endpoint override.
Prerequisites
- A running kubemq-server with the AWS connector enabled and reachable on port 4566 (the enable step is below — all six wire-protocol connectors are opt-in).
- One of the AWS SDKs below for your language. There is no KubeMQ SDK; you use the native AWS SDK with only its endpoint overridden.
- Dummy AWS credentials and a region. The connector's default accept-any mode does not verify the signature value, but the SDK must still form a valid SigV4 request — so an access key, secret, and region are required even though their values are not checked.
Every example reads a single convenience variable for the connector endpoint, which maps to both the SQS and SNS endpoint overrides:
export KUBEMQ_AWS_URL="http://localhost:4566" # default; mapped to AWS_ENDPOINT_URL_SQS / _SNS
# Dummy credentials + region — STILL required even in accept-any mode.
export AWS_ACCESS_KEY_ID="test"
export AWS_SECRET_ACCESS_KEY="test"
export AWS_REGION="us-east-1" # NOT enforced (default ARN segment "kubemq")Enable the connector
The AWS connector is opt-in — disabled by default. A stock kubemq-server does not serve AWS until you turn it on. Enable it with its enable variable:
docker run -d \ --name kubemq \ -p 4566:4566 \ -p 50000:50000 \ -e KUBEMQ_TOKEN=YOUR_LICENSE_KEY \ -e CONNECTORS_AWS_ENABLE=true \ europe-docker.pkg.dev/kubemq/images/kubemq:nextEnabling the connector opens a new HTTP listener on port 4566. That port is not bound
until you set CONNECTORS_AWS_ENABLE=true, and it must differ from the server's
gRPC/REST/HTTP ports — this is exactly why the connector is opt-in rather than on by default.
Until you enable it, no AWS endpoint exists and the SDK cannot connect. To turn it off again,
set CONNECTORS_AWS_ENABLE=false (a config-only rollback; no data migration). See
Configuration for the full settings list.
How it works
You override only the endpoint URL on a standard AWS SDK client. CreateQueue("orders")
registers the queue and maps it to the KubeMQ Queue channel sqs.orders; SendMessage
writes to that channel through the message broker; ReceiveMessage returns the message plus
a receipt handle; DeleteMessage acks it off the queue.
The SQS queue orders maps to the KubeMQ Queue channel sqs.orders; the broker stores the message and the receive returns it with a node-local receipt handle.
Steps
Point the SDK at the connector
Build a standard AWS SDK SQS client and override only the endpoint URL to the connector's
endpoint in KUBEMQ_AWS_URL (default http://localhost:4566). Supply dummy credentials and
a region so the SDK forms a valid SigV4 request.
The language tabs run the complete round-trip from a single program: create the queue, send one message, receive it, and delete it by receipt handle.
package main
import (
"context"
"fmt"
"log"
"os"
"time"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/sqs"
)
func awsURL() string {
if v := os.Getenv("KUBEMQ_AWS_URL"); v != "" {
return v
}
return "http://localhost:4566"
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
// Dummy static credentials form a valid SigV4 request; accept-any mode
// checks the signature shape, not its value.
cfg, err := config.LoadDefaultConfig(ctx,
config.WithRegion("us-east-1"),
config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider("test", "test", "")),
)
if err != nil {
log.Fatalf("load config: %v", err)
}
// Override ONLY the endpoint URL.
client := sqs.NewFromConfig(cfg, func(o *sqs.Options) {
o.BaseEndpoint = aws.String(awsURL())
})
// 1. CreateQueue "orders" -> KubeMQ Queue channel "sqs.orders".
created, err := client.CreateQueue(ctx, &sqs.CreateQueueInput{QueueName: aws.String("orders")})
if err != nil {
log.Fatalf("CreateQueue: %v", err)
}
queueURL := aws.ToString(created.QueueUrl)
fmt.Printf("queue ready: %s\n", queueURL)
// 2. SendMessage.
if _, err := client.SendMessage(ctx, &sqs.SendMessageInput{
QueueUrl: aws.String(queueURL),
MessageBody: aws.String("hello from the AWS SDK"),
}); err != nil {
log.Fatalf("SendMessage: %v", err)
}
// 3. ReceiveMessage (long-poll a few seconds for the message).
recv, err := client.ReceiveMessage(ctx, &sqs.ReceiveMessageInput{
QueueUrl: aws.String(queueURL),
MaxNumberOfMessages: 1,
WaitTimeSeconds: 5,
})
if err != nil || len(recv.Messages) != 1 {
log.Fatalf("ReceiveMessage: %v (got %d)", err, len(recv.Messages))
}
msg := recv.Messages[0]
fmt.Printf("received: %q\n", aws.ToString(msg.Body))
// 4. DeleteMessage by receipt handle.
if _, err := client.DeleteMessage(ctx, &sqs.DeleteMessageInput{
QueueUrl: aws.String(queueURL),
ReceiptHandle: msg.ReceiptHandle,
}); err != nil {
log.Fatalf("DeleteMessage: %v", err)
}
fmt.Println("deleted; round-trip complete")
}import os
import boto3
def make_sqs():
# Override ONLY the endpoint URL; dummy credentials form a valid SigV4
# request (accept-any mode checks the signature shape, not its value).
return boto3.client(
"sqs",
endpoint_url=os.environ.get("KUBEMQ_AWS_URL", "http://localhost:4566"),
region_name="us-east-1",
aws_access_key_id="test",
aws_secret_access_key="test",
)
def main() -> None:
sqs = make_sqs()
# 1. CreateQueue "orders" -> KubeMQ Queue channel "sqs.orders".
queue_url = sqs.create_queue(QueueName="orders")["QueueUrl"]
print(f"queue ready: {queue_url}")
# 2. SendMessage.
sqs.send_message(QueueUrl=queue_url, MessageBody="hello from boto3")
# 3. ReceiveMessage (long-poll a few seconds).
recv = sqs.receive_message(QueueUrl=queue_url, MaxNumberOfMessages=1, WaitTimeSeconds=5)
msg = recv["Messages"][0]
print(f"received: {msg['Body']!r}")
# 4. DeleteMessage by receipt handle.
sqs.delete_message(QueueUrl=queue_url, ReceiptHandle=msg["ReceiptHandle"])
print("deleted; round-trip complete")
if __name__ == "__main__":
main()import java.net.URI;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.Message;
public final class Main {
public static void main(String[] args) {
String url = System.getenv().getOrDefault("KUBEMQ_AWS_URL", "http://localhost:4566");
// endpointOverride is the only change; dummy credentials form a valid
// SigV4 request (accept-any mode checks the signature shape).
try (SqsClient sqs = SqsClient.builder()
.endpointOverride(URI.create(url))
.region(Region.US_EAST_1)
.credentialsProvider(StaticCredentialsProvider.create(
AwsBasicCredentials.create("test", "test")))
.build()) {
// 1. CreateQueue "orders" -> KubeMQ Queue channel "sqs.orders".
String queueUrl = sqs.createQueue(b -> b.queueName("orders")).queueUrl();
System.out.println("queue ready: " + queueUrl);
// 2. SendMessage.
sqs.sendMessage(b -> b.queueUrl(queueUrl).messageBody("hello from the AWS SDK for Java"));
// 3. ReceiveMessage (long-poll a few seconds).
Message msg = sqs.receiveMessage(b -> b
.queueUrl(queueUrl)
.maxNumberOfMessages(1)
.waitTimeSeconds(5))
.messages().get(0);
System.out.printf("received: %s%n", msg.body());
// 4. DeleteMessage by receipt handle.
sqs.deleteMessage(b -> b.queueUrl(queueUrl).receiptHandle(msg.receiptHandle()));
System.out.println("deleted; round-trip complete");
}
}
}import {
SQSClient,
CreateQueueCommand,
SendMessageCommand,
ReceiveMessageCommand,
DeleteMessageCommand,
} from "@aws-sdk/client-sqs";
// Override ONLY the endpoint; dummy credentials form a valid SigV4 request
// (accept-any mode checks the signature shape, not its value).
const sqs = new SQSClient({
endpoint: process.env["KUBEMQ_AWS_URL"] ?? "http://localhost:4566",
region: "us-east-1",
credentials: { accessKeyId: "test", secretAccessKey: "test" },
});
async function main(): Promise<void> {
// 1. CreateQueue "orders" -> KubeMQ Queue channel "sqs.orders".
const created = await sqs.send(new CreateQueueCommand({ QueueName: "orders" }));
const queueUrl = created.QueueUrl!;
console.log(`queue ready: ${queueUrl}`);
// 2. SendMessage.
await sqs.send(new SendMessageCommand({ QueueUrl: queueUrl, MessageBody: "hello from the AWS SDK v3" }));
// 3. ReceiveMessage (long-poll a few seconds).
const recv = await sqs.send(
new ReceiveMessageCommand({ QueueUrl: queueUrl, MaxNumberOfMessages: 1, WaitTimeSeconds: 5 }),
);
const msg = recv.Messages![0];
console.log(`received: ${msg.Body}`);
// 4. DeleteMessage by receipt handle.
await sqs.send(new DeleteMessageCommand({ QueueUrl: queueUrl, ReceiptHandle: msg.ReceiptHandle! }));
console.log("deleted; round-trip complete");
}
main().catch((err) => {
console.error(err);
process.exit(1);
});using Amazon.Runtime;
using Amazon.SQS;
using Amazon.SQS.Model;
var url = Environment.GetEnvironmentVariable("KUBEMQ_AWS_URL") ?? "http://localhost:4566";
// ServiceURL carries the full http://host:port; dummy credentials form a valid
// SigV4 request (accept-any mode checks the signature shape, not its value).
var config = new AmazonSQSConfig { ServiceURL = url, AuthenticationRegion = "us-east-1" };
using var sqs = new AmazonSQSClient(new BasicAWSCredentials("test", "test"), config);
// 1. CreateQueue "orders" -> KubeMQ Queue channel "sqs.orders".
var created = await sqs.CreateQueueAsync(new CreateQueueRequest { QueueName = "orders" });
var queueUrl = created.QueueUrl;
Console.WriteLine($"queue ready: {queueUrl}");
// 2. SendMessage.
await sqs.SendMessageAsync(new SendMessageRequest { QueueUrl = queueUrl, MessageBody = "hello from AWSSDK.NET" });
// 3. ReceiveMessage (long-poll a few seconds).
var recv = await sqs.ReceiveMessageAsync(new ReceiveMessageRequest
{
QueueUrl = queueUrl,
MaxNumberOfMessages = 1,
WaitTimeSeconds = 5,
});
var msg = recv.Messages[0];
Console.WriteLine($"received: {msg.Body}");
// 4. DeleteMessage by receipt handle.
await sqs.DeleteMessageAsync(new DeleteMessageRequest { QueueUrl = queueUrl, ReceiptHandle = msg.ReceiptHandle });
Console.WriteLine("deleted; round-trip complete");# frozen_string_literal: true
require "aws-sdk-sqs"
# The Ruby SQS plugin rewrites the request endpoint to the full QueueUrl path,
# which the single-endpoint connector rejects — remove it so requests stay on
# the configured base endpoint (as boto3 and aws-sdk-go-v2 do).
Aws::SQS::Client.remove_plugin(Aws::SQS::Plugins::QueueUrls)
url = ENV.fetch("KUBEMQ_AWS_URL", "http://localhost:4566")
# Override ONLY the endpoint; dummy credentials form a valid SigV4 request
# (accept-any mode checks the signature shape, not its value).
sqs = Aws::SQS::Client.new(
endpoint: url,
region: "us-east-1",
credentials: Aws::Credentials.new("test", "test")
)
# 1. CreateQueue "orders" -> KubeMQ Queue channel "sqs.orders".
queue_url = sqs.create_queue(queue_name: "orders").queue_url
puts "queue ready: #{queue_url}"
# 2. SendMessage.
sqs.send_message(queue_url: queue_url, message_body: "hello from aws-sdk-ruby")
# 3. ReceiveMessage (long-poll a few seconds).
recv = sqs.receive_message(queue_url: queue_url, max_number_of_messages: 1, wait_time_seconds: 5)
msg = recv.messages.first
puts "received: #{msg.body.inspect}"
# 4. DeleteMessage by receipt handle.
sqs.delete_message(queue_url: queue_url, receipt_handle: msg.receipt_handle)
puts "deleted; round-trip complete"use aws_config::BehaviorVersion;
use aws_sdk_sqs::config::Credentials;
use aws_sdk_sqs::config::Region;
use std::error::Error;
fn aws_url() -> String {
std::env::var("KUBEMQ_AWS_URL").unwrap_or_else(|_| "http://localhost:4566".to_string())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
// Override ONLY the endpoint; dummy credentials form a valid SigV4 request
// (accept-any mode checks the signature shape, not its value).
let creds = Credentials::new("test", "test", None, None, "kubemq-aws");
let conf = aws_config::defaults(BehaviorVersion::latest())
.region(Region::new("us-east-1"))
.credentials_provider(creds)
.endpoint_url(aws_url())
.load()
.await;
let sqs = aws_sdk_sqs::Client::new(&conf);
// 1. CreateQueue "orders" -> KubeMQ Queue channel "sqs.orders".
sqs.create_queue().queue_name("orders").send().await?;
let url = sqs
.get_queue_url()
.queue_name("orders")
.send()
.await?
.queue_url
.ok_or("GetQueueUrl returned no URL")?;
println!("queue ready: {url}");
// 2. SendMessage.
sqs.send_message()
.queue_url(&url)
.message_body("hello from aws-sdk-rust")
.send()
.await?;
// 3. ReceiveMessage (long-poll a few seconds).
let received = sqs
.receive_message()
.queue_url(&url)
.max_number_of_messages(1)
.wait_time_seconds(5)
.send()
.await?;
let msg = &received.messages()[0];
println!("received: {}", msg.body().unwrap_or_default());
// 4. DeleteMessage by receipt handle.
let handle = msg.receipt_handle().ok_or("no receipt handle")?;
sqs.delete_message().queue_url(&url).receipt_handle(handle).send().await?;
println!("deleted; round-trip complete");
Ok(())
}Create an SQS queue and send a message
CreateQueue("orders") registers the queue in the connector's registry and maps it to the
KubeMQ Queue channel sqs.orders. The returned queue URL is path-style —
{scheme}://{host}/{AccountId}/orders (the default AccountId is 000000000000).
SendMessage writes the body to that channel and returns a MessageId and an MD5OfBody
the connector computes exactly like AWS.
Receive and acknowledge
ReceiveMessage returns the message plus a receipt handle, and hides the message for its
visibility window. DeleteMessage(receiptHandle) acks it off the queue. A successful run
prints:
queue ready: http://localhost:4566/000000000000/orders
received: "hello from the AWS SDK"
deleted; round-trip completeReceipt handles and in-flight tracking are node-local — a handle minted on one node is rejected on another. In a clustered deployment, put the connector behind a sticky load balancer (session affinity). See Connectivity and security.
Next steps
Configuration
The opt-in enable variable, the ten CONNECTORS_AWS_* settings, and accept-any vs static credentials.
Architecture
One binary, two service surfaces — SQS as a Queue channel and the virtual SNS registry.
SQS queues
Visibility timeouts, long-poll, batch, message attributes, and FIFO over sqs.{name}.
SNS fan-out
Publish once and fan out to subscribed SQS queues and HTTP/HTTPS webhooks.
Was this page helpful?
Cross-Protocol Interop
Share an sqs.* channel between an AWS SDK app and a native KubeMQ gRPC/REST client — produce with boto3, consume with kubemq-go, and migrate one side at a time.
Authentication
How the AWS connector authenticates SQS and SNS requests — SigV4 verification, the accept-any local-dev default, static credentials, and Casbin authorization.