@go-to-k/cdkd 0.274.0 → 0.275.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import { $ as WorkGraph, A as slowCcOperationTimeoutMs, At as warnDeprecatedNoPrefixCliFlag, B as applyRoleArnIfSet, Bt as resolveBucketRegion, C as yellow, Ct as resolveAutoAssetStorage, D as ProviderRegistry, Dt as resolveStateBucketWithDefaultAndSource, E as clearOnUpdateRemoval, Et as resolveStateBucketWithDefault, F as refStateLookupFromResource, Ft as uploadCfnTemplate, G as DagBuilder, H as describeTypeWithThrottleRetry, Ht as getAwsClients, I as WAFv2WebACLProvider, It as expectedOwnerParam, J as S3StateBackend, K as TemplateParser, Kt as CdkdError, L as normalizeAwsTagsToCfn, Lt as AssemblyReader, M as isTerminationProtectionPropagationError, Mt as CFN_TEMPLATE_URL_LIMIT, N as IntrinsicFunctionResolver, Nt as MIGRATE_TMP_PREFIX, O as findActionableSilentDrops, Ot as resolveUseCdkBootstrapAssets, P as cfnRefValueFromPhysicalId, Pt as findLargeInlineResources, Q as stringifyValue, Qt as LocalStartServiceError, R as resolveExplicitPhysicalId, Rt as processStackMessages, S as red, St as resolveApp, T as collectInlinePolicyNamesManagedBySiblings, Tt as resolveSkipPrefix, U as withRetry, Ut as resetAwsClients, V as DiffCalculator, Vt as AwsClients, W as isRetryableTransientError, Wt as setAwsClients, X as shouldRetainResource, Xt as LocalInvokeBuildError$1, Y as rebuildClientForBucketRegion, Yt as DeployCancelledError, Z as AssetPublisher, Zt as LocalMigrateError, _ as formatResourceLine, _t as getDockerImageBySourceHash, a as DeploymentEventsStore, an as ResourceUpdateNotSupportedError, at as BOOTSTRAP_MARKER_PREFIX, b as gray, bt as getDefaultStateBucketName, c as replayFailedOperations, ct as parseBootstrapMarker, d as IMPLICIT_DELETE_DEPENDENCIES, dt as buildDockerImage, en as MissingCdkCliError, et as buildAssetRedirectMap, f as computeImplicitDeleteEdges, fn as normalizeAwsError, ft as formatDockerLoginError, g as renderStatefulReason, gt as AssetManifestLoader, h as isStatefulRecreateTargetSync, ht as runDockerStreaming, i as DeploymentEventsReader, in as ResourceTimeoutError, it as AssetModeResolver, j as disableInstanceApiTermination, jt as CFN_TEMPLATE_BODY_LIMIT, k as CloudControlProvider, kt as stateBucketExistenceConfirmed, l as replayRollback, lt as validateAssetBucketName, m as MULTI_REGION_RECREATE_BLOCKED_TYPES, mt as runDockerForeground, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as PartialFailureError, nt as loadPublishableAssetManifest, o as planFailedOps, on as StackHasActiveImportsError, ot as ensureAssetStorage, p as extractDeploymentEventError, pn as withErrorHandling, pt as getDockerCmd, q as LockManager, r as DeployEngine, rn as ProvisioningError, rt as rewriteTemplateAssetReferences, s as planRollback, sn as StackTerminationProtectionError, st as getBootstrapMarkerKey, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as NestedStackChildDirectDestroyError, tt as createAssetRedirectResolver, u as withResourceDeadline, ut as validateContainerRepoName, v as bold, vt as Synthesizer, w as IAMRoleProvider, wt as resolveCaptureObservedState, x as green, xt as getLegacyStateBucketName, y as cyan, yt as synthesisStatusMessage, z as assertRegionMatch } from "./deploy-engine-BVpbuTRu.js";
2
+ import { $ as WorkGraph, A as slowCcOperationTimeoutMs, At as warnDeprecatedNoPrefixCliFlag, B as applyRoleArnIfSet, Bt as resolveBucketRegion, C as yellow, Ct as resolveAutoAssetStorage, D as ProviderRegistry, Dt as resolveStateBucketWithDefaultAndSource, E as clearOnUpdateRemoval, Et as resolveStateBucketWithDefault, F as refStateLookupFromResource, Ft as uploadCfnTemplate, G as DagBuilder, H as describeTypeWithThrottleRetry, Ht as getAwsClients, I as WAFv2WebACLProvider, It as expectedOwnerParam, J as S3StateBackend, K as TemplateParser, Kt as CdkdError, L as normalizeAwsTagsToCfn, Lt as AssemblyReader, M as isTerminationProtectionPropagationError, Mt as CFN_TEMPLATE_URL_LIMIT, N as IntrinsicFunctionResolver, Nt as MIGRATE_TMP_PREFIX, O as findActionableSilentDrops, Ot as resolveUseCdkBootstrapAssets, P as cfnRefValueFromPhysicalId, Pt as findLargeInlineResources, Q as stringifyValue, Qt as LocalStartServiceError, R as resolveExplicitPhysicalId, Rt as processStackMessages, S as red, St as resolveApp, T as collectInlinePolicyNamesManagedBySiblings, Tt as resolveSkipPrefix, U as withRetry, Ut as resetAwsClients, V as DiffCalculator, Vt as AwsClients, W as isRetryableTransientError, Wt as setAwsClients, X as shouldRetainResource, Xt as LocalInvokeBuildError$1, Y as rebuildClientForBucketRegion, Yt as DeployCancelledError, Z as AssetPublisher, Zt as LocalMigrateError, _ as formatResourceLine, _t as getDockerImageBySourceHash, a as DeploymentEventsStore, an as ResourceUpdateNotSupportedError, at as BOOTSTRAP_MARKER_PREFIX, b as gray, bt as getDefaultStateBucketName, c as replayFailedOperations, ct as parseBootstrapMarker, d as IMPLICIT_DELETE_DEPENDENCIES, dt as buildDockerImage, en as MissingCdkCliError, et as buildAssetRedirectMap, f as computeImplicitDeleteEdges, fn as normalizeAwsError, ft as formatDockerLoginError, g as renderStatefulReason, gt as AssetManifestLoader, h as isStatefulRecreateTargetSync, ht as runDockerStreaming, i as DeploymentEventsReader, in as ResourceTimeoutError, it as AssetModeResolver, j as disableInstanceApiTermination, jt as CFN_TEMPLATE_BODY_LIMIT, k as CloudControlProvider, kt as stateBucketExistenceConfirmed, l as replayRollback, lt as validateAssetBucketName, m as MULTI_REGION_RECREATE_BLOCKED_TYPES, mt as runDockerForeground, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as PartialFailureError, nt as loadPublishableAssetManifest, o as planFailedOps, on as StackHasActiveImportsError, ot as ensureAssetStorage, p as extractDeploymentEventError, pn as withErrorHandling, pt as getDockerCmd, q as LockManager, r as DeployEngine, rn as ProvisioningError, rt as rewriteTemplateAssetReferences, s as planRollback, sn as StackTerminationProtectionError, st as getBootstrapMarkerKey, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as NestedStackChildDirectDestroyError, tt as createAssetRedirectResolver, u as withResourceDeadline, ut as validateContainerRepoName, v as bold, vt as Synthesizer, w as IAMRoleProvider, wt as resolveCaptureObservedState, x as green, xt as getLegacyStateBucketName, y as cyan, yt as synthesisStatusMessage, z as assertRegionMatch } from "./deploy-engine-DkdxZIwS.js";
3
3
  import { a as getLiveRenderer, c as PATTERN_B_RESOURCE_TYPES, d as generateResourceNameWithFallback, f as withSkipPrefix, i as runStackBuffered, n as getLogger, o as PATTERN_B_NAME_OPTIONS, p as withStackName, s as PATTERN_B_NAME_PROPERTIES, u as generateResourceName } from "./logger-BYMEE-BS.js";
4
- import { t as ASGProvider } from "./asg-provider-C1xO9Hg8.js";
4
+ import { t as ASGProvider } from "./asg-provider-BfdF-bjF.js";
5
5
  import { AsyncLocalStorage } from "node:async_hooks";
6
6
  import { createHash, randomBytes, randomUUID } from "node:crypto";
7
7
  import { CopyObjectCommand, CreateBucketCommand, DeleteBucketAnalyticsConfigurationCommand, DeleteBucketCommand, DeleteBucketCorsCommand, DeleteBucketIntelligentTieringConfigurationCommand, DeleteBucketInventoryConfigurationCommand, DeleteBucketLifecycleCommand, DeleteBucketMetricsConfigurationCommand, DeleteBucketPolicyCommand, DeleteBucketReplicationCommand, DeleteBucketTaggingCommand, DeleteBucketWebsiteCommand, DeleteObjectsCommand, GetBucketAccelerateConfigurationCommand, GetBucketCorsCommand, GetBucketEncryptionCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketLoggingCommand, GetBucketNotificationConfigurationCommand, GetBucketPolicyCommand, GetBucketReplicationCommand, GetBucketTaggingCommand, GetBucketVersioningCommand, GetBucketWebsiteCommand, GetObjectCommand, GetObjectLockConfigurationCommand, GetPublicAccessBlockCommand, HeadBucketCommand, ListBucketAnalyticsConfigurationsCommand, ListBucketIntelligentTieringConfigurationsCommand, ListBucketInventoryConfigurationsCommand, ListBucketMetricsConfigurationsCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, PutBucketAccelerateConfigurationCommand, PutBucketAnalyticsConfigurationCommand, PutBucketCorsCommand, PutBucketEncryptionCommand, PutBucketIntelligentTieringConfigurationCommand, PutBucketInventoryConfigurationCommand, PutBucketLifecycleConfigurationCommand, PutBucketLoggingCommand, PutBucketMetricsConfigurationCommand, PutBucketNotificationConfigurationCommand, PutBucketOwnershipControlsCommand, PutBucketPolicyCommand, PutBucketReplicationCommand, PutBucketTaggingCommand, PutBucketVersioningCommand, PutBucketWebsiteCommand, PutObjectCommand, PutObjectLockConfigurationCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
8
- import { AddRoleToInstanceProfileCommand, AddUserToGroupCommand, AttachGroupPolicyCommand, AttachRolePolicyCommand, AttachUserPolicyCommand, CreateGroupCommand, CreateInstanceProfileCommand, CreateLoginProfileCommand, CreatePolicyCommand, CreatePolicyVersionCommand, CreateUserCommand, DeleteAccessKeyCommand, DeleteGroupCommand, DeleteGroupPolicyCommand, DeleteInstanceProfileCommand, DeleteLoginProfileCommand, DeletePolicyCommand, DeletePolicyVersionCommand, DeleteRolePolicyCommand, DeleteUserCommand, DeleteUserPermissionsBoundaryCommand, DeleteUserPolicyCommand, DetachGroupPolicyCommand, DetachRolePolicyCommand, DetachUserPolicyCommand, GetGroupCommand, GetGroupPolicyCommand, GetInstanceProfileCommand, GetPolicyCommand, GetPolicyVersionCommand, GetRolePolicyCommand, GetUserCommand, GetUserPolicyCommand, IAMClient, ListAccessKeysCommand, ListAttachedGroupPoliciesCommand, ListAttachedUserPoliciesCommand, ListEntitiesForPolicyCommand, ListGroupPoliciesCommand, ListGroupsForUserCommand, ListPoliciesCommand, ListPolicyTagsCommand, ListPolicyVersionsCommand, ListUserPoliciesCommand, NoSuchEntityException, PutGroupPolicyCommand, PutRolePolicyCommand, PutUserPermissionsBoundaryCommand, PutUserPolicyCommand, RemoveRoleFromInstanceProfileCommand, RemoveUserFromGroupCommand, TagPolicyCommand, TagUserCommand, UntagPolicyCommand, UntagUserCommand, UpdateLoginProfileCommand } from "@aws-sdk/client-iam";
8
+ import { AddRoleToInstanceProfileCommand, AddUserToGroupCommand, AttachGroupPolicyCommand, AttachRolePolicyCommand, AttachUserPolicyCommand, CreateAccessKeyCommand, CreateGroupCommand, CreateInstanceProfileCommand, CreateLoginProfileCommand, CreatePolicyCommand, CreatePolicyVersionCommand, CreateUserCommand, DeleteAccessKeyCommand, DeleteGroupCommand, DeleteGroupPolicyCommand, DeleteInstanceProfileCommand, DeleteLoginProfileCommand, DeletePolicyCommand, DeletePolicyVersionCommand, DeleteRolePolicyCommand, DeleteUserCommand, DeleteUserPermissionsBoundaryCommand, DeleteUserPolicyCommand, DetachGroupPolicyCommand, DetachRolePolicyCommand, DetachUserPolicyCommand, GetAccessKeyLastUsedCommand, GetGroupCommand, GetGroupPolicyCommand, GetInstanceProfileCommand, GetPolicyCommand, GetPolicyVersionCommand, GetRolePolicyCommand, GetUserCommand, GetUserPolicyCommand, IAMClient, ListAccessKeysCommand, ListAttachedGroupPoliciesCommand, ListAttachedUserPoliciesCommand, ListEntitiesForPolicyCommand, ListGroupPoliciesCommand, ListGroupsForUserCommand, ListPoliciesCommand, ListPolicyTagsCommand, ListPolicyVersionsCommand, ListUserPoliciesCommand, NoSuchEntityException, PutGroupPolicyCommand, PutRolePolicyCommand, PutUserPermissionsBoundaryCommand, PutUserPolicyCommand, RemoveRoleFromInstanceProfileCommand, RemoveUserFromGroupCommand, TagPolicyCommand, TagUserCommand, UntagPolicyCommand, UntagUserCommand, UpdateAccessKeyCommand, UpdateLoginProfileCommand } from "@aws-sdk/client-iam";
9
9
  import { CreateQueueCommand, DeleteQueueCommand, GetQueueAttributesCommand, GetQueueUrlCommand, ListQueueTagsCommand, QueueDoesNotExist, SQSClient, SetQueueAttributesCommand, TagQueueCommand, UntagQueueCommand } from "@aws-sdk/client-sqs";
10
10
  import { CreateTopicCommand, DeleteTopicCommand, GetSubscriptionAttributesCommand, GetTopicAttributesCommand, InvalidParameterException, ListSubscriptionsByTopicCommand, ListTagsForResourceCommand, ListTopicsCommand, NotFoundException, SNSClient, SetTopicAttributesCommand, SubscribeCommand, TagResourceCommand, UnsubscribeCommand, UntagResourceCommand } from "@aws-sdk/client-sns";
11
11
  import { AddPermissionCommand, CreateEventSourceMappingCommand, CreateFunctionCommand, CreateFunctionUrlConfigCommand, DeleteEventSourceMappingCommand, DeleteFunctionCommand, DeleteFunctionConcurrencyCommand, DeleteFunctionEventInvokeConfigCommand, DeleteFunctionUrlConfigCommand, DeleteLayerVersionCommand, GetEventSourceMappingCommand, GetFunctionCommand, GetFunctionConcurrencyCommand, GetFunctionEventInvokeConfigCommand, GetFunctionRecursionConfigCommand, GetFunctionUrlConfigCommand, GetLayerVersionByArnCommand, GetPolicyCommand as GetPolicyCommand$1, LambdaClient, ListTagsCommand, PublishLayerVersionCommand, PutFunctionConcurrencyCommand, PutFunctionEventInvokeConfigCommand, PutFunctionRecursionConfigCommand, RemovePermissionCommand, ResourceNotFoundException, TagResourceCommand as TagResourceCommand$1, UntagResourceCommand as UntagResourceCommand$1, UpdateEventSourceMappingCommand, UpdateFunctionCodeCommand, UpdateFunctionConfigurationCommand, UpdateFunctionUrlConfigCommand, waitUntilFunctionUpdatedV2 } from "@aws-sdk/client-lambda";
@@ -3560,6 +3560,264 @@ var IAMInstanceProfileProvider = class {
3560
3560
  }
3561
3561
  };
3562
3562
 
3563
+ //#endregion
3564
+ //#region src/provisioning/providers/iam-access-key-provider.ts
3565
+ /**
3566
+ * AWS IAM AccessKey Provider (issue #1323)
3567
+ *
3568
+ * Implements resource provisioning for AWS::IAM::AccessKey using the IAM SDK.
3569
+ * The type is NON_PROVISIONABLE in the CloudFormation registry (no Cloud
3570
+ * Control handlers), so without this provider cdkd's pre-flight rejects any
3571
+ * template that declares it — including the documented CDK pattern for CI
3572
+ * credentials (`iam.AccessKey` + piping `secretAccessKey` into a Secrets
3573
+ * Manager secret).
3574
+ *
3575
+ * `SecretAccessKey` is a CREATE-TIME-ONLY attribute: `CreateAccessKey` is the
3576
+ * only API call that ever returns the secret, and there is no read-back. The
3577
+ * provider therefore captures it from the create response into the returned
3578
+ * `attributes`, exactly like CloudFormation does — `Fn::GetAtt` resolution
3579
+ * reads the cached value from cdkd state. This means the secret is persisted
3580
+ * in the S3 state file; that is the same trust boundary as the rest of cdkd
3581
+ * state (and CloudFormation likewise embeds the resolved value into whatever
3582
+ * resource consumed the `Fn::GetAtt`). `update()` deliberately omits
3583
+ * `attributes` so the create-time secret is preserved in state (a partial
3584
+ * attribute set would REPLACE the stored attributes, not merge).
3585
+ *
3586
+ * `Serial` is a replacement trigger with no API counterpart: the registry
3587
+ * schema marks it createOnly, so the diff layer classifies any change as a
3588
+ * REPLACEMENT (a new key is minted); the integer itself is never sent to IAM
3589
+ * (see the `handledProperties` note for why it is still declared handled).
3590
+ */
3591
+ var IAMAccessKeyProvider = class {
3592
+ iamClient;
3593
+ logger = getLogger().child("IAMAccessKeyProvider");
3594
+ /**
3595
+ * NON_PROVISIONABLE type: Cloud Control has no handlers for it, so the
3596
+ * #614 unhandled-property auto-route must never send an AccessKey
3597
+ * template to the CC path (it would fail at deploy time with no handler).
3598
+ */
3599
+ disableCcApiFallback = true;
3600
+ /**
3601
+ * `Serial` is listed as HANDLED even though it is never sent to IAM: its
3602
+ * entire CloudFormation semantic is "changing it forces a new key", which
3603
+ * the diff layer implements via the registry-schema createOnly
3604
+ * classification. Declaring it `unhandledByDesign` instead would put it in
3605
+ * the silent-drop set, and on a NON_PROVISIONABLE type with
3606
+ * `disableCcApiFallback` the #614 auto-route viability guard turns every
3607
+ * silent drop into a pre-flight HARD REJECT — wrongly refusing any
3608
+ * template that uses `serial`.
3609
+ */
3610
+ handledProperties = /* @__PURE__ */ new Map([["AWS::IAM::AccessKey", /* @__PURE__ */ new Set([
3611
+ "UserName",
3612
+ "Serial",
3613
+ "Status"
3614
+ ])]]);
3615
+ constructor() {
3616
+ const awsClients = getAwsClients();
3617
+ this.iamClient = awsClients.iam;
3618
+ }
3619
+ /**
3620
+ * Create an IAM access key via `CreateAccessKey`.
3621
+ *
3622
+ * `Status: Inactive` is applied with a follow-up `UpdateAccessKey` (the
3623
+ * create API always mints Active keys). If that follow-up fails, the
3624
+ * just-created key is deleted before rethrowing — otherwise the key would
3625
+ * exist on AWS without a cdkd state record, and the next deploy's re-CREATE
3626
+ * would burn the user's 2-keys-per-user quota.
3627
+ */
3628
+ async create(logicalId, resourceType, properties) {
3629
+ this.logger.debug(`Creating IAM access key ${logicalId}`);
3630
+ const userName = properties["UserName"];
3631
+ if (!userName) throw new ProvisioningError(`AccessKey ${logicalId} requires UserName`, resourceType, logicalId);
3632
+ const status = properties["Status"] ?? "Active";
3633
+ try {
3634
+ const response = await this.iamClient.send(new CreateAccessKeyCommand({ UserName: userName }));
3635
+ const accessKeyId = response.AccessKey?.AccessKeyId;
3636
+ const secretAccessKey = response.AccessKey?.SecretAccessKey;
3637
+ if (!accessKeyId || !secretAccessKey) {
3638
+ if (accessKeyId) try {
3639
+ await this.iamClient.send(new DeleteAccessKeyCommand({
3640
+ UserName: userName,
3641
+ AccessKeyId: accessKeyId
3642
+ }));
3643
+ } catch (cleanupError) {
3644
+ this.logger.warn(`Failed to clean up IAM access key ${logicalId} (${accessKeyId}) minted by a partial CreateAccessKey response: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. Manual deletion may be required: aws iam delete-access-key --user-name ${userName} --access-key-id ${accessKeyId}`);
3645
+ }
3646
+ throw new Error("CreateAccessKey returned no AccessKeyId/SecretAccessKey");
3647
+ }
3648
+ if (status === "Inactive") try {
3649
+ await this.iamClient.send(new UpdateAccessKeyCommand({
3650
+ UserName: userName,
3651
+ AccessKeyId: accessKeyId,
3652
+ Status: "Inactive"
3653
+ }));
3654
+ } catch (innerError) {
3655
+ try {
3656
+ await this.iamClient.send(new DeleteAccessKeyCommand({
3657
+ UserName: userName,
3658
+ AccessKeyId: accessKeyId
3659
+ }));
3660
+ this.logger.debug(`Cleaned up partially-created IAM access key ${logicalId} (${accessKeyId}) after status wiring failure`);
3661
+ } catch (cleanupError) {
3662
+ this.logger.warn(`Failed to clean up partially-created IAM access key ${logicalId} (${accessKeyId}): ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}. Manual deletion may be required before the next deploy: aws iam delete-access-key --user-name ${userName} --access-key-id ${accessKeyId}`);
3663
+ }
3664
+ throw innerError;
3665
+ }
3666
+ this.logger.debug(`Successfully created IAM access key ${logicalId}: ${accessKeyId}`);
3667
+ return {
3668
+ physicalId: accessKeyId,
3669
+ attributes: {
3670
+ SecretAccessKey: secretAccessKey,
3671
+ Id: accessKeyId
3672
+ }
3673
+ };
3674
+ } catch (error) {
3675
+ const cause = error instanceof Error ? error : void 0;
3676
+ throw new ProvisioningError(`Failed to create IAM access key ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, cause);
3677
+ }
3678
+ }
3679
+ /**
3680
+ * Update an IAM access key.
3681
+ *
3682
+ * `UserName` / `Serial` are createOnly (replacement — this method never
3683
+ * sees them change), so the only in-place change is `Status`. A template
3684
+ * that REMOVES `Status` resets to the CFn default `Active` (absent-field
3685
+ * removal semantics), so the desired status is always sent explicitly.
3686
+ */
3687
+ async update(logicalId, physicalId, resourceType, properties, _previousProperties) {
3688
+ this.logger.debug(`Updating IAM access key ${logicalId}: ${physicalId}`);
3689
+ const userName = properties["UserName"];
3690
+ const status = properties["Status"] ?? "Active";
3691
+ try {
3692
+ await this.iamClient.send(new UpdateAccessKeyCommand({
3693
+ UserName: userName,
3694
+ AccessKeyId: physicalId,
3695
+ Status: status
3696
+ }));
3697
+ this.logger.debug(`Successfully updated IAM access key ${logicalId}`);
3698
+ return {
3699
+ physicalId,
3700
+ wasReplaced: false
3701
+ };
3702
+ } catch (error) {
3703
+ const cause = error instanceof Error ? error : void 0;
3704
+ throw new ProvisioningError(`Failed to update IAM access key ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, physicalId, cause);
3705
+ }
3706
+ }
3707
+ /**
3708
+ * Delete an IAM access key via `DeleteAccessKey`.
3709
+ *
3710
+ * `UserName` comes from the state-recorded properties; when absent (e.g. a
3711
+ * hand-edited state record), it is recovered via `GetAccessKeyLastUsed`,
3712
+ * which resolves the owning user from the key id alone.
3713
+ * `NoSuchEntityException` is treated as idempotent success (after the
3714
+ * shared region check).
3715
+ */
3716
+ async delete(logicalId, physicalId, resourceType, properties, context) {
3717
+ this.logger.debug(`Deleting IAM access key ${logicalId}: ${physicalId}`);
3718
+ try {
3719
+ let userName = properties?.["UserName"];
3720
+ if (!userName) userName = (await this.iamClient.send(new GetAccessKeyLastUsedCommand({ AccessKeyId: physicalId }))).UserName;
3721
+ if (!userName) throw new Error(`cannot resolve the owning user for access key ${physicalId}`);
3722
+ await this.iamClient.send(new DeleteAccessKeyCommand({
3723
+ UserName: userName,
3724
+ AccessKeyId: physicalId
3725
+ }));
3726
+ this.logger.debug(`Successfully deleted IAM access key ${logicalId}`);
3727
+ } catch (error) {
3728
+ if (error instanceof NoSuchEntityException) {
3729
+ assertRegionMatch(await this.iamClient.config.region(), context?.expectedRegion, resourceType, logicalId, physicalId);
3730
+ this.logger.debug(`Access key ${physicalId} does not exist, skipping deletion`);
3731
+ return;
3732
+ }
3733
+ const cause = error instanceof Error ? error : void 0;
3734
+ throw new ProvisioningError(`Failed to delete IAM access key ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, physicalId, cause);
3735
+ }
3736
+ }
3737
+ /**
3738
+ * Resolve a `Fn::GetAtt` attribute.
3739
+ *
3740
+ * `Id` is the physical id. `SecretAccessKey` can NEVER be re-fetched from
3741
+ * AWS (create-time-only) — deploy-time resolution reads it from the cached
3742
+ * state attributes and never reaches this method; a live fetch (e.g.
3743
+ * `cdkd orphan` reference rewriting on a state record missing the cached
3744
+ * value) fails with an explicit error instead of a silent wrong answer.
3745
+ */
3746
+ async getAttribute(physicalId, resourceType, attributeName) {
3747
+ if (attributeName === "Id") return physicalId;
3748
+ if (attributeName === "SecretAccessKey") throw new ProvisioningError(`SecretAccessKey for ${physicalId} cannot be read back from AWS — IAM returns it only from CreateAccessKey. cdkd resolves it from the attributes cached in state at create time; this record has no cached value.`, resourceType, physicalId);
3749
+ throw new ProvisioningError(`Unknown attribute ${attributeName} for ${resourceType} (only 'Id' and 'SecretAccessKey' are defined)`, resourceType, physicalId);
3750
+ }
3751
+ /**
3752
+ * Read the AWS-current access key configuration in CFn-property shape.
3753
+ *
3754
+ * Resolves the owning user via `GetAccessKeyLastUsed(AccessKeyId)`, then
3755
+ * finds the key's `Status` in `ListAccessKeys(UserName)`. Returns
3756
+ * `undefined` when the key is gone.
3757
+ */
3758
+ async readCurrentState(physicalId, _logicalId, _resourceType) {
3759
+ let userName;
3760
+ try {
3761
+ userName = (await this.iamClient.send(new GetAccessKeyLastUsedCommand({ AccessKeyId: physicalId }))).UserName;
3762
+ } catch (err) {
3763
+ if (err instanceof NoSuchEntityException) return void 0;
3764
+ throw err;
3765
+ }
3766
+ if (!userName) return void 0;
3767
+ let marker;
3768
+ do {
3769
+ let page;
3770
+ try {
3771
+ page = await this.iamClient.send(new ListAccessKeysCommand({
3772
+ UserName: userName,
3773
+ ...marker && { Marker: marker }
3774
+ }));
3775
+ } catch (err) {
3776
+ if (err instanceof NoSuchEntityException) return void 0;
3777
+ throw err;
3778
+ }
3779
+ for (const key of page.AccessKeyMetadata ?? []) if (key.AccessKeyId === physicalId) {
3780
+ const result = { UserName: userName };
3781
+ if (key.Status !== void 0) result["Status"] = key.Status;
3782
+ return result;
3783
+ }
3784
+ marker = page.IsTruncated ? page.Marker : void 0;
3785
+ } while (marker);
3786
+ }
3787
+ /**
3788
+ * `Serial` has no read API (it is a template-side replacement trigger, never
3789
+ * stored by IAM), so it can never be verified against AWS.
3790
+ */
3791
+ getDriftUnknownPaths(resourceType) {
3792
+ if (resourceType === "AWS::IAM::AccessKey") return ["Serial"];
3793
+ return [];
3794
+ }
3795
+ /**
3796
+ * Adopt an existing IAM access key into cdkd state.
3797
+ *
3798
+ * **Explicit override only** (`--resource <logicalId>=<AccessKeyId>`): the
3799
+ * template carries no property equal to the key id, and IAM access keys
3800
+ * support no tags. The override is verified via `GetAccessKeyLastUsed`.
3801
+ *
3802
+ * The imported record has NO cached `SecretAccessKey` (IAM never returns it
3803
+ * again), so `Fn::GetAtt [<key>, SecretAccessKey]` cannot resolve for an
3804
+ * imported key — mint a new key via replacement if the secret is needed.
3805
+ */
3806
+ async import(input) {
3807
+ if (!input.knownPhysicalId) return null;
3808
+ try {
3809
+ await this.iamClient.send(new GetAccessKeyLastUsedCommand({ AccessKeyId: input.knownPhysicalId }));
3810
+ return {
3811
+ physicalId: input.knownPhysicalId,
3812
+ attributes: { Id: input.knownPhysicalId }
3813
+ };
3814
+ } catch (err) {
3815
+ if (err instanceof NoSuchEntityException) return null;
3816
+ throw err;
3817
+ }
3818
+ }
3819
+ };
3820
+
3563
3821
  //#endregion
3564
3822
  //#region src/provisioning/providers/iam-user-group-provider.ts
3565
3823
  /**
@@ -43239,6 +43497,7 @@ function registerAllProviders(registry) {
43239
43497
  registry.register("AWS::IAM::Policy", new IAMPolicyProvider());
43240
43498
  registry.register("AWS::IAM::ManagedPolicy", new IAMManagedPolicyProvider());
43241
43499
  registry.register("AWS::IAM::InstanceProfile", new IAMInstanceProfileProvider());
43500
+ registry.register("AWS::IAM::AccessKey", new IAMAccessKeyProvider());
43242
43501
  const iamUserGroupProvider = new IAMUserGroupProvider();
43243
43502
  registry.register("AWS::IAM::User", iamUserGroupProvider);
43244
43503
  registry.register("AWS::IAM::Group", iamUserGroupProvider);
@@ -63224,7 +63483,7 @@ function createMigrateCommand() {
63224
63483
  */
63225
63484
  function buildProgram() {
63226
63485
  const program = new Command();
63227
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.274.0");
63486
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.275.0");
63228
63487
  program.hook("preAction", (_thisCommand, actionCommand) => {
63229
63488
  const { profile } = actionCommand.optsWithGlobals();
63230
63489
  if (profile !== void 0) process.env["AWS_PROFILE"] = profile;