aws-config-gen: Continued development and moved to XDG_CONFIG_HOME

This commit is contained in:
Gregor Bückendorf 2019-05-19 21:06:33 +02:00
parent dd57915320
commit 26c997d416
2 changed files with 104 additions and 76 deletions

104
.local/bin/aws-config-gen Executable file
View file

@ -0,0 +1,104 @@
#!/usr/bin/env python3
"""
Parse the HTML of https://signin.aws.amazon.com/saml to extract all assumable
roles for use in .aws/config
Usage:
aws-config-gen [--print-default-profile] [--default-role=<name>]
[--region=<name>] [--suffix=<name>] <file>
aws-config-gen -h | --help
aws-config-gen --version
Arguments:
file Downloaded HTML File of the AWS SAML login page
Options:
-d, --print-default-profile Begin output with an empty [default] profile.
--default-role=<name> If more than one role can be assumed in the
same account, this option determines which one
will get the shorthand profile name without an
additional suffix. [default: developer-admin]
-r, --region=<name> Add the specified aws region to each profile's
properties.
-s, --suffix=<name> Append a suffix to each profile name.
--version Show version info.
-h --help Show this help screen.
Examples:
aws-config-gen -d aws-signin.html > ~/.aws/config
aws-config-gen -r eu-central-1 -s -fra aws-signin.html >> ~/.aws/config
"""
import sys
import re
from docopt import docopt
from bs4 import BeautifulSoup
from pathlib import Path
from configparser import ConfigParser
from itertools import starmap, chain
from functools import partial
def get_account_roles (soup):
for saml_account in soup.fieldset(class_='saml-account', recursive=False):
account_title = saml_account.find(class_='saml-account-name').string
account_alias = account_title.split()[1]
account_roles = map(get_saml_role_arn, saml_account(class_='saml-role'))
yield account_alias, list(account_roles)
def get_saml_role_arn (saml_role_tag):
saml_radio_tag = saml_role_tag.find(class_='saml-radio')
saml_role_arn = saml_radio_tag['value']
return saml_role_arn
def seperate_account_roles (alias, roles, role_type_pattern):
if len(roles) == 1:
yield alias, roles[0]
else:
for role in roles:
role_type = role_type_pattern.fullmatch(role).group('type')
role_alias = f'{alias}{"-" if role_type else ""}{role_type or ""}'
yield role_alias, role
def assemble_profile(name, role_arn, suffix=None, region=None):
section = f'profile {name}{suffix or ""}'
properties = {'azure_default_role_arn': role_arn}
if region is not None:
properties['region'] = region
return section, properties
def print_config(profiles, print_default=False):
config = ConfigParser()
if print_default:
config.add_section('default')
for section, properties in profiles:
config[section] = properties
config.write(sys.stdout)
if __name__ == '__main__':
# Parse CLI arguments
arguments = docopt(__doc__, version='AWS Config Generator 1.0')
# Prepare some objects for later use
baked_profile = partial(assemble_profile, suffix=arguments['--suffix'],
region=arguments['--region'])
default_role_type=arguments['--default-role']
role_type_pattern = re.compile(
r'(?:arn\:aws\:iam\:\:\d+\:role/)'
r'(?:netrtl\.com-)?'
f'((?:{default_role_type})|(?P<type>.*?))'
r'(?:-access-role)?')
baked_role_seperator = partial(seperate_account_roles,
role_type_pattern=role_type_pattern)
# Read the document
html_location = Path(arguments['<file>']).resolve()
with open(html_location) as document:
page = BeautifulSoup(document, 'html.parser')
# Mangle the data
accounts = get_account_roles(page)
roles = chain.from_iterable( starmap( baked_role_seperator, accounts ) )
profiles = starmap(baked_profile, roles)
# Output the config
print_config(profiles, arguments['--print-default-profile'])

View file

@ -1,76 +0,0 @@
#!/usr/bin/env python3
"""
Parse the HTML of https://signin.aws.amazon.com/saml to extract all assumable
roles for use in .aws/config
Usage:
aws-config-gen.py [options] <file>
aws-config-gen.py -h | --help
aws-config-gen.py --version
Options:
-d --print-default Begin output with an empty [default] profile
-r REGION, --region=REGION Add the specified aws region to each profile
-s SUFFIX, --suffix=SUFFIX Append SUFFIX to each profile name
--version Show version info
-h --help Show this help screen
"""
import sys
from docopt import docopt
from bs4 import BeautifulSoup
from pathlib import Path
from configparser import ConfigParser
from itertools import starmap, chain
from functools import partial
def get_saml_role_arn (saml_role_tag):
saml_radio_tag = saml_role_tag.find(class_='saml-radio')
saml_role_arn = saml_radio_tag['value']
return saml_role_arn
def get_account_roles (html_file):
with open(Path(html_file).resolve()) as document:
page = BeautifulSoup(document, 'html.parser')
# The <fieldset> tag should contain the main list of selectable accounts
for saml_account in page.fieldset(class_='saml-account', recursive=False):
account_title = saml_account.find(class_='saml-account-name').string
account_alias = account_title.split()[1]
account_roles = map(get_saml_role_arn, saml_account(class_='saml-role'))
yield account_alias, list(account_roles)
def seperate_account_roles (alias, roles):
if len(roles) == 1:
yield alias, roles[0]
else:
for role in roles:
role_class = role.split('/')[1]
role_alias = '-'.join(alias, role_class)
yield role_alias, role
def assemble_profile(name, role_arn, suffix=None, region=None):
section = f'profile {name}{suffix or ""}'
properties = {'azure_default_role_arn': role_arn}
if region is not None:
properties['region'] = region
return section, properties
def print_config(profiles, print_default=False):
config = ConfigParser()
if print_default:
config.add_section('default')
for section, properties in profiles:
config[section] = properties
config.write(sys.stdout)
if __name__ == '__main__':
arguments = docopt(__doc__, version='AWS Config Generator alpha')
accounts = get_account_roles(arguments['<file>'])
roles = chain.from_iterable( starmap( seperate_account_roles, accounts ) )
baked_profile = partial(assemble_profile, suffix=arguments['--suffix'],
region=arguments['--region'])
profiles = starmap(baked_profile, roles)
print_config(profiles, arguments['--print-default'])