SaveMyCert
Log in
5 of 5 free questions left today·for unlimited practice
Security Foundations and Governance

Secure IaC Deployment: CloudFormation, StackSets, and Service Catalog

15 min readSCS-C03 · Security Foundations and GovernanceUpdated

Task 6.2 is about making every deployment secure and identical — the same reviewed template, the same guardrails, in every account, every time. Infrastructure as code is the mechanism: CloudFormation templates become versioned, peer-reviewed security artifacts, validated before deployment with CloudFormation Guard and cfn-lint, protected in production by stack policies and <code>DeletionPolicy</code>, and pushed organization-wide with StackSets so every current and future account receives the same security baseline automatically. Around that core, this lesson covers the supporting cast the exam guide names: dynamic references that keep secrets out of templates, Service Catalog launch roles that let teams deploy approved stacks without holding the underlying permissions, AWS RAM for sharing resources across accounts, Firewall Manager for centrally enforced network policies, tag policies for deploy-time organization, and least-privilege CI/CD pipelines with OIDC federation instead of long-term keys. You finish by troubleshooting the three failures examiners reuse: broken StackSet execution roles, drift on security stacks, and deploy roles blocked by SCPs.

What you’ll learn
  • Treat CloudFormation templates as security artifacts: version-controlled, peer-reviewed, drift-detected, and protected by stack policies and DeletionPolicy attributes.
  • Deploy a security baseline to every current and future account with service-managed StackSets and automatic deployment.
  • Validate templates before deployment with CloudFormation Guard and cfn-lint, and keep secrets out of templates using dynamic references to Secrets Manager and Parameter Store.
  • Use Service Catalog launch constraints, AWS RAM, and Firewall Manager to share and enforce approved resources and policies across accounts.
  • Design least-privilege deployment pipelines: scoped service roles, per-environment cross-account deploy roles, OIDC federation, and change-set approval gates.
  • Diagnose the classic failures: StackSet instances failing in member accounts, drift on security stacks, and deployments denied by SCPs.

IaC as the security baseline: templates are security artifacts

Consistency is a security property. A control that exists in most accounts is a finding waiting to happen in the rest, and hand-built infrastructure guarantees inconsistency. Infrastructure as code fixes this at the root: when every resource comes from a CloudFormation template, the template — not the console — is where security is defined, reviewed, and versioned. A template in a Git repository gets the same treatment as application code: pull-request review by security engineers, a full change history showing who changed which security group and when, and rollback to a known-good configuration. The exam expects you to frame IaC this way — templates as reviewed, versioned security artifacts, not merely automation.

The counterpart to declared state is detecting departure from it. Drift detection compares a stack's actual resource configuration against its template and reports resources as IN_SYNC, MODIFIED, or DELETED. Drift on an ordinary stack is a hygiene problem; drift on a security stack — an IAM role's trust policy widened, a security group rule added out-of-band — is a potential incident. Drift detection tells you what changed, not who: for attribution you pivot to CloudTrail, which records the API call, the principal, and the source IP behind the modification.

Note the boundary: CloudFormation drift and template review govern deployment consistency. Continuously evaluating whether deployed resources comply with rules is AWS Config's job, which belongs to Task 6.3. And where accounts, OUs, and SCPs come from is Task 6.1 — this lesson assumes that structure exists and deploys into it.

Protecting security resources: stack policies, DeletionPolicy, and service roles

Once a security stack is deployed, CloudFormation gives you three distinct protections, and the exam tests whether you know which does what.

A stack policy is a JSON document attached to a stack that controls which resources can be modified during stack updates. The pattern: deny Update:* on critical logical resources — the CloudTrail trail, the central logging bucket, the audit IAM roles — so a routine template update cannot accidentally replace or delete them. Updating a protected resource requires an explicit, temporary policy override, which turns a silent mistake into a deliberate act.

The DeletionPolicy attribute works per resource: Retain keeps the resource when its stack is deleted, and Snapshot (for supported types) captures a final snapshot first. Security-relevant stores — log buckets, KMS keys, audit tables — should carry DeletionPolicy: Retain so evidence survives a stack deletion; the companion UpdateReplacePolicy gives the same protection when an update forces resource replacement. Stack-level termination protection additionally blocks whole-stack deletion.

A service role answers the question of who deploys what. Instead of CloudFormation acting with the caller's credentials, it assumes a dedicated IAM role scoped to exactly the resource types a template legitimately creates. The deploying human or pipeline then needs only CloudFormation permissions plus iam:PassRole for that specific role — they never hold the underlying resource permissions themselves. That separation is the load-bearing idea of this whole task, and it returns in Service Catalog launch roles and pipeline design below.

StackSets: the security baseline in every account, automatically

CloudFormation StackSets deploy one template as stack instances across many accounts and Regions from a single administration point — the mechanism behind the exam's favorite requirement: every account gets the same security stack. The baseline StackSet typically carries the resources Task 6.1 decided every account needs: GuardDuty detector configuration, the AWS Config recorder and delivery channel, standard IAM roles for security tooling, and log-forwarding plumbing.

The two permission models are a guaranteed exam discriminator:

  • Self-managed permissions — you create the roles yourself: an administration role in the admin account and an execution role (by default named AWSCloudFormationStackSetExecutionRole) in every target account, trusting the administration role. Flexible, works outside an organization, but every missing or mangled execution role is a failed deployment.
  • Service-managed permissions — StackSets integrates with AWS Organizations through trusted access and creates the necessary roles itself. You target OUs rather than account lists, and — the key feature — automatic deployment: when a new account joins a targeted OU, the stack instance deploys to it automatically, and when an account leaves, its instances can be removed.

When a scenario says "deploy the security baseline to every current and future account," the answer is service-managed StackSets with automatic deployment enabled — no distractor involving scripts, manual enrollment, or self-managed roles matches "future accounts." StackSets also supports a delegated administrator account, keeping baseline operations out of the management account, consistent with Task 6.1 discipline. Deployment order, failure tolerance, and Region concurrency are operational preferences; the security substance is the permission model and auto-deployment.

Shift-left validation: cfn-lint, CloudFormation Guard, and change sets

A misconfiguration caught before deployment costs a failed pipeline stage; caught after, it costs an incident. Task 6.2 names the pre-deployment toolchain explicitly.

cfn-lint validates templates against the CloudFormation resource specification plus best-practice rules — malformed properties, invalid values, structural mistakes. It is correctness linting, not policy. CloudFormation Guard (cfn-guard) is the policy-as-code layer: you write rules in a declarative DSL asserting what templates must and must not contain — every S3 bucket encrypted, no security group open to 0.0.0.0/0 on port 22, all IAM policies free of "Action": "*" — and evaluate templates against those rules in the pipeline, failing the build on violation. Guard rules are how a security team's requirements become machine-enforceable instead of living in a wiki. The same rule language backs proactive evaluation hooks, which is why Control Tower's proactive controls feel familiar here. For CDK shops, cdk-nag plays the equivalent role, applying rule packs to synthesized output; remember that CDK apps ultimately synthesize to CloudFormation templates, so every template-level control in this lesson still applies downstream.

The last gate is human: a change set previews exactly what a stack update will do — which resources are added, modified with or without replacement, or deleted — before anything executes. Requiring a reviewed change set for production stacks turns "deploy and hope" into an explicit approval step, and it pairs naturally with the pipeline approval actions covered later. Order matters and is testable: lint and Guard run in CI on every commit; change-set review guards the production apply.

Secrets in templates: NoEcho is masking, dynamic references are the answer

The classic Task 6.2 scenario: a security review finds a database password visible in a CloudFormation template or in the stack's parameter history. The exam wants you to rank the mitigations correctly.

Plaintext secrets in templates are always wrong. Templates live in Git, flow through pipelines, and are readable via cloudformation:GetTemplate — a secret in a template is a secret published to everyone with repository or stack read access, preserved forever in version history.

The NoEcho parameter attribute is the half-measure candidates are tempted by: it masks the parameter's value (as asterisks) in console and describe-API output. It does not encrypt anything, does not remove the value from what was submitted, and does nothing if a default value sits in the template itself. Treat NoEcho as display hygiene, never as secrets management.

The correct pattern is a dynamic reference: the template stores a pointer, and CloudFormation resolves the value at deployment time from the secret store. {{resolve:secretsmanager:MySecret:SecretString:password}} pulls from AWS Secrets Manager — the right home for credentials because it adds automatic rotation; {{resolve:ssm-secure:ParameterName}} pulls a SecureString from Systems Manager Parameter Store for supported resource properties. The secret never appears in the template, the repository, or the stack's stored parameters, and access to it is separately governed by IAM and the secret's resource policy. Even better, resources like AWS::RDS::DBInstance can reference a Secrets Manager-managed master password so no human ever supplies one. Trigger phrasing to recognize: "secret visible in template" → dynamic references, with rotation favoring Secrets Manager over Parameter Store.

Service Catalog, AWS RAM, and Firewall Manager: sharing and central enforcement

AWS Service Catalog packages approved CloudFormation templates as products in portfolios, giving teams a golden path: they launch vetted, pre-hardened stacks instead of authoring their own. The security win is the launch constraint: a product launches under a designated launch role that holds the permissions to create the underlying resources, while the end user needs only Service Catalog permissions. Users launch what they could never build by hand — provisioning without permission sprawl, the same separation as a CloudFormation service role but productized for self-service. Template constraints go further, restricting which parameter values a user may choose (instance types, CIDR ranges). Portfolios are shared across the organization via Organizations integration, so one security-owned catalog serves every account; Control Tower's Account Factory itself is built on Service Catalog, and Terraform-based products are supported for shops standardized on third-party IaC.

AWS RAM (Resource Access Manager) solves a different sharing problem: not templates, but live resources. RAM shares resources such as VPC subnets, Transit Gateways, and Route 53 Resolver rules with specific accounts or entire OUs — so a network account can own the inspected, centrally managed VPC fabric while workload accounts deploy into shared subnets they cannot alter. Sharing beats duplicating and beats loosening resource policies.

AWS Firewall Manager is central enforcement for network protections: from a delegated administrator account, it deploys and continuously maintains AWS WAF rules, security group policies, Shield Advanced protections, and Network Firewall deployments across all accounts — automatically covering new accounts and new resources, and remediating drift from the policy. When the requirement is "WAF on every ALB in every account, including future ones," Firewall Manager is the answer, not a StackSet.

Choosing the mechanism — and tagging at deploy time

Four services in this lesson all "deploy things to many accounts." The exam separates them by what is standardized and who initiates:

MechanismWhat it standardizesInitiated byNew accountsClassic trigger
StackSets (service-managed)A stack deployed into every target accountCentral admin, pushed to OUsAuto-deployment on OU join"Same security stack in every current and future account"
Service CatalogApproved products teams launch on demandEnd user, self-servicePortfolio shared org-wide"Teams launch approved stacks without the underlying permissions"
Control Tower Account FactoryThe account itself, vended pre-governedCentral admin or delegated requesterBaseline applied at creation"Standardized, compliant new accounts"
Firewall ManagerNetwork protections (WAF, SGs, Shield, Network Firewall)Central admin policy, continuously enforcedCovered automatically"Apply and maintain WAF rules across all accounts"

Tagging is the other consistency requirement the guide names: tags group resources by department, cost center, and environment, and they drive attribute-based access control and cost allocation — so untagged resources are a governance failure, not a cosmetic one. Enforce at two layers. Tag policies (an Organizations management policy) standardize tag keys and permitted values, report noncompliance, and can optionally prevent noncompliant tagging operations on supported resource types. Baking required tags into StackSet templates and Service Catalog products makes correct tagging the default; a detective required-tags AWS Config rule then catches stragglers — evaluation of which is Task 6.3's business.

Least-privilege pipelines and a troubleshooting walkthrough

The pipeline that deploys infrastructure is itself infrastructure to secure. The pattern: the CI/CD system holds almost nothing, and assumes a scoped deploy role per environment — a cross-account role in each target account (dev, staging, prod), each trusting only the pipeline's principal and each scoped to the resource types its templates create. Production adds a manual approval gate reviewing the change set before execute. External CI systems authenticate via OIDC federation — the provider's identity is trusted to assume a role directly, so no long-term access keys sit in pipeline configuration (the federation mechanics live in Domain 4). Artifact integrity closes the loop at concept level: the template that was reviewed and scanned must be the template that deploys, so artifacts flow through access-controlled stores and pipeline stages consume them immutably rather than re-fetching from a mutable branch.

Walkthrough. Your organization's baseline StackSet reports FAILED for one member account. First diagnosis: the permission model. Under self-managed permissions, the usual cause is the AWSCloudFormationStackSetExecutionRole missing from that account or its trust policy not naming the administration account — recreate the role and retry the stack instance. Second: the account's OU carries an SCP denying an action the execution role needs — the role's identity policy allows it, but the SCP caps it; check the deny in CloudTrail's errorCode and fix the guardrail exemption or the template. Third case: drift detection later shows the account's Config recorder MODIFIED. Drift names the change; CloudTrail names the actor — query for the modifying API call, identify the principal, then re-apply the template and close the gap (an SCP denying recorder modification, per Task 6.1) so the out-of-band path is shut, not just repaired.

Tip. Task 6.2 scenarios hinge on matching the requirement's phrasing to the mechanism. "Deploy the security baseline to every current and future account" → service-managed StackSets with automatic deployment; "let teams launch approved stacks without holding the underlying permissions" → a Service Catalog launch constraint with a launch role; "secret visible in the template" → dynamic references to Secrets Manager or SSM SecureString, never NoEcho. Expect one troubleshooting item — a StackSet failing in a single account almost always means a missing or untrusted execution role, or an SCP capping it — and one validation item where CloudFormation Guard rules in the pipeline beat any after-the-fact detection.

Key takeaways
  • IaC makes security consistent: templates are versioned, peer-reviewed security artifacts, and drift detection flags out-of-band changes — with CloudTrail supplying who made them.
  • Protect deployed security resources in layers: stack policies block risky updates, DeletionPolicy: Retain preserves log buckets and keys through stack deletion, and service roles scope who can deploy what.
  • "Every current and future account" → service-managed StackSets with automatic deployment targeting OUs; self-managed StackSets need an execution role hand-built in every target account.
  • Shift validation left: cfn-lint for template correctness, CloudFormation Guard rules for policy-as-code, cdk-nag for CDK, and reviewed change sets as the production approval gate.
  • Never put secrets in templates — NoEcho only masks display; the answer is dynamic references that resolve from Secrets Manager (with rotation) or SSM SecureString parameters at deploy time.
  • Service Catalog launch constraints let users launch approved products under a launch role without holding the underlying permissions; AWS RAM shares live resources like subnets across accounts; Firewall Manager centrally enforces WAF, security group, Shield, and Network Firewall policies.
  • Enforce tags at deploy time with tag policies and tagged baseline templates, backed by a detective required-tags Config rule.
  • Pipelines get least privilege: per-environment cross-account deploy roles, OIDC federation instead of stored keys, and approval gates on production change sets.

Frequently asked questions

What is the difference between CloudFormation StackSets and AWS Service Catalog?

They standardize different things in different directions. StackSets push one template from a central administrator into many accounts and Regions — the mechanism for a mandatory security baseline, especially with service-managed permissions and automatic deployment covering future accounts. Service Catalog is pull, not push: it publishes approved templates as products that end users launch on demand, under a launch role, without holding the underlying resource permissions. Baseline everyone must have → StackSets; golden path teams choose from → Service Catalog.

How do you keep secrets out of CloudFormation templates?

Use dynamic references so the template stores a pointer instead of a value: {{resolve:secretsmanager:...}} pulls from AWS Secrets Manager at deployment time, and {{resolve:ssm-secure:...}} pulls a SecureString from Systems Manager Parameter Store for supported properties. Prefer Secrets Manager for credentials because it adds automatic rotation, and let resources like RDS manage their master password directly in Secrets Manager. The NoEcho parameter attribute is not a substitute — it only masks the value in console and API output and encrypts nothing.

What is CloudFormation drift detection and what does it not tell you?

Drift detection compares a stack's deployed resources against the template that created them and marks each resource IN_SYNC, MODIFIED, or DELETED — surfacing out-of-band changes made outside CloudFormation, which on a security stack may indicate tampering. What it does not tell you is who made the change or when: for attribution you query CloudTrail for the modifying API call and its principal. The durable fix is preventive — re-apply the template, then close the out-of-band path, for example with an SCP denying direct modification of the resource.

What is the difference between cfn-lint and CloudFormation Guard?

cfn-lint checks that a template is well-formed: it validates against the CloudFormation resource specification and best-practice rules, catching invalid properties and structural errors. CloudFormation Guard checks that a template is compliant with your policy: you author rules in its DSL — every bucket encrypted, no wide-open security groups — and evaluate templates against them in CI, failing the build on violations. Run both before deployment: lint answers "is this valid CloudFormation?", Guard answers "is this allowed here?". For CDK projects, cdk-nag applies equivalent rule packs to the synthesized templates.

Why would a StackSet deployment fail in only one member account?

The usual causes are permissions in the target account. Under self-managed permissions, the AWSCloudFormationStackSetExecutionRole is missing, misnamed, or its trust policy does not trust the administration account — StackSets cannot assume it, and that stack instance fails. Under either model, an SCP on the account's OU can deny an action the execution role needs, capping its permissions regardless of its identity policy; CloudTrail's access-denied events reveal the blocked call. Fix the role or the guardrail, then retry the failed stack instances.

How does a Service Catalog launch constraint improve security?

A launch constraint attaches a launch role to a product; when a user provisions the product, Service Catalog assumes that role to create the resources. The user therefore needs only Service Catalog permissions — not EC2, IAM, or any underlying service permissions — so teams can self-serve approved, security-hardened stacks without those permissions existing in their identity policies to be misused elsewhere. Template constraints tighten it further by restricting which parameter values users may choose at launch.

Test yourself on this topic
Practice questions with full explanations.
Practice now

Sign up free to mark lessons complete, bookmark topics and track your exam readiness.