AWS Custom Authorizer with request parameters - amazon-web-services

I'm building a rest API with serverless. I've built a custom authorizer to retrieve custom policies, everything was working fine until I've bump into retrieving policies with request parameters, example: base/As/{aId}/Bs/{bId}
Example of policies I'm retrieving right now:
{
"principalId": "some id",
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "allow",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:{region}:{apiId}/{stage}/GET/As/*"
}
]
}
so my issue is the above policy should only be to retrieve a specific "A", but when I want to call some "B" that only is accessible through a "A", I'll need to call a endpoint like base/As/{aId}/Bs/{bId}, with the above policy I'll have permission to access request this endpoint, when I shouldn't.
Is there a way to have request parameters in the resource in the policy?

There isn't a way to put request parameters in the resource policy. I don't see how that could be secure. The policy should only be stating explicitly allowed actions on resources.
You may have to enumerate several resources in your policy (array is allowed).

Related

Can I grant lambda access to other accounts using Organization Unit IDs?

I want to create a lambda that will exist in one central account and that will get invoked by other accounts within my Organization. I know it is possible to grant access for another individual account to invoke a lambda using a resource policy, but can I grant access to all accounts in my Organization using Organization Unit IDs somehow? If so, how?
Ideally I want to make it so as new accounts get added in my Organization they will automatically have access to invoke the lambda without requiring me to update the policy and grant them access via the individual account ID.
In the Principal part of the resource policy, you can only provide AWS accounts, users, roles etc but no organizational units. However, there is a condition called aws:PrincipalOrgPaths which I think can help you achieve what you want.
I found this can be done using a resource policy on the lambda function with a condition that specifies the aws:PrincipalOrgID, such as
{
"Version": "2012-10-17",
"Id": "default",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "lambda:InvokeFunction",
"Resource": "arn:aws:lambda:us-east-1:098765432109:function:My_Example_Function",
"Condition": {
"StringEquals": {
"aws:PrincipalOrgID": "o-myorgidexample"
}
}
}
]
}

Control role permission in AWS

I'm new to AWS. I'm developing an application using Spring boot. I use AWS cognito for the sign in and sign up. I created a group called ROLE_ADMIN in cognito and connect with IAM role which was also created by me as ROLE_ADMIN_IAM.
I'm using AWS Api gateway (HTTP Apis, but similarly REST Apis) to communicate with Apis. Then integrated the Cognito jwt authorizer in Api gateway.
Everything working perfectly. The problem I'm facing now is, when a user sign in, I need to prevent few Apis based on his role which is in cognito groups. So I tried to attach policies to IAM role (ROLE_ADMIN_IAM already created), but it doesn't work.
This is what I attached to ROLE_ADMIN_IAM
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": [
"apigateway:GET"
],
"Resource": [
"arn:aws:apigateway:ap-south-1::/apis/09bccr0"
]
}
]
}
I tried restrict every resources also. But doesn't work
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": "*",
"Resource": "*"
}
]
}
I'm afraid whether the way I tried is wrong or correct? I've been working for days. But couldn't find any solution. Please anyone give me a solution. Thanks in advance.
Update 1.
Since this doesn't work, I created a Identity pool and attached user pool Id and client id with it. It automatically creates two Roles for authentication user and unauthentication user. Then I went to Api gateway and changed the authorizer to IAM. The documentation itself says when we use IAM as an authorizer we need to use Signature 4 version. (I switched to IAM form cognito jwt, because I don't find any documentation or article say I can go with cognito jwt when we use Identity pool to define roles).
In the react application, I use amplify. When I configure Identity pool, it provides temporary Accesskey and SecretKey after a successful login. I tried to use it with postman -> Authorization -> AWS Signature, it always gives {"message":"Forbidden"}
When you create a group in a Cognito user pool you need to attach proper IAM role to that group. IAM policy that allows actual API calls should look like that:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"execute-api:Invoke"
],
"Resource": [
"arn:aws:execute-api:us-east-1:*:a123456789/test/POST/mydemoresource/*"
]
}
]
}
You just need to replace demo string with your API Gateway ARN, method and endpoint. Pay attention to the "execute-api:Invoke" action.
Permission "apigateway:GET" does not allow you to call an API but to get service information about API. "apigateway:*" permissions allow you to make management AWS API call not actual API call.
For more information please check these articles:
Management calls
Execution calls

How to create an IAM role of specific type using boto3?

I'm trying to lock down a user to a specific VPC in AWS and following How to Help Lock Down a User’s Amazon EC2 Capabilities to a Single VPC | AWS Security Blog.
It is mentioned that we need to create an IAM role with name VPCLockDown of type AWS Service
and add the services for which the role needs access to. like ec2, lambda etc.
I was trying to create this role programatically using boto3.
I checked the create_role documentation for creating a role using boto3.
However, they haven't mentioned anything to specify the type of role and the services that I can specify that the role should have access to.
Is there any way to specify these items while creation of the IAM role using boto3
Edit1:
I tried creating a service_linked_role as per Sudarshan Rampuria's answer like
response = iam.create_service_linked_role(
AWSServiceName='ec2.amazonaws.com',
)
But getting the following error:
An error occurred (AccessDenied) when calling the
CreateServiceLinkedRole operation: Cannot find Service Linked Role
template for ec2.amazonaws.com
You can use create_service_linked_role() function boto3 to link a role to a service.
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/iam.html#IAM.Client.create_service_linked_role
Here is a policy that allows a specific IAM User to launch an instance (RunInstances), but only in a given VPC:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EC2RunInstancesVPC",
"Effect": "Allow",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:ap-southeast-2:111111111111:subnet/*",
"Condition": {
"StringEquals": {
"ec2:vpc": "arn:aws:ec2:ap-southeast-2:111111111111:vpc/vpc-abcd1234" <--- Change this
}
}
},
{
"Sid": "RemainingRunInstancePermissions",
"Effect": "Allow",
"Action": "ec2:RunInstances",
"Resource": [
"arn:aws:ec2:ap-southeast-2:111111111111:instance/*",
"arn:aws:ec2:ap-southeast-2:111111111111:volume/*",
"arn:aws:ec2:ap-southeast-2::image/*",
"arn:aws:ec2:ap-southeast-2::snapshot/*",
"arn:aws:ec2:ap-southeast-2:111111111111:network-interface/*",
"arn:aws:ec2:ap-southeast-2:111111111111:key-pair/*",
"arn:aws:ec2:ap-southeast-2:111111111111:security-group/*"
]
}
]
}
You might need to change the Region. (I tested it in the Sydney region.)
For anyone trying to do this for Lambda, we get the similar error mentioned by the question author under "Edit". Lambda doesn't have a service linked role. You can see from the AWS Lambda documentation that "create-role" is used for creating lambda execution role.
You can also see here that only Lambda#Edge has service linked role.
One just needs to use use boto3 create-role with a policy document
response = iam_client.create_role(
RoleName="some-role-name",
AssumeRolePolicyDocument='{"Version": "2012-10-17","Statement": [{ "Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole"}]}',
Description='Lambda role'
)

Restrict access to S3 static website that uses API Gateway as a proxy

I have an S3 bucket that acts as a static website and I am using API Gateway to distribute traffic to it. I understand CloudFront is a better option here, but please do not suggest it. It is not an option, due to reasons I won't go into.
I am accomplishing my solution by configuring a {proxy+} resource. Image below:
I would like to only allow access to the S3 website from the API Gateway proxy resource. Is there a way I can provide an execution role to the proxy resource, similarly to how you can provide an execution role to a resource to runs a lambda function? Lambda execution role example below:
The integration request portion of the proxy resource doesn't seem to have an execution role:
Or is there a way I can assign a role to the entire API Gateway to provide it the right to access the S3 bucket?
Other things I have tried:
Editing the bucket policy to only allow traffic from the API gateway service:
{
"Version": "2012-10-17",
"Id": "apiGatewayOnly",
"Statement": [
{
"Sid": "apiGW",
"Effect": "Allow",
"Principal": {
"Service": ["api-gateway-amazonaws.com"]
},
"Action": "s3:GetObject",
"Resource": "http://test-proxy-bucket-01.s3-website.us-east-2.amazonaws.com/*"
}
]
}
Editing the bucket policy to only allow traffic from API Gateway's URL:
{
"Version": "2012-10-17",
"Id": "http referer policy example",
"Statement": [
{
"Sid": "Allow get requests originating from www.example.com and example.com.",
"Effect": "Allow",
"Principal": "",
"Action": "s3:GetObject",
"Resource": "http://test-proxy-bucket-01.s3-website.us-east-2.amazonaws.com/",
"Condition": {
"StringLike": {
"aws:Referer": [
"https://xxxxxxx.execute-api.us-east-2.amazonaws.com/prod/",
"http://xxxxxxxx.execute-api.us-east-2.amazonaws.com/prod"
]
}
}
}
]
}
Create a private S3 bucket
Create an IAM role that can access the bucket. Set the trusted entity/principal who can assume this role to apigateway.amazonaws.com
Use AWS service integration type and select s3. Set the execution role to the role created in 2
Refer to docs for more details.

How do I limit access to S3 Bucket for particular IAM Role?

We want to store some data on S3 and only allow EC2 instances or a particular user with a particular IAM role to access them. Unfortunately we're having some trouble doing this.
We set a policy on the bucket like this
{
"Version": "2012-10-17",
"Id": "SamplePolicy",
"Statement": [
{
"Sid": "Stmt1331136294179",
"Effect": "Deny",
"NotPrincipal": {
"AWS": [
"arn:aws:iam::our-account-number:user/the-user",
"arn:aws:iam::our-account-number:role/the-role"
]
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::the-bucket/*"
},
{
"Sid": "Stmt1331136364169",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::our-account-number:user/the-user",
"arn:aws:iam::our-account-number:role/the-role"
]
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::the-bucket/*"
}
]}
When we access the Bucket (using boto) with users key it works fine, from a local machine or any EC2 instance.
But, when we access the bucket from Boto we get
ClientError: An error occurred (AccessDenied) when calling the GetObject operation: Access Denied
I've confirmed that the instance has the correct IAM role
curl http://169.254.169.254/latest/meta-data/iam/info/
{
"Code" : "Success",
"LastUpdated" : "2015-10-22T09:09:31Z",
"InstanceProfileArn" : "our-account-number:instance-profile/the-role",
"InstanceProfileId" : "instance-rpofile-id"
}
I've also tried to remove the policy from the bucket, which indeed makes it accessible again.
Any ideas how to handle this?
The sample I shared here is a simplified version I've been doing for debugging. In production, we want are forcing the object to be encrypted with KMS and have an access policy on the key as well. We like that solution alot, and prefer to keep it if we can.
Thanks
One mistake with this that I've made many times involves your ARN
For some permissions you need it on the bucket itself (no /*)... and some you need on it's contents.
I'd attempt to use what you currently have, only include both, so something like...
"Resource": ["arn:aws:s3:::the-bucket/*", "arn:aws:s3:::the-bucket"]
The issue here is that for NotPrincipal you have to provide the specific session role. Unfortunately, when using InstanceProfiles (or Lambda), this session role is dynamic. AWS does not support wildcards in the principal field so therefore it is basically impossible to use NotPrincipal with an InstanceProfile.
See AWS support response here that acknowledges it as a known limitation: https://forums.aws.amazon.com/message.jspa?messageID=740656#740656