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.
Related
I have a serverless project written with node.js.
This service defines an IAM role for use at runtime with the following policy:
{
"Version": "2012-10-17",
"Statement": [
// statement to allow logging omitted
// statement for VPC stuff omitted (CreateNetworkInterface, etc)
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue"
],
"Resource": "arn:aws:secretsmanager:eu-west-1:*:secret:my_secret_name-*"
}
]
}
I have a lambda that then tries to read that secrets:
import SecretsManager from 'aws-sdk/clients/secretsmanager' // v2
...
export const handler: ValidatedEventAPIGatewayProxyEvent<typeof schema> = async (event, context: any) => {
try {
const sm = new SecretsManager({ region }) // region is defined as "eu-west-1"
const secret = await sm.getSecretValue({
SecretId: 'my_secret_name'
})
} catch (e) {
console.error(e)
}
This errors with the following:
AccessDeniedException: User: arn:aws:sts::{accountId}:assumed-role/my-service-lambda-role/my-service-my-stage-my-function is not authorized to perform: secretsmanager:GetSecretValue
I'm not sure why the permissions would not allow me to retrieve the secret. I'm further not sure why this is using sts and using an assumed-role rather than just using the serverless lambda role directly. Can someone explain this to me and how to fix this?
NOTE: using the policysimulator, I can confirm the role created with the above policy does have access to read the defined secret, so this must be to do with assumed roles?
I'm trying to use some of the new Amazon Location Service endpoints from the SDK itself (Location) and I have run into some inconsistent errors.
Even with everything allowed in the IAM Role geo:* (same for every resource), I always find errors of not authorization for functions like locationClient.listGeofences.
Arbitrarily, some other functions like getMapStyleDescriptor, searchPlaceIndexForText or calculateRoute do not give problems. Those functions are using their respective policies within geo:..., so it's pretty confusing to me to see how it detects some policies and others not.
The error is pretty common, it shows the following and the policy it's already allowed:
Uncaught (in promise) AccessDeniedException: User: arn:aws:sts::xxxx:assumed-role/AmazonLocationTestRole/CognitoIdentityCredentials is not authorized to perform: geo:ListGeofences on resource: arn:aws:geo:eu-west-1:xxxx:*
Note that the acess is for unauthenticated users withing an indentity pool in Cognito, but that shouldn't be the problem.
const client = new AWS.Location({
credentials: credentials,
region: AWS.config.region
});
console.log(await client.listGeofences({
CollectionName: "explore.geofence-collection"
}).promise())
console.log(await client.getMapStyleDescriptor({
MapName: mapName
}).promise());
Just in case, the trust relationships in the IAM role look like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws.com:aud": "eu-west-1:xxxx"
},
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "unauthenticated"
}
}
}
]
}
And every policy for every resource in Amazon Location Service it's already allowed.
Do you have any idea what could be happening?
Many thanks!
According to https://docs.aws.amazon.com/location/latest/developerguide/authenticating-using-cognito.html#cognito-create-user-pool unauthenticated identities have access only to the following operations:
geo:GetMap*
geo:SearchPlaceIndex*
geo:BatchUpdateDevicePosition
geo:CalculateRoute
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 am trying to change the elastic search access policy through lambda function using node js currently access policy looks like bellow
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "es:*",
"Resource": "arn:aws:es:us-east-1:XXXX:domain/YYY/*"
}
]
}
the code which i have tried in lambda
var params = {
DomainName: 'YYYY'
};
const es = new AWS.ES();
es.upgradeElasticsearchDomain(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
this always throw error
is not authorized to perform: es:UpdateElasticsearchDomainConfig on resource with error code "code": "AccessDeniedException",
in the param i will add AccessPolicies this is same as the policy added in my question but the Effect will be Deny
After discussing it further with the OP, it turned out it was the lack of permissions on the IAM role attached to the Lambda function.
For others facing the same issue, make sure to attach ESFullAccess to the Lambda function that is playing with ElasticSearch.
To do so, go to IAM -> Roles and select the role attached to your Lambda function.
Click on attach policies and attach ESFullAccess, like the image below:
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.