From 71b3d4c72137f56849921c8085b020f36683f04e Mon Sep 17 00:00:00 2001 From: Snigdhajyoti Ghosh Date: Thu, 9 Nov 2023 01:22:07 +0530 Subject: [PATCH] add credential fetcher for IAM user from system credential store --- aws_console/__init__.py | 36 +++++++++++----- ...{aws_console_login.py => aws_login_api.py} | 0 ...edentials.py => aws_session_credential.py} | 7 +-- aws_console/input_output/browser.py | 6 +-- aws_console/input_output/cli.py | 43 ++++++++++++++++--- aws_console/system_credential_store.py | 22 ++++++++++ setup.py | 6 ++- 7 files changed, 94 insertions(+), 26 deletions(-) rename aws_console/{aws_console_login.py => aws_login_api.py} (100%) rename aws_console/{credentials.py => aws_session_credential.py} (86%) create mode 100644 aws_console/system_credential_store.py diff --git a/aws_console/__init__.py b/aws_console/__init__.py index dbca002..2835129 100644 --- a/aws_console/__init__.py +++ b/aws_console/__init__.py @@ -1,20 +1,36 @@ -from .input_output.cli import parse_arguments +from .input_output.cli import open_console_arguments, credential_process_arguments from .input_output.browser import open_console -from .credentials import aws_credentials -from .aws_console_login import signin_url +from .aws_session_credential import aws_session_credential +from .aws_login_api import signin_url +from .system_credential_store import store_aws_credential, get_aws_credential -__version__ = '0.3' +__version__ = '0.4' def aws_console(): - args = parse_arguments() + args = open_console_arguments() - if args.version: - print(__version__) - return + __show_version_if_requested(args) - creds, region_name = aws_credentials(args) + creds, region_name = aws_session_credential(args.profile, args.region) url = signin_url(creds, region_name) - open_console(url, args) + open_console(url, args.clip, args.stdout) + + +def aws_system_credential(): + args = credential_process_arguments() + + __show_version_if_requested(args) + + if args.command == 'store': + store_aws_credential(args.account_id, args.username, args.access_key, args.secret_key) + elif args.command == 'get': + get_aws_credential(args.account_id, args.username, args.access_key, args.credential_process) + + +def __show_version_if_requested(args): + if args.version: + print(__version__) + return diff --git a/aws_console/aws_console_login.py b/aws_console/aws_login_api.py similarity index 100% rename from aws_console/aws_console_login.py rename to aws_console/aws_login_api.py diff --git a/aws_console/credentials.py b/aws_console/aws_session_credential.py similarity index 86% rename from aws_console/credentials.py rename to aws_console/aws_session_credential.py index a0055fb..d36f491 100644 --- a/aws_console/credentials.py +++ b/aws_console/aws_session_credential.py @@ -11,11 +11,8 @@ class TokenGenerationException(Exception): pass -def aws_credentials(argument): - session = boto3.Session( - profile_name=argument.profile, - region_name=argument.region - ) +def aws_session_credential(profile_name, region_name): + session = boto3.Session(profile_name=profile_name, region_name=region_name) __update_credential_provider_cache(session) diff --git a/aws_console/input_output/browser.py b/aws_console/input_output/browser.py index dd467d8..75ff7cb 100644 --- a/aws_console/input_output/browser.py +++ b/aws_console/input_output/browser.py @@ -2,10 +2,10 @@ import pyperclip import sys -def open_console(url: str, argument): - if argument.clip: +def open_console(url: str, copy_to_clipboard, print_output): + if copy_to_clipboard: pyperclip.copy(url) - elif argument.stdout: + elif print_output: print(url) elif not webbrowser.open_new_tab(url): sys.exit("No browser found. Try --help for other options") \ No newline at end of file diff --git a/aws_console/input_output/cli.py b/aws_console/input_output/cli.py index dc421e9..aafca20 100644 --- a/aws_console/input_output/cli.py +++ b/aws_console/input_output/cli.py @@ -2,11 +2,7 @@ import argparse -def parse_arguments(): - return __arg_parser().parse_args() - - -def __arg_parser(): +def open_console_arguments(): parser = argparse.ArgumentParser( description="Open the AWS console in your web browser, using your AWS CLI credentials") @@ -23,4 +19,39 @@ def __arg_parser(): group1.add_argument('--stdout', action='store_true', help="don't open the web browser, but echo the signin URL to stdout") - return parser + return parser.parse_args() + + +def credential_process_arguments(): + parser = argparse.ArgumentParser( + description='AWS Credential Management CLI') + + parser.add_argument('-v', '--version', action='store_true', + help="Display the version of this tool") + + subparsers = parser.add_subparsers( + dest='command', help='Available commands') + + # Subparser for 'store' command + store_parser = subparsers.add_parser('store', help='Store AWS credentials') + store_parser.add_argument( + '--account-id', required=False, help='AWS Account ID for the name') + store_parser.add_argument( + '--username', required=False, help='Username of a AWS user associated with the access key for the name') + store_parser.add_argument( + '--access-key', required=True, help='AWS access key') + store_parser.add_argument( + '--secret-key', required=True, help='AWS secret key') + + # Subparser for 'get' command + get_parser = subparsers.add_parser('get', help='Get AWS credentials') + get_parser.add_argument( + '--account-id', required=False, help='AWS Account ID for the name') + get_parser.add_argument( + '--username', required=False, help='Username of a AWS user associated with the access key for the name') + get_parser.add_argument( + '--access-key', required=True, help='AWS access key') + get_parser.add_argument( + '--credential-process', action='store_true', help='Use credential process') + + return parser.parse_args() diff --git a/aws_console/system_credential_store.py b/aws_console/system_credential_store.py new file mode 100644 index 0000000..fe494fd --- /dev/null +++ b/aws_console/system_credential_store.py @@ -0,0 +1,22 @@ +import keyring +import json + + +def store_aws_credential(account_id, username, access_key, secret_key): + service_name = '-'.join(filter(None, ['aws', account_id, username])) + keyring.set_password(service_name, access_key, secret_key) + + +def get_aws_credential(account_id, username, access_key, for_credential_process): + service_name = '-'.join(filter(None, ['aws', account_id, username])) + secret_key = keyring.get_password(service_name, access_key) + + if for_credential_process: + # https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sourcing-external.html + print(json.dumps({ + "Version": 1, + "AccessKeyId": access_key, + "SecretAccessKey": secret_key + })) + else: + print(secret_key) diff --git a/setup.py b/setup.py index 38c6e5e..3a0a530 100755 --- a/setup.py +++ b/setup.py @@ -35,12 +35,14 @@ def find_version(*file_paths): packages=find_packages(), entry_points={ 'console_scripts': [ - 'aws-console = aws_console:aws_console' + 'aws-console = aws_console:aws_console', + 'aws-system-credential = aws_console:aws_system_credential' ] }, install_requires=[ 'boto3>=1.28', - 'pyperclip>=1.8,<1.9' + 'pyperclip>=1.8,<1.9', + 'keyring>=24.2,<24.3' ], author='Snigdhajyoti Ghosh', author_email='snigdhajyotighos.h@gmail.com',