How to get AWS email address for a user? - amazon-web-services

In these docs:
https://docs.aws.amazon.com/cli/latest/reference/iam/get-user.html
we can get a user with:
aws iam get-user --user-name Bob
and the result is:
{
"User": {
"UserName": "Bob",
"Path": "/",
"CreateDate": "2012-09-21T23:03:13Z",
"UserId": "AKIAIOSFODNN7EXAMPLE",
"Arn": "arn:aws:iam::123456789012:user/Bob"
}
}
but how do we get this user's email address?

IAM users do not have an email address property. Are you sure you're referring to IAM users?
The root user for your AWS account will have an email address associated with it, but there is only one of these users.
Also, if you have a Cognito user pool, these users can have an email address associated with them.
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iam-user.html
https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools.html

Related

Allow cognito users to view images in s3

I have granted the Cognito user access to the S3 object matching that user attribute with Cognito Identity Pool.
How can I view images in a bucket from a URL in a browser logged in as the Cognito user?
What I want to
To split the s3 bucket into tenants and only allow image files from the tenant to which the Cognito user belongs to be viewed.
To display images with img tag <img src="">.
What I did
S3 object arn: arn:aws:s3:::sample-tenant-bucket/public/1/photos/test.jpg
Create Cognito User with custom attributes
aws cognito-idp admin-create-user \
--user-pool-id "ap-northeast-1_xxxx" \
--username "USER_NAME" \
--user-attributes Name=custom:tenant_id,Value=1
Cognito Identity Pool
Mapping of user attributes to principal tags
"tenantId": "custom:tenant_id"
Added sts:TagSession permission to the authenticated role
Attach policy to the authenticated role
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "*",
"Resource": "arn:aws:s3:::sample-tenant-bucket/public/${aws:PrincipalTag/tenantId}/*",
"Effect": "Allow"
}
]
}
Hypothesis
Typing the object URL (https://sample-tenant-bucket.s3.ap-northeast-1.amazonaws.com/public/1/1670773819-1.jpg) into the address bar results in a 403, even when logged in with an AWS account as an administrator, not as a Cognito User. Therefore,
I thought that Object URLs could not be used for non-public objects.
The Presigned URL seems to work, but I was wondering if there is another way to do it, since it is a method that does not depend on whether the user is already logged in to the AWS account or not.
Maybe this question is the same as asking how to display an image in a bucket by URL in a browser that is already logged in with the object owner's AWS account

Airflow: Boto3: AssumeRole in one account and get credentials from secretmanager in another account

I'm trying to use the assume_role_arn and then get the credentials from another account to connect to the API application.
If the first conn_id I pass into the Hook, has no user/pwd but assume_role
{
"conn_type": "api",
"login": "na",
"password": "na",
"host": "na",
"port": 443,
"extra": {
"assume_role_arn":"arn:aws:iam::xxxxxxxxxx:role/us-west-2-dev-acm-assume-role",
}
Then after assuming the role it needs to fetch credentials from another account in which conn_id is stored in the secret manager
def assume_role_for_acm(self, assume_role_arn, external_id):
sts_client = boto3.client("sts", region_name="us-west-2")
assumed_role_object = sts_client.assume_role(
RoleArn=assume_role_arn,
RoleSessionName="AssumeRoleForACMExportCert",
ExternalId="external_id",
)
credentials = assumed_role_object["Credentials"]
acm_client = boto3.client(
"acm",
aws_access_key_id=credentials["AccessKeyId"],
aws_secret_access_key=credentials["SecretAccessKey"],
aws_session_token=credentials["SessionToken"],
region_name="us-west-2",
)
return acm_client
How can after assuming the role, it gets the credentials from another conn_id from the secret manager and get the credentials for authentication
Need help extending the hook to add extra conn_id and get credentials
https://github.com/apache/airflow/blob/dac590948eac07e9b611c2f160d798ae05c13177/airflow/providers/amazon/aws/hooks/base_aws.py#L357

How to use Okta username in IAM policy?

I am using Federated Identity with Okta being the IDP. I would like to add an Identity based policy which provides access to resources which are tagged with the user's Okta username. For each resource, I want to set the tag username and give it a value of the user who needs to access it.
"Condition": { "StringEquals": {"aws:ResourceTag/username": "${????}"} }
What should I add to the StringEquals condition so that the Okta username gets used?

AWS Cognito - Users lost "non-mutable" attribute "email_verified"

After using Cognito for a few months, some users in a user pool have now lost the "email_verified" attribute. I can't understand how it is missing or how to recover.
Symptoms are:
Users can still login
User password can not change (eg via JS SDK - changePassword), produces error: "x-amzn-errormessage: Cannot reset password for the user as there is no registered/verified email or phone_number"
Getting the user attributes for the user with the list-users CLI shows the attribute is missing
aws cognito-idp list-users --user-pool-id MYID-123 --query 'Users[?Username==`error#bla.com`].[*]'
[
[
[
"error#bla.com",
true,
"CONFIRMED",
1522127817.526,
1522127819.369,
[
{
"Name": "sub",
"Value": "123123123341241238"
},
{
"Name": "email",
"Value": "bla#bla.com"
}
]
]
]
]
vs. one with the attribute in place
aws cognito-idp list-users --user-pool-id MYID-123 --query 'Users[?Username==`bla#bla.com`].[*]'
[
[
[
"bla#bla.com",
true,
"CONFIRMED",
1524048734.588,
1524048737.777,
[
{
"Name": "sub",
"Value": "1231231231231235"
},
{
"Name": "email_verified",
"Value": "true"
},
{
"Name": "email",
"Value": "bla#bla.com"
}
]
]
]
]
If I try deleting the attribute (with enough permissions), it fails - as one would expect - explaining it is not mutable.
aws cognito-idp admin-delete-user-attributes --user-pool-id MYID-123 --username test2#test.com --user-attribute-names email_verified
An error occurred (InvalidParameterException) when calling the AdminDeleteUserAttributes operation: Cannot modify the non-mutable attribute email_verified
I can not find the cause for this problem, other than blaming AWS Cognito.
A workaround/hack/patch is to add the attribute back, this time, the non-mutable check is not a problem
aws cognito-idp admin-update-user-attributes --user-pool-id MYID-123 --username error#bla.com --user-attributes Name=email_verified,Value=true
And now the user has the attribute again and I can reset the password.
If there are 2 users with same email address, and email_verified is true for one and not the other, it is possible it is an issue with your client code.
When you call confirmRegistration the first parameter is the confirmation code and the second is a boolean: forceAliasCreation. If set to true, then if a user already exists with the email address that is being used to register with, the new user "steals" the email address of the existing user.
It's not obvious this is a problem cause the Cognito API docs show examples of confirmRegistration with forceAliasCreation as true and not explaining what the parameter does (https://github.com/aws-amplify/amplify-js/tree/master/packages/amazon-cognito-identity-js - Use Case 2, assuming you are using JS). We ran into this problem with our app and this was the culprit.

Cognito Groups with IAM Permissions

What I want to implement:
I have a Cognito User-Pool and I have some Users and some Groups. I want that certain Users have access to API Gateway functions, some Users can access some functions and others have no access.
What I did:
I created three groups and assigned the Users to each of the groups. I gave each of the groups an IAM role and gave each roled spezific policies. The permission for the group for all users looks like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "execute-api:*",
"Resource": "*"
}
]
}
I created Lambda functions and API Gateway Resources through the Serverless framework. I set the authorizer to a Cognito User-Pool authorizer.
(I tried a couple different things like using federated identities but that didnt seem to work as well)
What is my result:
All Users have full access to the API Gateway. The given permissions do not seem to make any difference to the access of each user.
Help:
What did I do wrong?
How can I achieve my goal?
The roles attached to a user pool group only come into picture when you generate credentials for the user using Cognito Federated Identity. Adding groups to a user pool
IAM roles and their permissions are tied to the temporary AWS
credentials that Amazon Cognito identity pools provide for
authenticated users. Users in a group are automatically assigned the
IAM role for the group when AWS credentials are provided by Amazon
Cognito Federated Identities using the Choose role from token option.
So basically
create an identity pool attached to your user pool.
change authorization for API gateway to IAM
after login to user pool, user id_token to generate the federated identity
use this identity (secret key + access key + token) for authorization with API gateway.
Now your roles should be honored. But mind you - you will be required to generate AWS SigV4 credentials on your own as for some reason this is not provided out of the box. I ended up using aws-sign-web for use in browser.
PS: your role seems to give blanket access to API gateway. you will need to fix that as well. e.g. sample role I used to limit access to one API endpoint
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Resource": [
"arn:aws:execute-api:us-east-2:<aws account id>:<API id>/*/*/acc/*"
],
"Effect": "Allow"
}
]
}
Sample code to generate federated identity
function getAccessToken(idToken, idenPoolId, userPool) {
let region = idenPoolId.split(":")[0];
let provider = "cognito-idp." + region + ".amazonaws.com/" + userPool;
let login = {};
login[provider] = idToken;
// Add the User's Id Token to the Cognito credentials login map.
let credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: idenPoolId,
Logins: login
});
//call refresh method in order to authenticate user and get new temp credentials
credentials.get((error) => {
if (error) {
console.error(error);
//let response = {
// statusCode: 500,
// body: JSON.stringify(error)
//};
return null;
} else {
console.log('Successfully logged!');
console.log('AKI:'+ credentials.accessKeyId);
console.log('AKS:'+ credentials.secretAccessKey);
console.log('token:' + credentials.sessionToken);
let response = JSON.stringify({
'AKI': credentials.accessKeyId,
'AKS': credentials.secretAccessKey,
'token': credentials.sessionToken
});
return response;
}
});
}
I have a much better solution, and you don't need the IAM.
Simply save the pair of {username, serviceName} in a S3 or DB. So every time, you get the request for a service:
Check if the user is authorized (from Cognito).
Check if the user is authorized for the service (S3, MySQL, RDS, etc.).
Why I think it is better
Because adding/removing users from services, you don't need to login as an admin to IAM. And hopefully later on, you can create a dashboard for management.
Work Flow
UserA sends a request to your securityApi.
SecurityApi checks the token is authorized (user is valid or not).
If the UserA is valid, the securityApi, sends the username of the user (can get it from the payload of the token) and the service name to a DB, to see if the user has access to the user. For example for Mysql (use RDS for this):
SELECT username from ServiceX LIMIT 1 WHERE username = "xyz";
If the second or third steps passed the user is 1. valid user and 2. has the right to use the service. If the user is failed in step 2 or 3, the user is not authorized to use the service.