> ## Documentation Index
> Fetch the complete documentation index at: https://docs.runlayer.com/llms.txt
> Use this file to discover all available pages before exploring further.

# ECS Networking and Private Connectivity

> Plan VPCs, DNS, TLS, WAF, and private connectivity before deploying Runlayer on ECS

Choose the network, DNS, and access settings before following the [ECS deployment guide](/deployment/terraform). Add these inputs inside `module "runlayer_infrastructure"` in your root configuration. Merge examples with your existing values; do not declare the same input twice.

## DNS and TLS

`domain_name` is the application hostname, such as `ai.example.com`. `hosted_zone_name` is the existing authoritative Route 53 zone, such as `example.com`; they are usually different. The deployment guide creates and validates `*.example.com` in ACM and creates the application DNS record in that zone.

For DNS in another account, configure `aws.route53` with the DNS account role and set `cross_account_hosted_zone_id` to that zone's ID. Always pass both provider aliases to the module. The certificate must be in the workload account and ALB region.

For DNS outside Route 53, supply an issued `ssl_certificate_arn`, leave `enable_acm_dns_validation = false` and `create_dns_records = false`, then create the application DNS record yourself using the module's `alb_dns_name` output. Complete ACM validation with your DNS provider before deploying.

Choose one certificate strategy:

```hcl theme={null}
# Create and validate a new wildcard certificate in the existing Route 53 zone.
enable_acm_dns_validation = true
hosted_zone_name          = "example.com"
create_dns_records        = true
```

```hcl theme={null}
# Look up an existing issued wildcard certificate for the hostname's parent.
enable_acm_dns_validation = false
hosted_zone_name          = "example.com"
create_dns_records        = true
```

```hcl theme={null}
# Use an issued certificate and manage DNS outside Terraform.
ssl_certificate_arn       = "arn:aws:acm:us-east-1:123456789012:certificate/REPLACE_ME"
enable_acm_dns_validation = false
create_dns_records        = false
```

## Access choices

| Need | Configuration |
| - | - |
| Public HTTPS | Public ALB, restricted source ranges or WAF as needed |
| Private HTTPS | Internal ALB plus client routing and DNS into the VPC |
| Public and private HTTPS on one hostname | Dual ALBs with split-horizon DNS |
| Consumer VPC → Runlayer | Inbound PrivateLink endpoint service |
| Deployed MCP → private upstream | Runlayer Deploy private connections (PrivateLink or tunnels) |

Private ALBs and PrivateLink do not remove outbound requirements. AWS VPC endpoints cover specific AWS APIs; WorkOS, AuthKit, catalog, and other external services still need outbound HTTPS. Review [egress requirements](/deployment/egress-requirements).

## Network Configuration

```hcl theme={null}
vpc_cidr             = "10.0.0.0/16"
region_az            = ["us-east-1a", "us-east-1b", "us-east-1c"]
public_subnets       = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
private_subnets      = ["10.0.4.0/24", "10.0.5.0/24", "10.0.6.0/24"]
enable_ipv6          = true # set false for IPv4-only networks
single_nat_gateway   = false
enable_vpc_endpoints = true

# Extra private routes via Transit Gateway (module-created VPC only)
private_additional_transit_gateway_routes = [
  { cidr_block = "10.100.0.0/16", transit_gateway_id = "tgw-xxxxxxxx" },
]

alb_additional_inbound_security_group_ids = ["sg-xxxxxxxx"]
```

**Use an existing VPC** — all three variables must be provided together:

```hcl theme={null}
existing_vpc_id             = "vpc-xxxxx"
existing_private_subnet_ids = ["subnet-xxxxx", "subnet-yyyyy", "subnet-zzzzz"]
existing_public_subnet_ids  = ["subnet-aaaaa", "subnet-bbbbb", "subnet-ccccc"]
# Must match the existing VPC CIDR (default is 10.0.0.0/16). Used for SG/WAF-related
# CIDR rules even when the module does not create the VPC.
vpc_cidr = "10.8.0.0/16"
```

Private subnets need ECR/S3 endpoints or NAT for image pulls, plus NAT or another outbound HTTPS path for the external hosts in [Self-Hosted Egress Requirements](/deployment/egress-requirements). Public subnets need an internet gateway for the ALB.

Pass **one public subnet per Availability Zone**. Multiple subnets in the same AZ cause `CreateLoadBalancer` to fail with *A load balancer cannot be attached to multiple subnets in the same Availability Zone*. Subnet size can be small (for example `/26`) as long as the ALB has free IPs (\~8+). Multiple ALBs may share the same public subnets.

For topology options, see [Networking](/infrastructure/networking).

## Security Configuration

```hcl theme={null}
alb_access_type = "public" # "public" or "private"
alb_allowed_cidrs = [
  "0.0.0.0/0" # tighten for production
]
alb_allowed_ipv6_cidrs = ["::/0"]

# WAF IP allowlisting (recommended for production)
waf_enable_ip_allowlisting = true
waf_allowlist_ipv4_cidrs = [
  "203.0.113.0/24",
  "198.51.100.42/32",
]
waf_allowlist_ipv6_cidrs = [
  "2001:db8::/48",
]

# Optional: additional source ranges for agent webhook invocation only
waf_webhook_allowlist_ipv4_cidrs = ["198.51.100.0/24"]
waf_webhook_allowlist_ipv6_cidrs = ["2001:db8:5678::/48"]

```

`waf_webhook_allowlist_ipv4_cidrs` and `waf_webhook_allowlist_ipv6_cidrs`
default to `[]`. They admit the specified request-origin IPs only for `POST`
agent webhook invocation: `/api/v1/agents/{uuid}/webhooks/{token}` and the
legacy `/api/v1/assistants/{uuid}/webhooks/{token}`, with an optional trailing
slash. Paths are URL-decoded and normalized before matching. Webhook management
routes and other methods receive no additional access; existing general
allowlists and public-path exemptions still apply.

Nonempty lists require `waf_enable_ip_allowlisting = true`; nonempty IPv6 lists
also require `enable_ipv6 = true`. Invalid configurations fail planning; empty
lists remain valid when either feature is disabled. General allowlist CIDRs
remain required when allowlisting is enabled. Entries must be valid IPv4 CIDRs
with prefix lengths 1–32 or IPv6 CIDRs with prefix lengths 1–128.
The caller maintains these ranges; the module does not fetch vendor IP lists.
Managed WAF rules and webhook authentication still apply. These lists cover
invocation routes across agents, so review the admitted ranges, webhook
credentials/signing, and execution identity with your security team before
activation. ALB security groups must also permit the integration's source IPs.

When AgentCore is enabled, WAF IP allowlisting requires AgentCore **VPC** mode with PrivateLink. PUBLIC mode has no stable source IP to allowlist. Configure this before deployment:

```hcl theme={null}
enable_runlayer_agents                         = true
enable_runlayer_agentcore_runtime              = true
enable_privatelink                             = true
runlayer_agentcore_network_mode                = "VPC"
runlayer_agentcore_consumer_vpc_id             = "vpc-REPLACE_ME"
runlayer_agentcore_consumer_private_subnet_ids = ["subnet-REPLACE_ME", "subnet-REPLACE_ME_TOO"]
```

The consumer subnets need the [AgentCore egress paths](/deployment/egress-requirements#agentcore-runtime-subnets). See [AgentCore with WAF](/deployment/egress-requirements#agentcore-with-waf-ip-allowlisting).

## Dual ALB Setup (Split-Horizon DNS)

```hcl theme={null}
enable_dual_alb = true

# Optional: existing private hosted zone
private_hosted_zone_id     = "Z1234567890ABC"
private_hosted_zone_vpc_id = "vpc-1234567890abcdef0"
private_hosted_zone_additional_vpc_ids = [
  "vpc-0987654321fedcba0",
]

alb_internal_allowed_cidrs = [
  "10.200.0.0/16", # Corporate VPN
]
alb_internal_allowed_ipv6_cidrs = [
  "fd00::/64",
]
```

**Use case:** public access (for example ChatGPT / external integrations) plus private network access on the same hostname via split-horizon DNS.

* Public DNS → public ALB
* Private DNS → internal ALB
* ECS services register with both ALBs
* WAF applies only to the public ALB

```hcl theme={null}
enable_dual_alb          = true
enable_resolver_endpoint = true # Route53 Resolver inbound for private DNS
# cross_account_hosted_zone_id = "ZXXXXXXXX"  # configure aws.route53 assume_role when set
# manage_service_vpc_private_hosted_zone_association = true
```

## VPC Peering for Cross-VPC Connectivity

<Warning>
  **Security note:** every peering connection must set `peer_owner_id`. The module validates ownership before accepting the connection.
</Warning>

```hcl theme={null}
vpc_peering_connections = {
  "customer-vpc" = {
    peering_connection_id = "pcx-0abc123def456"
    peer_vpc_cidr         = "172.16.0.0/16"
    peer_owner_id         = "123456789012" # REQUIRED
    peer_region           = "us-east-1"    # optional
  }
}
```

VPC peering only applies when the module creates the VPC (not with `existing_vpc_id`).

## Inbound PrivateLink access to Runlayer

Expose Runlayer to consumer VPCs with an endpoint service:

```hcl theme={null}
enable_privatelink              = true
privatelink_allowed_principals  = ["arn:aws:iam::123456789012:root"]
privatelink_acceptance_required = true
# privatelink_subnet_ids = ["subnet-aaaa", "subnet-bbbb"]
# privatelink_additional_supported_regions = ["us-west-2"]
```

Expose the child module output in your root configuration:

```hcl theme={null}
output "privatelink_service_name" {
  value = module.runlayer_infrastructure.privatelink_service_name
}
```

After apply, use `terraform output -raw privatelink_service_name` to create consumer interface endpoints. Accept endpoint requests when acceptance is required and configure consumer DNS, routing, and security groups.

## Outbound private connections for Runlayer Deploy

These connect your deployed MCPs to private upstream systems. Select the connection types you need:

```hcl theme={null}
private_connection_types = ["aws_privatelink"] # add "tunnel" if needed
# tunnel_router_listener_priority = 15
# tunnel_trace_sample_ratio = 0.1
# tunnel_aws_endpoint_security_group_id = "sg-xxxxxxxx" # required for tunnels with an existing VPC
```

Upgrade the module with the application: each module release selects the matching router, endpoint, and connector bundle. Enable tunnels only with a compatible application release. Upgrade the application before the module; on rollback, restore the previous module configuration before the application. See [Updates](/operations/updates).

### Private connection provisioning

ECS private connections reconcile asynchronously. **Revision `2` is an internal private-connection configuration marker, separate from the ECS module release (for example, `v33.1.0`).** This migration guidance applies to existing connections, not initial platform installation. Existing Deploy PrivateLink
connections upgrade to connection configuration revision `2`, adding connection-owned access
security groups while retaining the existing endpoint and legacy security group.
Wait for reconciliation before creating or redeploying an MCP deployment that uses
the connection. Existing running deployments retain their legacy access rules;
redeployment switches them to access-SG attachment. Each deployment supports up
to four private connections.

`RUNLAYER_PRIVATE_CONNECTION_TERRAFORM_TIMEOUT_SECONDS` defaults to `1800` and
must be a positive finite number. Set it through `additional_backend_env_vars`
to override the shared deadline for Terraform init, apply/destroy, and output
commands. It does not change ordinary MCP deployment timeouts. Failed
reconciliation preserves the connection's prior usable state and is retried
automatically up to 3 times, at least 15 minutes apart; if it still fails,
contact Runlayer support to inspect and recover the upgrade before retrying the
deployment.

## Private CA certificates

To trust MCP servers or HTTPS proxies whose certificates use your private CA,
pass the CA certificate bundle to the ECS module:

```hcl theme={null}
trusted_ca_pem = file("${path.module}/company-ca.pem")
```

The file may concatenate multiple PEM certificate blocks. Include CA
certificates only—never private keys. The module combines them with the public
roots already in the Runlayer image and configures the backend, shared worker,
and MCP execution worker to use the combined bundle. Frontend and migration
tasks are intentionally unchanged because neither connects to customer MCP
servers or customer-managed private-CA HTTPS endpoints.

Changing the file and applying Terraform rolls the affected ECS tasks. The
tasks start only after an init container validates and writes the bundle.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.