Skip to content

Enhanced account switching for AWS, supports Yubikey as MFA source

License

Notifications You must be signed in to change notification settings

kreuzwerker/awsu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Amazon Web Services Switch User (awsu)

Release Build Status Documentation Go Report Card

awsu provides a convenient integration of AWS virtual MFA devices into commandline based workflows. It does use Yubikeys to provide the underlying TOTP one-time passwords but does not rely on additional external infrastructure such as e.g. federation.

There is also a high-level video overview from This Is My Architecture Munich:

Video overview

[ Installation | Usage | Configuration | Caching | Commands | General multifactor considerations ]

Installation

Production-ready Mac releases can be installed e.g.through brew via kreuzwerker/homebrew-taps:

brew tap kreuzwerker/taps && brew install kreuzwerker/taps/awsu

Linux is only available for download from the release tab. No Windows builds are provided at the moment.

Prequisites

awsu relies on shared credentials files (the same configuration files that other tools such as e.g. the AWS commandline utilities are also using) being configured. The profiles are used to determine

  1. which IAM long-term credentials (access key pairs) are going to be used
  2. if a / which virtual MFA device is going to be used
  3. if a / which IAM role is going be used

In contrast to the official AWS CLI awsu also supports putting an mfa_serial key into a profile which contains long-term credentials (instead of a role). In this case a virtual MFA device is always used when using the long-term credential profile in question.

Usage

An abstract overview of the usage workflow of awsu looks like this:

  1. You ensure you fulfill the prerequisites above
  2. You start using awsu by using the register command: this will create a virtual MFA device on AWS, store the secret of that device on your Yubikey and enable the virtual MFA device by getting two valid one-time passwords from the Yubikey
  3. Now you just run awsu and - after a double-dash — - you specify the program you want to run in a given profile (e.g. admin); depending on the profile awsu will
    1. determine the access-key pair to use
    2. optionally use TOTP tokens from your Yubikey device (to get a session token from AWS in order to add the MFA context to the request) and
    3. optionally assume an IAM role
    4. use the credentials resulting from these operation(s), cache them and export them to the environment of the program specified after the double-dash

Given the following shared credentials config:

[default]
aws_access_key_id     = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

[foo]
aws_access_key_id     = AKIAIFODNNOS7EXAMPLE
aws_secret_access_key = bPxRfiCYEXAMPLEKEY/K7MDENG/wJalrXUtnFEMI
mfa_serial            = arn:aws:iam::123456789012:mfa/user@example.com

[bar]
mfa_serial            = arn:aws:iam::123456789012:mfa/user@example.com
role_arn              = arn:aws:iam::123456789012:role/foo-cross-account
source_profile        = default

[wee]
external_id           = 1a03197b-3cb5-491b-bc06-84795afc95ef
mfa_serial            = arn:aws:iam::123456789012:mfa/user@example.com
role_arn              = arn:aws:iam::121234567890:role/bar-cross-account
source_profile        = default

[gee]
role_arn              = arn:aws:iam::121234567890:role/wee-cross-account
source_profile        = foo

awsu will produce the following results:

Profile Credentials Cached? MFA?
default Long-term* No* No*
foo Short-term session-token Yes Yes, from "foo" itself**
bar Short-term session-token, then role Yes Yes, from "bar" itself
wee Short-term session-token, then role with external ID Yes Yes, from "wee" itself
gee Short-term session-token, then role Yes Yes, from "foo"

*) unless a MFA is specified as parameter to awsu - then a short-term session-token (equivalent to foo) is produced

**) the form of using mfa_serial directly long-term credential profiles is not supported by the official AWS CLI (it will just ignore it) - please note that this form will always produce short-term credentials which may not be useful in some circumstances e.g. when re-registering a previously unregistered virtual MFA device

Configuration

In the following the global configuration parameters are described. Note that all parameters are implemented as flags with environment variable equivalents - when these start with AWS_ (like the setting of profiles) they have equivalent semantics to e.g. other SDK using applications such as the AWS CLI.

Profile and shared credential files

These options describe the currently selected profile and the locations of the shared credential files.

Long Short Environment Default
Currently used profile profile p AWS_PROFILE default
Shared config file location config-file c AWS_CONFIG_FILE Platform
Shared credentials file shared-credentials-file s AWS_SHARED_CREDENTIALS_FILE Platform

Short-term credentials

These options describe caching options, session token and role durations and other aspects of short-term credentials.

Description Long Short Environment Default
Disable caching no-cache n AWSU_NO_CACHE false
Duration of session tokens & roles duration d AWSU_DURATION 1 hour, maximum depends on config of the role in question (up to 12 hours)
Grace period until caches expire - in other words: the time a session will be guaranteed to be valid grace r AWSU_GRACE 45 minutes
Source of OTP tokens generator g AWSU_GENERATOR yubikey - can be set to manual if you want to manually enter OTP passwords
MFA serial override mfa m AWSU_SERIAL None - can be used to set or override MFA serials

Other

Description Long Short Environment Default
Verbose logging verbose v AWSU_VERBOSE false

Caching

Caching is only used for cacheable (short-term) credentials. It can be disabled completely (even on a case-by-case basis) and is controlled by two primary factors: duration and grace.

The duration is always equivalent to the duration of the session token used which - in turn - is equivalent to the duration of the optionally assumed role (1 hour by default).

The grace period is the minimum safe distance to the duration before it's considered invalid (45 minutes by default). This is useful for dealing with long-running deployments that might be interrupted when e.g. a role becomes invalid mid-deployment.

Example: in the default setting with a duration of 1 hour and a grace period of 45 minutes awsu will consider cached credentials invalid after 15 minutes.

Commands

Default

The default command (invoking just awsu) has two modes: export and exec. It supports just the global parameters described above.

Export mode

When awsu is invoked without additional arguments, the resulting credentials are exposed as shell exports. In this mode, awsu can be used with eval to actually set these variables like this:

eval $(awsu)

After using export mode, credentials can used until they expire.

Exec mode

When awsu is invoked with a doubledash (--) as the last argument it will execute the application specified after the doubledash (including all arguments) with the resulting credentials being set into the environment of this application.

In exec mode it makes sense to use shell aliases to drive awsu like e.g. in zsh:

alias aws="awsu -v -- aws"
alias terraform="awsu -v -- terraform"
# etc ...

Note that when using this alias style:

  1. you can always reference the alias targets with absolute paths to temporarily escape, e.g. by referring to aws as e.g. /usr/local/bin/aws
  2. you can still configure awsu by using the environment variable style of parameter passing

Register

awsu register :iam-username will perform the following actions:

  1. create a new virtual MFA device that is named after the :iam-username
  2. store the secret key of this device with a name derived from the virtual MFA's serial number (ARN) that is compatible with Yubikey
  3. enable the virtual MFA device with the given :iam-username

After successful registration awsu will log the serial of the MFA for usage as mfa_serial in your profiles.

Parameters

The following parameters are exclusive to register.

Description Long Short Environment Default
Generates a QR code of the MFA secret that can be used for backup purposes on smartphones qr q AWSU_QR true
Sets the "issuer" part of the QR code URL - depending on the smartphone app used this may add stylistic information to the one-time passwords (e.g. an icon) issuer i AWSU_ISSUER Amazon

Unregister

awsu unregister :iam-username will perform the following actions:

  1. deactivate the virtual MFA device that is named after the :iam-username
  2. remove the matching TOTP secret from the Yubikey
  3. delete the virtual MFA device that is named after the :iam-username

Console

awsu console will open (in a browser) the link to the AWS console for a profile. It supports:

  1. long-term credentials
  2. short-term credentials for
    1. cross-account ("internal") roles
    2. external ("federated") roles (role with an external_id field in their profile)

Parameters

The following parameters are exclusive to console.

Description Long Short Environment Default
Opens the resulting link in a browser (as opposed to just returning it) open o - true

Token

awsu token will generate a fresh one-time password from an inserted Yubikey. In order to determine the correct secret it will

  1. use the MFA directly configured on the currently used profile or
  2. use the the MFA configured through the mfa-serial parameter.

General multifactor considerations

The goal of this section is to consider the multifactor options that are available on AWS without involving additional external infrastructure (e.g. by utilizing federation). Under these constraints there are two options available:

  1. Restricing access by IPv4 addresses and/or networks, expressed in CIDR notation
    1. Easy to implement in AWS and requires no additional effort except for the control of static IPv4 IPs or ranges
    2. Hard to restrict to the right people in an organization e.g. your operators network vs. your backoffice network or guest wifi network
    3. Some impact on remote workers - you'll need a VPN solution that routes all traffic for AWS IP addresses (or just all traffic)
    4. Difficult to spoof unless you are a very privileged attacker
  2. Restricing access by proving the possession of a virtual or hardware MFA device, specifically a device that can emit 6-digits TOTP one-time passwords (OTP)
    1. More difficult to implement in AWS since you'll want to introduce smartcards as sources for OTPs (unless users want to type in OTPs every n minutes) - awsu supports Yubikey USB smartcards here
    2. Easy to restrict in usage to the right people since MFA devices are first-class entities in IAM
    3. No impact on remote workers
    4. Difficult to spoof due to the aggressive rate-limits of MFA authentication attempts - since AWS uses a 6-digit configuration it's nevertheless possible and failures to authenticate with MFA should be monitoried through AWS CloudTrail

When possible we recommend to require both seconds factors.

Providing second factors

IP based second factors are provided implicitly by virtue of being the address from which a request originates.

MFA based second factors are provided through one of the following mechanisms:

  1. Using long-term credentials (the access key pair associated with an IAM user) to get a session token via STS
    1. this yields new short-term credentials (a new access key pair plus the session token itself) that now contains
      1. the information about the MFA context but
      2. no new principal (the IAM user remains the principal)
    2. a session token can be requested to be valid for a period between 15 minutes and 12 hours - there is no way of directly configuring an upper ceiling
  2. Using long- or short-term credentials to assume a role via STS
    1. this yields new short-term credentials with a new principal (the role)
      1. when using long-term credentials the MFA serial and OTP token must be passed to the STS API when assuming the role
      2. when using short-credentials aquired from the session token mechanism described above the MFA serial and OTP token can be omitted
      3. in both cases the role now includes a MFA context
    2. a role can be requested to be valid for a period between 15 minutes and 12 hours - it's upper ceiling (between 1 hour and 12 hours, with 1 hour being the default) is configured directly on the IAM role

Requiring second factors

Second factor requirements are expressed in the form of global conditions keys in the the optional Condition block that is found in most of the available types of IAM policies such as

  1. Trust policies of roles
  2. Policies attached to e.g. roles or users
  3. Permission boundaries attached to e.g. roles or users
  4. Selected service policies e.g. S3 bucket policies

Service control policies that can be applied globally on AWS Organization members are not supported at the moment.

Regardless of its location the Condition for an IP-based second factor would look like this:

"IpAddress": {
  "aws:SourceIp": "203.0.113.0/24"
}

The Condition content for an MFA-based second factor can have two forms.

The "age" form:

"NumericLessThan": {
  "aws:MultiFactorAuthAge": "3600"
}

Or the "boolean" form:

"Bool": {
  "aws:MultiFactorAuthPresent": "true"
}

The "age" form is preferred as the means of requiring a MFA. Since a session token (see the section before) cannot directly be configured for a maximum duration the "age" form is the only way to set an acceptable window for the proof of possession of a MFA device.

Location implications

The type of policy where a second factor requirement is enforced at has some implications.

When applied to a non-trust policy, the requirement is enforced on every interaction. That also means that if a permission is denied (e.g. due to aws:MultiFactorAuthAge) the user has not always a way of knowing exactly why it's denied (in some AWS APIs the UnauthorizedOperation response contains an EncodedMessage that can be decoded using the appropriate STS API - this may or may not clarify a permission issue).

When applied to a trust policy, the requirement is only enforced when assuming the role. Since a trust policy usually only regulates the acceptable principals (e.g. an AWS account) and second factor conditions the user should be able to deduce why the permission to assume the role has been denied (e.g. no access to the admin role in this account, not in the office / not dialed into the VPN, no MFA device active). Both approaches can also be mixed either through policies or through permission boundaries (under the usability constraints described above).

Since an assumed role also has an explicit time-to-live that is clearly visible to users only using trust policies for MFA conditions makes MFA based second factors easier to handle in practice. This approach can be summarized as following:

  1. A role requires the proof of posession once at the beginning of it's lifetime through an aws:MultiFactorAuthAge condition that should set to the duration attribute (the maximum lifetime) of a role (as discussed above: since an older session token could have been used to assume the role, the "boolean" form is not sufficient)
  2. The longer a role can last, the greater the window of opportunity gets for an attacker to gain control of the principal (e.g. by gaining access to the computer where the short-term credentials reside)
  3. Therefore long lasting session should have less permissions than shorter lasting roles

This summary leads to the following basic setup recommendations:

  1. Plan a permission schema that differentiates between the levels of access different functional roles should have - typical examples include the AWS Managed Policies for Job Functions as well as e.g. roles for removing MFA devices from IAM users in self-service
  2. Map those functional roles to IAM roles
    1. Role durations and matching MFA conditions should reflect the level of access the associated policies will have
    2. Consider that API operations carried with roles that expire mid-deployment will get aborted mid-deployment and that 1 hour might not be enough for certain operations to complete (such as e.g. RDS deployments) - awsu handles this problem by re-assuming roles that are due to expire in a configurable amount of time
    3. Consider adopting an AWS Organization setup with multiple member accounts and locate these roles in different accounts
  3. Map the right to assume these IAM roles to IAM groups
    1. Also give users in these groups (by using policy variables) the right to create and enable a virtual MFA device for themselves
    2. Do not directly allow them to deactive and delete their own MFA device (this would allow an attacker to simply replace an MFA device with one they control) - monitor deletions via CloudTrail and consider outsourcing this to dedicated privileged users or - at minimum - require second factors for the MFA deletion alone (directly or via a role dedicated to this purpose)
  4. Do not give IAM users any other direct permissions
  5. Add IAM users to IAM groups appropriate for their function roles

Protecting second factor requirements

With second factor conditions in various policies (likely in multiple accounts) in place one must consider protecting them from modification by regular and privileged users.

Privileged users in this context are users that can create and update IAM resources beyond the self-service permissions describe in the section above. Such privileged users are an unfortunate reality in AWS where service-linked permissions are not always fine-granular enough or are not supported at all. The unfortunate part is that it's currently impossible to restrict role creation to service principals which implies that privileged users can create cross-account roles to arbitrary accounts.

The following approaches are recommend in order to protect your second factor requirements:

  1. Implement all IAM that regulate access under a dedicated path, e.g. /master/
  2. Create an IAM policy ("master") that restricts create, update and delete operations on IAM resources under this path
    1. attach this IAM policy as a permission boundary to your IAM roles
    2. enforce the attachment of this permission boundary by expressing it as a iam:PermissionsBoundary condition to all applicate IAM actions
  3. Carefully monitor the creation of roles closely and consider implementing indirections (e.g. using the AWS Service Catalog) as an alternative to directly creating IAM roles (e.g. for usage in instance profiles) and IAM users (e.g. for creating SMTP credentials for SES)

Please don't hesitate to contact us when you need consulting around the design of your organizational setup.