I've created a lambda function to add new users created in my React app to a group in my cognito user pool.
I used this guide from the docs to be able to call the the lambda function via AppSync.
Now when I run the function I get the following expected error:
User: [redacted] is not authorized to perform: cognito-idp:AdminAddUserToGroup on resource: [redacted]
So far I've added this additional policy to the role in CustomResources.json:
{
"PolicyName": "CognitoAuthLambdaFunction",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["cognito-idp:AdminAddUserToGroup"],
"Resource": [
{
"Fn::Sub": [
"arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:setUsersGroup-${env}",
{ "env": { "Ref": "env" } }
]
}
]
}
]
}
}
How do I dynamically reference the cognito user pool so that I can switch between envs?
I assume the policy you've given in the question is the Lambda Execution policy, i.e. the one passed to Lambda at runtime. This policy will authorise your code running in Lambda to call the given list of API.
If my assumption is correct, there is a mistake in the policy, as the resource property refers to your Lambda function itself (ARN starts with arn:aws:lambda), while it should refer to the User Pool you want to grant access to (ARN should start with arn:aws:cognito-identity).
See https://docs.aws.amazon.com/cognito/latest/developerguide/resource-permissions.html
Assuming the Cognito User Pool is created in the same CloudFormation template, you can access the Cognito User Pool ARN using the Fn::GetAtt intrinsic function, such as
{ "Fn::GetAtt" : [ "logical_resource_id_cognito_user_pool", "ARN" ] }
See https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cognito-userpool.html for attributes available on AWS::Cognito::UserPool resource type.
Related
We're using AWS Cognito and AWS IAM to manage our users and their permissions to access certain resources in our static website built in JavaScript. Before we make certain requests using the AWS SDK we'd like to know what permissions the user has via their Role.
For example in AWS Console we can see the following:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"cognito-idp:GetUser",
"iam:ListPoliciesGrantingServiceAccess",
"cognito-idp:ListUsers"
],
"Resource": "*"
}
]
}
Using the SDK we've found a method to get the Policies for the User/Role:
const iam = new AWS.IAM();
iam.listPoliciesGrantingServiceAccess({
Arn: arn,
ServiceNamespaces: [
"iam",
"cognito-idp"
]
}, (err, data) => {
if (err) {
console.log(err);
}
else {
console.log(data);
}
})
However this doesn't return the permissions these policies contain and only returns the actual policies themselves...
[
{
"ServiceNamespace":"iam",
"Policies":[
{
"PolicyName":"admin-policy",
"PolicyType":"INLINE",
"EntityType":"ROLE",
"EntityName":"Cognito_Auth_Role"
}
]
},
{
"ServiceNamespace":"cognito-idp",
"Policies":[
{
"PolicyName":"admin-policy",
"PolicyType":"INLINE",
"EntityType":"ROLE",
"EntityName":"Cognito_Auth_Role"
}
]
}
We haven't been able to find any methods that get permissions for a policy... How can we access this information for a given User/Role?
Here are the relevant SDK v3 methods. For the above example, you would use GetRolePolicy or ListRolePolicies:
PolicyType: INLINE
Get[User|Role|Group]PolicyCommand: Retrieves the specified inline policy document that is embedded in the specified entity.
List[User|Role|Group]PoliciesCommand: Lists the names of the inline policies embedded in the specified entity.
PolicyType: MANAGED
GetPolicyCommand to get the default version and GetPolicyVersionCommand to retrieve the policy document.
ListAttached[User|Role|Group]PoliciesCommand: Lists all managed policies that are attached to the specified IAM entity.
I am logged in as LeadDeveloperRole in aws console and created a secret in secrets manager. I want this secret to be only accessible to
LeadDeveloperRole and AdminRole, so i used below mentioned resource policy on this secret. While saving this policy it shows an error saying:
"This resource policy will not allow you to manage this secret in the future."
As per my understanding, Deny + NotPrincipal implies apart from LeadDeveloperRole and AdminRole, no one will have access to this.
Am i missing something here ?
{
"Version":"2012-10-17",
"Statement":[
{
"Effect":"Allow",
"Principal":{
"AWS":[
"arn:aws:iam::111111111:role/LeadDeveloperRole",
"arn:aws:iam::111111111:role/AdminRole"
]
},
"Action": [
"secretsmanager:*"
],
"Resource":"arn:aws:secretsmanager:region:111111111:secret:secretid-xxxx1i"
},
{
"Effect":"Deny",
"NotPrincipal":{
"AWS":[
"arn:aws:iam::111111111:role/LeadDeveloperRole",
"arn:aws:iam::111111111:role/AdminRole"
]
},
"Action": [
"secretsmanager:*"
],
"Resource":"arn:aws:secretsmanager:region:111111111:secret:secretid-xxxx1i"
}
]
}
UPDATED:
updated the policy with explicit allow which is giving same error.
Try adding the account principal to the list of NotPrincipals, as without it a request can be blocked e.g. "arn:aws:iam::111111111:root" or just the account ID number.
From the docs:
When you use NotPrincipal with Deny, you must also specify the account ARN of the not-denied principal.
Try to use cognitoIdentityService.listUsers with a role running ec2 machine and it works great in the local org (orgA).
I also want the same role to listUser in another org (orgB).
I created a a role with trust in the orgB with orgA in the Trust relationship and gave it Cognito permissions
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::xxxxxxxxxxxx:root"
},
"Action": "sts:AssumeRole"
}
]
}
Then in orgA i added an inline policy to the role i want to give access
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::xxxxxxxxxxxx:role/orgBCognitoAccess"
}
}
I pass the REGION and USERPOOLID to my function.
const params = {
"UserPoolId": UserPoolId,
"Filter": `email = \"${email}\"`,
"Limit": 1
}
cognitoIdentityService.listUsers(params, (err, data) => {
But all i get in return is an error. Should it be switch roles when it sees the userpool does not exist? Is that logic I have to write in or can it be done at all?
{"message":"User pool ca-central-1_BBBBBBBB does not exist.","code":"ResourceNotFoundException","time":"2021-01-18T18:01:29.279Z","requestId":"acc14424-9f1d-411a-95f2-1a302e5773f8","statusCode":400,"retryable":false,"retryDelay":21.27495199615266}
Thanks
Yes, you have given permissions and everything to the roles, but you are still using role in OrgA, so to make the API call you to have to switch role in OrgB and use those credentials for making the client and eventually make the call.
sts_client = boto3.client('sts')
# Call the assume_role method of the STSConnection object and pass the role
# ARN and a role session name.
assumed_role_object=sts_client.assume_role(
RoleArn="arn:aws:iam::account-of-role-to-assume:role/name-of-role",
RoleSessionName="AssumeRoleSession1"
)
# From the response that contains the assumed role, get the temporary
# credentials that can be used to make subsequent API calls
credentials=assumed_role_object['Credentials']
# Use the temporary credentials that AssumeRole returns to make a
# connection to Amazon S3
s3_resource=boto3.resource(
's3',
aws_access_key_id=credentials['AccessKeyId'],
aws_secret_access_key=credentials['SecretAccessKey'],
aws_session_token=credentials['SessionToken'],
)
# Use the Amazon S3 resource object that is now configured with the
# credentials to access your S3 buckets.
for bucket in s3_resource.buckets.all():
print(bucket.name)
you can find more details in the documentation
To verify this during the testing you can make GetCallerIdentity this gives you enough details.
{
"UserId": "AIDASAMPLEUSERID",
"Account": "123456789012",
"Arn": "arn:aws:iam::123456789012:user/DevAdmin"
}
I have an IAM role(MyIAMrole) which has already been created. I want to attach a policy to this role using a Cloudformation template.
"Mypolicy":{
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "assume-role-policy",
"PolicyDocument": {
"Version" : "2012-10-17",
"Statement": [
{ "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "*" }
]
},
"Roles": [ { "Ref": "arn:aws:iam::*:role/MyIAMrole" } ]
}
}
When I try to validate this I am getting an error saying "Unreolved reference options".
How to attach this policy to an already existing role?
I managed to get your code snippet to work by referring to the Name of a role rather than the ARN.
As per the AWS::IAM::Policy documentation:
Roles: The names of AWS::IAM::Roles to which this policy will be attached.
However, while the stack went to CREATE_COMPLETE, I couldn't see the policy listed in the Policies section of IAM, nor could I see the policy attached to the referenced role.
It might be that you cannot use CloudFormation to attach a policy to an existing role. You might need to create the Role as part of the CloudFormation template to be able to attach a role.
I am trying to use aws cli to tag a lambda function. However, I keep getting the access decided error. I even tried to give the user admin access in IAM, and still it does not work. I guess something else has to be configured somewhere that currently overrides the policy
root#fd9f516869e1:~# aws lambda tag-resource --resource $FUNCTION_ARN --tags CURRENT_COMMIT=${CIRCLE_SHA1}
An error occurred (AccessDeniedException) when calling the TagResource operation: User: <user ARN> is not authorized to perform: lambda:TagResource
The policy attached to the user is
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "<SID>",
"Effect": "Allow",
"Action": [
"tag:*",
"lambda:ListTags",
"lambda:TagResource",
"lambda:UntagResource",
"lambda:GetFunction",
"lambda:UpdateFunctionCode"
],
"Resource": [
"<my lambda ARN>"
]
}
]
}
As noted in the documentation for Lambda API Permissions and AWS Services That Work with IAM tag-related calls (ListTags, TagResources, UntagResources) can't be restricted to specific resources.
So access for tagging has to be granted for all Lambda functions. To get it working, you'd need to replace <my lambda ARN> in the policy above with *.