aws-cdk: [@aws-cdk/pipelines] failed to import a vpc from a stack into application stage

A stack inside the CodePipeline application stage doesn’t recognize an existing VPC

Reproduction Steps

export class ApplicationStage extends cdk.Stage {
    public readonly urlOutput: cdk.CfnOutput
    constructor(scope: cdk.Construct, id: string, props?: cdk.StageProps) {
        super(scope, id, props)
        const service = new ApplicationStack(this, id, config.VPC_NAME, props)
        this.urlOutput = service.urlOutput
    }
} 

export class ApplicationStack extends cdk.Stack {
	public readonly urlOutput: cdk.CfnOutput;

	constructor(scope: cdk.Construct, id: string, vpc_name: string, props?: cdk.StackProps) {
		super(scope, id, props)

		console.log("VPC NAME: ")
		console.log(JSON.stringify(vpc_name))
		console.log("PROPS: ")
		console.log(JSON.stringify(props))

		const vpc = ec2.Vpc.fromLookup(this, "vpc", { vpcName: vpc_name })

		console.log("VPC IMPORTED ")
		console.log(vpc)

		const sg = new ec2.SecurityGroup(this, 'sg', {
			vpc: vpc
		})

	}
}

What did you expect to happen?

I’m expecting the creation of the security group referenced to the existing VPC

What actually happened?

CloudFromation error:

The vpc ID ‘vpc-12345’ does not exist (Service: AmazonEC2; Status Code: 400; Error Code: InvalidVpcID.NotFound; Request ID: 1e003787-3b4f-4d13-8033-48fb609d4447; Proxy: null)

The console logs added for debugging inside the stack from the synth stage:

34 | VPC NAME: 35 | “VPC-RD” 36 | PROPS: 37 | {“env”:{“account”:“946412081729”,“region”:“eu-west-1”}} 38 | VPC IMPORTED 39 | LookedUpVpc { 40 | node: ConstructNode { 41 | host: [Circular], 42 | _actualNode: Node { 43 | host: [Circular], 44 | _locked: false, 45 | _aspects: [], 46 | _children: [Object], 47 | _context: {}, 48 | _metadata: [], 49 | _dependencies: Set {}, 50 | invokedAspects: [], 51 | id: ‘vpc’, 52 | scope: [ApplicationStack] 53 | } 54 | }, 55 | stack: ApplicationStack { 56 | node: ConstructNode { host: [Circular], _actualNode: [Node] }, 57 | _missingContext: [ [Object] ], 58 | _stackDependencies: {}, 59 | templateOptions: {}, 60 | _logicalIds: LogicalIDs { renames: {}, reverse: {} }, 61 | account: ‘946412081729’, 62 | region: ‘eu-west-1’, 63 | environment: ‘aws://946412081729/eu-west-1’, 64 | terminationProtection: undefined, 65 | _stackName: ‘stg-stg’, 66 | tags: TagManager { 67 | tags: Map {}, 68 | priorities: Map {}, 69 | initialTagPriority: 50, 70 | resourceTypeName: ‘aws:cdk:stack’, 71 | tagFormatter: KeyValueFormatter {}, 72 | tagPropertyName: ‘tags’ 73 | }, 74 | artifactId: ‘awsomepipelinespipelinestgC171B70D’, 75 | templateFile: ‘awsomepipelinespipelinestgC171B70D.template.json’, 76 | synthesizer: DefaultStackSynthesizer { 77 | props: {}, 78 | files: {}, 79 | dockerImages: {}, 80 | _stack: [Circular], 81 | bucketName: ‘cdk-hnb659fds-assets-946412081729-eu-west-1’, 82 | repositoryName: ‘cdk-hnb659fds-container-assets-946412081729-eu-west-1’, 83 | _deployRoleArn: ‘arn:${AWS::Partition}:iam::946412081729:role/cdk-hnb659fds-deploy-role-946412081729-eu-west-1’, 84 | _cloudFormationExecutionRoleArn: ‘arn:${AWS::Partition}:iam::946412081729:role/cdk-hnb659fds-cfn-exec-role-946412081729-eu-west-1’, 85 | fileAssetPublishingRoleArn: ‘arn:${AWS::Partition}:iam::946412081729:role/cdk-hnb659fds-file-publishing-role-946412081729-eu-west-1’, 86 | imageAssetPublishingRoleArn: ‘arn:${AWS::Partition}:iam::946412081729:role/cdk-hnb659fds-image-publishing-role-946412081729-eu-west-1’, 87 | _kmsKeyArnExportName: ‘CdkBootstrap-hnb659fds-FileAssetKeyArn’ 88 | }, 89 | [Symbol(@aws-cdk/core.DependableTrait)]: { dependencyRoots: [Array] } 90 | }, 91 | env: { account: ‘946412081729’, region: ‘eu-west-1’ }, 92 | _physicalName: undefined, 93 | _allowCrossEnvironment: false, 94 | physicalName: ‘${Token[TOKEN.187]}’, 95 | natDependencies: [], 96 | incompleteSubnetDefinition: true, 97 | internetConnectivityEstablished: ConcreteDependable { 98 | _dependencyRoots: [], 99 | [Symbol(@aws-cdk/core.DependableTrait)]: { dependencyRoots: [Getter] } 100 | }, 101 | vpcId: ‘vpc-12345’, 102 | cidr: ‘1.2.3.4/5’, 103 | _vpnGatewayId: undefined, 104 | availabilityZones: [ ‘dummy1a’, ‘dummy1b’ ], 105 | publicSubnets: [ 106 | ImportedSubnet { 107 | node: [ConstructNode], 108 | stack: [ApplicationStack], 109 | env: [Object], 110 | _physicalName: undefined, 111 | _allowCrossEnvironment: false, 112 | physicalName: ‘${Token[TOKEN.188]}’, 113 | internetConnectivityEstablished: [ConcreteDependable], 114 | _availabilityZone: ‘dummy1a’, 115 | subnetId: ‘s-12345’, 116 | routeTable: [Object], 117 | [Symbol(@aws-cdk/core.DependableTrait)]: [Object] 118 | }, 119 | ImportedSubnet { 120 | node: [ConstructNode], 121 | stack: [ApplicationStack], 122 | env: [Object], 123 | _physicalName: undefined, 124 | _allowCrossEnvironment: false, 125 | physicalName: ‘${Token[TOKEN.189]}’, 126 | internetConnectivityEstablished: [ConcreteDependable], 127 | _availabilityZone: ‘dummy1b’, 128 | subnetId: ‘s-67890’, 129 | routeTable: [Object], 130 | [Symbol(@aws-cdk/core.DependableTrait)]: [Object] 131 | } 132 | ], 133 | privateSubnets: [ 134 | ImportedSubnet { 135 | node: [ConstructNode], 136 | stack: [ApplicationStack], 137 | env: [Object], 138 | _physicalName: undefined, 139 | _allowCrossEnvironment: false, 140 | physicalName: ‘${Token[TOKEN.190]}’, 141 | internetConnectivityEstablished: [ConcreteDependable], 142 | _availabilityZone: ‘dummy1a’, 143 | subnetId: ‘p-12345’, 144 | routeTable: [Object], 145 | [Symbol(@aws-cdk/core.DependableTrait)]: [Object] 146 | }, 147 | ImportedSubnet { 148 | node: [ConstructNode], 149 | stack: [ApplicationStack], 150 | env: [Object], 151 | _physicalName: undefined, 152 | _allowCrossEnvironment: false, 153 | physicalName: ‘${Token[TOKEN.191]}’, 154 | internetConnectivityEstablished: [ConcreteDependable], 155 | _availabilityZone: ‘dummy1b’, 156 | subnetId: ‘p-67890’, 157 | routeTable: [Object], 158 | [Symbol(@aws-cdk/core.DependableTrait)]: [Object] 159 | } 160 | ], 161 | isolatedSubnets: [], 162 | [Symbol(@aws-cdk/core.DependableTrait)]: { dependencyRoots: [ [Circular] ] } 163 | }

Environment

  • CLI Version : 1.61.1 (build 347918f)
  • Framework Version: 1.60.0
  • OS : aws/codebuild/standard:4.0
  • *Language (Version): TypeScript (3.9.7)

Other

The full code is present on this repo https://github.com/enricopesce/AWSome-pipeline/tree/pipelines


This is 🐛 Bug Report

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 20 (1 by maintainers)

Most upvoted comments

This is currently the only reason we’re not using CDK Pipelines. Would love to see this issue resolved.

Thank you @jguice is it a very big limitation!

I’m also looking for a workaround @rix0rrr

Is anyone using a workaround like this?

vpc = ec2.Vpc.from_vpc_attributes(self, 'VPC',
            vpc_id='vpc-xxxxxxxxx',
            availability_zones=["us-west-2a","us-west-2b","us-west-2c","us-west-2d"],
            private_subnet_ids=["subnet-xxxxxxxxxx", "subnet-xxxxxxxxxx", "subnet-xxxxxxxxxx", "subnet-xxxxxxxxxx"],

            )

I’m assuming most of us that are trying to use Vpc.fromLookup already know the vpc-id/az/subnet/etc information.

This issue shouldn’t be closed just yet @rix0rrr - we need a formal workaround for the limitation of context queries before CDK Pipelines can be used for an enterprise production solution. Happy to test against an actual use case.

For what it’s worth, here’s the meat of what I ended up doing. This is used in a CDK app using a CDKPipeline. The lambda itself needs access to RDS, which is granted by associating the lambda with a pre-existing SecurityGroup.

from aws_cdk import core, \
    aws_codedeploy as codedeploy, \
    aws_lambda as lambda_, \
    aws_iam as iam, \
    aws_events, \
    aws_events_targets, \
    aws_ec2

import datetime


class MyLambdaStack(core.Stack):

    def __init__(self, app: core.App, id: str, **kwargs):
        super().__init__(app, id, **kwargs)

        # change me
        vpc_id = 'vpc-<your id>'
        sg_id = 'sg-<some existing security group with rds access>' 
        sub_net_ids = ["subnet-<some subnet id 1>", "subnet-<some subnet id 2>", "subnet-<some subnet id 3>"]
        azs = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
    
        # get vpc
        vpc = aws_ec2.Vpc.from_vpc_attributes(self, 'vpc', vpc_id=vpc_id, availability_zones=azs)
        sub_nets = [
		          aws_ec2.Subnet.from_subnet_attributes(self, f'subnet{idx}', subnet_id=sni)
		          for idx, sni in enumerate(sub_net_ids)
        ]
        sub_net_selection = aws_ec2.SubnetSelection(subnets=sub_nets)
    
        # Lambda SG
        sg = aws_ec2.SecurityGroup.from_security_group_id(self, 'lambda-rds', security_group_id=sg_id)
    
        func = lambda_.Function(self, "Lambda",
		                              code=self.lambda_code,
		                              handler="handler.lambda_handler",
		                              runtime=lambda_.Runtime.PYTHON_3_8,
		                              description="Function generated on {}".format(datetime.datetime.now()),
		                              vpc=vpc,
		                              timeout=core.Duration.seconds(10),
		                              vpc_subnets=sub_net_selection,
		                              security_groups=[sg]
		                              )


account = '<id without hyphen>'
region = 'eu-west-1'
env_eu = core.Environment(account=account, region=region)

app = core.App()
my_lambda_stack = MyLambdaStack(app, id="MyLambdaStack", env=env_eu)
app.synth()

This looks like the known limitation of context queries not being support in pipelines (#8905 tracks the feature request).

Anyone know how to fix this?

@ayk33 Can you try defining the private_subnet_route_table_ids?

vpc = ec2.Vpc.from_vpc_attributes(self, 'VPC',
            vpc_id='vpc-xxxxxxxxx',
            availability_zones=["us-west-2a","us-west-2b","us-west-2c","us-west-2d"],
            private_subnet_ids=["subnet-xxxxxxxxxx", "subnet-xxxxxxxxxx", "subnet-xxxxxxxxxx", "subnet-xxxxxxxxxx"],
            private_subnet_route_table_ids=["id1","id2","id3","id4"]
            )

Don’t print the result of a fromLookup(). On the first iteration it’s not going to contain what you think it does.