feat(aws): optional permissions boundary for workload IAM roles - #376
Merged
Conversation
Add an optional permissionsBoundary field to the AWS AccountConfig. When set to an IAM policy ARN, it is applied as the PermissionsBoundary on every IAM role SC creates for workloads: ECS task/execution roles, Lambda execution roles, the alert Lambda roles, and the ECS init-task (pg-init / mysql-init) execution roles. Empty by default, so existing stacks are unaffected: permissionsBoundaryPtr returns nil for an empty or whitespace ARN, i.e. no boundary is set. This lets an operator cap what a deployed workload role can ever do, independent of the role's own policy. ConvertAuth carries only credential fields when it rebuilds an AccountConfig, so the non-credential boundary is explicitly preserved at the converters that rebuild it (lambda, cloudtrail alerts, pg-init and mysql-init exec tasks); the ecs-fargate path already reads the template's AccountConfig directly. Setting or adding a permissions boundary on an aws.iam.Role is an in-place update (PutRolePermissionsBoundary), not a replacement, so running tasks are not disrupted. Regenerated JSON schemas (field is optional, so it is not marked required). Added unit tests for the YAML round-trip and the nil-when-empty contract. Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
Cre-eD
requested review from
Laboratory,
smecsia and
universe-ops
as code owners
August 10, 2026 08:42
Semgrep Scan ResultsRepository:
Scanned at 2026-08-11 08:52 UTC |
Security Scan ResultsRepository:
Scanned at 2026-08-11 08:53 UTC |
📊 Statement coverageMeasured on the documented included set (see
Baseline: |
The preserve-after-ConvertAuth lines were unconditional, which clobbered an auth-level permissionsBoundary (declared inside the resolved credentials) with the empty template-level sibling, silently no-opping it for the lambda, cloudtrail alert, and pg-init/mysql-init exec roles. Guard each assignment so a template-level value still wins but an auth-level value ConvertAuth already loaded is kept. Consistent behavior regardless of where the field is declared. Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
…vival tests Multi-model review of the change surfaced a consistency bug and a coverage gap (no correctness P0). Address them: - Precedence: the two in-place ConvertAuth sites (ecs_fargate, aws_lambda pulumi layer) had no guard, so a boundary declared at BOTH template and auth level let the auth value overwrite the template one, contradicting the "template wins" the other two constructors enforce. Introduce AccountConfig.KeepBoundary and route all six ConvertAuth-into-workload-role sites through it, so precedence is defined once and ECS is explicit instead of correct-by-accident. - permissionsBoundaryPtr now trims the returned value, not just the emptiness check, so a padded ARN can't reach the API malformed. - Broaden the field doc to list all covered role kinds and warn that one boundary caps every workload role in the stack at once (too-tight = whole-stack outage). - Tests: add boundary-survival coverage (KeepBoundary precedence; in-place ConvertAuth; ToAwsLambdaConfig template-level/auth-level/unset) using a boundary-free credentials blob so the preserve logic is actually load-bearing (verified: deleting a KeepBoundary call fails the test). Assert the exact value in TestPermissionsBoundaryPtr, incl. a trimmed padded-ARN case. Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
Adds a section to the ECS Fargate parent guide covering the optional permissionsBoundary field: which workload roles it caps, the ceiling/intersection semantics, empty-by-default compatibility, the in-place PutRolePermissionsBoundary update, template-vs-auth precedence, and a too-tight-boundary warning. Adds a commented example line to the multi-region parent server.yaml. Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
smecsia
approved these changes
Aug 11, 2026
universe-ops
approved these changes
Aug 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds an optional
permissionsBoundaryfield to the AWSAccountConfig. When set to an IAM policy ARN, SC applies it as the PermissionsBoundary on every IAM role it creates for workloads:ecs_fargate,exec_ecs_task)aws_lambda)alerts/ cloudtrail security alerts)Why
A permissions boundary caps what a deployed workload role can ever do, independent of the role's own policy — useful for operators who provision SC workloads under a least-privilege deploy identity and want a hard ceiling on the roles it can mint.
Backward compatibility
Empty by default.
permissionsBoundaryPtrreturnsnilfor an empty/whitespace ARN, so no boundary is set and existing stacks are byte-for-byte unaffected. The field isomitempty, so it is not added to any schema'srequiredlist.Notes for reviewers
ConvertAuthonly carries credential fields when it rebuilds anAccountConfigfrom a resolved${auth:...}blob, which would drop this non-credential field. It is therefore explicitly preserved at each converter that rebuilds the config (lambda, cloudtrail alerts, pg-init/mysql-init). Theecs-fargatepath reads the template'sAccountConfigdirectly (embedded viaTemplateConfig), so it needs no preserve.permissionsBoundaryonaws.iam.Roleis an in-place update (PutRolePermissionsBoundary), not a replacement — no role churn for existing deployments when a boundary is later added.docs/schemas(only the AWS configs that embedAccountConfig).Tests
pkg/clouds/aws: YAML round-trip ofpermissionsBoundary(+ empty-when-absent).pkg/clouds/pulumi/aws:permissionsBoundaryPtrreturns nil for empty/whitespace, non-nil for an ARN (the backward-compat contract).go vet+ package tests pass (thecmd/scbinary link is unrelated).