How the templates read their configuration
Each stack template fetches internal configuration from the Nuon control plane using thenuonco/stack Terraform
provider, then layers the customer-provided inputs and secrets over that.
install_id, cloud provider configuration, and any
input or secret overrides. The Stack provider authenticates the read; the install ID is not a credential. The attribute
reference for every value the data source exposes is in
The Nuon Stack Terraform Provider.
AWS
The AWS stack lives interraform-aws-stack.
Runner instance
-
An EC2 instance (typically launched by an Auto Scaling Group) in a subnet with outbound HTTPS to the Nuon API and to
GitHub raw — the boot process downloads
init-mng-v2.shand therunnerbinary over the public internet. - IMDSv2 must be enabled with required tokens. The runner authenticates to ctl-api using its Instance Identity Document, which is read from IMDS.
-
Instance tags must include:
nuon_runner_idnuon_runner_api_urlnuon_install_id— used in the per-install CloudWatch log group path.
init-mng-v2.shreads these viaec2:DescribeTags. Missing or misnamed tags cause the runner to fail to start. -
user_datamust exportRUNNER_AUTH_METHOD=iidbefore invoking the init script. The init script defaults tostsauth (legacy) if this is not set.
Runner IAM role
Attached to the instance via an instance profile. The inline policy must allow:sts:AssumeRoleon every operation, break-glass, and custom role the stack creates. The runner switches into these roles to execute components.secretsmanager:GetSecretValueandsecretsmanager:DescribeSecreton the secret ARN pattern your stack uses (the default stack uses<prefix>-*). Required for components that consume secrets.logs:CreateLogGroup,CreateLogStream,PutLogEvents,DescribeLogStreamson/nuon/<install_id>/*andrunner-*log groups.ec2:DescribeTagson*— the init script’s tag lookups.
Operation, break-glass, and custom roles
- One IAM role per
[operation_role],[[break_glass_role]], and[[custom_role]]block declared instack.toml. - Trust policy must allow
sts:AssumeRolefrom:- The runner role ARN — the runner assumes them when executing components or actions.
- The Nuon control-plane principals (
data.stack_config.this.aws.nuon_support_iam_role_arns, falling back to account root) — used for ad-hoc actions and break-glass operations initiated from ctl-api.
- Permissions on each role come from your
stack.toml(provision_inline_policy,provision_managed_policy_arns, etc.). The stack’s job is to translate those into IAM resources. - Role names must match
each.keyfromstack.tomlverbatim. ctl-api looks roles up by exact name, and the default stack deliberately doesn’t double-prefix break-glass / custom roles. If you rewrap names with a prefix you’ll hit the 64-character IAM role-name limit and break role lookups.
Phone-home payload
Afterterraform apply succeeds, the stack reports a JSON payload to the control plane — either through the
stack_phone_home resource or by POSTing to the
phone_home_url from the data source. ctl-api persists every key in this payload as an install stack output,
accessible from app templates as nuon.install_stack.outputs.<key>.
The required keys (matching the CloudFormation phone-home Lambda payload exactly):
GCP
The GCP stack lives interraform-gcp-stack.
Runner instance
- A
google_compute_instance(or MIG) in a subnet with outbound HTTPS to the Nuon API and to GitHub raw. - The runner authenticates with the token returned by
data.stack_config.this.gcp.runner_api_token. Protect Terraform state as sensitive because the token is stored in instance metadata. - The same
init-mng-v2.shflow applies: instance metadata must carrynuon_runner_id,nuon_runner_api_url, andnuon_install_idso the init script can read them.
Runner service account
Attached to the runner instance. The IAM policy must allow:iam.serviceAccounts.getAccessTokenandiam.serviceAccounts.signBlobon every operation, break-glass, and custom service account the stack creates — the runner impersonates these to execute components.- Read access to whatever Secret Manager secrets the stack provisions (the default stack scopes by name prefix).
logging.logEntries.createfor runner logs.
Operation, break-glass, and custom service accounts
- One service account per
[operation_role],[[break_glass_role]], and[[custom_role]]block instack.toml. - Each must grant the runner service account
roles/iam.serviceAccountTokenCreatorso the runner can impersonate it. - Permissions on each service account come from your
stack.toml(inline + managed policies are translated into IAM bindings on the project). - Report each role under its exact configured role name. Resource names may use deterministic hashes to satisfy GCP’s 30-character service-account ID limit.
Phone-home payload
Afterterraform apply succeeds, the stack reports a JSON payload to the control plane (via the stack_phone_home
resource or a POST to the phone_home_url from the data source). Required keys:
Azure
The Azure stack lives interraform-azure-stack.
Runner virtual machine
- A Linux virtual machine in a subnet with outbound HTTPS to the Nuon API and artifact hosts.
- Metadata passed to cloud-init must include the runner ID and runner API URL from
stack_config. - The runner identity needs the role assignments required to assume configured operation, break-glass, and custom roles.
Phone-home payload
Report the subscription, resource group, VNet, runner subnet, runner identity, configured role IDs, install inputs, and custom-stack outputs throughstack_phone_home. Keep the payload keys emitted by the published module even if a fork
changes the underlying Azure resources; ctl-api and app templates treat those keys as the stable contract.
Azure custom stacks use an Azure Deployment Stack backed by the uploaded linked ARM template. Preserve its
actionOnUnmanage and delete query parameters unless intentionally changing whether removed resources are deleted or
detached. See Custom Install Stacks for the cross-cloud custom-stack contract.
What you can customize freely
- VPC / VNet / VPC layout, CIDRs, subnet count and sizes — as long as the runner subnet has working egress to the Nuon API.
- NAT vs public-subnet egress.
-
Instance type / machine type and image — anything that supports cloud-init and can run the
runnerbinary works (AL2023, Ubuntu LTS, Amazon Linux 2, Debian, COS). - Tags / labels, KMS keys, access logging, flow logs, private service endpoints, peering, transit gateways, DNS zones.
-
Wrapping the published registry module from a parent Terraform configuration instead of forking:
The module reads the rest of its configuration from the control plane via the
stack_configdata source, so you pass only the install ID and supported overrides. Use each module’s README for its current source, version, required cloud provider configuration, and supported overrides.