Add GoBridge to an established AWS environment with an existing VPC, ALB, and ECS cluster. Instead of creating all resources from scratch, this scenario imports shared infrastructure and layers the GoBridge Fargate service on top.
Use a consumer-built image with embedded initial config, or provide an existing target. Registry images are not changed by CDK. Missing config keeps the data plane idle; only control can initialize it. See initial configuration.
An enterprise platform team maintains a shared landing zone with a centralized VPC, a shared ECS cluster, and an internal Application Load Balancer. Individual service teams deploy into this environment without creating their own networking primitives.
Your team needs to add GoBridge for bridging MQTT telemetry into SQS queues. The constraints are:
platform-ecs) that already
runs other services. You add your task definitions to it.flowchart TD
subgraph VPC["Existing VPC (10.0.0.0/16)"]
subgraph Private["Private Subnets"]
subgraph Cluster["ECS Cluster: platform-ecs"]
T1[GoBridge Task 1]
T2[GoBridge Task N]
Other[Other Services...]
end
EFS[(EFS\nbridge.yaml)]
end
ALB["Internal ALB\n(existing)"]
end
SSM[SSM Parameter Store] --> Private
ECR[ECR Registry] --> Cluster
ALB -->|:8080 admin| T1
ALB -->|:8081 monitor| T2
ALB -->|:8082 transport| T1
T1 -- NFS 2049 --> EFS
T2 -- NFS 2049 --> EFS
Client([Internal Clients]) --> ALB
style fill:#f96,stroke:#333
style fill:#f96,stroke:#333
style Other fill:#6bf,stroke:#333
GoBridge tasks run alongside other workloads in the shared cluster. The ALB routes traffic to GoBridge target groups using path-based rules.
Import the existing VPC by its ID. CDK performs a context lookup at synth time to resolve subnets, availability zones, and route tables.
import (
"github.com/aws/aws-cdk-go/awscdk/v2/awsec2"
"github.com/aws/jsii-runtime-go"
)
vpc := awsec2.Vpc_FromLookup(stack, jsii.String("Vpc"), &awsec2.VpcLookupOptions{
VpcId: jsii.String("vpc-0abc1234def56789a"),
})
If you prefer lookup by tag instead of a hard-coded ID:
vpc := awsec2.Vpc_FromLookup(stack, jsii.String("Vpc"), &awsec2.VpcLookupOptions{
Tags: &map[string]string{
"environment": "production",
"team": "platform",
},
})
When the VPC contains multiple subnet tiers, select private subnets explicitly for Fargate task placement:
privateSubnets := &awsec2.SubnetSelection{
SubnetType: awsec2.SubnetType_PRIVATE_WITH_EGRESS,
}
This selection is used later when creating the Fargate service and EFS mount targets to ensure resources stay within private subnets with NAT-based egress.
Import the shared ECS cluster by name and VPC reference. CDK needs both the cluster name and the VPC to resolve service networking.
import "github.com/aws/aws-cdk-go/awscdk/v2/awsecs"
cluster := awsecs.Cluster_FromClusterAttributes(stack, jsii.String("Cluster"),
&awsecs.ClusterAttributes{
ClusterName: jsii.String("platform-ecs"),
Vpc: vpc,
SecurityGroups: &[]awsec2.ISecurityGroup{},
},
)
The empty SecurityGroups slice signals that task-level security groups are
managed per service, not at the cluster level. This is the recommended pattern
for shared clusters where each workload defines its own network rules.
Import the existing ALB by its ARN and create target groups for each GoBridge port. The platform team provides the ALB ARN and the HTTPS listener ARN.
Import the existing HTTPS listener using ApplicationListener_FromLookup with
the load balancer tags and port 443. The full import is shown in the
Complete CDK Code section below.
The admin target group requires ALB sticky sessions. Configuration transactions
are held in memory on a single GoBridge instance. When a client begins a
transaction (POST /api/v1/admin/config/transactions), all subsequent requests
for that transaction must reach the same task. Without stickiness, the ALB could
route a commit request to a different instance that has no knowledge of the
in-progress transaction.
adminTg := elbv2.NewApplicationTargetGroup(stack, jsii.String("AdminTG"),
&elbv2.ApplicationTargetGroupProps{
Port: jsii.Number(8080),
Protocol: elbv2.ApplicationProtocol_HTTP,
Vpc: vpc,
TargetType: elbv2.TargetType_IP,
HealthCheck: &elbv2.HealthCheck{
Path: jsii.String("/api/v1/monitor/health"),
Port: jsii.String("8081"),
Interval: awscdk.Duration_Seconds(jsii.Number(30)),
Timeout: awscdk.Duration_Seconds(jsii.Number(5)),
HealthyThresholdCount: jsii.Number(2),
UnhealthyThresholdCount: jsii.Number(3),
},
StickinessCookieDuration: awscdk.Duration_Minutes(jsii.Number(5)),
},
)
The 5-minute stickiness duration matches the default transaction auto-expiry timeout. If the client does not commit within 5 minutes, the transaction expires and the sticky cookie has no further effect. See HTTP API & Networking for a detailed explanation of the transaction flow and stickiness requirements.
Monitor and transport traffic is stateless, so stickiness is not needed.
monitorTg := elbv2.NewApplicationTargetGroup(stack, jsii.String("MonitorTG"),
&elbv2.ApplicationTargetGroupProps{
Port: jsii.Number(8081),
Protocol: elbv2.ApplicationProtocol_HTTP,
Vpc: vpc,
TargetType: elbv2.TargetType_IP,
HealthCheck: &elbv2.HealthCheck{
Path: jsii.String("/api/v1/monitor/health"),
Port: jsii.String("8081"),
Interval: awscdk.Duration_Seconds(jsii.Number(30)),
Timeout: awscdk.Duration_Seconds(jsii.Number(5)),
},
},
)
transportTg := elbv2.NewApplicationTargetGroup(stack, jsii.String("TransportTG"),
&elbv2.ApplicationTargetGroupProps{
Port: jsii.Number(8082),
Protocol: elbv2.ApplicationProtocol_HTTP,
Vpc: vpc,
TargetType: elbv2.TargetType_IP,
HealthCheck: &elbv2.HealthCheck{
Path: jsii.String("/api/v1/monitor/health"),
Port: jsii.String("8081"),
Interval: awscdk.Duration_Seconds(jsii.Number(30)),
Timeout: awscdk.Duration_Seconds(jsii.Number(5)),
},
},
)
Attach path-based routing rules to the shared HTTPS listener. Each target group
gets a priority-ordered rule matching its API path prefix (/api/v1/admin/*,
/api/v1/monitor/*, /api/v1/transport/*). The full listener rule setup is
shown in the Complete CDK Code section.
Define explicit security group rules to follow least-privilege networking within the shared VPC.
// Task security group -- applied to GoBridge Fargate tasks.
taskSG := awsec2.NewSecurityGroup(stack, jsii.String("TaskSG"),
&awsec2.SecurityGroupProps{
Vpc: vpc,
Description: jsii.String("GoBridge Fargate tasks"),
AllowAllOutbound: jsii.Bool(true),
},
)
// EFS security group -- controls NFS mount target access.
efsSG := awsec2.NewSecurityGroup(stack, jsii.String("EfsSG"),
&awsec2.SecurityGroupProps{
Vpc: vpc,
Description: jsii.String("GoBridge EFS mount targets"),
AllowAllOutbound: jsii.Bool(false),
},
)
// Allow Task -> EFS on NFS port 2049.
efsSG.AddIngressRule(
taskSG,
awsec2.Port_Tcp(jsii.Number(2049)),
jsii.String("GoBridge tasks NFS access"),
jsii.Bool(false),
)
// Allow ALB -> Task on admin, monitor, and transport ports.
// Import or reference the ALB security group.
albSG := awsec2.SecurityGroup_FromLookupById(stack, jsii.String("AlbSG"),
jsii.String("sg-0alb1234security56"),
)
taskSG.AddIngressRule(
albSG,
awsec2.Port_TcpRange(jsii.Number(8080), jsii.Number(8082)),
jsii.String("ALB to GoBridge ports"),
jsii.Bool(false),
)
// Restrict outbound from tasks to VPC CIDR only (tighten if needed).
taskSG.AddEgressRule(
awsec2.Peer_Ipv4(jsii.String("10.0.0.0/16")),
awsec2.Port_AllTraffic(),
jsii.String("VPC-internal traffic only"),
jsii.Bool(false),
)
This produces three security group relationships:
| Source | Destination | Port(s) | Purpose |
|---|---|---|---|
| ALB SG | Task SG | 8080-8082 | Load-balanced HTTP traffic |
| Task SG | EFS SG | 2049 | NFS config mount |
| Task SG | VPC CIDR | all | Outbound to internal services |
The full stack listing for this scenario is on its own page: Custom VPC — complete CDK stack.
When the platform team provides a shared EFS filesystem, pass it directly to
gobridge.EfsConfigProps.FileSystem. The construct creates control and worker
access points at / and skips filesystem creation.
import (
"github.com/aws/aws-cdk-go/awscdk/v2/awsefs"
"github.com/mariotoffia/gobridge/deployment/aws/cdk/gobridge"
)
existingFs := awsefs.FileSystem_FromFileSystemAttributes(stack, jsii.String("SharedEfs"),
&awsefs.FileSystemAttributes{
FileSystemId: jsii.String("fs-0abc1234def56789a"),
SecurityGroup: awsec2.SecurityGroup_FromSecurityGroupId(
stack, jsii.String("SharedEfsSG"),
jsii.String("sg-0efs1234security56"),
&awsec2.SecurityGroupImportOptions{},
),
},
)
efsConfig := gobridge.NewEfsConfig(stack, "Efs",
&gobridge.EfsConfigProps{
Vpc: vpc,
FileSystem: existingFs,
},
)
EFS mount targets must exist in every availability zone where Fargate tasks may run. When reusing a shared EFS, verify that mount targets cover all private subnets. If the platform team created the EFS with mount targets in only two AZs but the VPC has three, tasks scheduled in the third AZ will fail to mount the volume.
Check existing mount targets:
aws efs describe-mount-targets --file-system-id fs-0abc1234def56789a \
--query 'MountTargets[].{AZ:AvailabilityZoneName,SubnetId:SubnetId}'
If coverage is incomplete, the platform team must add mount targets to the missing subnets before deploying the GoBridge stack.
Multiple services can share one EFS filesystem, but GoBridge’s control and worker
access points both expose /; gobridge.EfsConfigProps has no configurable
access-point path. Another service can use a narrower path, but that does not
confine GoBridge to its own directory. Use a separate filesystem when services
require filesystem isolation.
// GoBridge's control and worker access points both expose the filesystem root.
gobridgeEfs := gobridge.NewEfsConfig(stack, "GoBridgeEfs",
&gobridge.EfsConfigProps{
Vpc: vpc,
FileSystem: sharedFs,
},
)
// Another service at /other-service (outside gobridge constructs)
otherAP := awsefs.NewAccessPoint(stack, jsii.String("OtherAP"),
&awsefs.AccessPointProps{
FileSystem: sharedFs,
Path: jsii.String("/other-service"),
PosixUser: &awsefs.PosixUser{Uid: jsii.String("1001"), Gid: jsii.String("1001")},
CreateAcl: &awsefs.Acl{OwnerUid: jsii.String("1001"), OwnerGid: jsii.String("1001"), Permissions: jsii.String("755")},
},
)
When GoBridge runs in a workload account but must reach an MQTT broker or SQS queue in a central account, set up VPC peering or Transit Gateway. The CDK stack itself does not change – VPC peering is configured at the networking layer. The key adjustment is ensuring that the GoBridge task security group allows egress to the peered CIDR range:
taskSG.AddEgressRule(
awsec2.Peer_Ipv4(jsii.String("10.1.0.0/16")), // peered VPC CIDR
awsec2.Port_Tcp(jsii.Number(1883)), // MQTT broker port
jsii.String("MQTT broker in central account"),
jsii.Bool(false),
)
To reach SQS without traversing the public internet, add a VPC endpoint. This is typically managed by the platform team, but you can verify it exists:
aws ec2 describe-vpc-endpoints \
--filters Name=vpc-id,Values=vpc-0abc1234def56789a \
Name=service-name,Values=com.amazonaws.eu-west-1.sqs
If it does not exist, add it in CDK:
vpc.AddInterfaceEndpoint(jsii.String("SqsEndpoint"),
&awsec2.InterfaceVpcEndpointOptions{
Service: awsec2.InterfaceVpcEndpointAwsService_SQS(),
},
)
GoBridge SQS transport configuration requires no changes – the AWS SDK automatically routes API calls through the VPC endpoint when one is present.