Provision AWS Resources with CDK
Deploy and audit AWS resource tags with Python, CDK, and CloudFormation.
Introduction
30 Second Summary
A one-off setup script can behave perfectly on its first run. The same script can fail as soon as it meets resources it already created.
In this project, you will replace the manual Part 3 fixture lifecycle with a Python AWS CDK app. The app turns the same two AWS Systems Manager Parameter Store fixtures into an AWS CloudFormation workflow you can review before deployment.
What You'll Build
You can demo one Python tag change moving from a reviewed infrastructure plan to a validator report with fewer issues.
By the end of this project, you'll have:
- A repeatable infrastructure as code workflow that synthesizes both fixture paths into a template before deployment.
- A change-review loop that shows exact resource additions or tag modifications before deployment.
- An end-to-end audit where the unchanged Boto3 validator shows one passing parameter beside one deliberate failure. After your update, the same audit shows one fewer issue.
- Secret Mission: Remediate the remaining Environment and CostCenter violations so both CDK-managed parameters pass the production tag policy.
Are there any prerequisites?
You need the completed Part 3 workspace inside Windows Subsystem for Linux 2 with Ubuntu 24.04 LTS plus its temporary-credential login flow. Your AWS account and Region must already be bootstrapped unless an administrator-approved identity can run the one-time bootstrap.
Before We Start
Before the hands-on work begins, lock in the boundary of this project. You will replace the imperative fixture lifecycle in fixtures.py with AWS CDK while preserving the existing AWS inventory adapter, validator, reporter, JSON Lines audit workflow, and JSON summary workflow from Part 3.
Set Up the AWS CDK Toolchain
Part 3's fixtures.py creates named test parameters through direct AWS API calls. A second create run exposes the script's lack of desired-state reconciliation.
That failure gives you a concrete requirement for the new provisioning workflow. You will also prepare the pinned Python and Node.js tools that support it.
In this step, get ready to:
- Reproduce the duplicate fixture creation failure.
- Install the pinned infrastructure toolchain.
- Verify the Python dependencies and bootstrap readiness.
Reproduce the duplicate-create failure
Temporary AWS credentials expire by design. A fresh session ensures every command uses your administrator-approved identity.
- Switch back to the WSL 2 shell for your existing ~/cloud-tag-validator workspace.
- Reactivate the existing .venv through the activation workflow from Part 3.
- Refresh your temporary AWS credentials through the approved Part 3 login flow if your session has expired.
- Confirm the active AWS identity by running this command:
aws sts get-caller-identity
What does this command confirm?
The identity check shows which authenticated AWS identity your shell currently uses. This prevents the fixture experiment from running in an unintended account.
Identity check unsuccessful?
Refresh the temporary credential session from Part 3. Run the identity check again after the approved login flow completes.
Ask for help with your session if the identity still cannot be confirmed. Help me troubleshoot my temporary AWS credential session.
The experiment needs an empty Parameter Store baseline. This ensures the first create run succeeds before the second run exposes the limitation.
- Remove any existing Part 3 fixture parameters by running:
python fixtures.py delete
What does this command do?
The fixtures.py delete workflow removes both named test parameters. This gives the duplicate-create experiment a known starting state.
- Wait at least 30 seconds before reusing the parameter names.
- Create both fixtures by running:
python fixtures.py create
What does the first create run prove?
The first run issues create calls for the compliant parameter and the non-compliant parameter. Both calls succeed because the names are available.
You should see both Part 3 fixtures created successfully.
- Predict whether the second create run can reconcile parameters that already exist.
- Run the same create command a second time:
python fixtures.py create
Why does the second run fail?
The second run reaches the handled AWS ParameterAlreadyExists failure. The script issues another create request for each fixed parameter name.
This failure is intentional. You have now reproduced the lifecycle gap that the infrastructure workflow needs to solve.
Why AWS CDK for this workflow?
AWS CDK lets you keep using Python while declaring the infrastructure you want. It synthesizes that declaration into an AWS CloudFormation template.
CloudFormation provides a stack boundary for reviewing changes. It also manages updates and teardown through the declared state.
- Remove the experiment's parameters by running:
python fixtures.py delete
What does the final cleanup do?
The final delete run removes the fixtures created by the experiment. The parameter names must be available before the CDK-managed stack uses them later.
- Wait at least 30 seconds before continuing.
You found the exact limitation this project addresses. The two test parameter names are now ready for a managed stack.
Pin Node.js and install AWS CDK
Node.js runs the AWS CDK command-line toolkit. The .nvmrc file gives this workspace a repeatable Node.js version.
- Create infrastructure/.nvmrc through the same file-editing workflow you used in Part 3.
- Set the file's contents by copying this value:
24.21.0
What does this file control?
The .nvmrc file pins Node.js to 24.21.0 for this workspace. The version manager reads this value when you run the installation command.
- Save infrastructure/.nvmrc.
- Confirm the file tree shows infrastructure/.nvmrc with 24.21.0 as its only value.
- Check whether nvm is available and print its installed version by running:
command -v nvm
nvm --version
What do these checks show?
The first check confirms that the nvm shell function is available. The second check prints the installed nvm version.
✔️ I see nvm 0.40.7
Your Ubuntu shell already has the pinned nvm version. Continue with the Node.js installation below.
ⓧ I see an older nvm version
Your existing nvm installation needs the project's pinned release. The official installer updates it to 0.40.7.
- Install the pinned nvm release by running:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.7/install.sh | bash
What does this installer do?
The command downloads the nvm 0.40.7 installation script from its official repository. The script installs the pinned release for your Ubuntu shell.
- Close the current WSL shell after the installer finishes.
- Press the Windows key to open Windows search.
- Type Ubuntu into Windows search.
- Press Enter to reopen the WSL shell.
- Return to the existing ~/cloud-tag-validator workspace through the navigation workflow from Part 3.
- Reactivate the existing .venv.
- Verify the updated nvm installation by running:
command -v nvm
nvm --version
What should you see?
The checks should confirm that nvm is available. The version output should show 0.40.7.
ⓧ nvm is unavailable
A blank availability result means nvm is not loaded in this Ubuntu shell. Install the pinned release before continuing.
- Install nvm 0.40.7 by running:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.7/install.sh | bash
What does this installer do?
The command downloads the pinned installation script from the official nvm repository. The script adds nvm to your Ubuntu shell environment.
- Close the current WSL shell after the installer finishes.
- Press the Windows key to open Windows search.
- Type Ubuntu into Windows search.
- Press Enter to reopen the WSL shell.
- Return to the existing ~/cloud-tag-validator workspace through the navigation workflow from Part 3.
- Reactivate the existing .venv.
- Verify the nvm installation by running:
command -v nvm
nvm --version
What should you see?
The checks should confirm that nvm is available. The version output should show 0.40.7.
Still cannot load nvm?
Confirm that you reopened the WSL shell after installation. The new shell loads the profile changes made by the installer.
Ask for environment-specific help if the check remains blank. Help me load nvm in Ubuntu on WSL 2.
- Switch the WSL shell to the infrastructure directory inside ~/cloud-tag-validator.
The first Node.js download can take a few minutes. A quiet progress pause is expected.
- Install the version pinned in .nvmrc by running:
nvm install
What does this command do?
nvm reads 24.21.0 from .nvmrc. It installs that Node.js release for the current workspace.
- Verify the active Node.js release by running:
node --version
What should you see?
The version output should show v24.21.0. This confirms that the workspace is using the pinned Node.js release.
- Install the pinned AWS CDK toolkit by running:
npm install -g aws-cdk@2.1141.0
What does this install provide?
The global package provides the cdk command used to synthesize and manage CDK stacks. Pinning 2.1141.0 keeps the toolkit consistent throughout the project.
- Verify the AWS CDK toolkit by running:
cdk --version
What should you see?
The version line should contain 2.1141.0. The CDK command-line toolkit is now available in this WSL shell.
AWS CDK install unsuccessful?
Confirm that the current shell uses the Node.js release installed through nvm. A separate system Node.js installation can send global packages to a protected directory.
Ask for help if the install still fails. Help me troubleshoot the pinned AWS CDK installation.
Install the Python CDK packages
The CDK command-line toolkit runs the workflow. The Python packages provide the APIs your application imports when it defines a stack.
- Create infrastructure/requirements-cdk.txt through the same file-editing workflow you used in Part 3.
- Set the file's contents by copying these dependency pins:
aws-cdk-lib==2.269.0
constructs==10.8.1
What do these packages provide?
The aws-cdk-lib package provides the AWS CDK APIs used by the Python application. The constructs package provides the base construct model used by CDK apps and stacks.
- Save infrastructure/requirements-cdk.txt.
- Confirm the file tree shows both dependency pins inside infrastructure/requirements-cdk.txt.
✔️ Awesome, I've got everything!
Great. Double-check that both pin files are saved before installing the Python packages.
ⓧ I'd like to double check the full code
Check infrastructure/.nvmrc
24.21.0
What should this file contain?
The complete file contains only the pinned Node.js version. Keep the value exactly as shown.
Check infrastructure/requirements-cdk.txt
aws-cdk-lib==2.269.0
constructs==10.8.1
What should this file contain?
The complete file pins both Python packages used by the CDK application. These versions are compatible with Python 3.12.
- Switch the WSL shell back to the ~/cloud-tag-validator workspace.
- Install the pinned Python dependencies by running:
python -m pip install -r infrastructure/requirements-cdk.txt
What does this command install?
Python reads the pinned versions from infrastructure/requirements-cdk.txt. The packages are installed into the active Part 3 virtual environment.
Python dependency install unsuccessful?
Confirm that the existing .venv is active before rerunning the installation. The package versions require a supported Python release.
Ask for help if the dependency resolver still cannot install the pins. Help me troubleshoot the Python CDK package installation.
Confirm bootstrap readiness
A later CDK workflow may need a one-time bootstrap for the selected AWS account and Region. That action requires an administrator-approved identity because it creates reusable deployment resources.
An environment that is already bootstrapped also satisfies this requirement. Confirm one approved path before proceeding.
- Confirm your approved bootstrap path with the administrator responsible for the selected AWS account and Region.
- Predict which three confirmations the final toolchain check should print.
- Verify Node.js, AWS CDK, and the Python imports by running:
node --version
cdk --version
python -c "import aws_cdk; import constructs; print('CDK Python imports ready')"
What should you see?
The first line should show v24.21.0. The second version line should contain 2.1141.0.
The final line should show CDK Python imports ready. That message proves both Python packages can be imported from the active virtual environment.
That's the toolchain ready. Your workspace now has repeatable Node.js and Python dependency pins for the CDK application.
Your pinned AWS CDK toolchain is ready. Next, you will model both Part 3 fixtures as one reviewable stack.
Model the Parameter Fixtures
You reproduced the duplicate-create failure from Part 3. The old fixture script cannot reconcile parameter names that already exist.
A Python AWS CDK app captures both fixtures as desired state. AWS CloudFormation can turn that model into a reviewable template.
In this step, get ready to:
- Configure the CDK CLI to run the Python app.
- Declare the compliant fixture plus the deliberately non-compliant fixture.
- Apply the shared project tag before synthesizing both resources.
Configure the CDK app entry point
The cdk.json file tells the CDK CLI how to run this app. The app.py file creates the construct tree that synthesis reads.
- Select the infrastructure folder in your Part 3 editor.
- Create cdk.json inside the infrastructure folder using your editor's file controls.
- Add the CDK app command by copying this configuration into cdk.json:
{
"app": "python3 app.py"
}
What does this configuration do?
This JSON file points the CDK CLI at the Python entry file. Keeping it inside infrastructure lets the CLI find the app command from that directory.
- Save cdk.json.
- Confirm cdk.json appears beside .nvmrc in the infrastructure folder.
Configuration file not appearing?
- Check that the filename is exactly cdk.json.
- Check that your editor created the file inside ~/cloud-tag-validator/infrastructure.
Help me check my CDK configuration file.
- Create app.py inside the infrastructure folder using your editor's file controls.
- Add the app entry point by copying this code into app.py:
import aws_cdk as cdk
from cloud_tag_validator_stack import CloudTagValidatorStack
app = cdk.App()
CloudTagValidatorStack(app, "CloudTagValidatorStack")
app.synth()
What does this code do?
- The import gives the app access to the CDK library plus your stack class.
- The app variable holds the root of the construct tree.
- The stack instance groups the fixture resources under CloudTagValidatorStack.
- The app.synth() call produces the cloud assembly used during synthesis.
- Save app.py.
- Confirm app.py appears beside cdk.json in the infrastructure folder.
Entry file saved elsewhere?
- Check that app.py is inside ~/cloud-tag-validator/infrastructure.
- Check that your editor did not add another file extension to the filename.
Help me check my CDK app entry file.
Declare the two parameter fixtures
Each L1 construct maps directly to an AWS::SSM::Parameter entry in the synthesized template. The first fixture carries the complete production tag set.
- Create cloud_tag_validator_stack.py inside the infrastructure folder using your editor's file controls.
- Define the stack plus its compliant fixture by copying this code into cloud_tag_validator_stack.py:
import aws_cdk as cdk
from aws_cdk import aws_ssm as ssm
from constructs import Construct
class CloudTagValidatorStack(cdk.Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
ssm.CfnParameter(
self,
"CompliantParameter",
name="/nextwork/tag-validator/compliant",
description="NextWork cloud tag validator fixture",
type="String",
value="demo",
tier="Standard",
tags={
"Environment": "prod",
"Owner": "platform-team",
"CostCenter": "CC-100",
},
)
How does the compliant fixture work?
- The imports provide the CDK stack class plus the low-level Parameter Store construct.
- The CloudTagValidatorStack class creates one CloudFormation stack boundary.
- The CompliantParameter construct declares the same compliant path used in Part 3.
- The tag mapping satisfies the production policy before the resource is created.
- Save cloud_tag_validator_stack.py.
- Return to the infrastructure directory in your terminal.
- Generate an intermediate template by running this command:
cdk synth CloudTagValidatorStack --json > synthesized-template.json
What does this command do?
The synthesis command runs the app without deploying resources. The output redirection saves the generated stack template in synthesized-template.json.
- Confirm synthesized-template.json now appears inside the infrastructure folder.
Synthesis stopped before creating the template?
- Check that your terminal is currently inside ~/cloud-tag-validator/infrastructure.
- Check the indentation inside CloudTagValidatorStack.__init__().
- Check that the stack import in app.py matches the filename exactly.
Help me debug my first CDK synthesis.
The first successful synthesis proves that your Python model can produce a CloudFormation template. The next construct adds the policy failure that your existing validator expects.
- Place your cursor on the blank line after the compliant parameter's closing ) in cloud_tag_validator_stack.py.
- Add the deliberately non-compliant fixture by copying this code:
ssm.CfnParameter(
self,
"NoncompliantParameter",
name="/nextwork/tag-validator/noncompliant",
description="NextWork cloud tag validator fixture",
type="String",
value="demo",
tier="Standard",
tags={
"Environment": "production",
},
)
Why model a failing fixture?
The NoncompliantParameter construct keeps the deliberate Part 3 policy violations. Its environment value is invalid for production.
The missing owner plus cost center tags give the unchanged validator known issues to detect after deployment.
- Save cloud_tag_validator_stack.py.
- Regenerate the intermediate template by running this command:
cdk synth CloudTagValidatorStack --json > synthesized-template.json
What changed during synthesis?
The command reruns the complete construct tree. The redirected output replaces the earlier template with a model containing both fixtures.
- Return to synthesized-template.json in your editor.
- Search the file for AWS::SSM::Parameter.
You should now find two resource entries. This proves that both fixture constructs participate in synthesis.
Only seeing one parameter resource?
- Check that the non-compliant construct is inside CloudTagValidatorStack.__init__().
- Check that the non-compliant construct appears after the compliant construct's closing ).
- Run the synthesis command again after saving the stack file.
Help me find why only one parameter is synthesized.
Apply the shared project tag
A stack-scoped tag keeps the shared discovery value in one place. The resource-type filter limits that tag rule to the two Parameter Store resources.
- Place your cursor after the non-compliant parameter's closing ) in cloud_tag_validator_stack.py.
- Apply Project=nextwork-tag-validator at stack scope by copying this code:
cdk.Tags.of(self).add(
"Project",
"nextwork-tag-validator",
include_resource_types=[ssm.CfnParameter.CFN_RESOURCE_TYPE_NAME],
)
How does the shared tag work?
- The cdk.Tags.of(self) expression targets resources within this stack.
- The add() call applies the shared discovery key plus its value.
- The resource-type filter keeps the rule focused on AWS::SSM::Parameter resources.
- Save cloud_tag_validator_stack.py.
Before you synthesize the complete stack, ask yourself how many Parameter Store resources you expect in the template.
- Generate the final template for this step by running this command:
cdk synth CloudTagValidatorStack --json > synthesized-template.json
What does the final synthesis prove?
The CDK CLI executes app.py before synthesizing CloudTagValidatorStack. A successful result proves that the app configuration plus both constructs form one valid model.
- Return to synthesized-template.json in your editor.
- Search the generated file for AWS::SSM::Parameter.
You should see two resource entries in the generated template. That is the declared fixture model working as one repeatable stack.
Final synthesis failing?
- Check that the shared tag block remains inside CloudTagValidatorStack.__init__().
- Check that include_resource_types uses ssm.CfnParameter.CFN_RESOURCE_TYPE_NAME.
- Check that every opening parenthesis has a matching closing parenthesis.
Help me debug my completed CDK stack.
✔️ Awesome, I've got everything!
Your CDK configuration plus Python source files are saved. Your synthesized template now contains both parameter fixtures.
ⓧ I'd like to double check the full code
- Compare each saved file with the references below.
The existing infrastructure/.nvmrc file remains unchanged.
24.21.0
What should match?
This file keeps the infrastructure workspace pinned to the existing Node.js version.
Your infrastructure/app.py file should match this entry point.
import aws_cdk as cdk
from cloud_tag_validator_stack import CloudTagValidatorStack
app = cdk.App()
CloudTagValidatorStack(app, "CloudTagValidatorStack")
app.synth()
What should the app contain?
This file creates one app plus one stack before triggering synthesis.
Your infrastructure/cdk.json file should match this configuration.
{
"app": "python3 app.py"
}
What should the configuration contain?
This file gives the CDK CLI the exact command for running the Python app.
Your infrastructure/cloud_tag_validator_stack.py file should match this complete stack.
import aws_cdk as cdk
from aws_cdk import aws_ssm as ssm
from constructs import Construct
class CloudTagValidatorStack(cdk.Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
ssm.CfnParameter(
self,
"CompliantParameter",
name="/nextwork/tag-validator/compliant",
description="NextWork cloud tag validator fixture",
type="String",
value="demo",
tier="Standard",
tags={
"Environment": "prod",
"Owner": "platform-team",
"CostCenter": "CC-100",
},
)
ssm.CfnParameter(
self,
"NoncompliantParameter",
name="/nextwork/tag-validator/noncompliant",
description="NextWork cloud tag validator fixture",
type="String",
value="demo",
tier="Standard",
tags={
"Environment": "production",
},
)
cdk.Tags.of(self).add(
"Project",
"nextwork-tag-validator",
include_resource_types=[ssm.CfnParameter.CFN_RESOURCE_TYPE_NAME],
)
What should the stack contain?
This file contains both parameter constructs plus the stack-scoped project tag.
The existing infrastructure/requirements-cdk.txt file remains unchanged.
aws-cdk-lib==2.269.0
constructs==10.8.1
What should the dependency file contain?
This file preserves the two Python package pins installed during setup.
Your fixtures now live in a repeatable infrastructure model. Next up, you will inspect the generated CloudFormation template before anything reaches AWS.
Review the CloudFormation Plan
Your Python AWS CDK app now synthesizes both Parameter Store fixtures into one CloudFormation template. The next job is to verify exactly what that template contains.
Reviewing the generated model makes infrastructure as code safer. A CDK diff then reveals the planned account changes before deployment.
In this step, get ready to:
- Inspect the generated CloudFormation resources.
- Bootstrap the selected AWS environment.
- Preview the planned account changes.
Inspect the synthesized template
The JSON template is the contract CloudFormation receives. Formatting it exposes the resource properties that CDK generated from your Python constructs.
- Format synthesized-template.json in the terminal from earlier by running this command:
python -m json.tool synthesized-template.json
What does this command do?
The json.tool module parses the synthesized JSON. Its indented output makes nested resource properties easier to inspect.
The command reads the existing template without changing your CDK source files or AWS resources.
- Find the Resources section in the formatted output.
- Locate /nextwork/tag-validator/compliant in the resource properties.
- Locate /nextwork/tag-validator/noncompliant in the resource properties.
- Confirm each resource entry has a Type of AWS::SSM::Parameter.
- Confirm each parameter property has a Type of String.
- Confirm each parameter has a Tier of Standard.
- Confirm both resources include Project=nextwork-tag-validator.
- Compare the Tags arrays to find the intentional policy difference.
You will see the compliant resource with Environment=prod, Owner=platform-team, and CostCenter=CC-100.
The non-compliant resource contains Environment=production without the required owner or cost center tags.
Cannot format the template?
- Check that your terminal is in ~/cloud-tag-validator/infrastructure.
- Confirm synthesized-template.json still exists in that directory.
Ask for help with the template inspection issue.
That inspection is complete. Your generated template contains the two intended fixtures with their deliberate policy difference.
Establish the deployment foundation
CDK deployments depend on reusable staging resources plus deployment roles in the target account. The CDKToolkit stack provides that foundation.
This is an account-level change, so using your administrator-approved identity matters. Your approved access keeps the bootstrap within the selected environment.
- Prepare the selected account and Region from ~/cloud-tag-validator/infrastructure by running this command:
cdk bootstrap
What does this command do?
The command prepares the selected account and Region for CDK deployments. It creates or updates the CDKToolkit stack.
The stack contains staging resources plus deployment roles. Later CDK commands use this shared foundation to deploy through CloudFormation.
- Wait for the bootstrap command to finish.
- Confirm the terminal reports a successful bootstrap for the selected environment.
- Confirm the result identifies the CDKToolkit stack as successful.
Bootstrap access denied?
- Stop the bootstrap attempt.
- Switch to an administrator-approved bootstrap role.
- Avoid granting permanent administrator permissions to the IAM user.
Ask for help checking the bootstrap identity and selected environment.
You have cleared the account-level prerequisite. The selected environment is ready to accept CDK deployments.
Preview the account changes
A diff compares your local stack template with the deployed CloudFormation state. This review gate shows the exact scope of the proposed change.
Before you run the review, do you expect the empty account to need additions, modifications, or removals?
- Generate the template-based infrastructure preview by running this command:
cdk diff CloudTagValidatorStack --method=template
How do I read the diff?
- The --method=template option compares the local template with the deployed CloudFormation template.
- The [+] marker identifies a resource addition.
- The [-] marker identifies a resource removal.
- The [~] marker identifies a resource modification.
You will see exactly two [+] additions. Both additions use AWS::SSM::Parameter.
- Confirm the diff lists exactly two [+] additions.
- Trace the first addition back to CompliantParameter in cloud_tag_validator_stack.py.
- Trace the second addition back to NoncompliantParameter in cloud_tag_validator_stack.py.
- Confirm no CI/CD resources appear in the diff.
- Confirm no monitoring resources appear in the diff.
- Confirm no compute resources appear in the diff.
Diff not showing two additions?
- Confirm both fixture parameters remain absent from the selected account and Region.
- Check that the terminal still uses the temporary AWS session from earlier.
- Compare cloud_tag_validator_stack.py with the two constructs you synthesized earlier.
Ask for help interpreting an unexpected CDK diff.
That review gate is complete. Your plan adds only the two intended parameters, so the next step can deploy them with a clear account-level change.
Deploy and Audit the Stack
Your reviewed AWS CDK diff shows exactly two AWS Systems Manager Parameter Store resources. Now the plan has to become live infrastructure that your existing validator can inspect.
A synthesized template only proves local intent. Deploying it through AWS CloudFormation turns that intent into managed resources. The unchanged Boto3 validator then proves that your infrastructure-as-code workflow connects to the existing audit path.
In this step, get ready to:
- Deploy the reviewed stack through CloudFormation.
- Audit both Parameter Store resources with the unchanged Part 3 validator.
- Generate fresh JSON Lines evidence plus a JSON summary.
Deploy the stack with CloudFormation
This deployment creates two Standard parameters in the selected account and Region. The project usage is expected to add no charge.
Before you deploy, do you expect CloudFormation to create only the two resources shown in your reviewed diff?
- Deploy CloudTagValidatorStack from the infrastructure directory by running this command:
cdk deploy CloudTagValidatorStack
What does this deployment do?
- The cdk deploy command deploys the selected stack through a CloudFormation change set.
- CloudFormation takes ownership of creating both parameters from the declared stack state.
- The parameter names remain /nextwork/tag-validator/compliant and /nextwork/tag-validator/noncompliant.
The deployment may take a few minutes while CloudFormation creates the stack. You should see the deployment complete for CloudTagValidatorStack.
Deployment blocked?
An expired temporary AWS session can stop the deployment. A missing deployment permission can also block CloudFormation.
- Refresh your temporary credentials through the approved Part 3 login flow.
- Recheck the active AWS identity with the identity command from earlier.
- Use an administrator-approved deployment identity if CloudFormation reports a permissions problem.
Help me troubleshoot my CDK deployment.
Audit the deployed parameters
The deployed resources use the same paths that the Part 3 inventory adapter already discovers. Keeping aws_inventory.py, validator.py, and reporter.py unchanged tests the connection between managed infrastructure and your existing policy engine.
- Return to the ~/cloud-tag-validator workspace in the terminal from earlier.
- Confirm that the existing .venv remains active.
- Use the same shell method from Part 3 to set VALIDATOR_ENV=prod.
- Remove any existing output/aws-cdk-validator.log so this run produces current evidence.
Before you run the audit, which parameter do you expect to pass the production policy?
- Run the unchanged AWS validator against the deployed resources by running this command:
python main.py validate --source aws --log output/aws-cdk-validator.log
What does this audit prove?
- The AWS inventory source discovers both parameters through their shared project tag.
- The validator applies the existing production policy without any inventory or policy changes.
- The reporter appends the audit event to output/aws-cdk-validator.log as JSON Lines evidence.
You should see two paginator page messages. The validator reports one compliant resource plus one non-compliant resource.
The failing resource has one INVALID_VALUE issue. It also has two MISSING_TAG issues.
Seeing empty or stale results?
Parameter Store tag discovery can lag behind a completed stack deployment. The inventory may briefly show missing resources or older tag data.
- Wait for a short period.
- Rerun the validator command above.
- Keep the validator modules unchanged while the AWS inventory catches up.
Help me troubleshoot stale Parameter Store tag results.
Summarize the audit evidence
The JSON Lines log preserves the individual audit event. The analyzer turns that evidence into a compact report that makes the policy issue totals easy to compare.
- Regenerate output/aws-cdk-summary.json from the current audit log by running this command:
python main.py analyze --log output/aws-cdk-validator.log --report output/aws-cdk-summary.json
What does this command do?
The analyzer reads the dedicated Part 4 JSON Lines log. It writes the aggregated event counts and issue totals to output/aws-cdk-summary.json.
Before you inspect the summary, which issue counts do you expect from the deliberate policy failure?
- Format the generated summary for inspection by running this command:
python -m json.tool output/aws-cdk-summary.json
What should I see?
- The summary contains one audit event.
- The summary contains two checked resources.
- The INVALID_VALUE count is 1.
- The MISSING_TAG count is 2.
That is the full infrastructure-to-audit loop working with real AWS resources. Next, you will update one missing tag in Python and watch CloudFormation reconcile the deployed parameter.
Update the Desired State
Your AWS CDK stack is live under AWS CloudFormation control. The unchanged validator has exposed the deliberate policy gap in the non-compliant parameter.
A declared desired state lets CloudFormation reconcile an existing resource with your code. Adding one missing tag in Python now shows that reconciliation without another parameter creation.
In this step, get ready to:
- Add the missing Owner tag to the non-compliant parameter.
- Preview the tag modification before deploying it.
- Regenerate the audit evidence after the stack update.
Add the Owner tag
The Owner tag is one of two missing policy fields on the non-compliant parameter. Adding it narrows the missing-tag count without completing the remediation.
The Environment value stays deliberately invalid. The CostCenter tag stays absent.
- In infrastructure/cloud_tag_validator_stack.py, locate the NoncompliantParameter construct.
- Find its tags mapping containing "Environment": "production",.
- Add the Owner entry so the mapping matches this reference:
tags={
"Environment": "production",
"Owner": "platform-team",
},
What Does This Change Do?
- The Owner entry adds one required production-policy tag to the existing non-compliant parameter.
- The Environment entry keeps its deliberate invalid value of production.
- The absent CostCenter entry preserves one missing-tag issue for the final challenge.
- Save infrastructure/cloud_tag_validator_stack.py.
✔️ Awesome, I've got everything!
Your non-compliant parameter now declares an owner while preserving the two deliberate policy problems.
ⓧ I'd like to double check the full code
import aws_cdk as cdk
from aws_cdk import aws_ssm as ssm
from constructs import Construct
class CloudTagValidatorStack(cdk.Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
ssm.CfnParameter(
self,
"CompliantParameter",
name="/nextwork/tag-validator/compliant",
description="NextWork cloud tag validator fixture",
type="String",
value="demo",
tier="Standard",
tags={
"Environment": "prod",
"Owner": "platform-team",
"CostCenter": "CC-100",
},
)
ssm.CfnParameter(
self,
"NoncompliantParameter",
name="/nextwork/tag-validator/noncompliant",
description="NextWork cloud tag validator fixture",
type="String",
value="demo",
tier="Standard",
tags={
"Environment": "production",
"Owner": "platform-team",
},
)
cdk.Tags.of(self).add(
"Project",
"nextwork-tag-validator",
include_resource_types=[ssm.CfnParameter.CFN_RESOURCE_TYPE_NAME],
)
What Should You Compare?
Compare the NoncompliantParameter mapping with your file. Its only new line is the Owner entry.
Preview and deploy the tag update
An infrastructure diff compares your local desired state with the deployed stack. This review reveals whether CloudFormation plans an update or a replacement.
- Return to the infrastructure directory inside ~/cloud-tag-validator in your existing terminal.
Before you run the preview, do you expect AWS CDK to add another parameter or modify the existing one?
- Preview the deployed stack delta by running this command:
cdk diff CloudTagValidatorStack --method=template
What Should the Diff Show?
The cdk diff command compares the local template with the deployed CloudFormation template. You should see one modification to the non-compliant AWS::SSM::Parameter resource.
A [~] marker identifies the modification. The diff should show the new Owner tag without showing a second parameter addition.
Diff Missing the Owner Change?
Confirm that you saved infrastructure/cloud_tag_validator_stack.py. Check that the new entry sits inside the NoncompliantParameter tag mapping.
If the diff cannot access AWS, refresh the temporary session through the established Part 3 login flow. Help me diagnose my CDK diff
The preview proves that CloudFormation recognizes the deployed parameter as the resource to update. The parameter name remains unchanged.
- Apply the reviewed tag update by running this command:
cdk deploy CloudTagValidatorStack
How Does the Update Converge?
The cdk deploy command sends the revised template to CloudFormation. Updating the parameter's Tags property does not require resource interruption.
CloudFormation updates the existing parameter until its tags match your Python declaration. That convergence is the core desired-state behavior.
That update is the key proof. CloudFormation changed the existing parameter without creating a duplicate.
Deployment Update Not Completing?
Confirm that the active AWS session targets the same account and Region used for the original deployment. Refresh the established temporary credentials if the session has expired.
Review the stack event details for the resource that stopped the update. Help me troubleshoot my CDK deployment
Regenerate the audit evidence
The existing validator now tests the deployed state after reconciliation. Fresh evidence keeps this update separate from the audit captured before deployment.
- Return to ~/cloud-tag-validator in your existing terminal.
- Delete output/aws-cdk-validator.log and output/aws-cdk-summary.json through your editor's file browser.
Before you rerun the validator, do you expect the missing-tag count to change while the invalid-value count stays the same?
- Run the unchanged AWS validation workflow by running this command:
python main.py validate --source aws --log output/aws-cdk-validator.log
What Does This Validation Prove?
The existing inventory adapter discovers the two deployed parameters. The validator evaluates their current tags without any changes to its inventory or policy logic.
The command writes a fresh JSON Lines event to output/aws-cdk-validator.log. This evidence links the infrastructure update to the policy result.
You should still see one compliant resource and one non-compliant resource. The findings now contain one INVALID_VALUE issue and one MISSING_TAG issue.
Still Seeing Two Missing Tags?
Parameter tag discovery can briefly return the previous state after a successful stack update. Wait for the updated tags to propagate before rerunning the validation command.
Confirm that the deployed account and Region match the active validator session. Help me investigate stale parameter tags
Before you generate the summary, do you expect its issue counts to match the fresh validator event?
- Regenerate the Part 4 summary by running this command:
python main.py analyze --log output/aws-cdk-validator.log --report output/aws-cdk-summary.json
How Is the Summary Refreshed?
The analyzer reads the new JSON Lines event from output/aws-cdk-validator.log. It writes the aggregated findings to output/aws-cdk-summary.json.
- Format the refreshed summary for inspection by running this command:
python -m json.tool output/aws-cdk-summary.json
What Should the Summary Confirm?
The formatted report should describe one audit event covering two resources. Its issue counts should show one INVALID_VALUE finding and one MISSING_TAG finding.
Strong finish. Your desired-state update removed one policy issue while preserving the deliberate failure for the final remediation challenge.
Secret mission
Remediate the Final Tag Violations
One CDK-managed parameter still breaks two production tag rules. Correct both properties in the desired state, review the in-place update, then produce final audit evidence showing two compliant resources.
Clean Up Your Resources
Clean Up Your Resources
This project's two Standard AWS Systems Manager Parameter Store parameters have no additional charge. Choose whether to keep everything, remove the cloud fixtures while preserving your local evidence, or delete the Part 4 files too.
Cost warning
Native AWS CloudFormation operations add no charge.
The reusable CDKToolkit stack can incur storage charges if later AWS CDK projects upload assets.
- Keep CDKToolkit when other CDK applications depend on it.
- Ask an administrator to remove it only after confirming that no other CDK application uses the selected account and Region.
Resources you used:
- CloudTagValidatorStack, containing the two Standard Parameter Store parameters.
- CDKToolkit, if this project created the bootstrap stack for the selected account and Region.
- ~/cloud-tag-validator/infrastructure, including synthesized-template.json and cdk.out.
- ~/cloud-tag-validator/output/aws-cdk-validator.log and ~/cloud-tag-validator/output/aws-cdk-summary.json, containing the final Part 4 audit evidence.
Keep everything running
No action is needed. Choose this option if you want to demonstrate the deployed fixtures or rerun the validator.
- Leave CloudTagValidatorStack deployed with both compliant parameters.
- Keep ~/cloud-tag-validator/infrastructure for future stack updates.
- Keep the final audit evidence in ~/cloud-tag-validator/output.
- Retain CDKToolkit for later CDK projects that use the same account and Region.
Pause - I'll come back to this later
Remove the deployed fixtures while keeping your local CDK source and audit evidence. The stack can be rebuilt from the same desired-state code when you return.
- Return to ~/cloud-tag-validator/infrastructure in your WSL terminal.
- Remove the project stack by running this command:
cdk destroy CloudTagValidatorStack --force
What does this command do?
- The --force flag skips the confirmation prompt.
- CloudFormation removes both parameters because the stack has no retention policy for them.
- Verify that both parameter names are absent by running this command:
aws ssm get-parameters --names "/nextwork/tag-validator/compliant" "/nextwork/tag-validator/noncompliant"
What should I see?
- Parameters is empty.
- InvalidParameters lists /nextwork/tag-validator/compliant and /nextwork/tag-validator/noncompliant.
That closes the cloud teardown loop. Both CDK-managed fixtures are absent while your reusable project files remain available.
Stack still present?
- Refresh the existing temporary AWS session if the credentials have expired.
- Confirm that the active session targets the same account and Region used for deployment.
- Wait for the stack deletion to finish before checking the parameter names.
Help me troubleshoot the cloud cleanup.
- Keep CDKToolkit for the planned CDK follow-on work.
Delete - I don't want to use this again
Remove the project-specific cloud resources and Part 4 files for a fresh start. Deleting the local files is permanent, so preserve any audit evidence you still need first.
- Copy any audit evidence you want to keep outside ~/cloud-tag-validator.
- Return to ~/cloud-tag-validator/infrastructure in your WSL terminal.
- Remove the project stack by running this command:
cdk destroy CloudTagValidatorStack --force
What does this command do?
- The --force flag skips the confirmation prompt.
- CloudFormation deletes the stack with its two managed parameters.
- Verify that both parameter names are absent by running this command:
aws ssm get-parameters --names "/nextwork/tag-validator/compliant" "/nextwork/tag-validator/noncompliant"
What should I see?
- Parameters is empty.
- InvalidParameters lists both project parameter paths.
Cloud resources still present?
- Refresh the existing temporary AWS session if the credentials have expired.
- Confirm that the active session targets the account and Region containing CloudTagValidatorStack.
- Wait for CloudFormation to finish deleting the stack before checking Parameter Store.
Help me troubleshoot the stack deletion.
- Ask an administrator to remove CDKToolkit only if no other CDK application uses the selected account and Region.
- Return to ~/cloud-tag-validator in your WSL terminal.
- Remove the Part 4 local artifacts by running these commands:
rm -rf ~/cloud-tag-validator/infrastructure
rm -f ~/cloud-tag-validator/output/aws-cdk-validator.log ~/cloud-tag-validator/output/aws-cdk-summary.json
What do these commands remove?
- The first command removes the CDK source with synthesized-template.json and cdk.out.
- The second command removes the dedicated Part 4 log and summary files.
- Your existing Part 3 source files remain in ~/cloud-tag-validator.
- Confirm the Part 4 files are gone by running these commands:
ls ~/cloud-tag-validator
ls ~/cloud-tag-validator/output
What should I see?
- The infrastructure directory is absent from the workspace listing.
- aws-cdk-validator.log and aws-cdk-summary.json are absent from the output listing.
- The Part 3 workspace files remain available.
Your cleanup is complete. The CDK-managed fixtures and their Part 4 local artifacts are now removed.
Still see Part 4 files?
- Check that the paths in the removal command begin with ~/cloud-tag-validator.
- Confirm that your WSL user has permission to remove the local files.
Help me troubleshoot the local cleanup.
Nice Work!
Nice Work!
Brilliant work! You replaced the manual fixture lifecycle with a repeatable Python AWS CDK workflow for two policy-tested AWS Systems Manager Parameter Store resources.
You've learned how to:
- Built a Python CDK app that defines both fixtures as infrastructure as code with shared discovery tags plus resource-specific policy tags.
- Used AWS CloudFormation synthesis plus infrastructure diffs to review additions and in-place tag updates before deployment.
- Connected deployed stack changes to the unchanged Boto3 validator. You also destroyed the project stack and verified that both parameter names were absent.
- Secret Mission: Remediated the final tag violations through desired-state code. The existing audit workflow confirmed two compliant resources with no remaining issues.
Ready to quiz yourself?