AWS API GW with Terraform and OpenAPI not enabling CORS settings

I’m using terraform with AWS provider to create an API Gateway. Everything seems to be fine except for the CORS settings. I’m also using OpenAPI for the configuration.

My “end user” problem is that my API call to my back end is returning 404 not found because it’s making an OPTIONS request first. Enabling CORS settings in API Gateway handles CORS for you and also automatically returns the correct response for the OPTIONS request. However, CORS settings are not being enabled. I believe they should be due to the x-amazon-apigateway-cors section.

Here is my OpenAPI file:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>openapi: 3.0.1
info:
title: App API
description: App API
version: 0.1.0
paths:
'/requisitions':
post:
operationId: createRequisition
summary: Create requisition
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- institutionId
properties:
institutionId:
type: string
responses:
'200':
description: 200 response
content:
application/json:
schema:
$ref: '#/components/schemas/Requisition'
'401':
$ref: '#/components/responses/Unauthenticated'
default:
$ref: '#/components/responses/Error'
x-amazon-apigateway-integration:
type: AWS_PROXY
httpMethod: POST
uri: '${gocardless_function_arn}'
payloadFormatVersion: 2.0
security:
- cognito-jwt: []
x-amazon-apigateway-cors:
allowOrigins:
- '*'
allowMethods:
- GET
- OPTIONS
- POST
allowHeaders:
- x-amzm-header
- x-apigateway-header
- x-api-key
- authorization
- x-amz-date
- content-type
components:
schemas:
AnyValue:
nullable: true
description: Can be any value - null, string, number, boolean, array or object.
Requisition:
type: object
properties:
id:
type: string
nullable: true
Error:
type: object
required:
- status
- statusCode
- error
properties:
status:
type: string
statusCode:
type: integer
requestId:
type: string
documentationUrl:
type: string
error:
type: object
required:
- code
- message
- timestamp
properties:
code:
type: string
message:
type: string
details:
$ref: '#/components/schemas/AnyValue'
timestamp:
type: string
path:
type: string
suggestion:
type: string
securitySchemes:
cognito-jwt:
type: oauth2
flows:
authorizationCode:
authorizationUrl: 'https://cognito-idp.eu-west-2.amazonaws.com/'
tokenUrl: ''
scopes: {}
x-amazon-apigateway-authorizer:
type: jwt
jwtConfiguration:
issuer: 'https://cognito-idp.eu-west-2.amazonaws.com/${cognito_user_pool_id}'
audience:
- '${cognito_app_client_id}'
identitySource: '$request.header.Authorization'
responses:
Unauthenticated:
description: Unauthenticated
headers:
www-authenticate:
schema:
type: string
content:
application/json:
schema:
type: object
required:
- message
properties:
message:
type: string
Error:
description: Error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
</code>
<code>openapi: 3.0.1 info: title: App API description: App API version: 0.1.0 paths: '/requisitions': post: operationId: createRequisition summary: Create requisition requestBody: required: true content: application/json: schema: type: object required: - institutionId properties: institutionId: type: string responses: '200': description: 200 response content: application/json: schema: $ref: '#/components/schemas/Requisition' '401': $ref: '#/components/responses/Unauthenticated' default: $ref: '#/components/responses/Error' x-amazon-apigateway-integration: type: AWS_PROXY httpMethod: POST uri: '${gocardless_function_arn}' payloadFormatVersion: 2.0 security: - cognito-jwt: [] x-amazon-apigateway-cors: allowOrigins: - '*' allowMethods: - GET - OPTIONS - POST allowHeaders: - x-amzm-header - x-apigateway-header - x-api-key - authorization - x-amz-date - content-type components: schemas: AnyValue: nullable: true description: Can be any value - null, string, number, boolean, array or object. Requisition: type: object properties: id: type: string nullable: true Error: type: object required: - status - statusCode - error properties: status: type: string statusCode: type: integer requestId: type: string documentationUrl: type: string error: type: object required: - code - message - timestamp properties: code: type: string message: type: string details: $ref: '#/components/schemas/AnyValue' timestamp: type: string path: type: string suggestion: type: string securitySchemes: cognito-jwt: type: oauth2 flows: authorizationCode: authorizationUrl: 'https://cognito-idp.eu-west-2.amazonaws.com/' tokenUrl: '' scopes: {} x-amazon-apigateway-authorizer: type: jwt jwtConfiguration: issuer: 'https://cognito-idp.eu-west-2.amazonaws.com/${cognito_user_pool_id}' audience: - '${cognito_app_client_id}' identitySource: '$request.header.Authorization' responses: Unauthenticated: description: Unauthenticated headers: www-authenticate: schema: type: string content: application/json: schema: type: object required: - message properties: message: type: string Error: description: Error content: application/json: schema: $ref: '#/components/schemas/Error' </code>
openapi: 3.0.1

info:
  title: App API
  description: App API
  version: 0.1.0

paths:
  '/requisitions':
    post:
      operationId: createRequisition
      summary: Create requisition
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - institutionId
              properties:
                institutionId:
                  type: string
      responses:
        '200':
          description: 200 response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Requisition'
        '401':
          $ref: '#/components/responses/Unauthenticated'
        default:
          $ref: '#/components/responses/Error'
      x-amazon-apigateway-integration:
        type: AWS_PROXY
        httpMethod: POST
        uri: '${gocardless_function_arn}'
        payloadFormatVersion: 2.0

security:
  - cognito-jwt: []

x-amazon-apigateway-cors:
  allowOrigins:
    - '*'
  allowMethods:
    - GET
    - OPTIONS
    - POST
  allowHeaders:
    - x-amzm-header
    - x-apigateway-header
    - x-api-key
    - authorization
    - x-amz-date
    - content-type

components:
  schemas:
    AnyValue:
      nullable: true
      description: Can be any value - null, string, number, boolean, array or object.
    Requisition:
      type: object
      properties:
        id:
          type: string
          nullable: true
    Error:
      type: object
      required:
        - status
        - statusCode
        - error
      properties:
        status:
          type: string
        statusCode:
          type: integer
        requestId:
          type: string
        documentationUrl:
          type: string
        error:
          type: object
          required:
            - code
            - message
            - timestamp
          properties:
            code:
              type: string
            message:
              type: string
            details:
              $ref: '#/components/schemas/AnyValue'
            timestamp:
              type: string
            path:
              type: string
            suggestion:
              type: string

  securitySchemes:
    cognito-jwt:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: 'https://cognito-idp.eu-west-2.amazonaws.com/'
          tokenUrl: ''
          scopes: {}

      x-amazon-apigateway-authorizer:
        type: jwt
        jwtConfiguration:
          issuer: 'https://cognito-idp.eu-west-2.amazonaws.com/${cognito_user_pool_id}'
          audience:
            - '${cognito_app_client_id}'
        identitySource: '$request.header.Authorization'

  responses:
    Unauthenticated:
      description: Unauthenticated
      headers:
        www-authenticate:
          schema:
            type: string
      content:
        application/json:
          schema:
            type: object
            required:
              - message
            properties:
              message:
                type: string
    Error:
      description: Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'

And here is the relevant part of my terraform:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>resource "aws_apigatewayv2_api" "api_gateway" {
name = "API Gateway"
version = "0.1.0"
protocol_type = "HTTP"
description = "API gateway"
body = templatefile("${path.module}/files/api-gateway-openapi.yaml", {
gocardless_function_arn = module.gocardless_create_requisition_lambda.lambda_function_arn,
cognito_user_pool_id = aws_cognito_user_pool.pool.id,
cognito_app_client_id = aws_cognito_user_pool_client.client.id,
region = var.region
})
}
resource "aws_apigatewayv2_deployment" "api_gateway_deployment" {
api_id = aws_apigatewayv2_api.api_gateway.id
description = "API Gateway deployment"
triggers = {
redeployment = sha1(join(
",", tolist([
templatefile("${path.module}/files/api-gateway-openapi.yaml", {
gocardless_function_arn = module.gocardless_create_requisition_lambda.lambda_function_arn,
cognito_user_pool_id = aws_cognito_user_pool.pool.id,
cognito_app_client_id = aws_cognito_user_pool_client.client.id,
region = var.region
}),
jsonencode(aws_apigatewayv2_stage.api_gateway_default_stage)
])
))
}
}
resource "aws_apigatewayv2_stage" "api_gateway_default_stage" {
api_id = aws_apigatewayv2_api.api_gateway.id
name = "default"
auto_deploy = true
default_route_settings {
throttling_rate_limit = 10
throttling_burst_limit = 10
}
}
</code>
<code>resource "aws_apigatewayv2_api" "api_gateway" { name = "API Gateway" version = "0.1.0" protocol_type = "HTTP" description = "API gateway" body = templatefile("${path.module}/files/api-gateway-openapi.yaml", { gocardless_function_arn = module.gocardless_create_requisition_lambda.lambda_function_arn, cognito_user_pool_id = aws_cognito_user_pool.pool.id, cognito_app_client_id = aws_cognito_user_pool_client.client.id, region = var.region }) } resource "aws_apigatewayv2_deployment" "api_gateway_deployment" { api_id = aws_apigatewayv2_api.api_gateway.id description = "API Gateway deployment" triggers = { redeployment = sha1(join( ",", tolist([ templatefile("${path.module}/files/api-gateway-openapi.yaml", { gocardless_function_arn = module.gocardless_create_requisition_lambda.lambda_function_arn, cognito_user_pool_id = aws_cognito_user_pool.pool.id, cognito_app_client_id = aws_cognito_user_pool_client.client.id, region = var.region }), jsonencode(aws_apigatewayv2_stage.api_gateway_default_stage) ]) )) } } resource "aws_apigatewayv2_stage" "api_gateway_default_stage" { api_id = aws_apigatewayv2_api.api_gateway.id name = "default" auto_deploy = true default_route_settings { throttling_rate_limit = 10 throttling_burst_limit = 10 } } </code>
resource "aws_apigatewayv2_api" "api_gateway" {
  name          = "API Gateway"
  version       = "0.1.0"
  protocol_type = "HTTP"
  description   = "API gateway"
  body = templatefile("${path.module}/files/api-gateway-openapi.yaml", {
    gocardless_function_arn = module.gocardless_create_requisition_lambda.lambda_function_arn,
    cognito_user_pool_id    = aws_cognito_user_pool.pool.id,
    cognito_app_client_id   = aws_cognito_user_pool_client.client.id,
    region                  = var.region
  })
}

resource "aws_apigatewayv2_deployment" "api_gateway_deployment" {
  api_id      = aws_apigatewayv2_api.api_gateway.id
  description = "API Gateway deployment"

  triggers = {
    redeployment = sha1(join(
      ",", tolist([
        templatefile("${path.module}/files/api-gateway-openapi.yaml", {
          gocardless_function_arn = module.gocardless_create_requisition_lambda.lambda_function_arn,
          cognito_user_pool_id    = aws_cognito_user_pool.pool.id,
          cognito_app_client_id   = aws_cognito_user_pool_client.client.id,
          region                  = var.region
        }),
        jsonencode(aws_apigatewayv2_stage.api_gateway_default_stage)
      ])
    ))
  }
}

resource "aws_apigatewayv2_stage" "api_gateway_default_stage" {
  api_id      = aws_apigatewayv2_api.api_gateway.id
  name        = "default"
  auto_deploy = true
  default_route_settings {
    throttling_rate_limit  = 10
    throttling_burst_limit = 10
  }
}

I tried enabling CORS manually through “ClickOps” in the AWS console. The request from my front end immediately started working (OPTIONS, followed by POST).

I’m expecting the x-amazon-apigateway-cors (https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions-cors-configuration.html) section to already be enabling these CORS options without me having to do them manually. By doing them manually, they also get overriden every time I re-run terraform apply.

What should I be change in the OpenAPI file to enable the CORS configuration in API GW?

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật