AWS API Gateway Reverse Http Proxy to SQS Access Denied - amazon-web-services

I am trying to use AWS API Gateway as a reverse (forwarding) proxy to AWS SQS using the configuration as seen in the screenshots. I essentially want to send a REST request to the API Gateway which then gets forwarded directly to the SQS REST API and returns the response.
When I send a request to the gateway, I immediately get back
<?xml version="1.0"?>
<ErrorResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/">
<Error>
<Type>Sender</Type>
<Code>AccessDenied</Code>
<Message>Access to the resource https://sqs.us-east-1.amazonaws.com/ is denied.</Message>
<Detail/>
</Error>
<RequestId>51c903b2-4da3-5d5e-a3b8-589ee72167de</RequestId>
</ErrorResponse>
However, when I switch the request URL to SQS directly (https://sqs.us-east-1.amazonaws.com) the request succeeds.
What am I missing?
curl --request POST 'https://my-api-gateway.com/sqs' \
--header 'X-Amz-Date: <date>' \
--header 'X-Amz-Security-Token: <token>' \
--header 'Authorization: <auth>' \
--header 'Amz-Sdk-Invocation-Id: <invocation>' \
--header 'Amz-Sdk-Request: attempt=1; max=10' \
--header 'User-Agent: aws-sdk-go-v2/1.16.5 os/macos lang/go/1.18.3 md/GOOS/darwin md/GOARCH/arm64 api/sqs/1.18.6' \
--header 'Content-Length: 206' \
--data-urlencode 'Action=ReceiveMessage' \
--data-urlencode 'MaxNumberOfMessages=10' \
--data-urlencode 'QueueUrl=<my-queue-url>' \
--data-urlencode 'Version=2012-11-05' \
--data-urlencode 'WaitTimeSeconds=20'

The API gateway integration needs to have an invocation role attached to it. This IAM role must have SendMessage policy for your SQS, so that your API gateway integration has access to push data to your queue.
For this, first create an IAM role with this policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "sqs:SendMessage",
"Resource": "arn:aws:sqs:eu-west-1:1234:your-queue-name"
}
]
}
Now go to API Gateway > Manage Integrations > Select your integration > Edit > Add the ARN of the newly created IAM role in Invocation role field
like this

Related

Request Contains Invalid Argument when calling signJwt

I'm attempting to call Google Cloud's signJwt method with Workload Identity Federation with a service account via domain wide delegation. As far as I can tell I'm following Google's instructions exactly but am getting the following error:
{
"error": {
"code": 400,
"message": "Request contains an invalid argument.",
"status": "INVALID_ARGUMENT"
}
}
I'm running the following curl command in the Cloud Shell
curl -X POST \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json; charset=utf-8" \
-d #request.json \
"https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/<SA_USERNAME>%40<PROJECT_NAME>.iam.gserviceaccount.com:signJwt"
where request.json contains the following:
{
"payload": "{\"iss\":\"<SA_USERNAME>#<PROJECT_NAME>.iam.gserviceaccount.com\",\"scope\":\"https://www.googleapis.com/auth/gmail.readonly\",\"aud\":\"https://oauth2.googleapis.com/token\",\"exp\":1672868057013,\"iat\":1672868053513,\"sub\":\"<USER_NAME_OF_USER_TO_IMPERSONATE>#<DOMAIN>\"}",
"delegates": [],
}
Why am I getting an invalid argument error?
Try something like this in the request body :
{
"delegates": [
string
],
"payload": string
}
As given in the document:
The sequence of service accounts in a delegation chain. Each service
account must be granted the roles/iam.serviceAccountTokenCreator role
on its next service account in the chain. The last service account in
the chain must be granted the roles/iam.serviceAccountTokenCreator
role on the service account that is specified in the name field of the
request.
The delegates must have the following format: projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}. The - wildcard character is required; replacing it with a project ID is invalid.
Also there is a bug request on it.You can raise a new request if you need it by using the issue tracker.

Invalid Credentials using Google Cloud Platform Buckets

We have a bucket in Google Cloud Platform to manage pictures.
I am trying to upload a picture to it using Curl.
Respective to the official documentation linked here, this is the Curl-command I used:
curl -X POST --data-binary #cat.jpeg \
-H "Authorization: Bearer A_STRING_SUPPOSED_TO_BE_A_KEY" \
-H "Content-Type: image/jpeg" \
"https://storage.googleapis.com/upload/storage/v1/b/upload_zone/o?uploadType=media&name=cat"
This is the answer we get:
{
"error": {
"code": 401,
"message": "Invalid Credentials",
"errors": [
{
"message": "Invalid Credentials",
"domain": "global",
"reason": "authError",
"locationType": "header",
"location": "Authorization"
}
]
}
}
It seems our key is invalid, we are not sure what to use as Authorization key. Where can we find the OAUTH2.0-key required to make use of the Google Cloud Platform Bucket, do we need to generate it somewhere?
Edit:
We have generated a key using the OAuth 2.0-Playground, and it worked! But the key expires every 3000 seconds...
If you are already authenticated to Google using the gcloud sdk, you can get the key like this:
-H "Authorization: Bearer $(gcloud auth print-identity-token)"
So, using your example above, this should work:
curl -X POST --data-binary #cat.jpeg \
-H "Authorization: Bearer $(gcloud auth print-identity-token)" \
-H "Content-Type: image/jpeg" \
"https://storage.googleapis.com/upload/storage/v1/b/upload_zone/o?uploadType=media&name=cat"

Error while creating service account in GCP via SDK

I have been using Google's SDKs to perform API calls such as creating a service account, creating service account keys, get the storage buckets, etc.. Recently I'm unable to create a service account due to the below error.
Request:
curl --location --request POST 'https://iam.googleapis.com/v1/projects/myproject/serviceAccounts' \
--header 'Authorization: Bearer <<token>>' \
--header 'Accept-Encoding: gzip' \
--header 'User-Agent: my test Google-API-Java-Client'
c.g.a.c.g.j.GoogleJsonResponseException: 404 Not Found
{
"code" : 404,
"errors" : [ {
"domain" : "global",
"message" : "Not found; Gaia id not found for email xxxxx#myproject.iam.gserviceaccount.com",
"reason" : "notFound"
} ],
"message" : "Not found; Gaia id not found for email xxxxx#myproject.iam.gserviceaccount.com",
"status" : "NOT_FOUND"
}
Why would I require Gaia id while creating service account? Where can I find this id? Any help is appreciated!!
Did you ever remove the service account 'xxxxx#myproject.iam.gserviceaccount.com' which should be the default service account for IAM API, you can recover it within the 30days after the deletion. or just disable it and re-enable it , will recreate the default service account for you. Let me know if it resolved the issue.
It seems that your request needs to have a body
The request body contains data with the following structure:
{
"accountId": string,
"serviceAccount": {
object (ServiceAccount)
}
}
And it is missing in your command.
You can obtain more information in this documentation.
In your case it should be something like:
curl --request POST \
'https://iam.googleapis.com/v1/projects/my-little-project/serviceAccounts?key=[YOUR_API_KEY]' \
--header 'Authorization: Bearer [YOUR_ACCESS_TOKEN]' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{"accountId":"sa-test","serviceAccount":{"description":"sa-description-test","displayName":"sa-display-testonly"}}' \
--compressed
You can test this API directly in the following link
Also, I have found a similar error, in this stackoverflow case according to this answer this error could be generated if the APIs are not enabled.

How can I attach an API Key as a token barer to a POST method with terraform aws api gateway resources

I have dissected the Terraform AWS Api Gateway Resources documentation and I don't find a clear documentation around how I can create and attach an API Key as a Token Barer autorization to an API Gateway POST method with terraform
My CURL command would look something like this:
curl --location --request POST 'https://foobar123.execute-api.us-east-1.amazonaws.com/test' \
--header 'Authorization: Bearer AAABBBsKen4vcVDQVkZyu7lpEWGcs1o64bz7TCb1' \
--header 'Content-Type: text/plain' \
--data-raw '{"foo": "bar"}'
How do I achieve this with terraform?
It's an option on the gateway method (the last option):
resource "aws_api_gateway_method" "task_method" {
rest_api_id = aws_api_gateway_rest_api.api.id
resource_id = aws_api_gateway_resource.api_task.id
http_method = "POST"
authorization = "NONE"
api_key_required = true
}
The documentation isn't very explicit, but this example does work.

How to use Custom Authorizer on Api Gateway?

Custom Authorization
Lambda Execution Role : Full Access Api Gateway and Lambda
Token Source: method.request.header.Authorization
Token Validation: blank
Add this custom authorization to api method request . Authorizers test is succes but ı request to api on Postman then 401.
{
"message": "Unauthorized"
}
Custom Authorizer Lambda
console.log('Loading function');
exports.handler = function(event, context, callback) {
console.log("event:",JSON.stringify(event)); console.log("event:",JSON.stringify(context));
console.log('Client token: ' + event.authorizationToken);
console.log('Method ARN: ' + event.methodArn);
callback(null, {
"principalId": "18",
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1459758003000",
"Effect": "Allow",
"Action": [
"execute-api:Invoke"
],
"Resource": [
"arn:aws:execute-api:*"
]
}
]
}
});
}
Postman Code:
curl --request GET \
--url {url} \
--header 'authorization: Test Token' \
--header 'cache-control: no-cache' \
--header 'content-type: application/json' \
--header 'postman-token: c9110a92-414e-e1aa-61fb-194758dace86'
Solution
Token Source: Authorization
API Gateway has changed, as of today Jan 18. Following needs to be know.
If the Method's Integration Request is not lambda proxied. While creating custom authorier (in Authorizer tab) , you should enter Token Source as "Authorization" and not "method.request.header.Authorization". Also , in the Method Request tab of the method ( eg GET) , you should set the HTTP Header Mapping , for 'Authorization'.
If the Method's Integration Request is proxied , no mapping is required. All the request body+header+parameter+AWSextraStuff is avaliable in the event[] object of lambda. Hence no mapping is required.
Few more pitfall be careful.
- Use standard string like 'Authorization' ( which is a standard) , is you use different string , change every where.
- The authorization token when passed to lambda, for no proxied integration request, as event['authorizationToken']and not event['Authorization']
- If you get error like Lambda Malform... , it is because you are using Lambda Proxy and it requires response in specific format, your not sending data in tha format.
- If your using Postman , switch to 'raw' against 'pretty' mode.
To call an API with the custom TOKEN authorizer
Open Postman, choose the GET method and paste the API's Invoke URL into the adjacent URL field.
Add the custom authorization token header and set the value to allow. Choose Send.
Worth read - http://docs.aws.amazon.com/apigateway/latest/developerguide/use-custom-authorizer.html#call-api-with-api-gateway-custom-authorization
You don't call the Custom Authorizer through Postman, that's API Gateways' job.
Every time that you call an endpoint protected by your custom authorizer the API Gateway will check if the value of the given Authorization Header exists in its Policies Cache. If the value does not exist, your Custom Authorizer will be called to authenticate the request.
A simple representation of the flow:
Lambda Handler (handles a protected endpoint GET /users/{id})
|
| ------------
| |
| Custom Authorizer
| /
| / (if the request is not authorized yet)
| /
Api Gateway
|
|
|
Request (with Authorization Header)
You just have to set the Authorization of your resource method to your custom authorizer and let the API Gateway do all the work.