Circular dependency issue when using OpenAPI spec for API Gateway with an Authoriser

The context:

  • I want to create an API Gateway
  • I want to specify the different routes using an OpenAPI yaml file
  • I want to setup a Cognito user pool authoriser, so that only logged in users can access the API

All this is relatively standard, the problem is: in order to create the authoriser, I need to reference the API Gateway, and in order to create the gateway, I need to reference the authoriser. So, we have a cyclical dependency, and terraform complains and blocks the deployment.

data "template_file" "apig_template" {
  template = file("${var.template_path_file}/${var.template_name}")

  vars = merge(
    var.apig_template_variables,
    {
      arnCognitoAuthorizer = "${aws_api_gateway_authorizer.eva_ui_authorizer.arn}"
    }
  )
}

resource "aws_api_gateway_rest_api" "apig" {
  name           = "${var.project_name}-${var.environment}-${var.apig_name}"
  description    = var.description
  api_key_source = "HEADER"

  body = data.template_file.apig_template.rendered
}

resource "aws_api_gateway_authorizer" "eva_ui_authorizer" {
  name            = "${var.project_name}-${var.environment}-${var.apig_name}-authorizer"
  rest_api_id     = aws_api_gateway_rest_api.apig.id
  type            = "COGNITO_USER_POOLS"
  identity_source = "method.request.header.Authorization"
  provider_arns   = [var.cognito_user_pool_arn]
}

with an OpenAPI yaml file:

openapi: "3.0.1"
info:
  title: "${name}-api-gw"
  version: "0.1.0"
components:
  securitySchemes:
    CognitoAuthorizer:
      type: "apiKey"
      name: "Authorization"
      in: "header"
      x-amazon-apigateway-authtype: "cognito_user_pools"
      x-amazon-apigateway-authorizer:
        type: "cognito_user_pools"
        authorizerUri: ${arnCognitoAuthorizer}
        identitySource: "method.request.header.Authorization"
        authorizerResultTtlInSeconds: 300
paths:
  /read-data:
    post:
      operationId: Get Reference Data
      summary: Get Reference Data
      responses: "200"
      security:
        - CognitoAuthorizer: []
      x-amazon-apigateway-integration:
        payloadFormatVersion: "1.0"
        type: "aws_proxy"
        httpMethod: "POST"
        uri: "arn:aws:apigateway:eu-west-1:lambda:path/2015-03-31/functions/${arnLambdaReadRefData}/invocations"
        timeoutInMilis: 30000

Does anyone have any thoughts on how I can resolve this problem? Thank you

Hi @rafaelmarques7!

I’m quite rusty on API Gateway so I’m guessing a bit here and can’t promise my answers will be accurate. If I’m making some incorrect assumptions then someone with more recent experience will speak up.

My memory of using API Gateway with an OpenAPI specification is that the OpenAPI specification entirely replaces all of the other explicit resources, because the API Gateway API automatically creates all of the other objects itself by parsing what’s in the API definition.

Therefore in your case I’d expect to be able to remove the aws_api_gateway_authorizer resource altogether, because the x-amazon-apigateway-authorizer property in your OpenAPI YAML contains all of the same information and so that should allow the API Gateway API to automatically create the authorizer itself as part of creating the Rest API object.

However, I’m not 100% sure that this works for authorizers in particular. In particular, I don’t think I ever used a Cognito authorizer; I only ever used Lambda-based authorizers. Can you give it a try and see if it works? If not, then hopefully someone else will have a different idea.

If that approach doesn’t work then the other thing I’d consider would be to remove the section from the OpenAPI definition and rely exclusively on the separate resource. Either way it seems like you shouldn’t have to state the same information in two different places.