2

I am trying to give admin rights to a specific user group and enforcing MFA for the same group. MFA should be only enforced for console users though, not when using the AWS CLI.

These are the policies I have been testing with:

Policy 1 - Administrator access granted if MFA

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowAdminAccessIfSignedInWithMFA",
            "Effect": "Allow",
            "Action": "*",
            "Resource": "*",
            "Condition": {
                "BoolIfExists": {
                    "aws:MultiFactorAuthPresent": "true"
                }
            }
        }
    ]
}

Policy 2 - Still, allow the user to set up MFA in case it is not yet active

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowViewAccountInfo",
            "Effect": "Allow",
            "Action": "iam:ListVirtualMFADevices",
            "Resource": "*"
        },
        {
            "Sid": "AllowManageOwnVirtualMFADevice",
            "Effect": "Allow",
            "Action": [
                "iam:CreateVirtualMFADevice",
                "iam:DeleteVirtualMFADevice"
            ],
            "Resource": "arn:aws:iam::*:mfa/${aws:username}"
        },
        {
            "Sid": "AllowManageOwnUserMFA",
            "Effect": "Allow",
            "Action": [
                "iam:DeactivateMFADevice",
                "iam:EnableMFADevice",
                "iam:GetUser",
                "iam:ListMFADevices",
                "iam:ResyncMFADevice"
            ],
            "Resource": "arn:aws:iam::*:user/${aws:username}"
        }
    ]
}

This last policy was adapted from this one.

The official documentation for aws:MultiFactorAuthPresent says, as I understand it, that the combination of "Allow", "BoolIfExists" and "true" should work well for my purpose:

This condition matches either if the key exists and is present or if the key does not exist. This combination of Allow, BoolIfExists, and true allows requests that are authenticated using MFA, or requests that cannot be authenticated using MFA. This means that AWS CLI, AWS API, and AWS SDK operations are allowed when the requester uses their long-term access keys. This combination does not allow requests from temporary credentials that could, but do not include MFA.

If you are wondering why I'm not using any (seemingly simpler) policy containing a "Deny" effect, like:

"Effect" : "Deny",
"Condition" : { "BoolIfExists" : { "aws:MultiFactorAuthPresent" : "false" } }

...the reason is:

This combination of Deny, BoolIfExists, and false denies requests that are not authenticated using MFA. Specifically, it denies requests from temporary credentials that do not include MFA. It also denies requests that are made using long-term credentials, such as AWS CLI or AWS API operations made using access keys. The *IfExists operator checks for the presence of the aws:MultiFactorAuthPresent key and whether or not it could be present, as indicated by its existence. Use this when you want to deny any request that is not authenticated using MFA. This is more secure, but can break any code or scripts that use access keys to access the AWS CLI or AWS API.

Everything works as expected, except for when I try to access resources using the AWS CLI (with an access key). Am I missing something or is the documentation misleading?

PS: I would like to avoid having separate user groups for console and CLI users.

Oleg
  • 654
  • 1
  • 7
  • 16
  • https://stackoverflow.com/questions/28177505/enforce-mfa-for-aws-console-login-but-not-for-api-calls – jellycsc Jun 25 '21 at 15:39
  • I had a look at that one already. The answer is wrong and explicitly not recommended by AWS: > "This is because when long-term credentials are used, the aws:MultiFactorAuthPresent key is not present in the request and the test always fails, resulting in a nonmatch. Instead, we recommend that you use the BoolIfExists operator to check the value." Furthermore, when using "Deny" instead of "Allow", as I already mentioned in the question, the following applies: > "It also denies requests that are made using long-term credentials, such as AWS CLI or AWS API operations made using access keys." – Oleg Jun 28 '21 at 07:29

0 Answers0