Google Cloud Platform swagger openapi config yaml file isn't properly rejecting requests that don't contain my api key in the header - authentication

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>'

Related

GCP API Gateway with an API Key fails with 403 error stating ... .cloud.goog is not enabled for the project

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!

How to use curl command to make a PUT request with api key and secret as authorisation method?

I want to execute an api call to a Saas platform. When I generate the api keys with my account in the platform then i get 2 things:-
api key id : 631f39f37564not/631f39f475646real/635c1192756key
Secret key : -----BEGIN RSA PRIVATE KEY----- ABCDE1234 -----END RSA PRIVATE KEY-----
I am executing the api with my following bash script
#!/bin/bash
export FIELD=90
HOST=https://example.com
PUT_BODY="{\"value\":\"${FIELD}\",\"valueObjectType\":\"String\"}"
curl -sk -X PUT "${HOST}/api/v3/xyz/endpoint" \
-H 'content-type: application/json' \
-H 'x-requested-with: XMLHttpRequest' \
-H "referer: ${HOST}/" \
-H "Authorization: apikey 631f39f37564not/631f39f475646real/635c1192756key" \
-d"${PUT_BODY}" | jq '.'
I get 401 unauthorized error
{
"error": {
"status_code": 401,
"status": "Unauthorized"
}
}
Is -H "Authorization: apikey 631f39f37564not/631f39f475646real/635c1192756key" the correct way to specify the apikey or do i need to append secret also in the request?
Edit: I cannot use bearer token, need to use api key only.
I converted your curl to PHP and changed the URL to my test site that response with the request header. Because you did not provide a link to the api documentation, I do not know if the request header is what they want.
I find the output request header is the first step in trouble shooting curl requests.
This is what my test site received:
BODY=
${PUT_BODY}
BODY urlencoded
${PUT_BODY}
Your request headers:
Content-Length: 11
Content-Type: application/json
Accept: */*
Referer: ${HOST}/
X-Requested-With: XMLHttpRequest
What is missing? The authorization not included?
So let's try another way.
When the is a key and secret they are usually posted as post data in a POST request.
Yours is a PUT request? No documentation.
When I tried your
"Authorization: apikey 631f39f37564not/631f39f475646real/635c1192756key"
curl ignored it and it was not in the request header.
Why the application/json content type header?
I would expect
Content-Type: application/x-www-form-urlencoded
And I would expect the key and secret to be posted as post data:
-d 'key=<key>&secret=<secret>'
But no documentation.
If it is supposed to be a PUT then the key and secret would be in the query string following the URL.
${HOST}/api/v3/xyz/endpoint?key=<key?&secret=<secret>"
Your api key does not look good. Again no documentation.
The secret is even not in your request. You say "need to use api key only".
If that is true, why does the secret exist?

How to enable a kv secret engine in vault using HTTP APIs

I am trying to enable kv secret engine at secret path in my vault setup..
I can easily do it using CLI
vault secrets enable -path=secret kv
But I have to make it work using Vault's HTTP APIs.
I have gone through documentation but could not find any endpoint for the above command.
Thanks in advance
This is covered under the System Backend/sys/mounts API reference page.
Issue a POST request to /v1/sys/mounts/<mountpoint> with a payload containing the type (kv) and various configuration options. For KV, you probably want to specify version: 2 (or type kv-v2) unless you want to stick to V1.
See the above link for details on the possible parameters.
Here is the example from the docs:
payload.json:
{
"type": "aws",
"config": {
"force_no_cache": true
}
}
Request:
$ curl \
--header "X-Vault-Token: ..." \
--request POST \
--data #payload.json \
http://127.0.0.1:8200/v1/sys/mounts/my-mount

Swagger/OpenAPI Bearer auth with custom header name

I'm defining (small parts of) an existing API (Samanage) using OpenAPI to assist with some integration work.
I need to authenticate using Bearer auth, but by sending the token in a header other than Authorize.
The server expects Bearer authentication in a header named X-Samanage-Authorization like this example:
curl -H "X-Samanage-Authorization: Bearer <TokenGoesHere>" -H 'Accept: application/vnd.samanage.v2.1+json' -H 'Content-Type: application/json' -X GET https://api.samanage.com/incidents.json
I'm aware of https://swagger.io/docs/specification/authentication/bearer-authentication/, but it doesn't seem to help me fully.
This (OpenAPI 3)
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
...
security:
- bearerAuth: []
Results in an authentication header named the default (Authorization)
curl -X GET "https://api.samanage.com/incidents/12341234.json" -H "accept: application/json" -H "Authorization: Bearer <TokenGoesHere>"
Which then fails (401).
I feel like I want this:
components:
securitySchemes:
bearerAuth:
type: http
name: X-Samanage-Authorization
in: header
scheme: bearer
But that fails validation in Swagger Editor as I believe a type of http doesn't allow the name component (like a type of apiKey would). I couldn't quite make full sense of the docs here to be honest.
I did read about Specification Extensions but being completely new to OpenAPI, I couldn't find any examples on how to actually implement what I need.
Any insight much appreciated!
type: http is for HTTP authentication as defined by RFC 7235 and the IANA HTTP Authentication Scheme Registry. HTTP authentication, by definition, uses the Authorization header.
To use a custom header name, you need to define it as an API key (type: apiKey):
components:
securitySchemes:
bearerAuth:
type: apiKey
name: X-Samanage-Authorization
in: header
Note that since it's a non-standard Bearer scheme, the clients will need to manually add the "Bearer " prefix to the token value. For example, when you click "Authorize" in Swagger UI, you'll need to enter "Bearer TOKEN" instead of just "TOKEN".

What is -u from cURL when adding an authorization header to an http request

I am trying to test one of Mix Panel's API endpoints. I'm using Postman to do this, and in Mix Panel's documentation they use cURL to show you how to make the request. When entering the URL, and the POST data for the request, it works in the sense that it hits the right place, and tells me that I need to be authenticated by adding an authorization header. What I'm confused on is, what should the key be for the header ? in their cURL example its -u API_SECRET, so would the authorization header key be 'username' ?
From documentation
# this uses a test project API secret, replace ce08d087255d5ceec741819a57174ce5
# with your own API secret
curl https://mixpanel.com/api/2.0/jql \
-u ce08d087255d5ceec741819a57174ce5: \
--data-urlencode params='{"from_date":"2016-01-01", "to_date": "2016-01-07"}' \
--data-urlencode script='function main(){ return Events(params).groupBy(["name"], mixpanel.reducer.count()) }'
If I wanted to create an AJAX query for example
$.ajax({
method: 'POST',
url: 'https://mixpanel.com/api/2.0/jql',
data: {
'params': '{"from_date":"2016-01-01", "to_date": "2016-01-07"}',
'script': '\'function main(){ return Events(params).groupBy(["name"], mixpanel.reducer.count()) }\''
},
headers: {
<WHAT GOES HERE>: API_SECRET
}
}).then(function success(response){
console.log('SUCCESS');
console.log(response)
}, function error(response){
console.log('There was an error running JQL');
console.log(response.error)
});
In this case, your API_SECRET is the username and there is no password. So using curl -u <API_SECRET>: without any "username" key is correct.
From the mixpanel documentation on an example call https://mixpanel.com/help/reference/data-export-api
Authorization steps The Data Export API accepts Basic access
authentication over HTTPS as an authorization method. To make an
authorized request, put your project's API Secret in the "username"
field of the Basic access authentication header. Make sure you use
HTTPS and not HTTP - our API rejects requests made over HTTP, since
this sends your API Secret over the internet in plain text.
Examples Here's an example of a properly-authenticated request made
with cURL:
curl https://mixpanel.com/api/2.0/segmentation/ \
-u YOUR_API_SECRET: \
-d from_date="2016-02-11" -d to_date="2016-02-11" -d event="Viewed Page"