How to secure IAM access key with MFA? - amazon-web-services

I know it is possible to enhance the security by putting another layer (virtual/hardware) MFA over password. Can I secure the access key by MFA.
The problem I am trying to solve is that I would some time commit my access key into github accidentally. so I need a MFA thing for that,

Yes, you can do this by adding a condition to your IAM policies that requires a recent MFA authentication. For example,
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["ec2:*"],
"Resource": ["*"],
"Condition": {"NumericLessThan": {"aws:MultiFactorAuthAge": "3600"}}
}]
}
Allows access to the ec2 Apis if you have authenticated with an MFA in the past hour. There are more examples in the docs.
This requires that you call the GetSessionToken api with your credentials and the MFA code and then use the returned temporary credentials for your actual api calls.
If your code is running on EC2 then you should instead use IAM roles - this sets up credentials available on the instance that are rotated every few hours.

Related

How should I permission my AWS Lambdas to be able to query OpenSearch?

I have an AWS OpenSearch cluster configured with an IAM master user role. I have an AWS Lambda which I want to be able to query both OpenSearch and other AWS services like DynamoDB. I don't want to modify the OpenSearch master user role to be able to access other AWS services - it should have zero permissions.
My current solution is letting my Lambda call assumeRole to assume the master user role before querying OpenSearch. Is this the approved way to do it? Seems like it would be more efficient not to have to do the assume role step. And it has the downside that the Lambda then has full access to OpenSearch - I would prefer to give it more granular permissions, e.g. only es:ESHttpGet.
This AWS documentation https://docs.aws.amazon.com/opensearch-service/latest/developerguide/ac.html seems to imply that you can set a resource-based access policy on domain setup which grants permissions to specific users. But I tried creating a maximally permissive policy and I still can't access the domain except as the master role. Am I misunderstanding the docs?
The permissive access policy I tried to use:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "es:*",
"Resource": "arn:aws:es:eu-west-1:REDACTED:domain/*/*"
}
]
}
I'm implementing something like that at the moment and it's not quite finished, but I am using API Gateway and a Lambda authoriser function to allow basic authentication. You could try that. The policy I have is almost the same as yours except after domain I have the name of the domain, not a star. I also have vpcs for security locked down to a cidr range.

S3 Bucket Policy to allow S3 Access to Current Authenicated user in AWS Console?

I have an application where I am using Cognito to authenticate users and giving temporary access to AWS Console but that user is able to see all other buckets, I want that user just should be able to see or access buckets created by him.
Currently, I have given S3FullAccess Policy to Cognito users. Can anyone suggest which policy I should attach?
As per my R&D, I can some policies are there that can restrict particular user or allow particular user but my users will be dynamic, so I cannot hard-code the values and also policies like allowing/restricting access to particular buckets, I want only users who create buckets should be able to access not other users.
This is something which i found
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListAllMyBuckets",
"s3:GetBucketLocation"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::bucket-name",
"Condition": {
"StringLike": {
"s3:prefix": [
"",
"home/",
"home/${aws:userid}/*"
]
}
}
},
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::bucket-name/home/${aws:userid}",
"arn:aws:s3:::bucket-name/home/${aws:userid}/*"
]
}
]
}
But this is listing all buckets and the only accessible bucket is what put in the code above, I want for new user, it should show nothing and as it creates, it should show that only
This is not going to be easy and you will need to create your own policy and enforce some conventions. You have 3 options.
But first, if each user just needs their own S3 space look at S3 Prefix [here](
https://aws.amazon.com/blogs/mobile/understanding-amazon-cognito-authentication-part-3-roles-and-policies/) Also, you can do this on the S3 resource bucket. I have a template for doing this here in gitlab
Now back to answering your question.
Option 1; They will need to set a tag when they create the bucket where an "owner" tag is equal to their identity. I striked this one out because despite being listed in the IAM policy I'm pretty sure it doesn't work with S3.
Option 2: The prefix of the bucket name is equal to their identity.
Then you can use the feature of variables and tags in IAM Policy. Read here
Note that coginto users are web federated identities so the variable aws:username is not aviable for you. Use the aws:userid variable and the value will be role id:caller-specified-role-name where role id is the unique id of the role and the caller-specified-role-name is specified by the RoleSessionName parameter passed to the AssumeRoleWithWebIdentity request
Option 3: Use IAM Access Policy
I can not find a link to the how to at the moment. But from here is a detailed description.
Q: How do I control what a federated user is allowed to do when signed in to the console?
When you request temporary security credentials for your federated
user using an AssumeRole API, you can optionally include an access
policy with the request. The federated user’s privileges are the
intersection of permissions granted by the access policy passed with
the request and the access policy attached to the IAM role that was
assumed. The access policy passed with the request cannot elevate the
privileges associated with the IAM role being assumed. When you
request temporary security credentials for your federated user using
the GetFederationToken API, you must provide an access control policy
with the request. The federated user’s privileges are the intersection
of the permissions granted by the access policy passed with the
request and the access policy attached to the IAM user that was used
to make the request. The access policy passed with the request cannot
elevate the privileges associated with the IAM user used to make the
request. These federated user permissions apply to both API access and
actions taken within the AWS Management Console.
The nice thing about this approach is you programmatically create the access policy.

Can we limit operations for an administrator in IAM?

Let's say, I have an user, say User-A, that is assigned the following policy (who is essentially an admin user):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
]
}
Can I create another policy and associate it to User-A, so that User-A can't launch EC2 instance? (I don't want to disassociate the above policy from User-A; because of some legacy reason, I only want to add rules/policies to a user)
Moreover, can I limit launching EC2 instance operation from an AWS account root user? (See the following statement on AWS IAM page)
When you sign in as the root user, you have complete, unrestricted
access to all resources in your AWS account, including access to your
billing information and the ability to change your password.
If you can edit the existing policy, then you can change the permissions that are being granted (eg by using NotAction, as #bishop suggested).
If you cannot edit the existing policy, you can add another policy with "Effect": "Deny" and then list the actions that are not permitted.
As to the Root account... It can basically do anything. That is why the recommendation is to attach Multi-Factor Authentication to the account, then lock away the MFA device for emergency use only.

AWS S3 - How to restrict an IAM user to just a single bucket?

I've been struggling with this for hours and cannot figure it out.
I've created a new user, duplicity, and I made a new bucket called bobs-house, and generated the following policy: (any numbers I'm not sure I should share are xxx'd out)
{
"Version": "2012-10-17",
"Id": "Policyxxx",
"Statement": [
{
"Sid": "Stmtxxx",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::xxx:user/duplicity"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::bobs-house/*"
}
]
}
I go to the policy simulator, and run some tests. Sure enough, it says I can do whatever I want as user duplicity, but only on bobs-house. If duplicity tries to do anything involving other buckets, it's denied. Great!
Now I fire up my FTP client and connect to s3.amazonaws.com (using Transmit's S3 protocol of course, not FTP protocol), using duplicity's IAM access key and secret key. I get "access denied." I can't figure out what I'm doing wrong. Any help would be appreciated!
EDIT:
Got it, thanks to John's answer below. I can use Transmit to connect and view only that bucket's contents, add files, etc. But duplicity (backup software) is complaining:
PermanentRedirect. The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint. bobs-house.s3.amazonaws.com
So I switch the formatting in duplicity's config to:
s3://bops-house.s3.amazonaws.com/test
And then I get this error:
The request signature we calculated does not match the signature you provided. Check your key and signing method.
My access key & secret key are definitely correct.
If you wish to give Amazon S3 permissions to a specific user, it is better to create the policy against the IAM User themselves, rather than the bucket policy.
A bucket policy is good for assigning universal permissions, while a policy in IAM is good for giving permissions to specific Users or Groups of users.
See: User Policy Examples

How to enforce IAM users to use multi factor authentication to use the console?

I'd like to require the usage of MFA to IAM users when they log into the AWS Console. I know that's possible to do that for API access, but not sure whether is possible to achieve the same when logging into the Console.
Update
You can enforce your requirement with an IAM Policy based on an IAM condition that specifies the aws:MultiFactorAuthAge key as outlined in section IAM Policies with MFA Conditions within Configuring MFA-Protected API Access - you can enforce this at two levels:
Existence — To simply verify that the user has been authenticated with MFA, check that the aws:MultiFactorAuthAge key is not null. (If the
user has not been authenticated with MFA, this key doesn't exist and
therefore is null.)
Duration — If you want to grant access only within a specified time after MFA authentication, use a numeric condition type to compare the
key's age to a value (such as 3600 seconds).
Accordingly, a generic IAM policy for all AWS actions that simply tests for the existence of MFA authentication might look as follows:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*",
"Condition":
{
"Null":{"aws:MultiFactorAuthAge":"false"}
}
}
]
}
Initial Answer
This is a case of 'it just works', i.e. there's nothing to be done regarding MFA-Protected Access for the AWS Management Console specifically, insofar the console uses the API in turn and calls every API action with the logged in user's IAM credentials accordingly (once a user has configured and enabled an MFA device, the login page will require entering the MFA token automatically) - see also section Using MFA-Protected APIs Through the Console within Configuring MFA-Protected API Access:
AWS evaluates MFA-protected API policies for actions in the console, such as terminating an Amazon EC2 instance. Set up the IAM user with an MFA device and enable an MFA-protected API policy. The user can then simply log into the console with MFA authentication and is subject to the policies for MFA-protected APIs. For users who already have an assigned MFA device, the console experience doesn't change (except for optional time limits on certain MFA-protected APIs that require more frequent re-authentication). For more information on setting up an IAM user with an MFA device, see Setting Up an MFA Device.
Requiring MFA for the Web Console
The IAM policy listed here will do the following:
Allow users to change their own password
Allow users to view and edit their own MFA devices (a necessary component to requiring them to have MFA)
Prevent users from doing most things if they logged in to the console without MFA
Still allow users to set up MFA if they logged in without it
Use API keys regardless of MFA
It is best to create this as an IAM policy, and then attach it to the user groups that have console users. You can also attach the policy to a user directly, but that's harder to manage.
Note that adding an MFA device to your account is insufficient to be able to access AWS resources; you need to have logged in with that MFA device for it to work. Thus, to get set up with MFA, you need to do the following steps:
Sign in to the AWS console.
In the top right, click the dropdown labeled with your username
Go to "Security Credentials"
Add an MFA device
Log out
Log back in using MFA; you can now use the AWS console normally
The IAM policy is the following:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:ChangePassword",
"iam:CreateVirtualMFADevice",
"iam:EnableMFADevice",
"iam:ResyncMFADevice",
"iam:DeleteVirtualMFADevice",
"iam:DeactivateMFADevice",
"iam:ListMFADevices",
"iam:ListVirtualMFADevices",
"iam:ListAccessKeys",
"iam:GetAccessKeyLastUsed",
"iam:GetUser"
],
"Resource": [
"arn:aws:iam::*:mfa/${aws:username}",
"arn:aws:iam::*:user/${aws:username}"
]
},
{
"Sid": "BlockMostAccessUnlessSignedInWithMFA",
"Effect": "Deny",
"NotAction": [
"iam:CreateVirtualMFADevice",
"iam:ListVirtualMFADevices",
"iam:EnableMFADevice",
"iam:ResyncMFADevice",
"iam:DeleteVirtualMFADevice",
"iam:DeactivateMFADevice",
"iam:ListAccountAliases",
"iam:ListUsers",
"iam:ListSSHPublicKeys",
"iam:ListAccessKeys",
"iam:GetAccessKeyLastUsed",
"iam:ListServiceSpecificCredentials",
"iam:ListMFADevices",
"iam:GetAccountSummary",
"iam:ChangePassword",
"iam:GetUser",
"sts:GetSessionToken"
],
"Resource": "*",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "false"
}
}
}
]
}
Note that while this allows use of most of the AWS API without needing MFA, some API calls won't work. In particular, any calls that use temporary AWS authentication credentials will fail. For example:
Using ECR login, as this generates a temporary key that it gives to docker
Retrieving a value from AWS Secrets Manager, as this uses temporary credentials to talk to KMS
Elastic Beanstalk operations, as these seem to use temporary credentials internally
In order to do these things, you need to get MFA API credentials (see below). The other option (especially good for ECR login) is to create a less privileged user in a group that doesn't have the MFA Required policy to use for making the API calls in question.
Requiring MFA Everywhere
For enhanced security, you can require MFA access for both the web console and the API. To do this, change the condition in the above policy to be the following:
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "false"
}
}
The reason that this works is that API calls with permanent credentials don't pass the MultiFactorAuthPresent key at all, whereas console requests always do. Changing this condition from Bool to BoolIfExists changes the condition to resolve to true if the MultiFactorAuthPresent key does not exist, which in turn blocks the requests.
To use the API with MFA, you need to use the sts get-session-token command. For example, with the AWS CLI:
# Get the serial number of your MFA device
aws --profile <PROFILE_NAME> iam list-mfa-devices --user-name <IAM_USER_NAME>
# Get temporary API keys that will pass MFA verification
aws --profile <PROFILE_NAME> sts get-session-token --serial-number <MFA_SERIAL_NUMBER> --token-code <MFA_TOKEN>
# Export the temporary credentials for use in subsequent calls
export AWS_ACCESS_KEY_ID=<KEY>
export AWS_SECRET_ACCESS_KEY=<SECRET>
export AWS_SESSION_TOKEN=<SESSION_TOKEN>
If you prefer a script that manages the credential acquisition process, use the command-line tool iam-mfa: https://github.com/zagaran/iam-mfa. (Disclaimer: I am the primary author of this tool.)
In the meantime AWS itself has provided a tutorial on how to force Users to use a MFA device while still enabling them to manage a MFA device on their own. This is quite similar to the updated answer from Steffen, but differs in the details.
It works by
Creating a IAM Policy based on this official AWS template which basically forbids everything except IAM operations without an active MFA Login
Assign the Policy to you relevant IAM users – or better – IAM Groups.
After you created IAM users and passed them their initial credentials, the users will receive a You are not authorized to perform this operation. on all operations except on accessing the IAM security console.
After registering a MFA device, logging out and then again in with their new MFA token they will be able to operate everything as expected.