Skip to main content

Command line tool to enable accessing AWS using federated single sign on

Project description

mozilla-aws-cli

Command line tool to enable accessing AWS using federated single sign on

Prerequisites

  • An OIDC provider like Auth0
  • A well-known openid-configuration URL
  • An Auth0 application created
    • Type : Native
    • Allowed Callback URLs : A list of the localhost URLs created from the POSSIBLE_PORTS list of ports
    • The client_id for this application will be used in the CLI config file
  • An AWS Identity provider
    • with an audience value of the Auth0 application client_id
    • with a valid thumbprint

Instructions

Create a config

cp config.yaml.inc config.yaml

  • well_known_url: The OpenID Connect Discovery Endpoint URL. (Auth0)
  • client_id: The Auth0 client_id generated when the Auth0 application was created in the prerequisites
  • scope: A space delimited list of OpenID Connect Scopes. For example openid. Avoid including a scope which passes too much data which will exceed the maximum AWS allowed size of the ID Token (for example at Mozilla we neglect to include the raw full group list which is included in the ID Token when the https://sso.mozilla.com/claim/groups scope is requested.

Run the tool

There are various ways you can run maws. The tool can output environment variable setting text to activate your AWS session inside your terminal. Here are some methods to use the tool.

Sub command

You could run maws within a $() sub-shell and execute the results

  • Interactively prompt for which IAM role to assume
    • $(maws)
  • Pass the IAM role to assume as a command line argument
    • $(maws --role-arn arn:aws:iam::123456789012:role/example-role)
  • Not only enable command line access to AWS, also log into the web console
    • $(maws -w)

Process substitution

This uses process substitution. Here are some examples of how you could run it

source <(maws -w)

Eval

You could eval the results

eval $(maws --role-arn arn:aws:iam::123456789012:role/example-role)

Copy paste

Take the output of the command and copy paste it into your terminal

maws

Sequence diagram

Notes

# https://community.auth0.com/t/custom-claims-without-namespace/10999
# https://community.auth0.com/t/how-to-set-audience-for-aws-iam-identity-provider-configuration/12951

Details

This is a collection of technical details that we've decided or discovered in building the mozilla-aws-cli

  • The user group list should be set in the OIDC claim as a list of groups instead of a string with delimiters
    • The amr claim allows for passing a list
    • By using a list we don't need to worry about choosing a delimiter and ensuring the delimiter is not allowed in the group name
    • The ForAnyValue:StringLike IAM policy condition operator doesn't need * wildcard characters in the value since each group listed in the policy is a full group name which will match a full group name in the list passed in amr
  • Even if you only wish to allow a single user group to assume a role, you still must use the ForAnyValue:StringLike operator, not the StringLike operator. It's not clear why this is the case.
  • AWS has a maximum size that either the id_token or the amr assertion can be.
    • When this maximum size is exceeded AWS returns the error PackedPolicyTooLarge Serialized token too large for session
    • It's possible that the size limit is not able to be determined because AWS performs a packing or compression step on it's size such that the size of the amr assertion doesn't have a linear relationship with the size of the object AWS tests against it's limit
    • For example a amr value that is a list of 30 group names with an id_token length of 800 characters triggers this error.
  • Currently, when a user logs into Auth0 for the first time and performs a Duo MFA authentication, Auth0 overwrites the amr assertion that we create with a new list containing a single element ["mfa"]. We've opened a bug with Auth0 in hopes that they will change to appending to the amr assertion.
    • If they make this change, the amr assertion would, in that case, contain the list of groups and what would appear like a group called mfa. We would need to do some checks to ensure that nobody starts using a real group called mfa
  • The amr assertion in the OIDC spec isn't supposed to be used to pass a list of groups. It's also not supposed to be used to pass a string like authenticated like AWS does with cognito.
    • The purpose of the amr assertion is to provide an RP with a list of

      identifiers for authentication methods used in the authentication

    • RFC8176 states

      The "amr" values defined by this specification are not intended to be an exhaustive set covering all use cases. Additional values can and will be added to the registry by other specifications.

    • The RFC then goes on to define a list of allowed values which make it clear that authenticated or group names are not correct
    • Given this, it's possible that down the road
      • AWS will begin to use a different assertion than amr to conform to the spec
      • Auth0 will disallow setting non conforming values in amr
    • If this happens we would need to change how we do things
  • By having an Auth0 rule that queries some external resource (such as the group to role mapping file) and added delay to login is introduced and a risk of a problem in fetching the mapping file which could cause login to fail
  • We use the amr assertion because it appears to be the only way to pass data to AWS
    • The documentation indicates that there are 3 assertions that can be used in IAM policy conditions, aud oaud and sub
    • In testing we've found that aud is passed and we use it for the Auth0 client ID sub is passed and we use it for the Auth0 username oaud is not passed amr is passed
  • By passing a group list in the amr assertion we take on the following risks
    • At some point some user may try to login to AWS with SSO and login will fail due to the PackedPolicyTooLarge error. This will occur when
      • Enough AWS account holders across our many AWs accounts create IAM policies which allow a diverse set of user groups to access various roles
      • This unlucky user has access to so many different AWS accounts and roles because they work across many teams that the union of all the AWS groups which grant them access to the various roles exceeds the PackedPolicyTooLarge limit
    • We can't be sure at the point that we send the assertion that it will fail because we can't know the hard limit on the size of the amr assertion or the id_token in total
  • We plan to try to log and track users experience over time to see if the group list size issue is becoming a problem. To do so we'll want to see
    • The size of the amr assertion being passed each time a user logs in
    • If AWS ever returns a PackedPolicyTooLarge error

Supported IAM Policy Features

The Auth0 rule which finds the intersection in the groups a user is a member of with the union of all groups used in all AWS accounts IAM policies won't support all IAM policy operators. Here are the various use cases and whether they are supported or not

Supported

An AWS account holder wants to

  • enable users that are members of group "foo" to assume role arn:aws:iam::123456789012:role/baz
    • supported
    • StringLike, StringEquals
  • enable users that are members of group "foo" as well as users that are members of group "bar" to assume role arn:aws:iam::123456789012:role/baz
    • supported
    • StringLike, StringEquals for a list of values
  • enable users that are members of any group like "fo*" to assume role arn:aws:iam::123456789012:role/baz
    • supported
    • StringLike with wildcards

Not Supported

An AWS account holder wants to

  • enable users that are members of both group "foo" and group "bar" to assume role arn:aws:iam::123456789012:role/baz
    • not supported
    • multiple StringLike or StringEquals conditions
  • enable users that are members of group "foo" but not allow users that are members of group "FOO" to assume role arn:aws:iam::123456789012:role/baz
    • not supported
    • when assembling the group list to pass to AWS, we will do case insensitive matching. Additionally, there shouldn't ever be a case where two groups exist with the same characters in their name but different cases
    • multiple StringEquals conditions where the values differ only in case
  • enable users that are not members of group "bar" to assume role arn:aws:iam::123456789012:role/baz
    • not supported
    • StringNotEquals, StringNotLike
  • enable users that are members of group "foo" but not members of group "bar" to assume role arn:aws:iam::123456789012:role/baz
    • not supported
    • multiple conditions including StringNotEquals, StringNotLike

Troubleshooting

If you don't see a role listed in the role picker which you would expect to have access to, possible reasons are :

  • The IAM role was recently modified and
    1. the hourly scanner hasn't yet run to update the list of available roles.
    2. the list of available roles is current but the API that sits in front of it is using an out of date cached copy
    3. the list of available roles is current but the Auth0 rule is using an out of date cached copy of the available roles and as a result, isn't passing an "amr" claim with your current complete list of groups
    • If the cause is 1 or 2 you can still assume that role, just not using this menu. Instead pass the role ARN on the command line.
  • The conditions in the role don't allow you to access it because
    • The role has a different "Principal" "Federated" value than it should
      • Dev
        • Federated : arn:aws:iam::*:oidc-provider/auth.mozilla.auth0.com/
        • Aud : N7lULzWtfVUDGymwDs0yDEq6ZcwmFazj
      • Prod
        • Federated : arn:aws:iam::*:oidc-provider/auth-dev.mozilla.auth0.com/
        • Aud : xRFzU2bj7Lrbo3875aXwyxIArdkq1AOT
    • The role has the wrong "Action" value which should be
      • sts:AssumeRoleWithWebIdentity
    • The role has an "aud" condition that doesn't match the Auth0 client ID being passed in the "aud" claim from Auth0
      • Dev : xRFzU2bj7Lrbo3875aXwyxIArdkq1AOT
      • Prod : N7lULzWtfVUDGymwDs0yDEq6ZcwmFazj
    • The key name of the "aud" condition is incorrect
      • Dev : auth-dev.mozilla.auth0.com/:aud
      • Prod : auth.mozilla.auth0.com/:aud
    • The key name of the "amr" condition is incorrect
      • Dev : auth-dev.mozilla.auth0.com/:amr
      • Prod : auth.mozilla.auth0.com/:amr
    • You aren't a member of any of the groups listed in "amr" conditions
  • Your AWS account does not delegate security auditing rights to the Enterprise Information Security team so the group role map builder can't scan the IAM roles in your AWS account
  • There is a bug
    • in the Auth0 rule that filters the list of groups that you are a member of such that the "amr" claim returned to you is missing a group that you need to meet an IAM Role condition
    • in the group role map builder that produces the map of groups to roles to enable the Auth0 rule and the role picker menu to know which roles are available to you
    • in the ID token for role API that allows you to exchange your ID token for a list of roles so that the role picker can show you a menu of available roles

Development

When developing the tool and testing you can run it without installing it like this

python -m mozilla_aws_cli.cli --role-arn arn:aws:iam::123456789012:role/example-role

Note : You must run python -m mozilla_aws_cli.cli instead of python mozilla_aws_cli/cli.py because mozilla_aws_cli uses absolute imports.

Creating enterprise / organization configuration

If you want to deploy the Mozilla AWS CLI across your organization and establish default configuration values without requiring users to create config files you can do so by implementing a standard mozilla_aws_cli_config module.

Here are the steps assuming an example organization called Yoyodyne

  1. Create a new code repo. A good name would be mozilla-aws-cli-yoyodyne
  2. In that repo create a setup.py
    #!/usr/bin/env python
    
    from setuptools import setup
    
    setup(
        name="mozilla-aws-cli-yoyodyne",
        description="Yoyodyne specific deployment of the mozilla_aws_cli",
        install_requires=["mozilla_aws_cli"],
        packages=["mozilla_aws_cli_config"],
        url="https://github.com/yoyodyne/mozilla-aws-cli-yoyodyne",
        version="1.0.0",
    )
    
    • install_requires depends on the mozilla_aws_cli to ensure that if you instruct the user to pip install mozilla-aws-cli-yoyodyne they will get the Yoyodyne config and the tool
  3. Create a directory called mozilla_aws_cli_config
    • This is the reserved / well known module name that every organization can implement. This name must be mozilla_aws_cli_config exactly and not include any part of your organization name (e.g. Yoyodyne)
  4. Within that mozilla_aws_cli_config directory create a single __init__.py file. This will contain your organizations default configuration settings
  5. In this __init__.py file create a single variable called config containing your organizations default configuration settings.
    • Yoyodyne's __init__.py might look like
      config = {
          "client_id": "abcdefghiJKLMNOPQRSTUVWXYZ012345",
          "idtoken_for_roles_url": "https://roles-and-aliases.sso.yoyodyne.com/roles",
          "well_known_url": "https://auth.yoyodyne.auth0.com/.well-known/openid-configuration"
      }
      

The resulting repository called mozilla-aws-cli-yoyodyne would look like this

mozilla-aws-cli-yoyodyne/
├── mozilla_aws_cli_config
│   └── __init__.py
└── setup.py

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mozilla_aws_cli-0.1.1.tar.gz (130.1 kB view details)

Uploaded Source

Built Distribution

mozilla_aws_cli-0.1.1-py2.py3-none-any.whl (355.0 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file mozilla_aws_cli-0.1.1.tar.gz.

File metadata

  • Download URL: mozilla_aws_cli-0.1.1.tar.gz
  • Upload date:
  • Size: 130.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.0.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.6.0 requests-toolbelt/0.9.1 tqdm/4.38.0 CPython/3.6.7

File hashes

Hashes for mozilla_aws_cli-0.1.1.tar.gz
Algorithm Hash digest
SHA256 1b4f64bbfd835be1b61f5672e4778f9a21426c6df318aab1357121c5a4bcc965
MD5 07a533487b901dccfdc3cd1047636b5b
BLAKE2b-256 dca9b89f3ff6e0687cf36dd0dfbd57a10c66017ee102b3e007a176d33672ce74

See more details on using hashes here.

File details

Details for the file mozilla_aws_cli-0.1.1-py2.py3-none-any.whl.

File metadata

  • Download URL: mozilla_aws_cli-0.1.1-py2.py3-none-any.whl
  • Upload date:
  • Size: 355.0 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.0.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.6.0 requests-toolbelt/0.9.1 tqdm/4.38.0 CPython/3.6.7

File hashes

Hashes for mozilla_aws_cli-0.1.1-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 4c0b2d86dde677ef553322b67c2f6c1a96f3414b3bf2360986dfee2ff6c786ea
MD5 c111d7a24b10b8230f8928fa84d1c63a
BLAKE2b-256 8968ac061a423789d2bd40d7f4d9622ef8e551423ae7829b70afd19be1d41ad9

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page