如何通过Terraform部署带路径通配符的GCP API Gateway配置?
问题:GCP API Gateway带路径参数的Terraform部署报错
我通过Terraform部署GCP API Gateway配置,因需为后端URL使用变量,将OpenAPI文档定义在tf文件中。当路径使用带参数的格式(如/devices/{deviceID})时部署报错,不使用参数(如/device)则可正常运行。相关资源配置如下:
resource "google_api_gateway_api_config" "device_management" { provider = google-beta project = var.project_id api = google_api_gateway_api.device_management.api_id api_config_id_prefix = "${google_api_gateway_api.device_management.api_id}-" gateway_config { backend_config { google_service_account = google_service_account.device_registration.id } } openapi_documents { document { path = "${google_api_gateway_api.device_management.api_id}_api_spec.yaml" contents = base64encode( jsonencode( { swagger : "2.0" info : { title : "Device Registration API" description : "Register devices and get their private keys" version : "0.0.1" } schemes : ["https"] produces : ["application/json"] x-google-allow : "configured" securityDefinitions : { api_key : { type : "apiKey" name : "apiKey" in : "query" } oauth2 : { authorizationUrl : "" flow : "implicit" type : "oauth2" x-google-issuer : google_service_account.device_registration.email x-google-jwks_uri : "https://www.googleapis.com/robot/v1/metadata/x509/${google_service_account.device_registration.email}" x-google-audiences : "device-registration" } } security : [ { oauth2 : [] } ] paths : { "/devices/{deviceID}" : { post : { summary : "Register a new device" operationId : "registerDevice" x-google-backend : { address : google_cloudfunctions_function.device_management_register_device.https_trigger_url } responses : { 201 : { description : "Device registered succesfully" schema : { type : "string" } } } } } } } ) ) } } }
部署时触发以下错误:
Error: Error creating ApiConfig: googleapi: Error 400: Cannot convert to service config. │ 'location: "unknown location" │ kind: ERROR │ message: "http: undefined field 'deviceID' on message 'google.protobuf.Empty'." │ │ location: "unknown location" │ kind: ERROR │ message: "http: undefined field 'deviceID' on message 'google.protobuf.Empty'." │ │ location: "device-registration_api_spec.yaml" │ message: "apiKey 'apiKey' is ignored. Only apiKey with 'name' as 'key' and 'in' as 'query', or 'name' as 'api_key' and 'in' as 'query', or 'name'as 'x-api-key' and 'in' as 'header' are supported" │ │ location: "device-registration_api_spec.yaml: Operation 'post' in path '/devices/{deviceID}'" │ message: "Operation does not require an API key; callers may invoke the method without specifying an associated API-consuming project. To enable API key all the SecurityRequirement Objects (https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-requirement-object) inside security definition must reference at least one SecurityDefinition of type : 'apiKey'." │ │ location: "device-registration_api_spec.yaml: Operation 'get' in path '/devices/{deviceID}/key'" │ message: "Operation does not require an API key; callers may invoke the method without specifying an associated API-consuming project. To enable API key all the SecurityRequirement Objects (https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-requirement-object) inside security definition must reference at least one SecurityDefinition of type : 'apiKey'." │ ' │ com.google.apps.framework.request.BadRequestException: Cannot convert to service config. │ 'location: "unknown location" │ kind: ERROR │ message: "http: undefined field 'deviceID' on message 'google.protobuf.Empty'." │ │ location: "unknown location" │ kind: ERROR │ message: "http: undefined field 'deviceID' on message 'google.protobuf.Empty'." │ │ location: "device-registration_api_spec.yaml" │ message: "apiKey 'apiKey' is ignored. Only apiKey with 'name' as 'key' and 'in' as 'query', or 'name' as 'api_key' and 'in' as 'query', or 'name'as 'x-api-key' and 'in' as 'header' are supported" │ │ location: "device-registration_api_spec.yaml: Operation 'post' in path '/devices/{deviceID}'" │ message: "Operation does not require an API key; callers may invoke the method without specifying an associated API-consuming project. To enable API key all the SecurityRequirement Objects (https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-requirement-object) inside security definition must reference at least one SecurityDefinition of type : 'apiKey'." │ │ location: "device-registration_api_spec.yaml: Operation 'get' in path '/devices/{deviceID}/key'" │ message: "Operation does not require an API key; callers may invoke the method without specifying an associated API-consuming project. To enable API key all the SecurityRequirement Objects (https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-requirement-object) inside security definition must reference at least one SecurityDefinition of type : 'apiKey'." │ ' │ │ with module.iot_backend.google_api_gateway_api_config.device_management, │ on ../../modules/iot_backend/device_management.tf line 92, in resource "google_api_gateway_api_config" "device_management": │ 92: resource "google_api_gateway_api_config" "device_management" { │ ╵
解决方案
1. 显式定义路径参数(解决核心报错)
GCP API Gateway要求OpenAPI规范必须显式声明路径参数,否则会认为参数未定义。在对应接口的post节点下添加parameters字段,明确参数的名称、位置、必填性和类型:
parameters: [ { name: "deviceID", in: "path", required: true, type: "string" } ]
2. 修正API Key配置格式
GCP仅支持三种API Key格式,原配置的name: "apiKey"不符合要求,修改为以下任一合法格式:
api_key: { type: "apiKey", name: "x-api-key", // 推荐用header传递的格式 in: "header" }
3. 调整安全验证规则
如果需要强制API Key验证,需在security数组中同时包含oauth2和api_key的要求;如果不需要API Key验证,可直接删除api_key相关的securityDefinitions:
- 同时启用OAuth2和API Key验证:
security: [ { oauth2: [], api_key: [] } ]
- 仅保留OAuth2验证:删除
securityDefinitions中的api_key节点,保留原security配置即可。
完整修正后的OpenAPI配置片段
整合修改后的内容,对应的paths部分如下:
paths : { "/devices/{deviceID}" : { post : { summary : "Register a new device" operationId : "registerDevice" parameters: [ { name: "deviceID", in: "path", required: true, type: "string" } ] x-google-backend : { address : google_cloudfunctions_function.device_management_register_device.https_trigger_url } responses : { 201 : { description : "Device registered succesfully" schema : { type : "string" } } } } } }
内容的提问来源于stack exchange,提问作者Mr P
相关产品推荐
相关产品推荐

