in packages/cdk-assets/lib/private/handlers/files.ts [58:174]
public async publish(options: PublishOptions = {}): Promise<void> {
const destination = await replaceAwsPlaceholders(this.asset.destination, this.host.aws);
const s3Url = `s3://${destination.bucketName}/${destination.objectKey}`;
const clientOptions = destinationToClientOptions(destination);
const s3 = await this.host.aws.s3Client(clientOptions);
this.host.emitMessage(EventType.CHECK, `Check ${s3Url}`);
const bucketInfo = BucketInformation.for(this.host);
// A thunk for describing the current account. Used when we need to format an error
// message, not in the success case.
const account = async () =>
(await this.host.aws.discoverTargetAccount(clientOptions)).accountId;
const allowCrossAccount = options.allowCrossAccount ?? true;
switch (
await bucketInfo.bucketOwnership(
s3,
destination.bucketName,
allowCrossAccount ? undefined : await account(),
)
) {
case BucketOwnership.MINE:
break;
case BucketOwnership.DOES_NOT_EXIST:
throw new Error(
`No bucket named '${destination.bucketName}'. Is account ${await account()} bootstrapped?`,
);
case BucketOwnership.NO_ACCESS:
throw new Error(
`Bucket named '${destination.bucketName}' exists, but we dont have access to it.`,
);
case BucketOwnership.SOMEONE_ELSES_AND_HAVE_ACCESS:
if (!allowCrossAccount) {
throw new Error(
`❗❗ UNEXPECTED BUCKET OWNER DETECTED ❗❗
We've detected that the S3 bucket ${destination.bucketName} was
originally created in account ${await account()} as part of the CloudFormation stack CDKToolkit,
but now resides in a different AWS account. To prevent cross-account asset bucket access of your
deployments, CDK will stop now.
If this situation is intentional and you own the AWS account that the bucket has moved to, remove the
resource named StagingBucket from the template of CloudFormation stack CDKToolkit and try again.
If this situation is not intentional, we strongly recommend auditing your account to make sure all
resources are configured the way you expect them [1]. For questions or concerns, please contact
AWS Support [2].
[1] https://repost.aws/knowledge-center/potential-account-compromise
[2] https://aws.amazon.com/support`,
);
}
break;
}
if (!options.force && await objectExists(s3, destination.bucketName, destination.objectKey)) {
this.host.emitMessage(EventType.FOUND, `Found ${s3Url}`);
return;
}
// Identify the the bucket encryption type to set the header on upload
// required for SCP rules denying uploads without encryption header
let paramsEncryption: { [index: string]: any } = {};
const encryption2 = await bucketInfo.bucketEncryption(s3, destination.bucketName);
switch (encryption2.type) {
case 'no_encryption':
break;
case 'aes256':
paramsEncryption = { ServerSideEncryption: 'AES256' };
break;
case 'kms':
// We must include the key ID otherwise S3 will encrypt with the default key
paramsEncryption = {
ServerSideEncryption: 'aws:kms',
SSEKMSKeyId: encryption2.kmsKeyId,
};
break;
case 'does_not_exist':
this.host.emitMessage(
EventType.DEBUG,
`No bucket named '${destination.bucketName}'. Is account ${await account()} bootstrapped?`,
);
break;
case 'access_denied':
this.host.emitMessage(
EventType.DEBUG,
`Could not read encryption settings of bucket '${destination.bucketName}': uploading with default settings ("cdk bootstrap" to version 9 if your organization's policies prevent a successful upload or to get rid of this message).`,
);
break;
}
if (this.host.aborted) {
return;
}
const publishFile = this.asset.source.executable
? await this.externalPackageFile(this.asset.source.executable)
: await this.packageFile(this.asset.source);
this.host.emitMessage(EventType.UPLOAD, `Upload ${s3Url}`);
const params = Object.assign(
{},
{
Bucket: destination.bucketName,
Key: destination.objectKey,
Body: createReadStream(publishFile.packagedPath),
ContentType: publishFile.contentType,
ChecksumAlgorithm: 'SHA256',
} satisfies PutObjectCommandInput,
paramsEncryption,
);
await s3.upload(params);
}