Back to Checks
aws

DMS replication instance is not publicly exposed to the Internet

dms_instance_no_public_access
Service: dmsSeverity: critical
OfficialBuilt-inVerified
Categories:internet-exposed
Resource Type:AwsDmsReplicationInstance

AWS DMS replication instances are evaluated for public exposure. Exposure is identified when PubliclyAccessible is enabled and an attached security group allows inbound traffic from any address. Private or allowlisted instances are not considered exposed.

Risk

Publicly reachable replication instances threaten:

  • Confidentiality: migration data and credentials can be intercepted or exfiltrated.
  • Integrity: attackers may alter tasks or inject records.
  • Availability: abuse or DDoS can stall replication and delay cutovers.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks dms_instance_no_public_access

Recommendation

Adopt a private-only design:

  • Disable PubliclyAccessible; place instances in private subnets.
  • Enforce least privilege security groups (no 0.0.0.0/0); allow only required sources/ports.
  • Provide access via VPN, peering, or Direct Connect.
  • Layer controls (ACLs, monitoring) and restrict IAM to necessary actions.

Remediation

Terraform

# DMS instance not publicly accessible
resource "aws_dms_replication_instance" "<example_resource_name>" {
  replication_instance_id    = "<example_resource_id>"
  replication_instance_class = "dms.t3.micro"
  publicly_accessible        = false  # Critical: disables public access to prevent Internet exposure
}

NativeIaC

# CloudFormation: DMS instance not publicly accessible
Resources:
  <example_resource_name>:
    Type: AWS::DMS::ReplicationInstance
    Properties:
      ReplicationInstanceClass: dms.t3.micro
      PubliclyAccessible: false  # Critical: disables public access to prevent Internet exposure

Other

1In the AWS Console, open Database Migration Service > Replication instances and select the instance
2In Details > Networking, click each attached Security Group ID to open it in the EC2 console
3In Inbound rules, delete any rule with Source 0.0.0.0/0 or ::/0
4Save rules for each security group

Check Code

from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.dms.dms_client import dms_client
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group


def _get_ec2_client():
    from prowler.providers.aws.services.ec2.ec2_client import ec2_client

    return ec2_client


class dms_instance_no_public_access(Check):
    def execute(self):
        findings = []
        for instance in dms_client.instances:
            report = Check_Report_AWS(metadata=self.metadata(), resource=instance)
            report.status = "PASS"
            report.status_extended = (
                f"DMS Replication Instance {instance.id} is not publicly accessible."
            )
            if instance.public:
                report.status_extended = f"DMS Replication Instance {instance.id} is set as publicly accessible, but is not publicly exposed."
                # Check if any DB Instance Security Group is publicly open
                if instance.security_groups:
                    report.status = "PASS"
                    report.status_extended = f"DMS Replication Instance {instance.id} is set as publicly accessible but filtered with security groups."
                    for security_group in _get_ec2_client().security_groups.values():
                        if security_group.id in instance.security_groups:
                            for ingress_rule in security_group.ingress_rules:
                                if check_security_group(
                                    ingress_rule,
                                    "-1",
                                    any_address=True,
                                    all_ports=True,
                                ):
                                    report.status = "FAIL"
                                    report.status_extended = f"DMS Replication Instance {instance.id} is set as publicly accessible and security group {security_group.name} ({security_group.id}) is open to the Internet."
                                    break
            findings.append(report)

        return findings