aws-samples / aws-samples/sample-agentic-runtime-security-on-aws-with-vault
At an event, the three tier-2 licensing secrets never reach the CloudFormation stack
- Dominant language
- Shell
- Stars
- 0
- Forks
- 0
- Avg merge
- 8m
- Merged PRs (30d)
- 5
Description
At an event, the organizer is meant to supply three licensing secrets once when the Workshop Studio event is created — the Vault Enterprise license, the IBM Container Registry entitlement key, and the IBM Verify MMFA push secret — so that every attendee account gets a fully deployed Tier 2 without any attendee ever holding a licensed credential. That is the entire premise of #21.
Workshop Studio presents no input field for any of the three. They reach the stack as empty strings, and the stack fails at create with `secretString must have length >= 1` on the three `AWS::SecretsManager::Secret` resources. No account gets provisioned — not even Tier 1.
### Why it passed every test we ran
The CloudFormation template is not the broken part. The only thing that ever fed it parameters was `workshop/cfn-wrapper/sim-workshop-studio.sh`, which reads the `.hclic` off local disk and calls `aws cloudformation deploy --parameter-overrides` straight at the template. Workshop Studio is not in that path. The sim proved the template, the buildspec, the Secrets Manager wiring, the CMK deny and both tiers — while silently supplying the one value Workshop Studio was supposed to supply. `TEMP-test-tier2-preprovision.md` Part 0 flags exactly this as `VERIFY-ON-REAL-WS`; this issue is that verification coming back negative.
### The claim in the repo that is wrong
`workshop/contentspec.yaml` states that the three parameters are settable at event creation "the same place `AcmeEmail` is set today, which is the precedent that NoEcho parameters are settable here." That is false. `AcmeEmail` has `Default: ""` in `workshop/static/cfn/bootstrap.yaml`, so it satisfied the content validator on its default — there is no evidence it was ever surfaced at event creation either. The PR #23 description repeated the claim.
### What the validator actually said
Building the content with the three parameters as `NoEcho` + `MinLength: 1` + no default fails with:
```
INFRASTRUCTURE_VALIDATION_ERROR: parameter does not have default value in CFN or ContentSpec and is not user overridable
```
That names the validator's own rule: a parameter needs **either** a default **or** to be marked user-overridable. Our contentspec never set the overridable flag, which is why it demanded defaults.
`userOverridable` is a real contentspec field — [aws-samples/sample-oneCx](https://github.com/aws-samples/sample-oneCx/blob/main/contentspec.yaml) sets `userOverridable: false` on its `{{.AssetsBucketName}}` parameters. What is **not** established is that `userOverridable: true` renders an input field at event creation: no public contentspec sets it to `true`, and the error string only proves the validator will accept such a parameter, not who supplies its value or in which UI. It may equally be an API or Catalog Builder path, or only present in the full published-event flow rather than the Test-event quick-create.
### The alternative: deliver them through the assets bucket
Workshop Studio already fills `TerraformSourceBucket` = `{{.AssetsBucketName}}` and `AssetsKeyPrefix` = `{{.AssetsBucketPrefix}}`, and CodeBuild sources `buildspec/` + `terraform/` from there as `Source.Type=S3`. If the three values sat in that same bucket, the buildspec would read them at the top of `pre_build` exactly like it reads everything else, and no parameter would need a UI at all. These three credentials are identical for every event — they were never genuinely per-event values.
Note that the proven S3 path carries code, never credentials: `workshop/scripts/package-assets.sh` (lines 57-140) hard-aborts if any tfvars, tfstate, `.acme-state`, private key or keystore reaches the assets tree, and the sim passes the secrets as CFN parameters rather than through the bucket.
Two unknowns block this path, both for the Workshop Studio side to answer:
1. Can a maintainer place an object in the real `{{.AssetsBucketName}}` under the workshop prefix that is **not** in the public GitHub repo? The bucket is populated from the repo at publish time, and these three can never be committed.
2. Can a participant in a provisioned account read objects under that prefix? If yes, this path is dead — the whole point of pre-provisioning Tier 2 is that a Vault Enterprise license and an IBM entitlement key are never readable from an attendee account.
If (1) is no, the variant is a maintainer-owned bucket read cross-account by the attendee's CodeBuild role — which needs the vended account IDs in a bucket policy ahead of time, so it depends on whether Workshop Studio has a supported shape for it.
### The fix under test
Branch `fix/24-ws-secret-parameters`:
- `workshop/contentspec.yaml` — `userOverridable: true` on `AcmeEmail` and the three secrets; `userOverridable: false` on `TerraformSourceBucket` and `AssetsKeyPrefix`.
- `workshop/static/cfn/bootstrap.yaml` — `MinLength: 1` restored on the three secrets, no `Default: ""`. `AcmeEmail` keeps its `Default: ""` and acts as a control: if it gets a field and the other three do not, the missing default is the cause rather than the flag.
Adding `Default: ""` to the three secrets is explicitly **not** the fix. Today an empty value fails loudly at Secrets Manager. With a default in place, one `Condition` added later turns that same state into a silently skipped Tier 2 — an account that looks fully provisioned with no Vault in it.
## How to test
Requires Workshop Studio access; this cannot be tested from the dev-account sim, which bypasses Workshop Studio entirely.
1. Build the workshop content from `fix/24-ws-secret-parameters`.
Expected: the content build passes validation. A failure here means `userOverridable: true` is not accepted without a default, and the error text settles it.
2. Create an event from that build and look at the parameter inputs.
Expected: input fields for `AcmeEmail`, `IcrEntitlementKey`, `VaultEnterpriseLicense` and `IviaMmfaPushClientSecret`. No field for `TerraformSourceBucket` or `AssetsKeyPrefix` — those are Workshop Studio's to fill.
Record which flow was used: Test-event quick-create or the full published-event creation. If prompts exist only in the full flow, a Test event coming up empty is not a verdict on the mechanism.
Negative test: `AcmeEmail` is the control. If it gets a field and the other three do not, the cause is the absent default, not `userOverridable`.
3. Enter the three values and provision an account. In the CodeBuild log for `/aws/codebuild/workshop-tier1`, find:
```
Vault Enterprise license materialized (N bytes)
```
Expected: `N` equals the real byte count of the `.hclic` (`wc -c` on the file). A smaller `N` means the event-creation UI collapsed the multi-line license into one line — the parameter arrived, but mangled. This reads as a pass at the stack level and still fails Vault activation, so check the number rather than the stack status.
4. Let the build run to completion.
Expected: the log reaches `Gate: Tier-2 exit contract (Vault issuer_id = https://wrp.….nip.io)`, then `Vault license file removed from the build container.`, and the stack lands `CREATE_COMPLETE`. The bar is Vault activating, not the stack creating.
5. Confirm the attendee still cannot read the secrets.
As `WSParticipantRole`, `aws secretsmanager get-secret-value --secret-id -vault-enterprise-license`.
Expected: `AccessDeniedException` from the KMS deny on `BuildSecretsKey` — not the secret value, and not a "secret not found".
Contributor guide
Research direction
Start with the fix/24-ws-secret-parameters branch, then inspect workshop/contentspec.yaml and workshop/static/cfn/bootstrap.yaml before building the workshop content. Test event creation in Workshop Studio, verify the three parameter inputs and the listed CodeBuild log milestones, then confirm CREATE_COMPLETE and AccessDeniedException for the attendee role.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, shell, terraform
- Domain
- cloud, devops, infrastructure, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 38/100