AWScon provides Single Sign On (SSO) users with AWS console access restricted by AWS IAM roles. Single Sign On is provided by SAML2, and role access is restricted by group membership.
-
AWScons
has been developed ant tested with Apache and mod_wsgi. -
The SAML IdP used for Single Sign On (SSO) is Microsoft Azure AD
-
However
AWScons
should be usable with any WSGI compliant web server environment and any SAML2 compatible IdP. -
You will need have the requisite skills for your web server and IdP to deploy this app, as it is impossible to cover and test all the variations, or to document them here.
% git clone https://github.com/Glocktober/AWSconsoleSSO.git
% cd AWSconsoleSSO
% python3 -m venv
% source venv/bin/activate
% pip install -r requirements.txt
% # Create config.py
% # start for test on <hostname>:8000/
% python3 app.py
- This will install the
AWScons
app and it's required components. - Generally you will want to deploy into a venv virtual environment.
- You still need to integrate the Python code into your WSGI web application service and your SAML IdP.
- Python components:
- Bottle WSGI web application server
- BottleSaml SAML2 Service Provider for Bottle using minisaml
- BottleSessions provides session state management for Bottle using the Pallets Project cachelib
- Additional more common component packages such as requests, cryptography, and boto3
In AWS IAM
- create a role selecting "For Another AWS Account".
- Use the account number of the Assuming User (this can be the same, or a different account as the role.)
- Attach the desired policy for this role.
- Set the maximum duration this role can be used (the default is 1 hour)
- Keep track of the ARN
Repeat this for each role you want to create.
For example, you can create a role called MyAdminRole
in your account with the id of 123456789012, providing that same account id as the accessing account. Then attach the AWS managed policy AdministratorAccess
, and edit the role to change the maximum duration to 8 hours (28800 seconds). The role ARN will be arn:aws:iam::123456789012:role/MyAdminRole
.
In a different account (999999789012) you can create a role called DBAdminRole
, listing account 123456789012 as the trusted account. Then attach the AWS managed policy AWSRDSFullAccess
. The role ARN will be arn:aws:iam::999999789012:role/DBAdminRole
.
The key is that the created roles must have trusted access to the account that will be generating the assume role credentials.
Create a policy with sts:AssumeRole
API access to the ARNs for the assumed roles created in the previous step. This is done in the account that was granted the trust to assume any of the roles you created.
In our example this was account 123456789012. So in account 123456789012 you would create a policy - we'll call it assumeSSOpolicy
:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:assumeRole",
"Resource": [
"arn:aws:iam::123456789012:role/MyAdminRole",
"arn:aws:iam::123456789012:role/ReadOnlyRole",
"arn:aws:iam::999999789012:role/DBAdminRole",
]
}
]
}
Apply the policy in one of two ways:
- Attach the policy to an EC2 IAM Role and attach to the EC2 instance
AWScons
is hosted. - Attach the policy directly to an IAM user account.
For EC2:
- In IAM create a new role, for EC2, and attach the policy (
assumeSSOpolicy
in our example) to this role. - Attache this role to the EC2 instance the code will be running on.
For IAM user:
- Create an IAM user (say
AWSconSSO
) with only API keys and save the keys - Apply the policy (
assumeSSOpolicy
in our example) to this user - On the hosting sever create a credentials file containing the API keys
- Use the config options
aws_credentials_file
andaws_profile
in the aws_config stanza of config.py
The EC2 Role is the preferred method when AWScons
is hosted in AWS; the IAM User account is required if AWScons
is not being hosted in AWS, or hosted with outher API applications.
An example file is provided config.py.sample'. You can use this file as a framework to create a config.py file that will be located in the same directory as the
AWScons` app.py file.
There are three sections in the config.py file:
- session_config - user session configuration
- saml_config - SAML SP configuration
- aws_config - maps url path to specific roles to assume
- This can be a simple null configuration in many cases:
session_config = {}
- For higher use environments you will want persistent caching. Consult BottleSessions documentation for more detail.
- With a low-volume of requests the memory-based SimpleCache is adequate
- With a higher-volume of requests FileCache is simple enough with only a path to a cache directory specified
- Configuring the SAML Service Provider (SP) is beyond the scope of this document. Refer to BottleSaml documentation for more detail.
- The
name_id
configured should be something useful (username or email), as it will be included in console and also in CloudTrail logging. - If
groups
will be used for authorization, these should be provided as IdP assertions, and listed in theassertions
configuration list so they will be kept as session attributes.
- This provides configuation options and url path to role mapping
These options are for the full AWScons instance.
parameter | type | default | description |
---|---|---|---|
url_prefix | String | "" | Prefix for target URLS (defaults to no URL prefix) |
aws_profile_name | String | None | For IAM user creds - sets AWS_PROFILE |
aws_credentials_file | String | None | For IAM user creds - sets AWS_SHARED_CREDENTIALS_FILE |
targets | List | None | Python Dict containing specific target entries |
- One or more targets can be included in the AWScons instance. Only the targets list is required.
A target configuration item contains specific information for a given service.
parameter | type | default | description |
---|---|---|---|
service | String | None (required) | Name of service target used as URL path |
duration | Integer | 3600 | Duration (Seconds) credentials for assumed role are valid |
role | String | None (required) | ARN of role assumed for this URL path |
groups | [String,..] | [] | User must have membership in one or more of these groups |
duration
can not exceed the maximum duration associated with the specified IAMrole
groups
is a list of groups restricting access to this role- The specific
service
is invoked when the final component of the url path matches theservice
name. i.e. https://www.example.com/aws/myadmin' matches the service target with the name 'myadmin' (but only when the instance has the url_prefix of '/aws')
aws_config = {
"targets" : [{
"service": "awsadm",
"role": "arn:aws:iam::123456789012:role/MyAdminRole",
} ]
}
Accessing https://www.example.com/awsadm will launch an AWS console to any authenticated user. The console will have access of the MyAdminRole
role in account 123456789012
. The console and credentials will be valid for 1 hour.
aws_config = {
"url_prefix": "/aws", # Base for URL
"aws_profile_name" : "cons", # Profile name
"aws_credentials_file" : "/usr/local/.aws/credentials", # Credentials file
"targets" : [
{
"service": "cloudadmin", # /aws/cloudadmin
"role": "arn:aws:iam::123456789012:role/MyAdminRole",
"duration": 28800,
"groups" : ["sysadmin", "cloudadmin"]
},
{
"service": "sandbox", # /aws/sandbox
"role": "arn:aws:iam::999999789012:role/DBAdmin",
"duration": 28800,
"groups" : ["dbs"]
}
]
}
This config uses API credentials with the specified credentials file and profile name; all target URLs are prefixed with /aws.
Accessing https://www.example.com/aws/cloudadmin, an authenticated user must be a member of either sysadmin
or cloudadmin
groups. The user will be provided a console with the privileges of MyAdminRole
that will be valid for 8 hours. The account accessed will be 123456789012.
With https://www.example.com/aws/sandbox, the authenticated user must be a member of the group `dba'. The privileges will be thoses of DBAdmin, and provides access to the AWS account with the id of 999999789012.
- The specific target is evaluated when a GET request is made to the URL path matching the form /<url_prefix>/
- If a match is not found the request failes with an HTML 401 Unknown error.
- The user is
authenticated
via SAML, with the IdP provided assertions added to user session as attributes forauthorization
. This includes 'groups' list. - The user is authorized if:
- The user is a member of at least one group specified in the
groups
of the target configuration. - If no groups are listed in the target config, the user is not rejected.
- Failing to meet this, the request fails with an HTML 403 Unauthorized error
AWScons
acquires temporary credentials forrole
specified in the target config using the AWS sts:AssumeRole APIAWScons
then calls AWS sts to generate a console login token- The login token is formed to a logon URL
- The login URL is returned as an HTML 301 redirect