After an Import
After cdkd import, compare the adopted state with your template and then
deploy. The rest of this page covers what the import recorded and the cases
where that needs your attention.
cdkd diff MyStack # what the next deploy will change
cdkd deploy MyStack
cdkd drift MyStack # later: has anything changed outside cdkd?
To start an import, see Importing Existing Resources.
Check the first diff
cdkd diff MyStack shows two kinds of rows after an import:
- A property that differs between AWS and your template shows as a change.
The next
cdkd deployapplies it. - A resource you did not import shows as
to create.
Read the diff before you deploy. An import changes nothing in AWS, but the first deploy after it does.
A region that uses cdkd-owned asset storage
In a region opted into cdkd-owned asset storage with cdkd bootstrap, cdkd
publishes assets such as Lambda code and container images to its own storage
(cdkd-assets-*), and rewrites the template's asset references to match. The
resources you adopt still point at the CDK bootstrap storage
(cdk-<qualifier>-assets-*).
cdkd records in state the values the resources hold today, and prints an info line with the count. Two things follow:
- The first
cdkd diffshows a change for every asset reference: LambdaCode, container image URIs, and the IAM grants CDK generates on the asset bucket. - The first
cdkd deployrepoints the resources at cdkd's storage. Do not skip it. Until it runs, an IAM policy that grants read on the asset bucket still names the CDK bootstrap bucket, while the custom resource thats3deploy.BucketDeploymentgenerates reads from the cdkd bucket and fails withAccessDenied.
To keep using the CDK bootstrap storage, with no change after the import, pass
--use-cdk-bootstrap-assets or set context.cdkd.useCdkBootstrapAssets in
cdk.json.
A stack with a failed deploy still to roll back
A failed cdkd deploy leaves a rollback journal: a file in the state bucket
that lists what the deploy did, so that cdkd rollback can undo it. If you
import into a stack that still has one, a later rollback must not undo a
resource you have since adopted.
The import therefore marks each resource it adopts on the journal before it
writes state. A later cdkd rollback then skips the journal's existing
entries for those logical IDs. It warns when an entry recorded a different
resource under the same logical ID. Entries that a later deploy adds are still
rolled back as usual.
If the import cannot read or write the journal, it refuses and writes no
state. See cdkd rollback.
An older cdkd binary that does not write these marks leaves the journal
untouched, so a rollback would still act on the adopted resources. Run the
import again with a current binary and --force before you roll back.
The drift baseline an import records
For each resource it adopts, cdkd reads the resource's current properties from
AWS and stores a copy in state. This copy is the drift baseline:
cdkd drift compares it with AWS later to find changes made outside cdkd. In
state.json it is the observedProperties field.
Because the baseline is a copy of what AWS holds, it can contain a secret. cdkd keeps secrets out of it where it can, as the next section describes, and skips the baseline altogether where it cannot do that safely.
Warning
Treat an imported
state.jsonas sensitive. cdkd puts a secret reference back by matching positions between your template and what AWS returned. Where the two cannot be matched, a decrypted value can remain in the record.
Secret references are stored as references
Suppose your template sets a property to {{resolve:secretsmanager:...}}.
AWS returns that property decrypted. cdkd finds the same position in what AWS
returned and writes the reference there, so the baseline holds the reference
and not the secret.
Where cdkd cannot match the position, it writes the mask *** there instead.
A masked position affects cdkd drift in two ways:
- While the mask is the only difference,
cdkd driftreports the position as not compared and exits2. - If anything else at that position changed,
cdkd driftreports drift, and--acceptrefuses it.
A deploy that changes nothing can clear a mask, when the resource's own secret
references are enough to confirm the value. cdkd drift lists
the property shapes that end up masked.
Resources that get no baseline
cdkd records no baseline for a resource when it cannot place the secret
references safely. Storing what AWS returned would risk storing a decrypted
secret. The import says so at --verbose, and cdkd state show prints an
ObservedBaseline: REFUSED line for the resource.
For such a resource:
cdkd driftcompares AWS against the properties recorded from your template instead. That can report drift that is not real.cdkd drift --acceptand--revertdecline the resource.- The decision is stored on the resource (
observedBaselineRefused), and every command that would otherwise record a baseline respects it: the refresh at the start of a deploy,cdkd state refresh-observed,cdkd drift --acceptand--revert, and a later import that leaves the resource in place. - When an import that lists other resources leaves this one in place, it also removes a baseline an earlier run recorded for it.
There are two causes, and the stored decision names which one applies.
incomplete-resolution
The recorded properties no longer spell the template's dynamic reference, or
resolution discarded part of the template (such as the untaken branch of an
Fn::If an import cannot bind).
This clears when a deploy creates, updates or replaces the resource, because
cdkd then rebuilds the record from your template and records a real baseline.
Importing the resource again clears it too. A deploy that does not change the
resource does not clear it, and neither does cdkd state refresh-observed.
unverifiable-parameter
The resource depends on a template parameter, and cdkd cannot prove that the
deployed value equals the parameter's Default. The next section explains the
situation and how it clears.
Parameters deployed with a non-default value
cdkd import takes no parameter values, so it records every template
parameter at its Default. A CloudFormation stack may have been deployed with
a different value. If cdkd then stored what AWS returned as the baseline, it
could store the real value of a parameter that was meant to stay secret.
So, when a CloudFormation stack backs the import, cdkd reads that stack's
deployed parameter values with DescribeStacks and compares them with the
defaults. The backing stack is the --migrate-from-cloudformation source and
each of its nested stacks. On any other import it is a CloudFormation stack
with the cdkd stack's name. cdkd only compares the deployed values. It never
records or logs them.
cdkd cannot confirm a parameter when:
- the deployed value differs from the
Default; - the value was deployed as a
{{resolve:...}}reference over a placeholderDefault; - the parameter is
NoEcho, because CloudFormation returns****for it.
These resources then get no baseline:
- every resource whose properties depend on such a parameter, through
Ref,Fn::Subor a condition; - every resource that reads an attribute of one of those with
Fn::GetAtt; - any resource cdkd cannot check for the dependence.
cdkd warns once per stack and names the parameters.
Important
For such a resource, state holds the template
Defaultand not the value that was deployed. A deploy that rewrites the property sends thatDefaultto AWS. Before you deploy, put the real value in the template: replace the parameter with the{{resolve:...}}reference, or make the value the parameter'sDefault. Then reviewcdkd diff.
How this clears
Deploying a change to the resource does not clear it. cdkd deploy binds the
same Default, and an update that leaves the parameter-bound property alone
does not rewrite it in AWS. A baseline recorded afterwards would hold the
deployed value, so an in-place update keeps the resource without a baseline.
There are two ways out:
- A deploy replaces the resource, or deletes and creates it again. The new resource is built from the properties cdkd sent, so it gets a normal baseline.
- A later
cdkd importadopts the resource again while a CloudFormation stack can prove the parameter was deployed at itsDefault. After--migrate-from-cloudformationthat stack is gone, so importing the same physical id again keeps the resource without a baseline.
Editing the template so that nothing references the parameter does not help. An import clears this only by proving the parameter's value.
Edge cases
- No
cloudformation:DescribeStackspermission. The import still succeeds. It warns and treats every parameter as unconfirmed. - Nothing references a declared parameter. cdkd makes no
DescribeStackscall. CDK's ownBootstrapVersionparameter is referenced only byRules, so it does not count. - No CloudFormation stack of that name. There is nothing to compare, and the import behaves as it would without this check.
Stacks imported with cdkd 0.290.35
cdkd 0.290.35 stored the "no baseline" decision without its cause, and cdkd
0.290.35 and 0.290.36 both remove a decision that has no cause. If a stack
imported with 0.290.35 has since had one of these resources updated by either
version, the deployed parameter value may be in state.json. Rotate the
secret, then follow
Import internals.
A secret set outside your template
cdkd can keep a secret out of the baseline only where your template spells a
{{resolve:...}} reference for it. A secret with no reference in the template
is recorded exactly as AWS returned it.
A value your template never references
lists the ways that happens and why cdkd does not prevent it.
Two details add to that summary:
- Inside a property that does carry a reference, AWS can return a field or
list element the template does not have. cdkd records it as returned. Where
that leaves a reference in the property unmatched, the position may be
masked as
***instead. - CloudFormation behaves the same way for a property the template sets. Its
drift detection reports the actual value (
ActualPropertiesinDescribeStackResourceDrifts), leaving out only a value the service never returns. cdkd's baseline also holds the properties the template never sets, and it is stored instate.json.
Remove a secret that reached state
-
Rotate the secret through a reference
Store the new value in Secrets Manager, write
{{resolve:secretsmanager:...}}at that property in the template, and deploy. The deploy sends the new value to AWS, and the next baseline records the reference. Confirm with:cdkd scrub MyStack --dry-run --failDo not rotate in the console. That sets another value outside the template, which cdkd records the next time it reads the resource.
-
If the template has no property to put a reference on
This is the case for a field AWS added, or for a property of a Cloud Control resource that the template never sets. No cdkd command removes such a value in place. Rotate the secret at its source first, then remove the value as described under Where the value sits.
Check any stack output that publishes the value as well. An output is stored in the stack's
outputs, and an exported output is also stored in the region's exports index, the file cdkd uses to resolve cross-stack references. -
Delete the earlier versions of the state file, last
cdkd scrub MyStack --purge-historyThe state bucket is versioned, so earlier copies of
state.jsonstill hold the old value. This command deletes the earlier versions of everystate.jsonit examines, including one it does not rewrite. It does not delete the exports index's earlier versions unless the same run rewrote that index.cdkd scrubdescribes what the purge does not reach.
Where the value sits
For a value the template has no property for, the removal depends on where it is in the record.
| Where | How to remove it |
|---|---|
| A nested field or list element inside a property | Remove it from the AWS resource, then run cdkd state refresh-observed MyStack or cdkd drift MyStack --accept. |
| A top-level key | Remove it from the AWS resource, or delete that key from the record's observedProperties in state.json by hand. |
A Cloud Control resource's attributes |
Also delete the key from attributes by hand. Neither command rewrites attributes. |
Two rules for editing state.json by hand:
- Do not delete a nested field from
observedProperties.cdkd driftcompares nested fields against what AWS returns, so every later run would report the field and print the value. - For a top-level key, delete only that key. If you delete the whole
observedPropertiesobject, anycdkd deployfills it again from AWS.
A hand edit lasts only while AWS no longer holds the value. cdkd records it
again the next time it reads the resource: on a deploy that updates the
resource, on cdkd state refresh-observed, or on cdkd drift --accept. An
edit to attributes lasts until the next deploy that updates the resource,
which writes every property back.
Related
- Importing Existing Resources: the walkthroughs
cdkd drift: how the baseline is comparedcdkd scrub: finding and removing secrets in state- State Management: who can read the state bucket
- Import internals: older baseline decisions and re-importing a Cloud Control resource