Reputation: 179
The API Gateway endpoints we are using shall be restricted via permissions to a specific audience.
The idea is to use the lambda authorizer to fetch the permissions from an external service and then create the policy to allow or deny access to the endpoint.
For the matching of the permissions to the API endpoint the endpoint would need to provide the permissions it needs to the authorizer.
My question is now how can I enrich the endpoint data with its own required permissions and use them in the authorizer lambda(probably via the event) for further validation.
Example:
Here is my code for the lambda:
import {Callback, Context} from 'aws-lambda';
import {Authorizer} from './authorizer';
export class App {
constructor(private authorizer: Authorizer = new Authorizer()) {
}
public handleEvent(event, callback: Callback): Promise<void> {
return this.authorizer.checkAuthorization(event, callback)
.then((policy) => callback(null, policy))
.catch((error) => callback(error, null));
}
}
const app: App = new App();
module.exports.lambda_handler = async (event) => {
return await app.handleEvent(event);
};
Code for the checkAuthorization method:
export class Authorizer {
public resourceAuthorizer: ResourceAuthorizer = new ResourceAuthorizer();
public authenticationChecker: AuthenticationChecker = new AuthenticationChecker();
public checkAuthorization(event, callback): Promise<object> {
const endpointPermissions = event.endpointPermissions; // <== this is what I need, a custom field in the event which
// is provided from the api endpoint in some way
// in my example this whould contain a string or json
// with 'View:Pets' and 'View:Somethingelse'
return this.authenticationChecker.check(event)
.then((decodedJwt) => {
const principalId: string = decodedJwt.payload.sub;
return Promise.resolve(decodedJwt)
.then((jwt) => this.resourceAuthorizer.check(jwt, event.endpointPermissions))
.then((payload) => callback(null,
getAuthorizationPolicy(principalId, 'Allow', event.endpointPermissions, payload)))
.catch((payload) => callback(null,
getAuthorizationPolicy(principalId, 'Deny', event.endpointPermissions, payload)));
}).catch((error) => {
console.log(error);
callback('Unauthorized');
});
}
}
The event.endpointPermissions is basically what I am looking for. Depending on the API endpoint this should be filled with the permissions neccessary for that endpoint. The resourceAuthorizer then fetches the users Permissions from the external service and compares them to the endpointPermissions and then creates the Allow or Deny policies.
So where can I enter the endpointPermissions in my API Endpoint to provide them to the Authorizer?
Upvotes: 2
Views: 802
Reputation: 91
After struggling research about this topic, I still couldn't find a best way to do. I have even tried to use request template to add custom value to the headers. But it seems the request template only be called after the Authorizer. I'm thinking about setting environments for each lambda function. The limitation of this way is we can only set environments on a Lambda function, not on each http event. And the way that @StV has mentioned above is not a bad idea also. But it's a bit inconvenience because we have to add query strings to all requests on Client site
Upvotes: 0
Reputation: 179
I got a solution to my problem without having to parse the ARN, but it's pretty unconventional:
The event received by the authorizer now contains the queryStringParameters which can be evaluated for further use.
Upvotes: 1
Reputation: 2155
The event being passed to the Authorizer contains a methodArn, which is in the format:
arn:aws:execute-api:<Region id>:<Account id>:<API id>/<Stage>/<Method>/<Resource path>
This would give you the Method and Resource Path that you need. It also would give you an identifier of the API, but not the name of the API itself.
The API id, can be used to get the API name by using the AWS SDK. See here.
This should give you everything you need to construct your endpointPermissions value.
Upvotes: 2