aws / aws-cdk

The AWS Cloud Development Kit is a framework for defining cloud infrastructure in code
https://aws.amazon.com/cdk
Apache License 2.0
11.51k stars 3.86k forks source link

aws_lambda: Edit DockerImageFunction ImageUri #29177

Open WayneLIT opened 7 months ago

WayneLIT commented 7 months ago

Describe the bug

I am trying to use a container registry located in a different account.

I have set image_assets_repository_name and image_asset_publishing_role_arn setting appropriately when instantiating my DefaultStackSynthesizer and have the appropriate permissions in place.

When performing a cdk deploy to account A (with account A credentials), the image is successfully created and pushed to ECR in Account B. However the cloudformation update fails as it cannot find the image. Upon investigation, I noticed in the synthesized template that the ImageUri value is prefixed with Account A details:

"ImageUri": { "Fn::Sub": "ACCOUNT-A.dkr.ecr.eu-west-1.${AWS::URLSuffix}/cdk-Qualifier-container-assets-ACCOUNT-B-eu-west-1:f3193b7321a34e0685a8fb9982ce250e2e6d8b45458d55b7c5c42132a7fe60ef" }

So Cloudformation is trying to find a repository and image that does not exist in account A

Expected Behavior

It makes sense to default to the account that is passed via the env dict but ImageUri in the resolved template should be configurable.

Current Behavior

ImageUri is always prefixed with the account details of the account that is passed in the env dict.

Reproduction Steps

synthesizer = cdk.DefaultStackSynthesizer(
    qualifier="MyQualifier",
    file_assets_bucket_name="cdk-MyQualifier-assets-ACCOUNT-B-eu-west-1",
    image_assets_repository_name="cdk-MyQualifier-container-assets-ACCOUNT-B-eu-west-1",
    image_asset_publishing_role_arn=(
        "arn:aws:iam::ACCOUNT-B:role/"
        "cdk-MyQualifier-image-publishing-role-ACCOUNT-B-eu-west-1"
    ),
)

MyStack(
    app,
    "my-stack",
    env=cdk.Environment(account="ACCOUNT-A", region="eu-west-1"),
    synthesizer=synthesizer,
)

app.synth()

Possible Solution

Make the ImageUri account-prefix configurable via an option in the DefaultSynthesizer

Additional Information/Context

Details taken from https://github.com/aws/aws-cdk/discussions/29091

I eventually came to a workaround.

I could find no way to change the account number for the ImageUri field. Looks like it takes it from the account details passed in the env dict when instantiating the stack.

The only way around this was to use the lower level CfnFunction resource instead of DockerImageFunction. I created the docker asset separately and constructed the desired imageUri field. In the future this could be included in an internal construct or synthesizer but for now it is a reasonable approach

code_asset = DockerImageAsset(self, "MyBuildImage", directory="pipeline/lambda")

image_uri = (
    f"ACCOUNT-B.dkr.ecr.{self.region}.",
    f"{self.url_suffix}/cdk-Qualifier-container-assets-ACCOUNT-B-",
    f"{self.region}:{code_asset.asset_hash}",
)
_lambda.CfnFunction(
    self,
    "DeployLambda",
    code=_lambda.CfnFunction.CodeProperty(image_uri=image_uri),
    timeout=30,
    memory_size=512,
    role=lambda_role.role_arn,
    package_type="Image",
)

CDK CLI Version

2.126.0

Framework Version

No response

Node.js Version

v20.10.0

OS

Ubuntu 22.04.4 LTS

Language

Python

Language Version

3.12

Other information

You may notice in my DefaultSynthesizer that it is not required to specify the file_asset_publishing_role_arn. The file asset publishing role created as part of bootstrapping ACCOUNT-A has permission to write to the S3 Bucket in ACCOUNT-B.

However, I must include the image_asset_publishing_role_arn as without it my workaround fails when performing a cdk deploy:

pipeline: fail: No ECR repository named 'cdk-MyQualifier-container-assets-ACCOUNT-B-eu-west-1' in account ACCOUNT-A. Is this account bootstrapped?

pahud commented 7 months ago

Agree and it makes sense to me as you have defined the image publishing assets to account B in the DefaultStackSynthesizer so the synthesized template for imageUri should point to account B. I am not sure if this is a bug but I'll bring this to the team for discussion.