Back to blog
AWSBest PracticesCloud SecurityNetworkingOperations & Compliance

MQ Broker Is Publicly Accessible: Risks and Remediation

Learn why a publicly accessible Amazon MQ broker is a serious security risk, how to make it private, and how to prevent it with IaC and policy-as-code.

TL;DR

This check flags Amazon MQ brokers that are reachable from the public internet. A publicly accessible message broker exposes your queues, credentials, and the systems behind them to brute force and exploitation. Fix it by setting the broker to private and locking down the security group, then route access through a VPN or VPC peering instead.

Amazon MQ is a managed message broker service for Apache ActiveMQ and RabbitMQ. It sits in the middle of your architecture, shuttling messages between producers and consumers across services that often have no business being on the internet. When a broker is configured for public accessibility, AWS gives it a public IP and a publicly resolvable endpoint, which means anyone who can reach that endpoint can attempt to connect.

This check, mq_public in the mq_checks module, looks at whether your broker has public accessibility enabled. If it does, the broker is exposed beyond your VPC and is a candidate for tightening.


What this check detects

Every Amazon MQ broker has a PubliclyAccessible attribute that you set at creation time. When it is set to true, the broker receives a public endpoint and can accept connections from outside your VPC. The check fails when this attribute is true.

You can confirm the current setting with a single API call:

aws mq describe-broker \
  --broker-id b-1234a5b6-78cd-901e-2fgh-3i45jk6lmn78 \
  --query 'PubliclyAccessible'

A response of true means the broker is internet-facing.

Note: Public accessibility is decided when the broker is created and cannot be changed in place. To move a broker from public to private, you create a new broker with the correct setting and migrate your clients over. Plan for this rather than expecting a one-line update.


Why it matters

A message broker is a high-value target because of what flows through it. Order events, payment notifications, user data, internal commands, and service-to-service traffic all land in queues. Exposing that surface to the internet creates several concrete risks.

Credential brute forcing

ActiveMQ and RabbitMQ authenticate connections with usernames and passwords. A public endpoint is a public login prompt. Attackers run automated credential stuffing and brute force tools against any open broker port they find. If your broker uses weak or reused credentials, it is only a matter of time.

Known CVEs and unpatched versions

ActiveMQ in particular has a history of serious remote vulnerabilities. CVE-2023-46604, a remote code execution flaw in the OpenWire protocol, was exploited in the wild within days of disclosure and used to drop ransomware. A broker that is both publicly accessible and running an outdated engine version is a direct path to compromise.

Danger: A publicly accessible ActiveMQ broker running a vulnerable engine version is one of the fastest ways to hand an attacker remote code execution inside your VPC. Treat any failing broker that also runs an old engine version as an active incident, not a backlog item.

Data interception and message tampering

Once an attacker can connect, they can read messages off queues, inject malicious messages that your trusting consumers will process, or simply delete everything and disrupt your application. Because brokers are usually treated as trusted internal infrastructure, downstream services rarely validate the messages they receive.

Lateral movement

A broker lives inside your VPC. Compromising it gives an attacker a foothold from which to probe internal services, the metadata endpoint, and other resources that assumed they were protected by the network perimeter.


How to fix it

Since public accessibility cannot be toggled on an existing broker, remediation means standing up a private broker and migrating to it. The work breaks down into three stages.

1. Create a private broker

Create a replacement broker with PubliclyAccessible set to false and place it in private subnets.

aws mq create-broker \
  --broker-name orders-broker-private \
  --engine-type ACTIVEMQ \
  --engine-version 5.18.4 \
  --host-instance-type mq.m5.large \
  --deployment-mode ACTIVE_STANDBY_MULTI_AZ \
  --no-publicly-accessible \
  --subnet-ids subnet-0abc123 subnet-0def456 \
  --security-groups sg-0broker789 \
  --users '[{"Username":"app","Password":"REPLACE_WITH_SECRET","ConsoleAccess":true}]' \
  --auto-minor-version-upgrade

Warning: Running two brokers in parallel during migration doubles your Amazon MQ cost for that window. Multi-AZ deployments cost more than single-instance brokers. Size the migration window tightly and decommission the old broker as soon as clients are cut over.

2. Lock down the security group

A private broker still needs a tight security group. Allow only the ports your clients use and only from the source ranges or security groups that actually need access. Never use 0.0.0.0/0.

# Allow ActiveMQ OpenWire (SSL) only from the application security group
aws ec2 authorize-security-group-ingress \
  --group-id sg-0broker789 \
  --protocol tcp \
  --port 61617 \
  --source-group sg-0appservers

For RabbitMQ, restrict the AMQPS port instead:

aws ec2 authorize-security-group-ingress \
  --group-id sg-0broker789 \
  --protocol tcp \
  --port 5671 \
  --source-group sg-0appservers

3. Migrate clients and decommission

Update your applications to point at the new private endpoint, which you can retrieve here:

aws mq describe-broker \
  --broker-id b-NEWBROKERID \
  --query 'BrokerInstances[*].Endpoints'

Drain the old queues, confirm consumers are processing from the new broker, then delete the public broker.

Danger: Deleting a broker is irreversible and destroys any messages still sitting in its queues. Confirm all queues are drained and all clients are connected to the new broker before you run the delete command.

aws mq delete-broker --broker-id b-OLDPUBLICBROKERID

Doing it with Infrastructure as Code

If you manage Amazon MQ through Terraform, set publicly_accessible = false explicitly so the setting is reviewed in every plan rather than left to a default.

resource "aws_mq_broker" "orders" {
  broker_name         = "orders-broker"
  engine_type         = "ActiveMQ"
  engine_version      = "5.18.4"
  host_instance_type  = "mq.m5.large"
  deployment_mode     = "ACTIVE_STANDBY_MULTI_AZ"
  publicly_accessible = false
  subnet_ids          = [aws_subnet.private_a.id, aws_subnet.private_b.id]
  security_groups     = [aws_security_group.mq.id]
  auto_minor_version_upgrade = true

  user {
    username = "app"
    password = var.mq_password
  }
}

Tip: Pull the broker password from AWS Secrets Manager rather than a Terraform variable. Use a data "aws_secretsmanager_secret_version" block so the credential never lands in your state file in plain text or in version control.


How to prevent it from happening again

The cleanest fix is making it impossible to ship a public broker in the first place. Catch the setting before it reaches an account.

Block it in CI with policy as code

If you use Terraform, an OPA or Conftest policy can fail the pipeline whenever a broker plans to be public:

package mq

deny[msg] {
  resource := input.resource_changes[_]
  resource.type == "aws_mq_broker"
  resource.change.after.publicly_accessible == true
  msg := sprintf("MQ broker '%s' must not be publicly accessible", [resource.address])
}

Wire this into your pull request checks so a public broker never merges.

Use a Service Control Policy as a backstop

For defense in depth, you can deny broker creation outside approved patterns at the organization level. Combined with the CI gate, this catches brokers created manually in the console or by scripts that bypass your pipeline.

Run continuous checks

Configuration drifts. Someone spins up a quick broker for testing and forgets it. Lensix runs the mq_public check continuously across your accounts so a newly exposed broker surfaces in hours, not at the next audit.

Tip: Pair the public accessibility check with an alert on broker engine versions. The combination of internet-facing plus outdated engine is where real incidents come from, and catching both together lets you prioritize the brokers that matter most.


Best practices

  • Keep brokers private by default. There is almost no legitimate reason for a message broker to face the internet. If a partner needs access, route it through a VPN, VPC peering, or PrivateLink.
  • Enforce TLS. Use the SSL ports (61617 for ActiveMQ OpenWire, 5671 for RabbitMQ AMQPS) and reject plaintext connections so credentials and messages are never sent in the clear.
  • Scope security groups tightly. Reference source security groups rather than CIDR ranges where possible, so access follows your application tier rather than IP addresses that change.
  • Manage credentials in Secrets Manager. Rotate broker passwords on a schedule and never hardcode them in application config or IaC.
  • Stay current on engine versions. Enable auto_minor_version_upgrade and track major version end-of-support dates so you are not running an engine with a known RCE.
  • Log and monitor connections. Publish broker logs to CloudWatch and watch for authentication failures, which are an early signal of a brute force attempt.

Public accessibility is one setting, but it is the difference between a broker that lives quietly inside your network and one that anyone on the internet can knock on. Set it to private, gate it in CI, and verify it continuously.

Fix Publicly Accessible Amazon MQ Brokers | Lensix | Lensix