The short version
- Nothing connects into your network. Your data plane opens every connection. The control plane never initiates a connection to the data plane and is not in any cluster’s security group ingress.
- The control plane holds none of the feature’s credentials. It cannot assume either IAM role, has no database credentials, and has no route to a cluster. What it stores is lifecycle state and connection metadata: which application has a database under which data tag, the cluster endpoint, and the database and role names. Application data and credentials never reach it.
- IAM policies you review and own decide which resources can change. The lifecycle worker role can create, modify, or delete only resources that carry the tags Superblocks stamps at creation, inside the one VPC you declared. Its trust policy names only your data plane’s identity, and you can revoke it at any time. IAM bounds the footprint, not every operation inside it; see What bounds a task.
- No application password ever exists. Applications connect with 15-minute RDS IAM tokens, each limited by a per-connection session policy to one PostgreSQL role on one cluster.
- Clusters cannot be public or unencrypted. IAM conditions require
publicly_accessible = false, storage encryption, and an RDS-managed master password on every cluster the worker creates, so a modified module cannot opt out.
What you are asked to grant
Setup runs one Terraform module,app-db-prereqs, once per region in each account. It creates the following. Nothing else is created until an organization admin clicks Provision, which creates the first Aurora cluster. From then on the worker acts without a human gate: it creates a database whenever a builder needs one, and another cluster whenever remaining pool capacity falls to the thresholds in your data plane configuration (max_databases, and minAvailableCapacityPercent on Helm). The number of clusters is bounded by those thresholds and your AWS quotas, not by IAM.
- No cross-account trust. No trust policy names a Superblocks account, and no Superblocks-operated system outside your account can assume either role. If Superblocks operates your data plane for you (Cloud-Prem with managed data planes), its operators act through the data plane’s own identity inside your account, and every role assumption is in your CloudTrail.
- No IAM administration. The worker’s only IAM permissions are
iam:PassRolefor the monitoring role to RDS andiam:CreateServiceLinkedRolefor the RDS service-linked role. It cannot create roles, attach policies, or change its own permissions. - No tagging escape hatch. The tagging permissions are conditioned too.
ec2:CreateTagsis allowed only in the request that creates a security group or rule, or on one that already carries the three scoping tags.rds:AddTagsToResourceis allowed only on RDS resources namedsb-*, and only with the scoping tags in the request. The worker cannot bring an arbitrary resource of yours into scope by tagging it, and it is explicitly denied removing the scoping tags from anything. - No reach outside the VPC. Every mutating permission is conditioned on the VPC you declared.
- No secrets of its own. The worker can read the RDS-managed master secret for clusters it created (
rds!cluster-*), which RDS creates and rotates. It cannot create, write, or export secrets, and it has no long-lived credentials: the role is assumed through ECS or IRSA, and the organization agent key it uses toward the control plane grants nothing in AWS.
What runs where
In a Hybrid deployment the control plane is Superblocks Cloud, outside your account. In Cloud-Prem it runs inside your AWS account under its own identity, operated by Superblocks. The trust boundary is the same in both: the control plane is not a principal in either role’s trust policy, is not in any cluster’s security group ingress, and never opens a connection to the data plane.- Hybrid
- Cloud-Prem
source_security_group_ids and allowed_cidr_blocks, which is normally your data plane’s security group and nothing else. See Physical database options.
How applications are kept apart
Each application gets its own PostgreSQL database,sbndb_<profile-token>_<application-token>, and its own PostgreSQL role, sbndb_<profile-token>_<application-token>_runtime, on a cluster shared with other applications under the same data tag. The tokens are hashes of the data tag and the application ID, so names are stable and cannot collide. See Data tag names. Edit-time and deploy-time databases are separate databases under different data tags; publishing creates the deploy-time database with the schema only, and no rows are copied.
The lifecycle worker creates the role with rds_iam and no password, so PostgreSQL delegates authentication for it to IAM: the only way to log in as that role is an RDS IAM token signed by an identity that IAM allows to rds-db:connect as that user. Two policies decide that, and the effective permission is their intersection:
- The connector role’s own policy allows
rds-db:connectonly for users matchingsbndb_<profile-token>_*_runtimefor the data tags you declared. It cannot connect as the master user, as a role from another data tag, or as anything that is not an application runtime role. - The per-connection session policy the data plane attaches when it assumes the connector role narrows that to the single user for the single application being served, on the single cluster that application’s database lives on.
How work is dispatched
Every change starts as a task the control plane queues and ends with your data plane deciding whether and how to carry it out. The control plane cannot skip the data plane, because it has nothing to call AWS or the database with. Registering the database capability rides on the same/api/v1/agents/register call every data plane already makes; the rest use the database-lifecycle routes.
The data plane always polls the claim route every 30 seconds. The server-sent events subscription only lets it notice new work sooner; if that route errors or is unavailable, polling continues and the subscription is re-probed periodically. Both paths are outbound, both authenticate with the agent key, and neither carries a task: the task is always fetched through the claim request, whichever path woke the data plane up. A proxy that buffers the stream adds latency and nothing else.
What bounds a task
Separate the controls that live in your account, which hold even if Superblocks is compromised, from the controls Superblocks enforces on its own side, which are defense in depth. Enforced in your account, independent of Superblocks:- Direction. The data plane pulls work over connections it opens. The control plane cannot reach the data plane, call AWS, or connect to a database.
- IAM on the AWS path. Creates require the scoping tags in the request; modifies and deletes require them on the existing resource; every mutation is confined to the declared VPC; public endpoints and unencrypted storage are denied by condition. A task that asked for a resource outside these bounds fails with
AccessDenied. - Identity on the database path. Application queries and schema migrations run over the connector role, which IAM limits to one application role on one cluster per connection, as described under How applications are kept apart. Create and retire tasks are different: they run as the master user, over a session the worker opens with the RDS-managed secret. What bounds those is not IAM but the allowlisted module, which executes the DDL for the named database and its roles and nothing else.
- Allowlists on the data plane. Before applying, the worker materializes the OpenTofu configuration from module sources on an allowlist in its own configuration, runs
tofu plan, and rejects any plan that touches a resource type outside its allowlist. These checks run in your VPC, on configuration you control. - Network. Clusters accept connections only from the security groups and CIDR ranges you configured.
- Tasks are routed only to a data plane that registered for the exact data tag the task belongs to, and wildcard data tags are rejected at registration.
- Wake-up hints are empty signals, task payloads contain intent and the application’s schema files but never credentials, and outcome reports that contain credential material are rejected.
- AWS path. The attacker can queue tasks that change Superblocks-managed clusters, which as of the current release includes destructive changes to a cluster the worker already manages, such as deleting or resizing it, and can queue cluster creations, so unexpected spend is part of the worst case. The allowlists prevent new resource types and foreign module sources, and IAM prevents any effect outside the tagged footprint, but neither independently blocks a destructive plan against an in-footprint cluster. The controls that apply there are the ones you set on the clusters:
deletion_protection, which defaults totrue, automated backups, and the final snapshot on deletion. Set them in your Terraform or Helm configuration, not in the console: the worker re-applies module-managed settings on later runs, so a console change to a module-managed attribute is reverted the next time a task touches that cluster. See Physical database options. - Migrations. Attacker-chosen SQL runs as one application’s
_runtimerole in that application’s database, one task at a time. It cannot authenticate as the master user or as another application, but the attacker can queue a migration for every application under the data plane’s data tags, so the aggregate is corruption of application data across that data plane. - Create and retire. These open a master-user session, but only the allowlisted module’s
CREATEandDROPof the named database and roles run on it, not attacker-supplied SQL. Queued retires for every application would drop every application database on that data plane, which is the same aggregate as above by a different route. Backups are the recovery path. - Outcome reports. The attacker controls both ends in this scenario, so the control plane’s credential-material check offers no protection here. It does not need to: outcome reports carry no credentials because none exist.
How to verify
Before setup
- Read the Raw IAM policy JSON for both roles. The Terraform module attaches exactly these policies, and that section is written to be handed to an IAM approver as is.
- Read the module source.
app-db-prereqsis published in thesuperblocksteam/superblocks/awsregistry module, and itsterraform planoutput lists every resource it will create before you apply it. - Read the outbound requests the data plane makes, and confirm your egress path allows them. No inbound rule is required.
- Confirm the inputs you will pass: the VPC, the private subnets, the security groups allowed to reach port 5432, and the data tags. Each becomes a condition in the policies above.
After setup
Everything the feature manages is discoverable from your account, without involving Superblocks. IAM is global, but the tagging and RDS commands below are regional; run them in every region where you deployed a data plane.AssumeRole on the connector role, and every master-user session starts with a GetSecretValue on the cluster’s rds!cluster-* secret. Individual PostgreSQL connections and statements are in the per-cluster logs exported to CloudWatch Logs; see Observing.
Next steps
Reference
Resource names, IAM scoping, tagging, and the full policy JSON.
Setup
Run the Terraform module and provision the first cluster.

