Passing custom data from AWS Lambda Authorizer - amazon-web-services

In short, I want to pass information from my custom Lambda Authorizer to the backend. I have an rest API GW with a proxy integrated lambda as backend. The return object form the custom authorizer looks like this the json below. In this case I want to pass var1 and var2 to the proxy lambda.
{
"principalId": "ExecuteAPISid",
"policyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Action": "execute-api:Invoke",
"Effect": "Allow",
"Resource": "*"
}]
},
"context": {
"var1": "hello_world",
"var2": "hello_world2"
}
}
I see that this question has been asked and answered previously, however the suggested solution, as mention for example here, refers to "header mappings" under Integration Request in the AWS API Gateway menu. For me however, I have no such options. Thus I have an idea of what I want to do but lack the ability to how to implement it.
Does anyone have an idea of how to implement these header mappings? Complete settings shown in image below.
Edit: After further digging it turns out that the issue relates to me using using a lambda-proxy integration. This answer highlights just that. However, that simply shifts my question to: why is my requestContext not containing the authorizer object.

Turns out that when you are using proxy integration then the context object from the custom Authorizer Lambda is automatically passed through to the event as:
"requestContext": {
"resourceId": "XXXX",
"authorizer": {
"var1": "hello_world1",
"var2": "hello_world2",
"principalId": "ExecuteAPIS",
"integrationLatency": 780
},
The problem was that I had forgotten to "deploy" my API GW.

Related

New AWS Lambda URLs - has anyone got the 'secure' version with the AWS_IAM working?

I have a simple function that returns an item of text.
When I set auth to NONE it works fine.
When I set auth to AWS_IAM and create the resource based policy within the permissions section of AWS Lambda I set the following:
"Version": "2012-10-17",
"Id": "default",
"Statement": [
{
"Sid": "sid8",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::xxxxxxxxxx:user/xxxxxxxxxx"
},
"Action": "lambda:InvokeFunctionUrl",
"Resource": "arn:aws:lambda:eu-west-1:xxxxxxxxx:function:simpleFunction",
"Condition": {
"StringEquals": {
"lambda:FunctionUrlAuthType": "AWS_IAM"
}
}
}
]
}
On this I get a forbidden error.
Every demo / example on the internet uses NONE for auth.
I have also tried adding the lambda:InvokeFunctionUrl to the IAM policy of the user for the specified resource but still getting a forbidden error.
Am I missing something or does this aspect of the new function not work?
The problem is that when you are using IAM_AUTH you're required to sign your requests with SigV4. Essentially, this is identical to using API Gateway with IAM_AUTH type.
There are multiple ways of signing requests you can even use botocore functionality to do so. The easiest would be to use awscurl or postman, also check this doco that confirms this requirement https://docs.aws.amazon.com/lambda/latest/dg/urls-invocation.html

AWS Serverless DynamoDB Row Level Authorization With Cognito and Lambda Functions

Alright, so I currently have almost everything working by following this guide here and pieces of several others.
https://aws.amazon.com/blogs/mobile/building-fine-grained-authorization-using-amazon-cognito-user-pools-groups/
However, instead of giving users direct access to the DynamoDB, I am running it through an API Gateway and then a Lambda Function using an Authorization header and the Cognito session id.
I have that part working.
In my lambda function I call the update function
const data = await documentClient.update(params).promise();
I have AWSLambdaBasicExecutionRole policy and the following policy added to my lambda function role to allow the row level access for Update
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": [
"dynamodb:UpdateItem"
],
"Resource": [
"arn:aws:dynamodb:us-east-2:mydynamodbid:table/userdata"
],
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": "${cognito-identity.amazonaws.com:sub}"
}
}
}
]
It works fine with the AmazonDynamoDBFullAccess but I am not sure that is accomplishing what I am looking for as I think it just completely bypasses the condition.
I am getting the following error though
"User: arn:aws:sts::**********:assumed-role/db-crud/update-user-info-by-id is not
authorized to perform: dynamodb:UpdateItem on resource: arn:aws:dynamodb:us-east-
2:************:table/userdata"
Has anyone encountered anything like this or see where I am possibly going wrong?
This is the flow I am going for, and this is related to step 6

Unable to send message from API Gateway to FIFO SQS

I have integrated a API Gateway with FIFO SQS queue using below link
https://medium.com/#pranaysankpal/aws-api-gateway-proxy-for-sqs-simple-queue-service-5b08fe18ce50
Below is the snippet of role policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"sqs:SendMessageBatch",
"sqs:ReceiveMessage",
"sqs:SendMessage"
],
"Resource": "arn:aws:sqs:*:12345678:Stg"
}
]
}
Whenever is try to test it from API Gateway it throws below error:-
"Message": "The request must contain the parameter MessageGroupId."
So I tried to send it via query string but still the error persist.
I have followed the same steps as per the above link for body template and header.
MessageGroupId=098
Simply passing above value in query string and body is below
{"ty":"ui"}
You need to add MessageGroupId, and MessageDeduplicationId to the URL Query String Parameters in Method Execution. Same way you did for MessageBody.
You'll also need to add MessageGroupId, and MessageDeduplicationId to Integration Request. Again the same way you did with MessageBody.
You can extract the MessageGroupId and MessageDeduplicationId from the response of API gateway. eg: if the payload is something like below, you can extract the any properties from the payload.
Clear video tutorial here. https://www.youtube.com/watch?v=dXa9KA-G9Dg
Assume the payload is like this:
{
"data" :{
"jobNumber": "123456"
}
}
Then the template in api gateway is below. It extract the jobNumber from the payload and set to MessageGroupId. Here the MessageDeduplicationId is getting from the context.
#set($dedupId = $context.requestId)
#set($groupId = $input.json('$.data.jobNumber'))
Action=SendMessage&MessageBody=$input.body&MessageGroupId=$groupId&MessageDeduplicationId=$dedupId

Can I allow anonymous access to AWS API Gateway documentation?

I have a CloudFormation template that includes an API Gateway configured using an OpenAPI 3.0 body. I would like to make the OpenAPI specification available to the users of my API. Ideally within a nice GUI but this answer suggests that's not possible. I do not want to set up a developer portal.
My CFT contains a DocumentationVersion element that creates documentation for the API.
According to this and this I should be able to download my documentation from a URL like
https://apigateway.[my_aws_region].amazonaws.com/restapis/[my_api_id]/stages/[my_api_stage]/exports/oas30
Indeed when I go to this URL I get something like
{"logref":"56f5173b-a329-11e9-a8d5-e97c525eb634","message":"Missing Authentication Token"}
Which suggests that this will work with the correct token.
This page shows that you can control access to API documentation with a policy. (Although oddly it says that the account_id to use is the one of the users you want to grant access to - is that correct?)
So I tried adding the following resource to my CFT:
"ApiDocumentationAccessPolicy": {
"Type": "AWS::IAM::ManagedPolicy",
"Properties": {
"Description": "Read access to API documentation restricted by IP",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"apigateway:GET"
],
"Resource": {
"Fn::Join": [
"",
[
"arn:aws:apigateway::",
{ "Ref": "AWS::AccountId" },
":/restapis/",
"*/documentation/*"
]
]
},
"Condition" : {
"IpAddress": {
"aws:SourceIp": ["xxx.xxx.xxx.xxx" ]
}
}
}
]
}
}
},
However, I still get "Missing Authentication Token". I am confident that the "condition" part is correct as it is used elsewhere in CFT.
Is what I want to do possible, and if so where am I going wrong?
EDIT Adding "Principal": "*" to the policy statement above and also moving it directly to the APIGateway's policy don't appear to help either.

How do I confirm a subscription created using CloudFormation?

I have created a CF script that creates an EC2 instance that contains a web service. It also creates an SNS Topic and a Subscription that uses this web service as it's http endpoint.
The script successfully creates the stack; the Topic and the Subscription exist. However, the Subscription remains in the PendingConfirmation state.
What must I do to get my script to confirm this Subscription upon creation?
I had a similar issue and my problem ended up being a misconfigured CloudFomation template. An AWS::SQS::QueuePolicy is required to give your SNS topic permission to send messages to the queue.
"SQSQueuePolicy": {
"Properties": {
"PolicyDocument": {
"Id": "usecase1",
"Statement": [
{
"Action": "SQS:SendMessage",
"Condition": {
"ArnEquals": {
"aws:SourceArn": {
"Ref": "SnsTopic"
}
}
},
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Resource": {
"Fn::GetAtt": [
"SqsQueue",
"Arn"
]
},
"Sid": "1"
}
],
"Version": "2012-10-17"
},
"Queues": [
{
"Ref": "SqsQueue"
}
]
},
"Type": "AWS::SQS::QueuePolicy"
}
You need to Subscribe to endpoint for this to work.
Read the value for SubscribeURL and visit that URL. To confirm the subscription and start receiving notifications at the endpoint, you must visit the SubscribeURLURL (for example, by sending an HTTP GET request to the URL)
When you visit the URL, you will get back a response that looks like the following XML document. The document returns the subscription ARN for the endpoint within the ConfirmSubscriptionResult element.
<ConfirmSubscriptionResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
<ConfirmSubscriptionResult>
<SubscriptionArn>arn:aws:sns:us-west-2:123456789012:MyTopic:2bcfbf39-05c3-41de-beaa-fcfcc21c8f55</SubscriptionArn>
</ConfirmSubscriptionResult>
<ResponseMetadata>
<RequestId>075ecce8-8dac-11e1-bf80-f781d96e9307</RequestId>
</ResponseMetadata>
</ConfirmSubscriptionResponse>
As an alternative to visiting the SubscribeURL, you can confirm the subscription using the ConfirmSubscription action with the Token set to its corresponding value in the SubscriptionConfirmation message. If you want to allow only the topic owner and subscription owner to be able to unsubscribe the endpoint, you call the ConfirmSubscription action with an AWS signature.
You can Refer to this AWS Documentation
Hope this Helps!