I'm getting an Error 404 when trying to set my authorization key (key-auth) in the request header. I'm sure that there isn't any problem with my key because if I don't set it a Forbidden status will return.
before setting any credentials:
$ curl http://localhost:8080/ip
will return:
{
"origin": "5.116.28.133"
}
after creating a key-auth credential:
$ curl -H "Authorization: apiKey ${keyId}:${keySecret}" http://localhost:8080/ip
will return:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot GET /ip</pre>
</body>
</html>
and it's my gateway config:
http:
port: 8080
admin:
port: 9876
hostname: localhost
apiEndpoints:
api:
host: localhost
paths: '/ip'
serviceEndpoints:
httpbin:
url: 'https://httpbin.org'
policies:
- basic-auth
- cors
- expression
- key-auth
- log
- oauth2
- proxy
- rate-limit
pipelines:
- name: default
apiEndpoints:
- api
policies:
- key-auth:
- proxy:
- action:
serviceEndpoint: httpbin
changeOrigin: true
Does anyone know why this issue happens?
find more information about express-gateway from http://www.express-gateway.io/
it should be key-auth
the problem is with indentation
- key-auth:
- proxy:
it must be on one level
basically this is an array:
policies: [{
'key-auth':null
},{
proxy:{ ... }
}]
this will fix the issue.
Try removing the hyphen from key-auth under policies: in your config file - this worked for me. It should just be keyauth.
Related
I'm setting up an instance of the express gateway for routing requests to microservices. It works as expected, but I get the following errors when I try to include redis in my system config
0|apigateway-service | 2020-01-09T18:50:10.118Z [EG:policy] error: Failed to initialize custom express-session store, please ensure you have connect-redis npm package installed
0|apigateway-service | 2020-01-09T18:50:10.118Z [EG:gateway] error: Could not hot-reload gateway.config.yml. Configuration is invalid. Error: A client must be directly provided to the RedisStore
0|apigateway-service | 2020-01-09T18:50:10.118Z [EG:gateway] warn: body-parser policy hasn't provided a schema. Validation for this policy will be skipped.
0|apigateway-service | 2020-01-09T18:50:10.118Z [EG:policy] error: Failed to initialize custom express-session store, please ensure you have connect-redis npm package installed
I have installed the necessary packages
npm install redis connect-redis express-session
and have updated the system.config.yml file like so,
# Core
db:
redis:
host: ${REDIS_HOST}
port: ${REDIS_PORT}
db: ${REDIS_DB}
namespace: EG
plugins:
# express-gateway-plugin-example:
# param1: 'param from system.config'
health-check:
package: './health-check/manifest.js'
body-parser:
package: './body-parser/manifest.js'
crypto:
cipherKey: sensitiveKey
algorithm: aes256
saltRounds: 10
# OAuth2 Settings
session:
storeProvider: connect-redis
storeOptions:
host: ${REDIS_HOST}
port: ${REDIS_PORT}
db: ${REDIS_DB}
secret: keyboard cat # replace with secure key that will be used to sign session cookie
resave: false
saveUninitialized: false
accessTokens:
timeToExpiry: 7200000
refreshTokens:
timeToExpiry: 7200000
authorizationCodes:
timeToExpiry: 300000
My gateway.config.yml file looks like this
http:
port: 8080
admin:
port: 9876
apiEndpoints:
accounts:
paths: '/accounts*'
billing:
paths: '/billing*'
serviceEndpoints:
accounts:
url: ${ACCOUNTS_URL}
billing:
url: ${BILLING_URL}
policies:
- body-parser
- basic-auth
- cors
- expression
- key-auth
- log
- oauth2
- proxy
- rate-limit
pipelines:
accounts:
apiEndpoints:
- accounts
policies:
# Uncomment `key-auth:` when instructed to in the Getting Started guide.
# - key-auth:
- body-parser:
- log: # policy name
- action: # array of condition/actions objects
message: ${req.method} ${req.originalUrl} ${JSON.stringify(req.body)} # parameter for log action
- proxy:
- action:
serviceEndpoint: accounts
changeOrigin: true
prependPath: true
ignorePath: false
stripPath: true
billing:
apiEndpoints:
- billing
policies:
# Uncomment `key-auth:` when instructed to in the Getting Started guide.
# - key-auth:
- body-parser:
- log: # policy name
- action: # array of condition/actions objects
message: ${req.method} ${req.originalUrl} ${JSON.stringify(req.body)} # parameter for log action
- proxy:
- action:
serviceEndpoint: billing
changeOrigin: true
prependPath: true
ignorePath: false
stripPath: true
package.json
{
"name": "max-apigateway-service",
"description": "Express Gateway Instance Bootstraped from Command Line",
"repository": {},
"license": "UNLICENSED",
"version": "1.0.0",
"main": "server.js",
"dependencies": {
"connect-redis": "^4.0.3",
"express-gateway": "^1.16.9",
"express-gateway-plugin-example": "^1.0.1",
"express-session": "^1.17.0",
"redis": "^2.8.0"
}
}
Am I missing anything?
In my case, I used AWS Elasticache for Redis. I tried to run it but I had "A client must be directly provided to the RedisStore" error. I found my problem from the security group setting. EC2(server) should have a proper security group for the port of Elasticache. And Elasticache should have the same security group.
Step1. Create new security group. Set the inbound rule
Step2. Add the security group to the EC2 server.
Step3. Add the security group to the Elasticache.
I'm writing a webapp using micronaut which uses oauth2 to secure the apis. its working well in the sense that the login page from the oauth provider is shown when a secured url is accessed. But after login the page doesn't redirect back to the original requested url, instead it goes bat to '/'. I believe this is because micronaut uses "micronaut.security.session.login-success-target-url" property find the url to go to after login. Since there are multiple secured urls I'd like to auto redirect to the original url if available.
Any help to achieve the same would be appreciated.
Please find below the properties:
---
micronaut:
security:
enabled: true
token:
propogation:
enabled: true
intercept-url-map:
-
pattern: /
http-method: GET
access:
- isAnonymous()
-
pattern: /oauth/**
http-method: GET
access:
- isAnonymous()
-
pattern: /**/login
access:
- isAnonymous()
endpoints:
login:
enabled: false
logout:
enabled: true
session:
enabled: true
login-failure-target-url: /oauth/login/cognito
unauthorized-target-url: /oauth/login/cognito
forbidden-target-url: /oauth/login/cognito
oauth2:
enabled: true
state:
persistence: session
clients:
cognito:
client-secret: '${OAUTH_CLIENT_SECRET}'
client-id: '${OAUTH_CLIENT_ID}'
openid:
issuer: 'https://cognito-idp.${COGNITO_REGION}.amazonaws.com/${COGNITO_POOL_ID}/'
authorization:
display: 'POPUP'
prompt: 'CONSENT'
token:
jwt:
enabled: true
signatures:
secret:
generator:
secret: '${JWT_GENERATOR_SIGNATURE_SECRET:pleaseChangeThisSecretForANewOne}'
endpoints:
oauth:
enabled: true
logout:
enabled: true
get-allowed: true
I've implemented a custom 'REQUEST' type authorizer for an API gateway which validates a JWT token passed in the 'Authorization' header. I've tested the lambda independently and it works as expected. I've also attached the authorizer to my routes and I can test it in the AWS console - again, everything seems to work (see image):
successful invoke via console
However, when I try to invoke my endpoints with the token in the Authorization header, I always receive an UNAUTHORIZED response:
{
"errors": [
{
"category": "ClientError",
"code": "UNAUTHORIZED",
"detail": "Unauthorized",
"method": "GET",
"path": "/cases",
"requestId": "004eb254-a926-45ad-96a5-ce3527621c81",
"retryable": false
}
]
}
From what I have gathered, API gateway never invokes my Authorizer as i don't see any log events in its cloudwatch. I was able to enable cloudwatch logging of my API gateway, and the only log information I see is as follows:
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| timestamp | message |
|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1578275720543 | (dac0d4f6-1380-4049-bcee-bf776ca78e5c) Extended Request Id: F2v9WFfiIAMF-9w= |
| 1578275720543 | (dac0d4f6-1380-4049-bcee-bf776ca78e5c) Unauthorized request: dac0d4f6-1380-4049-bcee-bf776ca78e5c |
| 1578275720543 | (dac0d4f6-1380-4049-bcee-bf776ca78e5c) Extended Request Id: F2v9WFfiIAMF-9w= |
| 1578275720544 | (dac0d4f6-1380-4049-bcee-bf776ca78e5c) Gateway response type: UNAUTHORIZED with status code: 401 |
| 1578275720544 | (dac0d4f6-1380-4049-bcee-bf776ca78e5c) Gateway response body: {"errors": [{"category": "ClientError","code": "UNAUTHORIZED","detail": "Unauthorized","method": "GET","path": "/cases","requestId": "dac0d4f6-1380-4049-bcee-bf776ca78e5c","retryable": false }]} |
| 1578275720544 | (dac0d4f6-1380-4049-bcee-bf776ca78e5c) Gateway response headers: {} |
| 1578275720544 | (dac0d4f6-1380-4049-bcee-bf776ca78e5c) Gateway response type: UNAUTHORIZED with status code: 401 |
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
At this point I am completely stuck and not sure how to debug this further. I'm assuming something must be configured wrong but the log information I can find doesn't given any indication of what the problem is. I've also pasted a copy of my authorizers configuration in the image below:
Authorizer Configuration
Screenshot of one endpoint configured to use the authorizer
I figured out the problem I was having:
I needed to set identitySource: method.request.header.Authorization in the authorizer field of the endpoint as well as in the CF stack.
Custom Authorizer definition in raw cloudformation:
service:
name: api-base
frameworkVersion: ">=1.2.0 <2.0.0"
plugins:
- serverless-plugin-optimize
- serverless-offline
- serverless-pseudo-parameters
- serverless-domain-manager
custom:
stage: ${self:provider.stage, 'dev'}
serverless-offline:
port: ${env:OFFLINE_PORT, '4000'}
false: false
cognitoStack: marley-auth
customDomain:
domainName: ${env:BE_HOST, ''}
enabled: ${env:EN_CUSTOM_DOMAIN, self:custom.false}
stage: ${self:provider.stage, 'dev'}
createRoute53Record: true
provider:
name: aws
runtime: nodejs10.x
versionFunctions: true
apiName: public
logs:
restApi: true
stackTags:
COMMIT_SHA: ${env:COMMIT_SHA, 'NO-SHA'}
environment:
USER_POOL_ID: ${cf:${self:custom.cognitoStack}-${self:custom.stage}.UserPoolId}
CLIENT_ID: ${cf:${self:custom.cognitoStack}-${self:custom.stage}.UserPoolClientId}
timeout: 30
iamRoleStatements:
- Effect: "Allow"
Action:
- "lambda:InvokeFunction"
Resource: "*"
functions:
authorizer:
handler: handler/authorize.handler
resources:
- Outputs:
ApiGatewayRestApiId:
Value:
Ref: ApiGatewayRestApi
Export:
Name: ${self:custom.stage}-${self:provider.apiName}-ApiGatewayRestApiId
ApiGatewayRestApiRootResourceId:
Value:
Fn::GetAtt:
- ApiGatewayRestApi
- RootResourceId
Export:
Name: ${self:custom.stage}-${self:provider.apiName}-ApiGatewayRestApiRootResourceId
SharedAuthorizerId:
Value:
Ref: SharedAuthorizer
Export:
Name: ${self:custom.stage}-${self:provider.apiName}-ApiGatewaySharedAuthorizerId
- Resources:
SharedAuthorizer:
Type: AWS::ApiGateway::Authorizer
Properties:
Name: public
AuthorizerUri: !Join
- ''
- - 'arn:aws:apigateway:'
- !Ref 'AWS::Region'
- ':lambda:path/2015-03-31/functions/'
- !GetAtt
- AuthorizerLambdaFunction
- Arn
- /invocations
RestApiId: !Ref 'ApiGatewayRestApi'
Type: REQUEST
IdentitySource: method.request.header.Authorization
AuthorizerResultTtlInSeconds: '300'
DependsOn: AuthorizerLambdaFunction
ApiAuthLambdaPermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !Ref AuthorizerLambdaFunction
Principal: apigateway.amazonaws.com
SourceArn: !Sub "arn:aws:execute-api:#{AWS::Region}:#{AWS::AccountId}:#{ApiGatewayRestApi}/authorizers/*"
DependsOn: ApiGatewayRestApi
Using the authorizer in another stack - note that I have specified IdentitySource here as well as in the definition of the authorizer - for some reason I had to do it in both places.
authorizer:
type: CUSTOM
authorizerId: ${cf:api-base-${self:custom.stage}.SharedAuthorizerId}
identitySource: method.request.header.Authorization
I am able to run an express gateway Docker container and a Redis Docker container locally and would like to deploy this to Azure. How do I go about it?
This is my docker-compose.yml file:
version: '2'
services:
eg_redis:
image: redis
hostname: redis
container_name: redisdocker
ports:
- "6379:6379"
networks:
gateway:
aliases:
- redis
express_gateway:
build: .
container_name: egdocker
ports:
- "9090:9090"
- "8443:8443"
- "9876:9876"
volumes:
- ./system.config.yml:/usr/src/app/config/system.config.yml
- ./gateway.config.yml:/usr/src/app/config/gateway.config.yml
networks:
- gateway
networks:
gateway:
And this is my system.config.yml file:
# Core
db:
redis:
host: 'redis'
port: 6379
namespace: EG
# plugins:
# express-gateway-plugin-example:
# param1: 'param from system.config'
crypto:
cipherKey: sensitiveKey
algorithm: aes256
saltRounds: 10
# OAuth2 Settings
session:
secret: keyboard cat
resave: false
saveUninitialized: false
accessTokens:
timeToExpiry: 7200000
refreshTokens:
timeToExpiry: 7200000
authorizationCodes:
timeToExpiry: 300000
And this is my gateway.config.yml file:
http:
port: 9090
admin:
port: 9876
hostname: 0.0.0.0
apiEndpoints:
# see: http://www.express-gateway.io/docs/configuration/gateway.config.yml/apiEndpoints
api:
host: '*'
paths: '/ip'
methods: ["POST"]
serviceEndpoints:
# see: http://www.express-gateway.io/docs/configuration/gateway.config.yml/serviceEndpoints
httpbin:
url: 'https://httpbin.org/'
policies:
- basic-auth
- cors
- expression
- key-auth
- log
- oauth2
- proxy
- rate-limit
- request-transformer
pipelines:
# see: https://www.express-gateway.io/docs/configuration/gateway.config.yml/pipelines
basic:
apiEndpoints:
- api
policies:
- request-transformer:
- action:
body:
add:
payload: "'Test'"
headers:
remove: ["'Authorization'"]
add:
Authorization: "'new key here'"
- key-auth:
- proxy:
- action:
serviceEndpoint: httpbin
changeOrigin: true
Mounting the YAML files and then hitting the /ip endpoint is where I am stuck.
According to the configuration file you've posted I'd say you need to instruct Express Gateway to listen on 0.0.0.0 if run from a container, otherwise it won't be able to listed to external connections.
Where exactly do I put proxyTimeout in gateway.config.yml?
You can set timeout for proxy in pipelines:
pipelines:
- name: default
apiEndpoints:
- test
policies:
- proxy:
- action:
serviceEndpoint: testService
proxyTimeout: 6000