Terraform使用OpenAPI定义API Gateway与Cognito授权器时的循环依赖问题
API Gateway与Cognito授权器的Terraform循环依赖问题解决
问题背景
- 目标创建一个API Gateway
- 通过OpenAPI YAML文件定义路由规则
- 配置Cognito用户池授权器,限制仅已登录用户可访问API
以上操作属于常规流程,但遇到了循环依赖问题:创建授权器需要引用API Gateway的ID,而创建API Gateway又需要在OpenAPI定义中引用授权器的ARN,导致Terraform报错无法部署。
现有代码
Terraform配置
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] }
OpenAPI YAML定义
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
错误信息
执行terraform init时出现以下循环依赖错误:
│ Error: Cycle: module.api_gateway_slips_website.aws_api_gateway_authorizer.eva_ui_authorizer, module.api_gateway_slips_website.data.template_file.apig_template, module.api_gateway_slips_website.aws_api_gateway_rest_api.apig
解决方案
要解决循环依赖,核心是打破API Gateway与授权器之间的双向直接引用,以下是两种可行方案:
方案一:分阶段部署,先创建基础API再更新配置
- 先创建不含授权器配置的基础API Gateway;
- 基于已创建的API Gateway创建Cognito授权器;
- 渲染包含授权器ARN的完整OpenAPI模板,更新API Gateway的配置。
修改后的Terraform代码示例:
# 1. 创建基础API(使用不含授权器的初始模板) resource "aws_api_gateway_rest_api" "apig_base" { name = "${var.project_name}-${var.environment}-${var.apig_name}" description = var.description api_key_source = "HEADER" # 初始模板仅定义路由结构,不包含授权器配置 body = file("${var.template_path_file}/${var.template_name_initial}") } # 2. 创建Cognito授权器,引用基础API的ID 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_base.id type = "COGNITO_USER_POOLS" identity_source = "method.request.header.Authorization" provider_arns = [var.cognito_user_pool_arn] } # 3. 渲染包含授权器ARN的完整OpenAPI模板 data "template_file" "apig_template_full" { template = file("${var.template_path_file}/${var.template_name}") vars = merge( var.apig_template_variables, { arnCognitoAuthorizer = aws_api_gateway_authorizer.eva_ui_authorizer.arn } ) # 强制依赖授权器创建完成 depends_on = [aws_api_gateway_authorizer.eva_ui_authorizer] } # 4. 更新API Gateway为完整配置 resource "aws_api_gateway_rest_api" "apig_updated" { name = "${var.project_name}-${var.environment}-${var.apig_name}" description = var.description api_key_source = "HEADER" rest_api_id = aws_api_gateway_rest_api.apig_base.id body = data.template_file.apig_template_full.rendered lifecycle { create_before_destroy = true } }
方案二:在OpenAPI中使用授权器名称关联,避免依赖ARN
在OpenAPI配置中,将authorizerUri替换为authorizerId或直接使用授权器名称,让API Gateway自动关联同实例下的授权器,从而避免直接引用授权器ARN。
修改后的OpenAPI YAML:
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" # 使用授权器名称关联,而非ARN authorizerId: "${authorizerName}" 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
对应的Terraform模板变量调整:
data "template_file" "apig_template" { template = file("${var.template_path_file}/${var.template_name}") vars = merge( var.apig_template_variables, { # 传递授权器名称而非ARN authorizerName = aws_api_gateway_authorizer.eva_ui_authorizer.name } ) } 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] }
注:方案二需要确保授权器名称在当前API Gateway实例中唯一,若仍出现依赖问题,可添加
depends_on强制授权器先于API更新完成。
内容的提问来源于stack exchange,提问作者Rafael Marques
相关产品推荐
相关产品推荐

