Express-Gateway: missing scopes under egContext - apiEndpoint.scopes - express-gateway

I want to force the add of a filed in the req.body, according to the scope of the credentials. I have 2 Apps (App1 and App2), and based on who is using my API, I want to programmatically add a field in the req. So credentials of App1 has scope app1, and app2 in App2's scopes.
Moreover, I have 2 Environments, with different endpoints. Both App has access to both Ends (using different credentials). So I first choose the Env (using dev_env or my_env scope), then I verify which App is accessing (checking app1 or app2 scope).
To do that, I use expression apiEndpoint.scopes.indexOf('app1')>=0. that actually is not working, since the condition is always false. So for debugging purpose, I put the content of apiEndpoint.scopes as additional field in the req.body, to see what there is in that.
And I see that apiEndpoint.scopes has just ["my_env"], not "app1". Why?
So I have
http:
port: ${PORT:-8080}
host: ${HOST:-localhost}
apiEndpoints:
myEndpoint:
host: "*"
scopes: ["my_env"] # I explain just this one here
devEndpoint:
host: "*"
scopes: ["dev_env"]
serviceEndpoints:
myEndpoint:
url: 'https://myserver'
policies:
- basic-auth
- cors
- expression
- key-auth
- request-transformer
- rewrite
- oauth2
- proxy
- rate-limit
pipelines:
myEndpoint:
apiEndpoints:
- myEndpoint
policies:
- request-transformer:
-
condition:
name: allOf
conditions:
- # check if scope 'app1' is present. expression not working
#name: expression
#expression: "apiEndpoint.scopes.indexOf('app1')>=0"
action:
body:
add:
available_scopes: "apiEndpoint.scopes" # debug of available scopes.
And the content of req.body is
{"available_scopes": ["my_env"]}
'app1' is missing!
==== update 1
If in req.body.available_scopes field I put "consumer", I got this:
{
"type": "application",
"isActive": true,
"id": "....",
"userId": "...",
"name": "...",
"company": "...",
"authorizedScopes": [
"my_env"
]
}
So it talks about "authorizedScopes", where are the others? How could I see them?
Thanks

You have specified the scopes my_env and dev_env for the apiEndpoints myEndpoint and devEndpoint (respectively), and these are the only scopes Express Gateway expects you to care about, so the other scopes associated with the user/app credential are not exposed.
You could add the app1 and app2 scopes to each path in the config file and then act based on whichever scope is set for the credentials of the connecting app:
apiEndpoints:
myEndpoint:
host: "*"
scopes: ["my_env","app1","app2"]
devEndpoint:
host: "*"
scopes: ["dev_env","app1","app2"]

Related

Why is my environment variable not recognized after Cloud Run deploy?

My node application needs an environment variable as requirement to make a POST request. Everything works fine in my local machine by accessing the .env file content directly. I also did make sure to set ${_TM_API_KEY} in GCP so I can trigger it, as suggested by the docs, however it doesn't seem to recognize the variable after the application is deployed. What am I doing wrong? Any further suggestion would be deeply appreciated it. My cloudbuild.yaml looks like this:
steps:
- id: build
name: gcr.io/cloud-builders/docker
args:
[
"build",
"-t",
"gcr.io/${PROJECT_ID}/suweb:${SHORT_SHA}",
"--build-arg=ENV=${_TM_API_KEY}",
".",
]
env:
- "TM_API_KEY=${_TM_API_KEY}"
- id: push
name: "gcr.io/cloud-builders/docker"
args: ["push", "gcr.io/${PROJECT_ID}/suweb:${SHORT_SHA}"]
- id: deploy
name: "gcr.io/cloud-builders/gcloud"
args:
- "run"
- "deploy"
- "suweb"
- "--set-env-vars=TM_API_KEY=${_TM_API_KEY}"
- "--image"
- "gcr.io/${PROJECT_ID}/suweb:${SHORT_SHA}"
- "--region"
- "us-central1"
- "--platform"
- "managed"
- "--allow-unauthenticated"
images:
- "gcr.io/${PROJECT_ID}/suweb:${SHORT_SHA}"
More details: the code where the API_KEY is being referenced is in the following header:
const headers = {
TM_API_KEY: process.env.TM_API_KEY,
"Content-Type": "multipart/form-data",
"Access-Control-Allow-Origin": "*",
};
And my .env file looks like this:
TM_API_KEY=_TM_API_KEY
It is a bit unclear for me if I should reference the trigger variable here as well (_TM_API_KEY) or write the key value.
After that, when doing a form post request, the server responds with a CORS policy error telling that such endpoint couldn't be reached. I tried by hard coding the API_KEY in the headers and everything works fine, no errors whatsoever.

AWS Elasticsearch IAM question to access Kibana via Browser

I've set up my elasticsearch yml file (deployed via Serverless) as follows:
Resources:
CRMSearch:
Type: "AWS::Elasticsearch::Domain"
Properties:
ElasticsearchVersion: "7.10"
DomainName: "crm-searchdb-${self:custom.stage}"
ElasticsearchClusterConfig:
DedicatedMasterEnabled: false
InstanceCount: "1"
ZoneAwarenessEnabled: false
InstanceType: "t3.medium.elasticsearch"
EBSOptions:
EBSEnabled: true
Iops: 0
VolumeSize: 10
VolumeType: "gp2"
AccessPolicies:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
AWS: [
"arn:aws:iam::#{AWS::AccountId}:role/crm-databases-dev-us-east-1-lambdaRole",
'#{AWS::AccountId}',
'arn:aws:iam::#{AWS::AccountId}:user/nicholas',
'arn:aws:iam::#{AWS::AccountId}:user/daniel'
]
Action: "es:*"
Resource: "arn:aws:es:us-east-1:#{AWS::AccountId}:domain/crm-searchdb-${self:custom.stage}"
- Effect: "Allow"
Principal:
AWS: [
"*"
]
Action: "es:*"
Resource: "arn:aws:es:us-east-1:#{AWS::AccountId}:domain/crm-searchdb-${self:custom.stage}"
AdvancedOptions:
rest.action.multi.allow_explicit_index: 'true'
AdvancedSecurityOptions:
Enabled: true
InternalUserDatabaseEnabled: true
MasterUserOptions:
MasterUserName: admin
MasterUserPassword: fD343sfdf!3rf
EncryptionAtRestOptions:
Enabled: true
NodeToNodeEncryptionOptions:
Enabled: true
DomainEndpointOptions:
EnforceHTTPS: true
I'm just trying to get access to Kibana via browser. I set up open permission Kibana a few months ago at a previous company, but can't seem to access Kibana via browser no matter what I do. I always get the {"Message":"User: anonymous is not authorized to perform: es:ESHttpGet"} error. How do I setup permissions (ideally via yml) to accomplish this?
User: anonymous is not authorized to perform: es:ESHttpGet
The breakdown of what results in this message is:
Your browser fetches Kibana assets / scripts
Kibana client-side code running on your browser makes a GET request to your ElasticsearchService domain.
Your browser is not a permitted principal and is denied access. The anonymous user from the message is your browser
This is explained in the AWS ElasticsearchService documentation:
Because Kibana is a JavaScript application, requests originate from the user's IP address.
In terms of your next step, the answers to the following question cover the two options you have:
How to access Kibana from Amazon elasticsearch service?
(Yaml solution, overall NOT advisable for several reasons) Add an extra statement to your access policy to allow actions from your device's IP address(es)
(Non-Yaml solution) Set up a proxy that will handle the requests from your browser and basically pass them on after signing them with the credentials of a trusted principal. This can either be a proxy running on additional AWS infrastructure or something running on your local machine. Again, the answers on the linked question go into more details.

Express Gateway - Proxy request with Bearer Token

I am trying to figure out how to get Express Gateway to use the Auth Bearer token in request, upstream to the api service.
Below is my config as of right now.
http:
port: 8080
admin:
port: 9876
host: localhost
apiEndpoints:
api:
host: localhost
paths:
- '/truck-api/*'
- '/car-api/*'
serviceEndpoints:
truck-service:
url: 'http://10.0.0.2:5010/api'
car-service:
url: 'http://10.0.0.2:5011/api'
policies:
- basic-auth
- cors
- expression
- key-auth
- log
- oauth2
- proxy
- rate-limit
- rewrite
- request-transformer
pipelines:
default:
apiEndpoints:
- api
policies:
- proxy:
-
condition:
name: pathMatch
pattern: "^/truck-api/(.*)"
action:
serviceEndpoint: truck-service
prependPath: true
ignorePath: false
stripPath: true
changeOrigin: true
-
condition:
name: pathMatch
pattern: "^/car-api/(.*)"
action:
serviceEndpoint: car-service
prependPath: true
ignorePath: false
stripPath: true
changeOrigin: true
The frontend calls express gateway with a proper auth bearer token, however the express gateway doesn't forward that auth bearer token on to the upstream service.
Advice?
After some digging and a lot of trial and error the solution was relatively simple, use request transformer.
added this to the policies section:
- request-transformer:
- action:
headers:
remove: ['Authorization']
add:
Authorization: "'Bearer ***'"
For me remove: ['Authorization'] did not work.
I was authenticating towards express gateway using:
"Authorization: apiKey ${keyId}:${keySecret}" and authenticating towards backend service by using Authorization: "'Bearer ***'" added by request-transformer. I would expect remove: ['Authorization'] would remove "Authorization: apiKey ${keyId}:${keySecret}", after I was already successfully authenticated at express gateway and add: Authorization: "'Bearer ***'" would add new Authorization header so newly constructed request would replace apiKey with Bearer token but using remove: ['Authorization'] resulted in failure to authenticate at express gateway.
I resolved this issue by changing HTTP header used for authorization at express gateway side with apiKeyHeader (https://www.express-gateway.io/docs/policies/key-authorization/).
policies:
- request-transformer:
- action:
headers:
add:
# pass oauth2 token
Authorization: "'Bearer ***'"
- key-auth:
- action:
# arbitrarily rename default header name from Authorization
apiKeyHeader: open_sesame
The open_sesame header grants us access to api gateway and request-transformer adds authorization header with proper token to the request for accessing the backend service.
curl -v -H "open_sesame: apiKey ${keyId}:${keySecret}"...

Google cloud endpoints API key is not verified

I'm now developing REST API with Cloud endpoints and App engine.
I will like to implement api key authentication but it does not work.
Looks good without query params of 'key=${API KEY}'.
# curl -X POST https://hogehoge.com/test -d '{"key":"value"}'
{
"code": 16,
"message": "Method doesn't allow unregistered callers (callers without established identity). Please use API Key or other form of API consumer identity to call this API.",
"details": [
{
"#type": "type.googleapis.com/google.rpc.DebugInfo",
"stackEntries": [],
"detail": "service_control"
}
]
}
But any key can be granted to access to the backend.
# curl -X POST https://hogehoge.com/test?key=aaa -d '{"key":"value"}'
POST is sended.
Of course, API key generated via API management will work.
# curl -X POST https://hogehoge.com/test?key=${realkey} -d '{"key":"value"}'
POST is sended.
Cloud endpoint file definition is
swagger: "2.0"
info:
title: "xxxxxxxxx"
description: "xxxxxxxxx"
version: "1.0.0"
host: "hogehoge.com"
schemes:
- "https"
security: []
paths:
"/test":
post:
description: "test"
operationId: "test"
security:
- api_key: []
parameters:
- name: body
in: body
required: true
schema:
$ref: '#/definitions/testRequest'
responses:
201:
description: "Success"
schema:
$ref: '#/definitions/testResponse'
definitions:
testRequest:
type: object
required:
- data
properties:
data:
type: object
required:
- key
properties:
token:
type: string
example: value
maxLength: 20
testResponse:
type: string
securityDefinitions:
api_key:
type: "apiKey"
name: "key"
in: "query"
What I expect is only key generated via API management will be granted to access.
Let me know how to solve this issue.
Thanks.
It seems that the Service Control API might not be enabled on your project.
In order to check that, you can run
gcloud services list --enabled
If servicecontrol.googleapis.com is not listed in the result of the previous command, you should run
gcloud services enable servicecontrol.googleapis.com
Furthermore, you could check that you have all the required services for Endpoints enabled. You can see how to do this in the documentation

express gateway jwt issuing not working

I'm kinda of new in EG. I have followed the documentation about issuing a jwt token instead of opaque but still receiving an opaque access token. Not sure what I'm missing to change.
This is my system.config file
db:
redis:
host: localhost
port: 6379
namespace: EG
crypto:
cipherKey: sensitiveKey
algorithm: aes256
saltRounds: 10
session:
secret: keyboard cat
resave: false
saveUninitialized: false
accessTokens:
timeToExpiry: 7200000
tokenType: 'jwt'
issuer: 'express-gateway'
audience: 'something'
subject: 'test'
secretOrPrivateKey: 'ssssst'
refreshTokens:
timeToExpiry: 7200000
authorizationCodes:
timeToExpiry: 300000
Already added a user and app with their own credentials (oauth2, basic-auth, jwt) without changing anything on the models.
this is my gateway.config file
http:
port: 8080
admin:
port: 9876
hostname: localhost
apiEndpoints:
api:
host: localhost
paths: '/api/*'
serviceEndpoints:
httpbin:
url: 'https://httpbin.org'
policies:
- jwt
- oauth2
- proxy
- rate-limit
pipelines:
default:
apiEndpoints:
- api
policies:
- oauth2:
action:
jwt:
issuer: express-gateway
audience: something
subject: test
secretOrPublicKey: ssssst
checkCredentialExistence: false
- proxy:
- action:
serviceEndpoint: httpbin
changeOrigin: true
the request for login is like this and secret is the keySecret generated with jwt credential of the app.
http://localhost:8080/oauth2/authorize?response_type=token&client_id=ae921ba9-7b4b-4c53-aaba-354bd6398e52&redirect_uri=http://localhost:3002/explorer&client_secret=0qOpBZkwO2ayQ8dO18yRuh
and the token response looks like this.
14070f7c4ffc49efb1fc1709cc4a7267|90c6efd2cf8342859756d8e3705417a3
Thanks for anyone who can help me.
The configuration looks correct. I've also personally tried the configuration you provided and I got back a JWT
Maybe you can try to set up a test project on Glitch.me so it's going to be easier to replicate locally.