Skip to content

Cybersecurity Engineering Handbook / Chapter 29

Infrastructure as Code and Configuration Security

Make infrastructure changes reviewable, testable, reproducible, and resistant to drift through policy-as-code, protected state, and evidence capture.

The document renderer accepted in Chapter 28 now needs a place to run. Its infrastructure pull request adds an object store for generated invoices, a worker identity that can write them, an outbound route for the renderer, and a retention rule. The source diff looks modest. The plan is not: it replaces an access policy, opens a network path, and recreates the store because one property cannot change in place.

That plan is where infrastructure security becomes concrete. A repository can describe the intended system, but only the evaluated change reveals which resources will appear, disappear, or gain authority. Secure infrastructure work keeps that chain intact: version the desired state, evaluate the exact plan, refuse clear hazards automatically, give contextual risk to a qualified reviewer, apply with narrow credentials, protect the resulting state, and treat divergence in production as an event that needs an owner.

Infrastructure as code change control loop from pull request to plan, policy-as-code checks, human review, approval, apply, evidence capture, drift detection, and response, with blocked examples for public storage, broad network exposure, privileged role, unencrypted data, and missing logs.
IaC security is a control loop. Plans, policy checks, reviews, apply logs, evidence, and drift detection must point to the same desired state instead of becoming separate rituals.

Put production intent in one reviewable place

The invoice-export environment belongs in version control with its modules, provider constraints, policy rules, and the non-secret inputs that distinguish environments. The repository should be able to account for every production resource class that affects confidentiality, integrity, availability, tenant isolation, recovery, or evidence. A console-only route or an administrator’s private script is not harmless glue; it is desired state that cannot be reviewed or reproduced.

Version control does not make that state safe by itself. Pin module and provider versions so a repeat evaluation does not silently acquire different behavior. Protect the main branch, require review by owners who understand the affected service and control surface, and create the plan from the reviewed revision rather than from a developer’s working tree. The plan, policy result, approval, and apply record must all identify that same revision and environment.

This provenance closes a common gap. If an engineer reviews one plan and automation later recalculates another after the provider, module, variables, or source revision changes, the approval no longer describes the operation. Re-evaluate and require another approval whenever an input that can affect the plan changes.

Let policy refuse the easy mistakes

The proposed object store has a public-access rule left over from a module example. No reviewer should have to notice that accident among hundreds of plan lines. A policy baseline should block it before approval, along with broad administrative ingress, wildcard or account-wide roles, unencrypted durable data, disabled audit logging, absent recovery protection for critical state, untrusted workload images, and privileged containers without an approved need.

Blocking policy is appropriate when the organization can state a reliable invariant: production invoice objects are never public; administrative ports are never reachable from the internet; deployment roles may not grant authority that they do not possess. A failure stops the change and explains the resource, rule, and remediation. An exception is a separate, reviewable object with an owner, reason, scope, compensating controls, and expiry—not a comment that disables the rule indefinitely.

Other findings require context. Replacing a database, changing an encryption key, deleting a route, or widening egress may be necessary, but the plan cannot know whether the migration is safe or the destination is trustworthy. Policy should surface those changes as warnings that demand human judgment. If a warning is repeatedly ignored even though every acceptable case looks the same, either turn the condition into a block or narrow the rule. A permanent wall of warnings trains reviewers to approve noise.

For the renderer change, policy rejects public storage outright. It warns that the new outbound route reaches a binary host and that the store will be replaced. The reviewer can now spend attention on the questions automation cannot settle: whether the destination matches the dependency decision from Chapter 28, whether replacement preserves existing invoices, and whether the rollout can be stopped before data is lost.

Read the plan as a security artifact

A useful review starts with behavior, not line count. Which resources are added, changed in place, replaced, or destroyed? Which trust boundaries move? Does an identity gain permission, a network gain reachability, data change location or encryption, a log source disappear, or a backup become unusable? Follow references through modules until the answer is visible; a friendly module name is not evidence of its effect.

The pull request should make these review questions answerable:

  • What operational purpose does the change serve, who owns it, and which environment, tenants, and data classes can it affect?
  • Which module, provider, policy, and variable versions produced this plan, and does the plan come from the reviewed revision?
  • What will be created, mutated, replaced, or destroyed? Which identity, route, storage policy, encryption setting, log source, backup, or retention rule changes with it?
  • Which findings were blocked, which require judgment, and which exception records remain in force?
  • What signals will show that the apply is healthy, where can it be halted, and is recovery a rollback, a forward fix, a restore, or a staged migration?
  • Which actor will apply it, what exact authority will that actor receive, and what evidence will remain afterward?

The reviewer of the invoice store rejects an in-place production replacement. The team first creates a private encrypted store, copies and verifies retained invoices, switches new writes, observes reads and export failures, and only then removes the old resource. The same desired end state now has a change path that respects the data already in production.

Keep state and deployment authority contained

Infrastructure state is a map of the system. Depending on the provider and resource, it may contain resource identifiers, addresses, relationships, generated credentials, connection material, or values supplied as “sensitive” even when the display redacts them. Treat the state backend as protected production metadata, not as a convenient build artifact.

Use a remote backend with encryption, narrowly scoped access, audit logging, version history, backup, and tested recovery. Separate environments and unrelated blast radii so access to a development state file does not imply access to production, and damage to one stack does not lock every team out of change. Limit routine downloads and local copies. A secret manager reference is preferable to a secret value, but verify provider behavior: some resources still copy supplied or generated secrets into state.

Plans and logs inherit this concern. Redaction in a terminal view does not prove that the underlying state, saved plan, CI artifact, debug log, or error message lacks the value. Test the actual toolchain, restrict retention and access, and remove designs that require secrets to flow through infrastructure variables when the workload can retrieve them at runtime.

The apply identity should be short-lived and bound to one environment and expected resource classes. It should not be able to rewrite its own trust policy, disable the evidence trail, or grant itself broader authority. Separate plan from apply where practical, require approval for production use, and keep human cloud administrators out of the ordinary automation path. A compromised pipeline with an account-wide role turns a source-control failure into control of the estate.

Promote a baseline without cloning environments

Development and production rarely have identical size or availability requirements, but their security invariants should come from the same reviewed modules and policy. Promote module revisions through environments with controlled, reviewable inputs. Copy-pasted stacks drift before anyone calls the difference an exception.

The baseline must reach every layer the team operates. Cloud resources need private access where appropriate, encryption, logging, recovery protection, retention, and ownership. Networks need minimal ingress, controlled administration, reviewed egress, and meaningful segmentation. Compute images need a hardening and patch path; containers need trusted images, non-root execution and read-only filesystems where the workload permits them, bounded resources, and constrained capabilities. Cluster admission and network policy should enforce the workload assumptions. SaaS configuration belongs in the same discipline when it controls administrator access, identity lifecycle, audit export, data sharing, or tenant-wide security settings.

Some settings cannot be expressed through one IaC tool. That does not make them optional. Use provider configuration, image pipelines, admission policy, device or operating-system management, SaaS APIs, and focused configuration tests as appropriate. Record the authoritative source and owner for each surface. A baseline document with no executable check or recurring audit becomes an account of what the organization once hoped was true.

Apply with a credible way forward

Before apply, retain the approved plan and policy result, confirm that the deployment identity and environment are the intended ones, and establish the signals and stop conditions. Apply the approved object rather than recalculating an unreviewed plan. Capture the actor, time, source revision, tool and module versions, affected resources, outcome, and any partial failure.

“Rollback” is often too simple a word for infrastructure. Removing a new firewall rule may be reversible; rotating a key, replacing a database, tightening an identity policy, or migrating encrypted data may not be. State the recovery action before approval. It may be a previous configuration, a forward fix, restored data, temporary dual-running, isolation, or an explicit decision not to proceed once a point of no return is reached.

Break-glass access exists for the moment when the normal path is too slow or unavailable. Give it strong authentication, narrow eligibility, time-limited elevation, prominent logging, and immediate review. An emergency console change must create a reconciliation task. Otherwise “temporary” production state becomes an invisible fork from the repository.

When production disagrees, investigate before reconciling

Two days after the renderer rollout, drift detection reports that its outbound rule now allows every destination. The fastest automated response would be to overwrite production with the repository value. That may be right, but the difference could also be an emergency repair, a partial apply, a changed provider default, a compromised administrator, or evidence that the source itself is stale. Blind reconciliation can erase evidence or undo a change that is keeping the service alive.

First preserve the observed configuration, resource history, actor, time, related ticket, audit events, and the desired revision. Then assess exposure: which destination became reachable, whether credentials or data could have crossed it, whether logging remained intact, and whether tenant or recovery boundaries changed. Isolate or revoke access immediately when continuing exposure is unsafe. Escalate to incident response when the actor or impact is unexplained.

The disposition should make one source of truth whole again. Revert through the reviewed pipeline when production is wrong; import and review the change when an authorized emergency action must remain; repair the module or provider assumption when the code could not produce the intended state. Rotate credentials or rebuild affected resources if the drift may have enabled compromise. Finally reduce the chance of recurrence through policy, permissions, ownership, or a better signal.

Drift tooling proves its value when it shortens the time between divergence and judgment. A dashboard of permanent differences merely documents that the team no longer knows which state to trust.

Close the loop

The invoice-export change is ready only when the reviewed revision produces the retained plan, automatic policy refuses public storage and excessive authority, a qualified reviewer understands the replacement and egress risks, and the apply identity can perform no broader operation than the rollout requires. State and plan artifacts stay inside their protected boundary. The migration has observable stop conditions and a recovery path. After apply, configuration tests and drift detection compare the running store, role, route, logging, and retention behavior with the decision that approved them.

Infrastructure as code is not the act of translating console clicks into files. It is the control loop that keeps intent, evaluated change, production state, and evidence from becoming four different accounts of the system.