aws-cdk icon indicating copy to clipboard operation
aws-cdk copied to clipboard

[apigateway] SpecRestAPI `x-amazon-apigateway-endpoint-configuration` not usable for private API initial deployment

Open IsmaelMartinez opened this issue 5 years ago • 10 comments

It is not possible to use the swagger/openAPI x-amazon-apigateway-endpoint-configuration option in conjunction with the private endpointType.

If you specify a vpce in the endpoint configuration, you get the following:

VPCEndpoints can only be specified with PRIVATE apis. (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: a2a6cebc-7004-4884-9398-0b83a384b49c)
	new SpecRestApi (/Users/ismael.martinez/projects/bitbucket/BIP/draw/draw-scheduler/node_modules/@aws-cdk/aws-apigateway/lib/restapi.ts:486:22)
...

If you deploy the stack without the x-amazon-apigateway-endpoint-configuration, it does create a usable and private API Gateway, but the vpce is not defined in the 'Settings - Endpoint configuration' section.

If you then deploy again the stack with the x-amazon-apigateway-endpoint-configuration, it does work, so this issue is only related to the initial creation of the API Gateway.

Reproduction Steps

Using the following code:

const api = new apigateway.SpecRestApi(this, 'ExampleRestApi', {
  apiDefinition: apigateway.ApiDefinition.fromInline(swaggerInline),
  endpointTypes: [apigateway.EndpointType.PRIVATE],
});

Where the swagger inline is as shown:

{
    "openapi": "3.0.1",
    "servers": [
        {
            "x-amazon-apigateway-endpoint-configuration": {
                "vpcEndpointIds": [
                    "${PPL::VPCId}"
                ]
            }
        }
    ],
    "paths": {
        "/example": {
            "get": {
                "responses": {
                    "200": {
                        "description": "200 response",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/200Response"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "400 response",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/400Response"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "404 response",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/404Response"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "500 response",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/500Response"
                                }
                            }
                        }
                    }
                },
                "x-amazon-apigateway-integration": {
                    "uri": "${PPL::LambdaAliasArn}",
                    "responses": {
                        "default": {
                            "statusCode": "200"
                        }
                    },
                    "passthroughBehavior": "when_no_match",
                    "httpMethod": "POST",
                    "contentHandling": "CONVERT_TO_TEXT",
                    "type": "aws_proxy"
                }
            }
        }
    },
    "components": {
        "schemas": {
            "200Response": {
                "type": "object",
                "properties": {
                    "message": {
                        "type": "string"
                    }
                }
            },
            "400Response": {
                "type": "object",
                "properties": {
                    "errors": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "404Response": {
                "$ref": "#/components/schemas/Error"
            },
            "500Response": {
                "$ref": "#/components/schemas/Error"
            },
            "Error": {
                "type": "object",
                "properties": {
                    "errorCode": {
                        "type": "string"
                    },
                    "message": {
                        "type": "string"
                    }
                }
            }
        }
    },
    "x-amazon-apigateway-policy": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": "*",
                "Action": [
                    "execute-api:Invoke",
                    "execute-api:GET"
                ],
                "Resource": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:*",
                "Condition": {
                    "StringEquals": {
                        "aws:sourceVpce": "${PPL::VPCId}"
                    }
                }
            }
        ]
    }
}

Where the PPL::VPCId is the endpoint id and the PPL::LambdaAliasArn is the lambda alias arn.

We substitute those values dynamically but I don't thinks that is the issue.

What did you expect to happen?

I will expect to get a private API Gateway with the vpce defined in the 'Settings - Endpoint configuration' section.

What actually happened?

The deployment fails with the following message:

VPCEndpoints can only be specified with PRIVATE apis. (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: a2a6cebc-7004-4884-9398-0b83a384b49c)
	new SpecRestApi (/Users/ismael.martinez/projects/bitbucket/BIP/draw/draw-scheduler/node_modules/@aws-cdk/aws-apigateway/lib/restapi.ts:486:22)
...

Environment

  • CLI Version : 1.57.0
  • Framework Version: 1.57.0
  • Node.js Version: 10.22.0
  • OS : MAC 10.15.6
  • Language (Version): TypeScript (3.8.2)

Other


This is :bug: Bug Report

IsmaelMartinez avatar Aug 13 '20 15:08 IsmaelMartinez

The requires investigation into how to correctly use x-amazon-apigateway-endpoint-configuration option in the OpenAPI definition.

nija-at avatar Aug 17 '20 08:08 nija-at

Is there any plan to fix this? Or perhaps enable SpecRestAPI to use the EndpointConfiguration interface ?

rishavpaul avatar Mar 30 '21 18:03 rishavpaul

let api = new SpecRestAPI(...)
(api.node.defaultChild as CfnRestApi).endpointConfiguration = {
  types: [EndpointType.PRIVATE],
  vpcEndpointIds: [ 'xyz' ],
};

Is a workaround until above is implemented for any else facing the same issue.

rishavpaul avatar Mar 30 '21 19:03 rishavpaul

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

github-actions[bot] avatar Jun 17 '22 16:06 github-actions[bot]

I also have a use case for the required feature. Is there a plan to address the issue?

oddg avatar Jun 23 '22 22:06 oddg

I am also having an issue with this. Same error, no VPC endpoint added to the REST Api after using SpecRestAPI.

I'm facing the same issue too. Any suggested workaround? The one indicated by @rishavpaul doesn't seem to fix the problem for me.

2023, and this is still not fixed. @RomainMuller can you help?

mattiamatrix avatar Mar 09 '23 10:03 mattiamatrix

This is still open, and is very annoying. Programmatic deployments shouldn't fail like this.

roypronoy avatar Dec 17 '23 14:12 roypronoy

I was unable to reproduce the issue. I used the following code, which is mostly the same code as the one in the reproduction step with some additional pieces that's missing to make it work. The solution worked without any problems, and I confirmed that the endpoint is displayed in the API Settings page of the AWS Console.

    const vpc = new Vpc(this, 'Vpc', {
    })

    const apiGatewayEndpoint = new InterfaceVpcEndpoint(this, 'ApiGatewayEndpoint', {
      vpc,
      service: InterfaceVpcEndpointAwsService.APIGATEWAY,
    });

    const lambdaFunction = new Function(this, 'ExampleFunction', {
      runtime: Runtime.NODEJS_18_X,
      handler: 'index.handler',
      code: Code.fromInline("foo")
    });



    const swaggerInline = {
      "openapi": "3.0.1",
      "servers": [
        {
          "x-amazon-apigateway-endpoint-configuration": {
            "vpcEndpointIds": [
              `${apiGatewayEndpoint.vpcEndpointId}`
            ]
          }
        }
      ],
      "paths": {
        "/example": {
          "get": {
            "responses": {
              "200": {
                "description": "200 response",
                "content": {
                  "application/json": {
                    "schema": {
                      "$ref": "#/components/schemas/200Response"
                    }
                  }
                }
              },
              "400": {
                "description": "400 response",
                "content": {
                  "application/json": {
                    "schema": {
                      "$ref": "#/components/schemas/400Response"
                    }
                  }
                }
              },
              "404": {
                "description": "404 response",
                "content": {
                  "application/json": {
                    "schema": {
                      "$ref": "#/components/schemas/404Response"
                    }
                  }
                }
              },
              "500": {
                "description": "500 response",
                "content": {
                  "application/json": {
                    "schema": {
                      "$ref": "#/components/schemas/500Response"
                    }
                  }
                }
              }
            },
            "x-amazon-apigateway-integration": {
              "uri": `arn:aws:apigateway:${this.region}:lambda:path/2015-03-31/functions/${lambdaFunction.functionArn}/invocations`,
              "responses": {
                "default": {
                  "statusCode": "200"
                }
              },
              "passthroughBehavior": "when_no_match",
              "httpMethod": "POST",
              "contentHandling": "CONVERT_TO_TEXT",
              "type": "aws_proxy"
            }
          }
        }
      },
      "components": {
        "schemas": {
          "200Response": {
            "type": "object",
            "properties": {
              "message": {
                "type": "string"
              }
            }
          },
          "400Response": {
            "type": "object",
            "properties": {
              "errors": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404Response": {
            "$ref": "#/components/schemas/Error"
          },
          "500Response": {
            "$ref": "#/components/schemas/Error"
          },
          "Error": {
            "type": "object",
            "properties": {
              "errorCode": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      },
      "x-amazon-apigateway-policy": {
        "Version": "2012-10-17",
        "Statement": [
          {
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
              "execute-api:Invoke",
              "execute-api:GET"
            ],
            "Resource": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:*",
            "Condition": {
              "StringEquals": {
                "aws:sourceVpce":
                  `${apiGatewayEndpoint.vpcEndpointId}`
              }
            }
          }
        ]
      }
    }
    const api = new SpecRestApi(this, 'ExampleRestApi', {
      apiDefinition: ApiDefinition.fromInline(swaggerInline),
      endpointTypes: [EndpointType.PRIVATE],
    });

gasolima avatar Jun 12 '25 16:06 gasolima

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.

github-actions[bot] avatar Jul 31 '25 12:07 github-actions[bot]