-
Notifications
You must be signed in to change notification settings - Fork 0
deployment patterns
Five deployment topologies. Example code in aws/examples/.
Directory: aws/examples/full-stack/
Deploys everything: VPC + Database + Storage + BRMS + Agent
flowchart TD
subgraph VPC["VPC (created)"]
subgraph Public[Public Subnets]
ALBs[ALBs]
end
subgraph Private[Private Subnets]
BRMS[BRMS ECS Service]
Agent[Agent ECS Service]
Aurora[Aurora PostgreSQL]
end
ALBs --> BRMS
ALBs --> Agent
end
S3[S3 Bucket\nrules storage]
- Single-account deployments
- Complete self-contained environments
- Development and testing
vpc.create = truestorage != null-
database != null(provide min/max capacity) -
brms != null(provide cpu, memory, domain) -
agent != null(provide cpu, memory)
Directory: aws/examples/agent-only/
Stateless rule execution: no database, no BRMS.
flowchart TD
subgraph VPC["VPC (created)"]
subgraph Public[Public Subnets]
ALB[Agent ALB]
end
subgraph Private[Private Subnets]
Agent[Agent ECS Service]
end
ALB --> Agent
end
S3[S3 Bucket\nrules storage, read-only]
- Dedicated rule execution environments
- High-throughput stateless processing
- Part of multi-environment setup
database = nullbrms = nullagent != null- Agent gets read-only S3 access via IAM Architecture
Directory: aws/examples/existing-vpc/
Integrate with an already-provisioned VPC.
flowchart TD
subgraph VPC["Existing VPC (not managed)"]
subgraph Public[Existing Public Subnets]
ALBs[ALBs]
end
subgraph Private[Existing Private Subnets]
BRMS[BRMS ECS Service]
Agent[Agent ECS Service]
Aurora[Aurora PostgreSQL]
end
ALBs --> BRMS
ALBs --> Agent
end
S3[S3 Bucket\nrules storage]
- Enterprise environments with centralized networking
- Shared VPCs managed by a platform team
- Compliance requirements for network topology
vpc = {
create = false
id = "vpc-0abc123..."
private_subnet_ids = ["subnet-0aaa...", "subnet-0bbb..."]
public_subnet_ids = ["subnet-0ccc...", "subnet-0ddd..."]
}Validation in the Root Module requires id and at least one private subnet ID when create = false. Public subnets are optional: provide public_subnet_ids only when an ALB is internet-facing (alb_internal = false). For internal-only deployments you can pass public_subnet_ids = [] (see Pattern 5).
Directory: aws/examples/multi-environment/
Cross-account deployment with centralized BRMS and distributed Agents.
flowchart LR
subgraph Mgmt[Management Account]
BRMS[BRMS Editor]
DB[Database]
AgentDev[DEV Agent]
S3Mgmt[S3\nDEV bucket]
S3Mgmt --> AgentDev
end
subgraph Staging[Staging Account]
AgentStg[Agent]
S3Stg[S3\nstaging bucket\ngrants write to mgmt]
S3Stg --> AgentStg
end
subgraph Prod[Production Account]
AgentProd[Agent]
S3Prod[S3\nprod bucket\ngrants write to mgmt]
S3Prod --> AgentProd
end
BRMS -- "Cross-Account Write" --> S3Stg
BRMS -- "Cross-Account Write" --> S3Prod
- Staging first: creates Agent infrastructure and its own S3 bucket
- Production second: creates Agent infrastructure and its own S3 bucket
- Management last: creates BRMS + DB + DEV Agent, referencing the staging/prod bucket ARNs
This order matters because the management account must reference the actual S3 bucket ARNs of the staging and prod accounts (via brms.external_buckets), and those ARNs only exist after staging and prod are deployed. The reverse is not a constraint: the staging/prod buckets grant cross-account write access using only the management account's 12-digit account ID (cross_account_write_principals), a static value known in advance.
The grant lives on the staging and prod buckets, not on the management bucket. Each downstream account creates its own bucket and grants the management account write access to it:
# In staging-account and prod-account:
storage = {
cross_account_write_principals = [var.management_account_id]
}The management account does not set cross_account_write_principals; its storage block is just storage = {}. Instead it lists the staging and prod bucket details in brms.external_buckets, which grants the BRMS task role IAM permission to publish rules into those buckets:
# In management-account:
storage = {}
brms = {
# ...
external_buckets = [
{ arn = "arn:aws:s3:::gorules-staging-rules-abc12345", name = "gorules-staging-rules-abc12345" },
{ arn = "arn:aws:s3:::gorules-prod-rules-def67890", name = "gorules-prod-rules-def67890" },
]
}The centralized BRMS in the management account writes (publishes rules) into the staging and prod buckets. Each environment's Agent reads rules from its own local bucket. See Storage Module for how the bucket policy is constructed.
Each environment (staging, prod) creates its own S3 bucket and grants the management account cross-account write access. The local Agent reads from that same-account bucket while BRMS in the management account writes rules into it. There is no create_bucket = false or existing_bucket_arn in the multi-environment example; the data flows the other way, with management publishing into each environment's bucket.
# In staging/prod accounts: create a local bucket, let management write to it
storage = {
cross_account_write_principals = [var.management_account_id]
}Directory: aws/examples/internal-alb/
Both load balancers use the internal scheme in private subnets. Nothing is created in a public subnet. Use this when policy forbids public-subnet resources, or when the services are reached only from inside the network.
flowchart TD
Clients((Internal network))
License[[portal.gorules.io]]
subgraph VPC["VPC (module creates nothing public)"]
subgraph Private[Private Subnets]
ALBs[Internal ALBs]
BRMS[BRMS ECS Service]
Agent[Agent ECS Service]
Aurora[Aurora PostgreSQL]
end
end
Egress[Your egress: NAT / TGW / proxy]
Clients --> ALBs
ALBs --> BRMS
ALBs --> Agent
BRMS --> Egress --> License
BRMS --> S3[S3 Bucket]
Agent --> S3
- Company policy forbids resources in public subnets
- Services reached only from inside the network
- Public ingress is layered on separately, for example CloudFront with a VPC origin
BRMS validates its license at https://portal.gorules.io, so a VPC with no egress cannot run BRMS. The Agent is self-contained. This pattern brings a VPC whose egress comes from your network, and the module creates nothing in a public subnet.
vpc = {
create = false # bring a VPC that already has egress
id = "vpc-0123456789abcdef0"
private_subnet_ids = ["subnet-aaa", "subnet-bbb"]
public_subnet_ids = []
}
brms = {
alb_internal = true
domain = "brms.internal.example.com"
certificate_arn = "arn:aws:acm:..." # internal ALB still terminates TLS
allowed_cidr_blocks = ["10.0.0.0/8"]
# ...
}
agent = { alb_internal = true, /* ... */ }An internal ALB still terminates TLS, so BRMS still needs HTTPS. Provide certificate_arn (the route53_zone_id auto-issue path needs a publicly resolvable zone), or set alb_http_only = true to run behind a TLS-terminating edge.
A fully air-gapped, module-built VPC (create = true, nat_gateway_mode = "none") has no internet egress, so it suits an agent-only deployment. In a no-NAT VPC the tasks reach AWS through auto-provisioned VPC endpoints, but those never reach Docker Hub. Mirror the default images to a private ECR repository and set agent.image (and brms.image) to the ECR URI, otherwise the tasks fail with CannotPullContainerError. See the internal-alb example and the Internal Load Balancers section of the module README.
If a trusted edge such as CloudFront (VPC origin) terminates HTTPS in front of the ALB, run the ALB over HTTP only and skip its certificate with alb_http_only = true. This is the shape GoRules runs in production.
brms = {
domain = "brms.example.com" # public hostname served by the edge
allowed_cidr_blocks = ["10.0.0.0/8"]
alb_internal = true
alb_http_only = true # requires alb_internal = true
}BRMS still requires the browser to use HTTPS, so the edge must provide it. domain is still required because BRMS uses it for APP_URL. See the HTTP-only ALB behind an edge section of the module README.
Different security postures are possible:
| Component | Mode 1 (Simple) | Mode 2 (IAM-Native) |
|---|---|---|
| Database | auth = "secrets" | auth = "iam" |
| Storage | auth = "iam" | auth = "iam" |
| BRMS Secrets | type = "env" | type = "aws-kms" |
See Secrets Management for details on each mode.