@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/README.md +2 -2
- package/dist/{asg-provider-C1xO9Hg8.js → asg-provider-BfdF-bjF.js} +2 -2
- package/dist/{asg-provider-C1xO9Hg8.js.map → asg-provider-BfdF-bjF.js.map} +1 -1
- package/dist/cli.js +263 -4
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-engine-BVpbuTRu.js → deploy-engine-DkdxZIwS.js} +41 -8
- package/dist/deploy-engine-DkdxZIwS.js.map +1 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-BVpbuTRu.js.map +0 -1
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-
|
|
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-
|
|
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.
|
|
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;
|