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.57k stars 3.88k forks source link

ec2: Unable to use imported interface VPC endpoint in another stack #30507

Closed vhryshchenko-source closed 3 months ago

vhryshchenko-source commented 3 months ago

Describe the bug

I am using two stacks. In one of them, I import the VPC endpoint if it already exists, and if not, I create a new one. Then I create a new stack in which I want to deploy a Private API Gateway, which needs to be provided with the VPC endpoint.

vps-stack.ts

    export class VpcStack extends Stack {

    public readonly vpc: aws_ec2.IVpc;
    public readonly executeApiEndpoint: aws_ec2.IVpcEndpoint;
    public readonly subnets: aws_ec2.ISubnet[];

    constructor(scope: Construct, id: string, props: StackProps, additionalProps: Props) {
        super(scope, id, props);

        // Lookup an existing VPC using its VPC ID from the configuration.
        this.vpc = aws_ec2.Vpc.fromLookup(this, 'vpc', {
            vpcId: additionalProps.VpcId
        })

        let executeApiEndpoint: aws_ec2.IVpcEndpoint;

        if (buildconfig.ExecuteApiEndpointId) {
        executeApiEndpoint = aws_ec2.InterfaceVpcEndpoint.fromInterfaceVpcEndpointAttributes(this, `vpc`, {
            vpcEndpointId: additionalProps.ExecuteApiEndpointId,
            port: 443
        });
        } else {
            ///Create VPC endpoint
        }

        this.executeApiEndpoint = executeApiEndpoint;

bin/app.ts

 const stack1 = new VpcStack(app, 'Stack-1', {
    description: 'Stack-1',
  },
  additionalProps
 );

 const stack2 = new ApplicationStack(app, 'Stack-2', {
    description: "Satck-2",
    vpc: stack1.vpc,
    subnets: stack1.subnets,
    executeApiEndpoint: stack1.executeApiEndpoint,
  }
  additionalProps
 );

application-stack.ts (api gateway part)

        this.restApiGateway = new apigateway.RestApi(this, 'RestApi', {
            restApiName: props.apiGatewayName,
            policy: policyDocument,
            endpointConfiguration: {
                types: [apigateway.EndpointType.PRIVATE],
                vpcEndpoints: [props.executeApiEndpoint]
            }

The problem is that if I import the resource from the same stack where the API Gateway is created, everything works, but if these are different stacks, I get an error. Error:

./node_modules/aws-cdk-lib/aws-apigateway/lib/restapi.js:1
"use strict";var _a,_b,_c;Object.defineProperty(exports,"__esModule",{value:!0}),exports.EndpointType=exports.ApiKeySourceType=exports.RestApi=exports.SpecRestApi=exports.RestApiBase=void 0;var jsiiDeprecationWarnings=()=>{var tmp=require("../../.warnings.jsii.js");return jsiiDeprecationWarnings=()=>tmp,tmp};const JSII_RTTI_SYMBOL_1=Symbol.for("jsii.rtti");var api_key_1=()=>{var tmp=require("./api-key");return api_key_1=()=>tmp,tmp},apigateway_canned_metrics_generated_1=()=>{var tmp=require("./apigateway ...........
**TypeError: Cannot read properties of undefined (reading 'vpcEndpointId')**
    at ./node_modules/aws-cdk-lib/aws-apigateway/lib/restapi.js:1:9674
    at Array.map (<anonymous>)
    at RestApi._configureEndpoints (./node_modules/aws-cdk-lib/aws-apigateway/lib/restapi.js:1:9645)

CDK synth fine If i will import VPC endpoint in the same stack, like in this the way:

 let executeApiEndpoint: aws_ec2.IVpcEndpoint;

  if (buildconfig.ExecuteApiEndpointId) {
  executeApiEndpoint = aws_ec2.InterfaceVpcEndpoint.fromInterfaceVpcEndpointAttributes(this, `vpc`, {
      vpcEndpointId: additionalProps.ExecuteApiEndpointId,
      port: 443
  });
  } else {
      ///Create VPC endpoint
  }
    this.restApiGateway = new apigateway.RestApi(this, 'RestApi', {
        restApiName: props.apiGatewayName,
        policy: policyDocument,
        endpointConfiguration: {
            types: [apigateway.EndpointType.PRIVATE],
            vpcEndpoints: [executeApiEndpoint]
        }

Expected Behavior

Import interface VPC endpoint in one Stack and use it for Private API Gateway in another stack should work.

Current Behavior

The problem is that if I import the resource from the same stack where the API Gateway is created, everything works, but if these are different stacks, I get an error. Error:

./node_modules/aws-cdk-lib/aws-apigateway/lib/restapi.js:1
"use strict";var _a,_b,_c;Object.defineProperty(exports,"__esModule",{value:!0}),exports.EndpointType=exports.ApiKeySourceType=exports.RestApi=exports.SpecRestApi=exports.RestApiBase=void 0;var jsiiDeprecationWarnings=()=>{var tmp=require("../../.warnings.jsii.js");return jsiiDeprecationWarnings=()=>tmp,tmp};const JSII_RTTI_SYMBOL_1=Symbol.for("jsii.rtti");var api_key_1=()=>{var tmp=require("./api-key");return api_key_1=()=>tmp,tmp},apigateway_canned_metrics_generated_1=()=>{var tmp=require("./apigateway ...........
**TypeError: Cannot read properties of undefined (reading 'vpcEndpointId')**
    at ./node_modules/aws-cdk-lib/aws-apigateway/lib/restapi.js:1:9674
    at Array.map (<anonymous>)
    at RestApi._configureEndpoints (./node_modules/aws-cdk-lib/aws-apigateway/lib/restapi.js:1:9645)

Reproduction Steps

Create two stacks. First contain

executeApiEndpoint = aws_ec2.InterfaceVpcEndpoint.fromInterfaceVpcEndpointAttributes(this, `vpc`, {
            vpcEndpointId: additionalProps.ExecuteApiEndpointId,
            port: 443
        });

Second contain

        this.restApiGateway = new apigateway.RestApi(this, 'RestApi', {
            restApiName: props.apiGatewayName,
            policy: policyDocument,
            endpointConfiguration: {
                types: [apigateway.EndpointType.PRIVATE],
                vpcEndpoints: [props.executeApiEndpoint]
            }

Possible Solution

No response

Additional Information/Context

No response

CDK CLI Version

2.145.0

Framework Version

No response

Node.js Version

v22.2.0

OS

Mac

Language

TypeScript

Language Version

No response

Other information

No response

pahud commented 3 months ago

I tried to simplify your provided code snippet and this works for me

stack.ts

export class Stack1 extends Stack {
  public readonly executeApiEndpoint: ec2.IInterfaceVpcEndpoint;
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    this.executeApiEndpoint = ec2.InterfaceVpcEndpoint.fromInterfaceVpcEndpointAttributes(this, `vpc`, {
      vpcEndpointId: 'dummy-id',
      port: 443
    });

  }
}

export interface Stack2Props extends StackProps {
  readonly executeApiEndpoint: ec2.IInterfaceVpcEndpoint;
}

export class Stack2 extends Stack {
  constructor(scope: Construct, id: string, props: Stack2Props) {
    super(scope, id, props);

    const api = new apigateway.RestApi(this, 'RestApi', {
      restApiName: 'dummy-name',
      endpointConfiguration: {
          types: [apigateway.EndpointType.PRIVATE],
          vpcEndpoints: [props.executeApiEndpoint]
      },
    });

    api.root.addMethod('GET');
  }
}

app.ts

const stack1 = new Stack1(app, 'stack1');
new Stack2(app, 'stack2', {
    executeApiEndpoint: stack1.executeApiEndpoint,
});

cdk diff

Resources
[+] AWS::ApiGateway::RestApi RestApi RestApi0C43BF4B 
[+] AWS::ApiGateway::Deployment RestApi/Deployment RestApiDeployment180EC5031e179fa89b23406b04ad2558c7819850 
[+] AWS::ApiGateway::Stage RestApi/DeploymentStage.prod RestApiDeploymentStageprod3855DE66 
[+] AWS::ApiGateway::Method RestApi/Default/GET RestApiGET0F59260B 
github-actions[bot] commented 3 months ago

This issue has not received a response in a while. If you want to keep this issue open, please leave a comment below and auto-close will be canceled.

vhryshchenko-source commented 3 months ago

I created stacks from scratch and it seems that everything really works, maybe I missed something somewhere. I'm closing the issue.

github-actions[bot] commented 3 months ago

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see. If you need more assistance, please either tag a team member or open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.

aws-cdk-automation commented 2 months ago

Comments on closed issues and PRs are hard for our team to see. If you need help, please open a new issue that references this one.