I have an API Gateway endpoint with IAM authentication, no Custom Domain Names, no API Key, API is deployed to Prod and no AWS WAF enabled (TBMK) and VPC proxy integration request method.
I am calling this endpoint from a Lambda (with attached execute-api:Invoke permission to call the API), however I am getting a 403 error with message Forbidden. Notice that if I remove the IAM authentication method, the call from Lambda works fine.
I've already seen this and this SO questions + AWS Doc on the topic but I've already tried these solutions (as explained before).
Sample code for calling API Gateway inside Lambda:
final HttpURLConnection connection = (HttpURLConnection) new URL(postApiUrl).openConnection();
connection.setRequestMethod("POST");
final int responseCode = connection.getResponseCode();
//...
How I attach API Gateway ARN to Lambda role in CDK:
this.addToRolePolicy(
new PolicyStatement({
actions: [execute-api:Invoke],
effect: Effect.ALLOW,
resources: [postMethod.methodArn],
}),
);
You have set up IAM authentication for your API GW method, but your Lambda function code does not sign the request made to API GW. Note: Simply adding the execute-api:Invoke permission to the Lambda function execution role does not sign the request.
You need to use the AWS SigV4 signing process to add the authentication information which is then verified on the API GW end. This doc lists the steps involved which basically are:
Create a canonical request.
Use the canonical request and additional metadata to create a string for signing.
Derive a signing key from your AWS secret access key. Then use the signing key, and the string from the previous step, to create a signature.
Add the resulting signature to the HTTP request in a header or as a query string parameter.
Since you're using Java, this blog post also provides some sample code which you can refer to.
APIG has a authorizer cache, check this out.
https://aws.amazon.com/premiumsupport/knowledge-center/api-gateway-403-error-lambda-authorizer/
If you could have a read and perhaps elaborate a little I'll include the proper solution.
Related
I have created a basic lambda with lambda function url.
auth_type = aws_iam
allowed permissions for ec2 role in lambda resource based policy.
created a role to ec2 instance with full lambda permissions in the policy and attached it to the ec2 instance.
While invoking it from ec2 as below its getting forbidden error.
curl "https://<url-id>.lambda-url.<region>.on.aws"
I have tried with auth_type as none. Its working, but not working when i try with auth_type as aws_iam.
As explained in the docs, to invoke a lambda url with AWS_IAM, you have to sign your url request by constracting special URL which has your signature. Please check docs on how to construct a valid signature for URL requests.
I have the following
let lambdaFunction = <some lambda construct here>
lambdaFunction.grantInvoke(props.invocationRole);
And that grants hydra the ability to invoke that lambda, but what if I had an api endpoint method?
let endpoint = resource.addMethod(method['method'], lambdaIntegration, {
authorizationType: AuthorizationType.IAM,
requestValidator: props.requestValidator,
requestModels: {'application/json': props.validationModel}
})
Is it possible to grant the role that I have access to just this endpoint access or do I have to do it on the api gateway resource level?
I have no experience with API Gateway, however it looks like it does support access control using the specificity of a particular endpoint.
Reference Docs:
https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-control-access-using-iam-policies-to-invoke-api.html
Using the CDK, you can apply a policy with the same structure as the examples in the docs.
Using CDK, I have a gateway rest api lambda which I want to be accessible to;
Members of a cognito user pool
Other lambdas in my stack
As far as I know there is no way to add 2 authorizers to the same gateway resource method?
So this means I have 2 options;
Create custom Lambda authoriser which verifies tokens for cognito and IAM
Add 2 separate recourses to my api and call a different endpoint from my client vs my lambdas. E.g:
/external/route1 with cognito authorizer
/internal/route1 with iam authorizer
Which of these approaches is better? I imagine option 2 is easier to setup. Are there any CDK examples or constructs that could help me with this?
You can run Cognito authorizers down the whole stack and then check the scopes per internal service. At a gateway, Cognito authorizers will validate the token and check the scopes against what you've specified. I don't know about CDK, but if you're using Pulumi Crosswalk, it's really trivial to setup Cognito Authorizers in APIGW, something like this:
const api = new awsx.apigateway.API(<NAME>, {
routes: [{
path: <PATH>,
method: <METHOD>,
eventHandler: <LAMBDA>,
authorizers: [awsx.apigateway.getCognitoAuthorizer({
providerARNs: [<USERPOOL>],
methodsToAuthorize: ['<RESOURCE>/<SCOPE>']
})]
}]
});
I am trying to get a session token for the given IAM in postman but not able to receive a token.
If I use boto3.client('sts'), I am able to get the token.
Use Case: I am trying to Invoke VPC Rest Endpoint from EC2 instance where ServiceNow mid-server instance is running. Since we have ServiceNow mid-server agent running on EC2 instance, I want to use IAM Role attached to EC2 to authenticate other VPC endpoints that are deployed in the same AWS account.
I have permission policy attached to IAM Role to allow Assume Role policy. If there any other approach, please suggest.
here HTML HTML response in postman. Postman redirecting to IAM Docs
client = boto3.client('sts')
response = client.assume_role(
RoleArn='arn:aws:iam::**************:role/ServiceNow-midserver-Role',
RoleSessionName='Session1',
DurationSeconds=3600
)
print(response)
anything wrong with postman request body or endpoint.
Authentication on postman is none.
To call AssumeRole from Postman (or curl etc.) as opposed to using a supported AWS SDK, you should follow the AssumeRole API documentation. You will also need to authenticate using AWS credentials.
Specifically, the request is an HTTP GET and parameters are passed as query strings, for example:
GET https://sts.amazonaws.com/
?Version=2011-06-15
&Action=AssumeRole
&RoleSessionName=stackoverflow-64706420
&RoleArn=arn:aws:iam::123456781234:role/myrole
&DurationSeconds=3600
Here's what this looks like in Postman:
And you will need to add AWS credentials so that your API request is signed correctly, for example:
Click 'Send' and the response will look something like this:
<AssumeRoleResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
<AssumeRoleResult>
<AssumedRoleUser>
<Arn>arn:aws:sts::123456781234:assumed-role/123456781234/stackoverflow-64706420</Arn>
<AssumedRoleId>ARO123EXAMPLE123:stackoverflow-64706420</AssumedRoleId>
</AssumedRoleUser>
<Credentials>
<AccessKeyId>ASIAIOSFODNN7EXAMPLE</AccessKeyId>
<SecretAccessKey>wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY</SecretAccessKey>
<SessionToken>
AQoDYXdzEPT//////////wEXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQW
LWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI/qkPpKPi/kMcGd
QrmGdeehM4IC1NtBmUpp2wUE8phUZampKsburEDy0KPkyQDYwT7WZ0wq5VSXDvp75YU
9HFvlRd8Tx6q6fE8YQcHNVXAkiY9q6d+xo0rKwT38xVqr7ZD0u0iPPkUL64lIZbqBAz
+scqKmlzm8FDrypNC9Yjc8fPOLn9FX9KSYvKTr4rvx3iSIlTJabIQwj2ICCR/oLxBA==
</SessionToken>
<Expiration>2020-12-09T13:34:41Z</Expiration>
</Credentials>
<PackedPolicySize>6</PackedPolicySize>
</AssumeRoleResult>
<ResponseMetadata>
<RequestId>c6104cbe-af31-11e0-8154-cbc7ccf896c7</RequestId>
</ResponseMetadata>
</AssumeRoleResponse>
You need to use credentials for an IAM user or an IAM role to call AssumeRole. boto3 must be getting credentials from the standard locations it look for (like ~/.aws/config) [ref:https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html]. May be you could try providing the AWS creds in Authorization tab in Postman selecting type as AWS Signature and then call assumeRole.
I've managed to successfull login to the API gateway I've made via my iOS device and Cognito. The problem is I'd like to use postman to test the API calls then implement them on the phone. Currently, Postman cannot authenticate (despite AWS saying it can). No matter what I do I get a 401 error (visible in the screen-shots)
What I've tried
Downloaded the postman collection from AWS Api Gateway
Then imported it into postman, and switch the authentication to "AWS Signature"
And Here is a screen shot of the Postman Generated Header Info
If I understand correctly, you are trying to call an API Gateway endpoint that is behind the built-in Cognito Authoriser.
I think you've misunderstood how you call an Cognito Authorised API Gateway:
Authorise against Cognito to get an id_token
Call API Gateway with the Authorization header set to id_token
Renew id_token every hour
By enabling ADMIN_NO_SRP_AUTH you're allowing the first step (sign-in to Cognito) to be simplified so that you can more easily do it manually. (If you hadn't, then you would need to do SRP calculations).
One way to get the id_token is to use the aws cli (further ways are shown in the documentation):
aws cognito-idp admin-initiate-auth --user-pool-id='[USER_POOL_ID]' --client-id='[CLIENT_ID]' --auth-flow=ADMIN_NO_SRP_AUTH --auth-parameters="USERNAME=[USERNAME],PASSWORD=[PASSWORD]"
You can then use the result (AuthenticationResult.IdToken) as the Authorization header in Postman (no need for the AWS v4 signature- that is only for IAM authentication).
n.b. a much fuller explanation with images can be found here.
Here is what I finally did to fix postman auth issues
1) Turned off App Client Secret in the Cognito pool.
2) Ran aws --region us-east-1 cognito-idp admin-initiate-auth --cli-input-json file://gettoken.json
JSON file example
{
"UserPoolId": "us-east-1_**********",
"ClientId": "******************",
"AuthFlow": "ADMIN_NO_SRP_AUTH",
"AuthParameters": {
"USERNAME": "*********",
"PASSWORD": "***********"
}
}
3) Went to Postman > Authorization > Bearer Copied the idToken value into the token field and everything worked.
NOTE: For those wondering if not using a secret client key is safe. See this article.