Review MFA protection when assuming AWS roles

Require MFA for people assuming sensitive roles and verify the actual policy.

Description

When a person can assume an AWS role without MFA, stolen credentials can be more readily used to access the role. The caller must still satisfy permissions, the role trust policy and other applicable controls.

Sending MFA values is different from enforcing a policy that rejects requests without MFA. Noninteractive workloads should use their environment’s roles or federated temporary credentials instead of storing a user’s MFA code.

Potential impact

  • Stolen user credentials can be used to misuse the permissions of an accessible role.
  • Adding MFA input alone can leave other request paths able to assume the role without MFA.

Remediation

  • Provide the correct mfa_serial_number and a currently valid mfa_token for AssumeRole requests that require MFA. Do not expose the token or returned credentials in logs.
  • Enforce an appropriate aws:MultiFactorAuthPresent condition in the trust policy for that human access path, and test actual allowed and denied requests. Design workload authentication separately.

Examples

These excerpts retain legacy module names. Check the installed collection’s supported name; the current module is amazon.aws.sts_assume_role. Supply the real role ARN and MFA device list, and provide a valid current_mfa_token at execution time.

Before

yaml
- name: Assume the existing role
  community.aws.sts_assume_role:
    mfa_serial_number: "{{ mfa_devices.mfa_devices[0].serial_number }}"
    role_arn: "arn:aws:iam::123456789012:role/someRole"
    role_session_name: "someRoleSession"
  register: assumed_role

- name: Assume a role
  sts_assume_role:
    role_arn: "arn:aws:iam::123456789012:role/someRole"
    role_session_name: "someRoleSession"
  register: assumed_role

After

yaml
- name: Assume the existing role
  community.aws.sts_assume_role:
    mfa_serial_number: "{{ mfa_devices.mfa_devices[0].serial_number }}"
    mfa_token: "{{ current_mfa_token }}"
    role_arn: "arn:aws:iam::123456789012:role/someRole"
    role_session_name: "someRoleSession"
  register: assumed_role
  no_log: true

Explanation:

  • Before: The first task supplies only the device identifier, and the second supplies no MFA values. Actual permission depends on IAM policy.
  • After: The task sends both the device identifier and current token and suppresses logging. Verify MFA enforcement in the policy separately.

References