How to use AWS SDK for request signing - amazon-web-services

I'm trying to invoke an api request (service: execute-api) and a Signature v4 is required. I've been going through the documentation and I see clearly this:
Alternatively, you can use the AWS CLI or one of the AWS SDKs to
handle request signing for you.
I don't own the API and originally just thought I could use CURL but obviously IAM is configured. I'm wondering what the best way of making this request signed is?
Note:
Looks like there is an AWS4Signer class that may be what I'm looking for to generate the signature non-manually

I'm sorry, but from your question it's not clear whether you're just experimenting with the API or if you want to write a client that calls it (as in production code).
If you're just testing, you can use Postman to call the API (it supports SigV4). Details here.
If you are writing a client, the way to go is generating the SDK from API gateway, as noted in the comments. Should that not be possible, the next best option is to use one of the language-specific SDK signers to generate the SigV4 signature. AWS4Signer, like you said, is the way to go. It should be straightforward to integrate with it, but if you can share more details of your specific use case (platform, language, where do you get the AWS credentials from, etc), people can give you a better answer.
Last, if you want to generate the signature yourself, here's how the canonical generation of signatures work.

Related

Integrating Telegram Bot with Google Cloud Functions and Gateway

I'm developing a Telegram bot that should send updated to a registered webhook.
The backed is implemented as a Cloud Function, sitting behind an API Gateway (eveyrhting's in Google Cloud Platform).
I want to make sure that only genuine requests come through and noone can abuse the endpoint. For this purpose, a secret_token can be configured for Telegram bot, which will be sent in the X-Telegram-Bot-Api-Secret-Token header with every request coming from this bot.
On the API side I can configure API key security for my API. However, based on the documentation, only x-api-key header name can be used in the Swagger specification (I tested this and, indeed, no other header names work).
So, how could I possibly make it work together? AFAIK, I can't choose a custom name for the secret token header on the Telegram side. In the same way, I can't choose an arbitrary name in the securityDefinitions of the Swagger spec for the API in Google API Gateway.
Are there any possible workarounds here? Maybe there's some "overwrite header" functionality in the Gateway? I tried searching for this, but didn't find anything that could be used. Or, maybe, it's possible to describe a required header value in the Swagger spec? I know that I can require the presence of a particular header, but, AFAIK, I can't require it to match some specific value...

AWS API Gateway Authentication with OneLogin

I've been exploring OneLogin and I think I have a basic understanding of how to use it; I was successful at configuring the Node+Passport sample application to authenticate with OneLogin and I understand the code.
I want to try it with AWS API Gateway. I've got an API already defined in AWS. On a high level I know I need to configure an Authorizer in AWS for OneLogin and that there is going to be some bit of information that I will need to pass in a header when I make my calls to the AWS Api Gateway (I assume a Bearer token that I get from authenticating with OneLogin before I interact with AWS, but I don't know).
Can someone give me a description of what I need to do? The most recent question that I see here on the topic was posted in 2016 back when the answer was "You can't do that." That answer has changed in the past 4 years. The OneLogin documentation says it can be done, but I have found not information on how to do it.
GENERAL PATTERN
The role of an authorizer function is to perform the following actions:
Validate access token
Optionally collect additional claims
Cache the claims for subsequent requests with the same token
Provide claims to business logic
In fact this is a general pattern that can be used anywhere, as referenced in my blog post.
TOKEN VALIDATION
I would use the One Login Introspection Endpoint.
Some NodeJS code of mine that calls an introspection endpoint is here.
AWS SPECIFICS
Since you are using OneLogin you will need to write some custom code. Your lambda authorizer will need to do standard OAuth 2.0 work, then return an AWS policy document. Some resources of mine may help you to understand how this works:
Lambda Authorizer Blog Post
Associated NodeJS Code
PAIN POINTS
The AWS plumbing is a bit painful, and it is possible you are using some different technology choices to me - I am using the Serverless Framework.
Hopefully though, this gives you something to run locally and compare against. Happy to answer any follow up questions ...

Serverless AWS - is it worth using custom authorizers (as a lambda)?

Hey I am getting started with the serverless framework, apigateway, lambdas and authorizers.
Here my questions:
In order to verify a proper JWT token (which seems nowadays the best solution for serverless authentication), I would need a client id. Since the authorizer lambda is not capable(?) of reaching any other parameters of the request into the lambda except for the token itself, this is a difficult task to do. How can I achieve this?
Since with every authenticated call, an additional lambda is called, my costs are doubled?! May be I am misunderstanding something here, but it seems to me like implementing a method for verifying my token without using the authorizer is cheaper and I don't need to implement the authorizer lambda itself.
The whole point of OAuth2 is that at the point of authorization you don't care who the bearer presenting you with a token is or which client they are using (web app, Postman, etc.), only that the token is valid for whatever the token bearer is trying to do. You trust that the authentication has happened because the token issuer has done the authentication.
When you talk about the aud(audience) (from comments) in JWTs, which may or may not be included dependent on the JWT issuer, this is intended to reflect the service or services that the JWT is valid for.
This could for example have a value of 'myAPIName' or 'myAPIName/test' or even ['myAPIName/test1', 'myAPIName/test2'].
If you need to validate an individual aud claim you have two choices, you can either have different Lambdas authorizing different api routes and methods with hardcoded aud variables or you can get the name of the api being called and map it back to something that would match an aud claim.
For example the method arn for the incoming request can be found in event.methodArn. This looks like arn:aws:execute-api:{regionId}:{accountId}:{apiId}/{stage}/{httpVerb}/ potentially with [{resource}/[{child-resources}]] dependent on your implementation. With a bit of string manipulation, you could map this back to the format of an audience claim (whatever that looks like for you).
If you would rather work an api name instead of an api name you can use the apigateway.getrestapi method for whatever sdk you are using. Documentation on this method for the JavaScript sdk can be found here.
The JWT may have a sub(subject claim), again dependent on implementation of the JWT issuer, this could relate to any of your users (or at least the users the JWT issuer knows about). Validating this beyond checking the signature of the JWT is pointless. The best you could do is check if that user exists and only if you have access to the same user database that the JWT issuer does. Although this can be used to ensure that UserA only has access to UserA's data. Again, you are trusting that the fact a bearer has a token is proof that they have authenticated (proved who they are).
I hope that answers part one of your question.
In regards to part 2, the advantage of using a Lambda Authorizer over doing the authorization in the target Lambda is caching.
So envisage I have a token valid for one hour and I call your API once every second for 30 minutes (1,800 calls). You have a Lambda authorizer with a response cache time of 10 minutes. That means you check the JWT 3 times for 1800 api calls.
But if you do the validation of that token in your target Lambda, you are doing that processing 1,800 times.
There is authentication with AWS Cognito which will allow you to use authentication outside your application and still being able to let your application divide the users into subgroups based on custom roles or similar.
If for some reason you cannot use AWS Cognito (Why not?) there is both the possibility of custom authentication (the same for each function with SLS) or even authenticating with custom code inside each lambda function.
I would recommend to use Cognito, and only custom if you know you need it.

AWS API Gateway Get Method How to Pass API Key?

I have a working AWS API Gateway GET method. I want to secure it using an API key, so I've created an API key and usage plan, etc.
So previously when I wanted to call the GET method, I would just type a URL with the appropriate parameters into the browser and send it. However, now that we've introduced the API key into the mix, I'm not sure how to call it.
I'm aware of the command line GET and curl tools. Which of these 3 tools (browser, GET, CURL) can accomplish this task and what syntax do I need to use to make the request to the GET method passing the API key?
Mark B is right, I'm just copying because it's the right answer.
You must pass an HTTP header named x-api-key with the API Key as the value. One tool is cURL, another is Postman.

Interaction with the AWS API?

I've gotten the necessary access key/signature from my client and I can interact with the API through the Ruby SDK right now. Thing is, the Ruby SDK doesn't have any kind of high-level API methods to request a spot instance. So, I need to do this manually via raw REST API requests.
Basically, the authentication information that I am using is correct (as it works via the Ruby SDK), but I can't get raw requests to work... I either get back the spot request wizard webpage as the response, or an error: The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
Here's the URL I'm using:
https://ec2.amazonaws.com/?Action=RequestSpotInstances
&SpotPrice.1=0.05
&AvailabilityZoneGroup.1=us-east-1c
&LaunchSpecification.ImageId.1=THE_AMI_ID
&LaunchSpecification.KeyName.1=THE_KEYPAIR
&LaunchSpecification.InstanceType.1=m1.medium
&AWSAccessKeyId=THE_ACCESS_KEY
&Signature=THE_ACCESS_SIGNATURE
&Version=>2013-10-01
&Expires=>THE_EXPIRATION_TIME_36000_SECONDS_LATER_THAN_NOW
&SignatureVersion=2
&SignatureMethod=HmacSHA256
Any ideas on why this won't work? I've tried exploring the Ruby SDK code to see how they are doing it, but it's so complex, I can't figure out where this action actually takes place. Thanks!
How do you calculate signature? First at all check that you use correct signing process version. AWS api actually supports versions v2 and v4. Some aws resources supports both versions, some just v2 or v4. Base on this I would recommend to do following:
Check what version of the signing did you implement. More on versions:
http://docs.aws.amazon.com/general/latest/gr/signing_aws_api_requests.html
Check is your implementation match with algorithm described here: http://docs.aws.amazon.com/general/latest/gr/signature-version-2.html