First things first, let me show you some of my gcloud settings. When I run gcloud config list, this is my output:
[core]
account = <SERVICE ACCOUNT NAME>#<PROJECT NAME>.iam.gserviceaccount.com
disable_usage_reporting = True
project = <PROJECT NAME>
Your active configuration is: [default]
When I run gcloud services list, this is my output:
apigateway.googleapis.com API Gateway API
artifactregistry.googleapis.com Artifact Registry API
bigquery.googleapis.com BigQuery API
bigquerymigration.googleapis.com BigQuery Migration API
bigquerystorage.googleapis.com BigQuery Storage API
cloudapis.googleapis.com Google Cloud APIs
cloudbuild.googleapis.com Cloud Build API
clouddebugger.googleapis.com Cloud Debugger API
cloudfunctions.googleapis.com Cloud Functions API
cloudresourcemanager.googleapis.com Cloud Resource Manager API
cloudtrace.googleapis.com Cloud Trace API
containerregistry.googleapis.com Container Registry API
datastore.googleapis.com Cloud Datastore API
eventarc.googleapis.com Eventarc API
iam.googleapis.com Identity and Access Management (IAM) API
iamcredentials.googleapis.com IAM Service Account Credentials API
logging.googleapis.com Cloud Logging API
monitoring.googleapis.com Cloud Monitoring API
oslogin.googleapis.com Cloud OS Login API
pubsub.googleapis.com Cloud Pub/Sub API
run.googleapis.com Cloud Run Admin API
secretmanager.googleapis.com Secret Manager API
servicecontrol.googleapis.com Service Control API
servicemanagement.googleapis.com Service Management API
serviceusage.googleapis.com Service Usage API
source.googleapis.com Legacy Cloud Source Repositories API
sql-component.googleapis.com Cloud SQL
storage-api.googleapis.com Google Cloud Storage JSON API
storage-component.googleapis.com Cloud Storage
storage.googleapis.com Cloud Storage API
sts.googleapis.com Security Token Service API
I have an API Gateway with the following config file:
swagger: '2.0'
info:
title: <API TITLE>
description: API Gateway First for Sphrn Testing
version: 1.0.0
securityDefinitions:
api_key_header:
type: apiKey
name: x-api-key
in: header
schemes:
- https
produces:
- application/json
paths:
/entrypoint1:
post:
summary: Simple echo service
operationId: <OPERATION ID HERE>
x-google-backend:
address: https://<CLOUD FUNCTION NAME>-<STRING I DON'T RECOGNIZE>-uc.a.run.app
security:
- api_key_header: []
responses:
'200':
description: OK
I call the api from my command line with this script:
curl --location --request POST 'https://<API CALLABLE ENDPOINT>.uc.gateway.dev/endpoint1' \
--header 'X-goog-api-key: <MY API KEY HERE>' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
"name": "Test1"
}'
but it fails with this in my terminal:
{"code":403,"message":"PERMISSION_DENIED:API <SERVICE ACCOUNT NAME>-<STRING I DON'T RECOGNIZE>.apigateway.<PROJECT NAME>.cloud.goog is not enabled for the project."}
My API key looks like this:
And I went into the logs explorer for the API Gateway endpoint and this is the more detailed logs from my 403 failed curl command (sanitized for identifying information of course):
{
"httpRequest": {
"latency": "0.040s",
"protocol": "http",
"remoteIp": "<MY IP ADDRESS>",
"requestMethod": "POST",
"requestSize": "1053",
"requestUrl": "/endpoint1",
"responseSize": "346",
"status": 403
},
"insertId": "<LONG GUID LOOKING STRING>#a1",
"jsonPayload": {
"api_key": "<MY API KEY>",
"api_key_state": "NOT ENABLED",
"api_method": "1.<API ID>_<STRING I DON'T RECOGNIZE>_apigateway_<PROJECT NAME>_cloud_goog.<OPERATIONID FROM CONFIG YAML>",
"api_name": "1.<API ID>_<STRING I DON'T RECOGNIZE>_apigateway_<PROJECT NAME>_cloud_goog",
"api_version": "1.0.0",
"error_cause": "API <API ID>_<STRING I DON'T RECOGNIZE>.apigateway.<PROJECT NAME>.cloud.goog is not enabled for the project.",
"http_status_code": 403,
"location": "us-central1",
"log_message": "1.<API ID>_<STRING 1 I DON'T RECOGNIZE>_apigateway_<PROJECT NAME>_cloud_goog.<OPERATIONID FROM CONFIG YAML> is called",
"producer_project_id": "<PROJECT NAME>",
"response_code_detail": "service_control_check_error{SERVICE_NOT_ACTIVATED}",
"service_agent": "ESPv2/2.40.0",
"service_config_id": "<CONFIGURATION ID>",
"timestamp": "<TIMESTAMP HERE AS DECIMAL>"
},
"logName": "projects/<PROJECT NAME>/logs/<API ID>_<STRING I DON'T RECOGNIZE>.apigateway.<PROJECT NAME>.cloud.goog%2Fendpoints_log",
"receiveTimestamp": "<TIMESTAMP HERE AS STRING>",
"resource": {
"labels": {
"location": "us-central1",
"method": "1.<API ID>-<STRING I DON'T RECOGNIZE>_apigateway_<PROJECT NAME>_cloud_goog.<OPERATIONID FROM CONFIG YAML>",
"project_id": "<PROJECT NAME>",
"service": "<API ID>-<STRING I DON'T RECOGNIZE>.apigateway.<PROJECT NAME>.cloud.goog",
"version": "1.0.0"
},
"type": "api"
},
"severity": "ERROR",
"timestamp": "<TIMESTAMP HERE AS STRING>"
}
So how do I get this curl to succeed...? I'm assuming it's a permissions issue, but what permission does my service account not have?
When I run:
gcloud projects get-iam-policy <PROJECT ID> \
--flatten="bindings[].members" \
--format='table(bindings.role)' \
--filter="bindings.members:<SERVICE ACCOUNT NAME>#<PROJECT NAME>.iam.gserviceaccount.com"
I get this output:
ROLE
roles/cloudfunctions.serviceAgent
roles/serviceusage.serviceUsageViewer
I had to enable the service by using my actual "master" Gmail account with which I created the GCP project and enabling the service <SERVICE ACCOUNT NAME>-....apigateway.<PROJECT NAME>.cloud.goog via gcloud commands. Then I had 1 more problem where I didn't enable the operationId listed in my openapi config yaml file in the API key restrictions menu.
I'm assuming anyone reading this has already logged in with their service account via gcloud auth login and activated their relevant service account with gcloud auth activate-service-account <SERVICE ACCOUNT NAME>#<PROJECT NAME>.iam.gserviceaccount.com --key-file=/path/to/keyfile.json
Enable Service Fix
I switched my gcloud account to my "master" account with gcloud config set account <MASTER GCLOUD ACCOUNT NAME>#gmail.com, then:
gcloud services enable <SERVICE ACCOUNT NAME>-....apigateway.<PROJECT NAME>.cloud.goog \
--project=<PROJECT ID (THE NUMBER NOT THE TEXT NAME>
This made it so calling the API with my API key in the header give me a new error {"message":"PERMISSION_DENIED: The API targeted by this request is invalid for the given API key.","code":403}
operationId API Restriction Menu Fix
I had to enable the operationId listed in my openapi config yaml file in the API key restrictions menu. After that it appeared in the "Selected APIs" section of the API Key Credentials page:
After making this change, my curl request:
curl --location --request POST 'https://<API CALLABLE ENDPOINT>.uc.gateway.dev/endpoint1' \
--header 'X-goog-api-key: <MY API KEY HERE>' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
"name": "Test1"
}'
worked perfectly!
I have this config file for my Google Cloud Platform API Gateway endpoint:
swagger: '2.0'
info:
title: api-1
description: API Gateway First for Testing
version: 1.0.0
securityDefinitions:
api_key_header:
type: apiKey
name: key
in: header
schemes:
- https
produces:
- application/json
paths:
/endpoint1:
post:
summary: Simple echo service
operationId: echo-1
x-google-backend:
address: https://<CLOUD FUNCTION GEN 2 NAME>-<MORE IDENTIFYING INFO>-uc.a.run.app
security:
- api_key_header: []
responses:
'200':
description: OK
As you can see, I'm trying to require an API key in order for my server to call the API safely. In my opinion, an API key is necessary for security to prevent someone from figuring out my endpoint and spaming the GCP function.
I created an API key to use for this API endpoint (I censored a lot of data for privacy reasons):
I tried to call the endpoint in Postman like this:
curl --location --request POST 'https://<API CALLABLE ENDPOINT>.uc.gateway.dev/endpoint1' \
--header 'X-goog-api-key: <MY API KEY HERE>' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
"name": "Test1"
}'
The problem is that the Postman request works... always lol. No matter what incorrect API key I use for the header...
I noticed that there is no place where I'm directly referencing my API key name. I'm not sure where I'd put this. How do I alter this API Gateway to properly reject requests that do not contain the correct API key?
All available formats are specified on this documentation.
When requesting Api Key through the header, you have to match a specific name which is "x-api-key".
So for your openapi file, it gives the following securityDefinitions:
securityDefinitions:
api_key_header:
type: "apiKey"
name: "x-api-key"
in: "header"
And the curl request should have this header then:
--header 'x-api-key: <MY API KEY HERE>'
I deployed 2 versions of openapi.yaml file to Google Cloud Endpoint using the Cloud Endpoint's versioning feature(i.e gcloud endpoints services deploy openapi_v1.yaml openapi_v2.yaml). Each version of the yaml file contains a version number and basepath different from the other, one endpoint that use api-key authentication, and definition for api-key authentication tag. After deployed to Endpoint, the configuration shows both yaml file, however deploying an api to Cloud Run ESPv2 using this configuration will only have api-key authentication turned on for the newer version.
Does anyone know if this is a known bug, or there is something else I need to do to enable authentication for all versions?
The .yaml file looks like the following. The two versions I used to test on are identical except version and bathpath:
swagger: "2.0"
info:
description: "This API is used to connect 3rd-party ids to a common user identity"
version: "1.0"
title: "****"
host: "uie-dot-user-id-exchange.appspot.com"
basePath: "/v1"
...
- "https"
x-google-allow: all
paths:
...
/ids/search:
get:
operationId: "id_search"
produces:
- "application/json"
security:
- api_key: []
tags:
- "Ids"
summary: "Privileged endpoint. Provide any id (3rd party or otherwise) and get a hash of all ids associated with it."
parameters:
- in: "query"
name: "id_type"
description: "Type of id to search"
required: true
type: string
- in: "query"
name: "id_value"
description: "Value of id to search"
required: true
type: string
responses:
200:
description: "AssociatedIdsHash"
schema:
$ref: '#/definitions/AssociatedIdsHash'
400:
description: "Bad request. Requires both id_type and id_value query parameters."
401:
description: "Unauthorized. Please provide a valid api-key in the \"api-key\" header."
404:
description: "Not found - no entry found for key provided"
...
################ SECURITY DEFINITIONS ################
securityDefinitions:
# This section configures basic authentication with an API key.
api_key:
type: "apiKey"
name: "key"
in: "query"
I tried to make the api-key work in v1 and v2 but it only works in version 2.
I have a Swagger 2.0 file that has an auth mechanism defined but am getting errors that tell me that we aren't using it. The exact error message is “Security scheme was defined but never used”.
How do I make sure my endpoints are protected using the authentication I created? I have tried a bunch of different things but nothing seems to work.
I am not sure if the actual security scheme is defined, I think it is because we are using it in production.
I would really love to have some help with this as I am worried that our competitor might use this to their advantage and steal some of our data.
swagger: "2.0"
# basic info is basic
info:
version: 1.0.0
title: Das ERP
# host config info
# Added by API Auto Mocking Plugin
host: virtserver.swaggerhub.com
basePath: /rossja/whatchamacallit/1.0.0
#host: whatchamacallit.lebonboncroissant.com
#basePath: /v1
# always be schemin'
schemes:
- https
# we believe in security!
securityDefinitions:
api_key:
type: apiKey
name: api_key
in: header
description: API Key
# a maze of twisty passages all alike
paths:
/dt/invoicestatuses:
get:
tags:
- invoice
summary: Returns a list of invoice statuses
produces:
- application/json
operationId: listInvoiceStatuses
responses:
200:
description: OK
schema:
type: object
properties:
code:
type: integer
value:
type: string
securityDefinitions alone is not enough, this section defines available security schemes but does not apply them.
To actually apply a security scheme to your API, you need to add security requirements on the root level or to individual operations.
security:
- api_key: []
See the API Keys guide for details.
I am looking for guidance on how to pass the API Gateway context variable (for example: $context.RequestTime) to the proxy lamba.
Basically I want to send the time request has reached in Api gateway to my lambda proxy method as a request header.
Note that I am using serverless framework (serverless.com)
I tried the following but it does not work
events:
- http:
path: /{proxy+}
method: ANY
request:
parameters:
paths:
proxy: true
headers:
requestTime: $context.requestTime