├── .editorconfig ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE.md └── workflows │ ├── build.action.yaml │ ├── pre-release.action.yaml │ ├── release.action.yaml │ └── test.action.yaml ├── .gitignore ├── AUTHORS.rst ├── CONTRIBUTING.rst ├── HISTORY.rst ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.rst ├── aws_consoler ├── __init__.py ├── cli.py └── logic.py ├── docs ├── Makefile ├── authors.rst ├── conf.py ├── contributing.rst ├── history.rst ├── index.rst ├── installation.rst ├── make.bat ├── readme.rst └── usage.rst ├── requirements.txt ├── requirements_dev.txt ├── requirements_test.txt ├── setup.cfg ├── setup.py ├── tests ├── __init__.py └── test_aws_consoler │ ├── __init__.py │ └── test_cli.py └── tox.ini /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 4 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | charset = utf-8 11 | end_of_line = lf 12 | 13 | [*.bat] 14 | indent_style = tab 15 | end_of_line = crlf 16 | 17 | [LICENSE] 18 | insert_final_newline = false 19 | 20 | [Makefile] 21 | indent_style = tab 22 | 23 | [*.py] 24 | max_line_length = 79 25 | 26 | [*.yaml] 27 | indent_size = 2 28 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # For full syntax, see https://git.io/JvlLV 2 | 3 | # Ian wrote the package, so default to him. 4 | * @aph3rson 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | * AWS Consoler version: 2 | * Python version: 3 | * Operating System: 4 | 5 | ### Description 6 | 7 | Describe what you were trying to get done. 8 | Tell us what happened, what went wrong, and what you expected to happen. 9 | 10 | ### What I Did 11 | 12 | ``` 13 | Paste the command(s) you ran and the output. 14 | If there was a crash, please include the traceback here. 15 | ``` 16 | -------------------------------------------------------------------------------- /.github/workflows/build.action.yaml: -------------------------------------------------------------------------------- 1 | name: Build package 2 | 3 | on: 4 | push: 5 | branches: 6 | - develop 7 | - master 8 | pull_request: 9 | branches: 10 | - develop 11 | - master 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | strategy: 17 | matrix: 18 | # TODO: How to pull this from tox.ini? 19 | python-version: [3.6, 3.7, 3.8] 20 | steps: 21 | - uses: actions/checkout@v2 22 | - name: Set up Python ${{ matrix.python-version }} 23 | uses: actions/setup-python@v1 24 | with: 25 | python-version: ${{ matrix.python-version }} 26 | - name: Install dependencies 27 | run: | 28 | python -m pip install --upgrade pip 29 | pip install setuptools wheel twine 30 | - name: Build dists 31 | run: | 32 | python setup.py sdist bdist_wheel 33 | -------------------------------------------------------------------------------- /.github/workflows/pre-release.action.yaml: -------------------------------------------------------------------------------- 1 | name: Upload latest pre-release 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*-rc.*" 7 | 8 | jobs: 9 | pre-release: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Set up Python 14 | uses: actions/setup-python@v1 15 | with: 16 | python-version: "3.x" 17 | - name: Install dependencies 18 | run: | 19 | python -m pip install --upgrade pip 20 | pip install setuptools wheel twine 21 | - name: Build dists 22 | run: | 23 | python setup.py sdist bdist_wheel 24 | - name: Draft GitHub release 25 | id: create_release 26 | uses: actions/create-release@latest 27 | env: 28 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 29 | with: 30 | tag_name: ${{ github.ref }} 31 | release_name: RC ${{ github.ref }} 32 | draft: true 33 | prerelease: true 34 | - name: Prep for asset upload 35 | run: | 36 | cp dist/aws_consoler-*-py2.py3-none-any.whl pre-release.whl 37 | cp dist/aws_consoler-*.tar.gz pre-release.tgz 38 | - name: Attach tgz to GitHub release 39 | uses: actions/upload-release-asset@latest 40 | env: 41 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 42 | with: 43 | upload_url: ${{ steps.create_release.outputs.upload_url }} 44 | asset_path: pre-release.tgz 45 | asset_name: pre-release.tgz 46 | asset_content_type: application/x-gtar 47 | - name: Attach whl to GitHub release 48 | uses: actions/upload-release-asset@latest 49 | env: 50 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 51 | with: 52 | upload_url: ${{ steps.create_release.outputs.upload_url }} 53 | asset_path: pre-release.whl 54 | asset_name: pre-release.whl 55 | asset_content_type: application/x-wheel+zip 56 | -------------------------------------------------------------------------------- /.github/workflows/release.action.yaml: -------------------------------------------------------------------------------- 1 | name: Upload latest release 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | - "!v*-rc*" 8 | 9 | jobs: 10 | release: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Set up Python 15 | uses: actions/setup-python@v1 16 | with: 17 | python-version: "3.x" 18 | - name: Install dependencies 19 | run: | 20 | python -m pip install --upgrade pip 21 | pip install setuptools wheel twine 22 | - name: Build dists 23 | run: | 24 | python setup.py sdist bdist_wheel 25 | - name: Draft GitHub release 26 | id: create_release 27 | uses: actions/create-release@latest 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | with: 31 | tag_name: ${{ github.ref }} 32 | release_name: Release ${{ github.ref }} 33 | draft: true 34 | - name: Prep for asset upload 35 | run: | 36 | cp dist/aws_consoler-*-py2.py3-none-any.whl release.whl 37 | cp dist/aws_consoler-*.tar.gz release.tgz 38 | - name: Attach tgz to GitHub release 39 | uses: actions/upload-release-asset@latest 40 | env: 41 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 42 | with: 43 | upload_url: ${{ steps.create_release.outputs.upload_url }} 44 | asset_path: release.tgz 45 | asset_name: release.tgz 46 | asset_content_type: application/x-gtar 47 | - name: Attach whl to GitHub release 48 | uses: actions/upload-release-asset@latest 49 | env: 50 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 51 | with: 52 | upload_url: ${{ steps.create_release.outputs.upload_url }} 53 | asset_path: release.whl 54 | asset_name: release.whl 55 | asset_content_type: application/x-wheel+zip 56 | - name: Upload to PyPI 57 | env: 58 | TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} 59 | TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} 60 | run: | 61 | twine upload dist/* 62 | -------------------------------------------------------------------------------- /.github/workflows/test.action.yaml: -------------------------------------------------------------------------------- 1 | name: Test package 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | # TODO: How to pull this from tox.ini? 12 | python-version: [3.6, 3.7, 3.8] 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Set up Python ${{ matrix.python-version }} 17 | uses: actions/setup-python@v1 18 | with: 19 | python-version: ${{ matrix.python-version }} 20 | - name: Install dependencies 21 | run: | 22 | python -m pip install --upgrade pip 23 | pip install -r requirements.txt 24 | pip install -r requirements_test.txt 25 | - name: Lint with flake8 26 | run: | 27 | pip install flake8 28 | # stop the build if there are Python syntax errors or undefined names 29 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 30 | # exit-zero treats all errors as warnings. 31 | flake8 . --count --exit-zero --max-complexity=10 --statistics 32 | - name: Test with tox 33 | run: | 34 | tox -e py 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | 58 | # Flask stuff: 59 | instance/ 60 | .webassets-cache 61 | 62 | # Scrapy stuff: 63 | .scrapy 64 | 65 | # Sphinx documentation 66 | docs/_build/ 67 | 68 | # PyBuilder 69 | target/ 70 | 71 | # Jupyter Notebook 72 | .ipynb_checkpoints 73 | 74 | # pyenv 75 | .python-version 76 | 77 | # celery beat schedule file 78 | celerybeat-schedule 79 | 80 | # SageMath parsed files 81 | *.sage.py 82 | 83 | # dotenv 84 | .env 85 | 86 | # virtualenv 87 | .venv 88 | venv/ 89 | ENV/ 90 | 91 | # Spyder project settings 92 | .spyderproject 93 | .spyproject 94 | 95 | # Rope project settings 96 | .ropeproject 97 | 98 | # mkdocs documentation 99 | /site 100 | 101 | # mypy 102 | .mypy_cache/ 103 | -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | Credits 3 | ======= 4 | 5 | Development Lead 6 | ---------------- 7 | 8 | * Ian Williams 9 | 10 | Contributors 11 | ------------ 12 | 13 | None yet. Why not be the first? 14 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: shell 2 | 3 | ============ 4 | Contributing 5 | ============ 6 | 7 | Contributions are welcome, and they are greatly appreciated! Every little bit 8 | helps, and credit will always be given. 9 | 10 | You can contribute in many ways: 11 | 12 | Types of Contributions 13 | ---------------------- 14 | 15 | Report Bugs 16 | ~~~~~~~~~~~ 17 | 18 | Report bugs at https://github.com/NetSPI/aws_consoler/issues. 19 | 20 | If you are reporting a bug, please include: 21 | 22 | * Your operating system name and version. 23 | * Any details about your local setup that might be helpful in troubleshooting. 24 | * Detailed steps to reproduce the bug. 25 | 26 | Fix Bugs 27 | ~~~~~~~~ 28 | 29 | Look through the GitHub issues for bugs. Anything tagged with "bug" and "help 30 | wanted" is open to whoever wants to implement it. 31 | 32 | Implement Features 33 | ~~~~~~~~~~~~~~~~~~ 34 | 35 | Look through the GitHub issues for features. Anything tagged with "enhancement" 36 | and "help wanted" is open to whoever wants to implement it. 37 | 38 | Write Documentation 39 | ~~~~~~~~~~~~~~~~~~~ 40 | 41 | AWS Consoler could always use more documentation, whether as part of the 42 | official AWS Consoler docs, in docstrings, or in other places. 43 | 44 | Submit Feedback 45 | ~~~~~~~~~~~~~~~ 46 | 47 | The best way to send feedback is to file an issue at https://github.com/NetSPI/aws_consoler/issues. 48 | 49 | If you are proposing a feature: 50 | 51 | * Explain in detail how it would work. 52 | * Keep the scope as narrow as possible, to make it easier to implement. 53 | * Remember that this is a volunteer-driven project, and that contributions 54 | are welcome :) 55 | 56 | Get Started! 57 | ------------ 58 | 59 | Ready to contribute? Here's how to set up `aws_consoler` for local development. 60 | 61 | 1. Fork the `aws_consoler` repo on GitHub. 62 | 2. Clone your fork locally:: 63 | 64 | $ git clone git@github.com:your_name_here/aws_consoler.git 65 | 66 | 3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:: 67 | 68 | $ mkvirtualenv aws_consoler 69 | $ cd aws_consoler/ 70 | $ python setup.py develop 71 | 72 | 4. Create a branch for local development:: 73 | 74 | $ git checkout -b name-of-your-bugfix-or-feature 75 | 76 | Now you can make your changes locally. 77 | 78 | 5. When you're done making changes, check that your changes pass flake8 and the 79 | tests, including testing other Python versions with tox:: 80 | 81 | $ flake8 aws_consoler tests 82 | $ python setup.py test or pytest 83 | $ tox 84 | 85 | To get flake8 and tox, just pip install them into your virtualenv. 86 | 87 | 6. Commit your changes and push your branch to GitHub:: 88 | 89 | $ git add . 90 | $ git commit -m "Your detailed description of your changes." 91 | $ git push origin name-of-your-bugfix-or-feature 92 | 93 | 7. Submit a pull request through the GitHub website. 94 | 95 | Pull Request Guidelines 96 | ----------------------- 97 | 98 | Before you submit a pull request, check that it meets these guidelines: 99 | 100 | 1. The pull request should include tests. 101 | 2. If the pull request adds functionality, the docs should be updated. Put 102 | your new functionality into a function with a docstring, and add the 103 | feature to the list in README.rst. 104 | 3. The pull request should work for Python 3.5, 3.6, 3.7 and 3.8, and for PyPy. Check 105 | the GitHub Actions page for your fork of the repository, and make sure that 106 | the tests pass for all supported Python versions. 107 | 108 | Tips 109 | ---- 110 | 111 | To run a subset of tests:: 112 | 113 | 114 | $ python -m unittest tests.test_aws_consoler 115 | 116 | Deploying 117 | --------- 118 | 119 | A reminder for the maintainers on how to deploy. 120 | Make sure all your changes are committed (including an entry in HISTORY.rst). 121 | Then run:: 122 | 123 | $ bump2version patch # possible: major / minor / patch / pre / prenum / build 124 | $ git push 125 | $ git push --tags 126 | 127 | GitHub will then deploy to PyPI if tests pass. 128 | -------------------------------------------------------------------------------- /HISTORY.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | History 3 | ======= 4 | 5 | 1.1.0 (2020-04-13) 6 | ------------------ 7 | 8 | * Added logic to auto-detect partitions 9 | * Added logic to override auto-detected endpoints, for corporate proxies 10 | 11 | 1.0.0 (2020-03-14) 12 | ------------------ 13 | 14 | * Release to GitHub. 15 | 16 | 0.1.0 (2020-02-24) 17 | ------------------ 18 | 19 | * Internal repository rehydration. 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, NetSPI 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS.rst 2 | include CONTRIBUTING.rst 3 | include HISTORY.rst 4 | include LICENSE 5 | include README.rst 6 | 7 | include requirements.txt 8 | include requirements_dev.txt 9 | include requirements_test.txt 10 | 11 | recursive-include tests * 12 | recursive-exclude * __pycache__ 13 | recursive-exclude * *.py[co] 14 | 15 | recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean clean-test clean-pyc clean-build docs help 2 | .DEFAULT_GOAL := help 3 | 4 | define BROWSER_PYSCRIPT 5 | import os, webbrowser, sys 6 | 7 | try: 8 | from urllib import pathname2url 9 | except: 10 | from urllib.request import pathname2url 11 | 12 | webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1]))) 13 | endef 14 | export BROWSER_PYSCRIPT 15 | 16 | define PRINT_HELP_PYSCRIPT 17 | import re, sys 18 | 19 | for line in sys.stdin: 20 | match = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line) 21 | if match: 22 | target, help = match.groups() 23 | print("%-20s %s" % (target, help)) 24 | endef 25 | export PRINT_HELP_PYSCRIPT 26 | 27 | BROWSER := python -c "$$BROWSER_PYSCRIPT" 28 | 29 | help: 30 | @python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST) 31 | 32 | clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts 33 | 34 | clean-build: ## remove build artifacts 35 | rm -fr build/ 36 | rm -fr dist/ 37 | rm -fr .eggs/ 38 | find . -name '*.egg-info' -exec rm -fr {} + 39 | find . -name '*.egg' -exec rm -f {} + 40 | 41 | clean-pyc: ## remove Python file artifacts 42 | find . -name '*.pyc' -exec rm -f {} + 43 | find . -name '*.pyo' -exec rm -f {} + 44 | find . -name '*~' -exec rm -f {} + 45 | find . -name '__pycache__' -exec rm -fr {} + 46 | 47 | clean-test: ## remove test and coverage artifacts 48 | rm -fr .tox/ 49 | rm -f .coverage 50 | rm -fr htmlcov/ 51 | rm -fr .pytest_cache 52 | 53 | lint: ## check style with flake8 54 | flake8 aws_consoler tests 55 | 56 | test: ## run tests quickly with the default Python 57 | python setup.py test 58 | 59 | test-all: ## run tests on every Python version with tox 60 | tox 61 | 62 | coverage: ## check code coverage quickly with the default Python 63 | coverage run --source aws_consoler setup.py test 64 | coverage report -m 65 | coverage html 66 | $(BROWSER) htmlcov/index.html 67 | 68 | docs: ## generate Sphinx HTML documentation, including API docs 69 | rm -f docs/aws_consoler.rst 70 | rm -f docs/modules.rst 71 | sphinx-apidoc -o docs/ aws_consoler 72 | $(MAKE) -C docs clean 73 | $(MAKE) -C docs html 74 | $(BROWSER) docs/_build/html/index.html 75 | 76 | servedocs: docs ## compile the docs watching for changes 77 | watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D . 78 | 79 | release: dist ## package and upload a release 80 | twine upload dist/* 81 | 82 | dist: clean ## builds source and wheel package 83 | python setup.py sdist 84 | python setup.py bdist_wheel 85 | ls -l dist 86 | 87 | install: clean ## install the package to the active Python's site-packages 88 | python setup.py install 89 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | AWS Consoler 3 | ============ 4 | 5 | 6 | .. image:: https://img.shields.io/pypi/v/aws_consoler.svg 7 | :target: https://pypi.python.org/pypi/aws_consoler 8 | 9 | .. image:: https://img.shields.io/github/workflow/status/netspi/aws_consoler/Build%20package 10 | :target: https://github.com/NetSPI/aws_consoler/actions 11 | 12 | .. image:: https://readthedocs.org/projects/aws-consoler/badge/?version=latest 13 | :target: https://aws-consoler.readthedocs.io/en/latest/?badge=latest 14 | :alt: Documentation Status 15 | 16 | 17 | A utility to convert your AWS CLI credentials into AWS console access. 18 | 19 | 20 | * Free software: BSD License 21 | * Documentation: https://aws-consoler.readthedocs.io. 22 | 23 | 24 | Features 25 | -------- 26 | 27 | * Load credentials from the command line or from boto3 sources (envvars, profiles, IMDS) 28 | * Coordinate communication to AWS Federation endpoint 29 | * Select appropriate endpoint based on partition 30 | * Load resultant URL in user's browser of choice 31 | 32 | Credits 33 | ------- 34 | 35 | Thanks to some of the bloggers at AWS (Jeff Barr, Kai Zhao) for the helpful guides on Federation in AWS. 36 | 37 | Thanks to Karl Fosaaen (@kfosaaen) for the inspiration to write this tool. 38 | 39 | This package was created with Cookiecutter_ and the `audreyr/cookiecutter-pypackage`_ project template. 40 | 41 | .. _Cookiecutter: https://github.com/audreyr/cookiecutter 42 | .. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage 43 | -------------------------------------------------------------------------------- /aws_consoler/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """Top-level package for AWS Consoler.""" 4 | 5 | __author__ = """Ian Williams""" 6 | __email__ = 'ian.williams@netspi.com' 7 | __version__ = '1.1.0' 8 | -------------------------------------------------------------------------------- /aws_consoler/cli.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """Console script for aws_consoler.""" 4 | import argparse 5 | import sys 6 | import webbrowser 7 | import logging 8 | from requests.exceptions import HTTPError 9 | 10 | from aws_consoler.logic import run 11 | 12 | LOG_FORMAT = "%(asctime)s [%(name)s] %(levelname)s: %(message)s" 13 | 14 | 15 | def main(argv=sys.argv[1:]): 16 | """Console script for aws_consoler. 17 | :return: shell exit code 18 | """ 19 | 20 | # Set up logging 21 | logging.basicConfig( 22 | level=logging.WARNING, 23 | format=LOG_FORMAT 24 | ) 25 | logger = logging.getLogger("aws_consoler.cli") 26 | 27 | # Set up parser 28 | logger.info("Setting up parser...") 29 | parser = argparse.ArgumentParser( 30 | description="A tool to generate an AWS console sign-in link from API " 31 | "credentials using the federation endpoint.", 32 | # TODO: Add link to blog post 33 | # epilog="Read more about the generation of this tool at XXX" 34 | ) 35 | 36 | # Add arguments 37 | logger.info("Adding parser argument groups...") 38 | profile_grp = parser.add_argument_group(title="Profile authentication") 39 | profile_grp.add_argument( 40 | "-p", "--profile", 41 | help="The profile to use for generating the link. Uses named " 42 | "profiles from the AWS CLI, as well as other Boto3 " 43 | "applications. Instructions available here: " 44 | "https://amzn.to/34ik2v7") 45 | logger.debug("Profile group ready.") 46 | 47 | creds_grp = parser.add_argument_group(title="Credential authentication") 48 | creds_grp.add_argument( 49 | "-a", "--access-key-id", 50 | help="The AWS access key ID to use for authentication. Should start " 51 | "with 'AKIA' or 'ASIA', depending on the credential type in use " 52 | "(permanent/temporary).") 53 | creds_grp.add_argument( 54 | "-s", "--secret-access-key", 55 | help="The AWS secret access key to use for authentication.") 56 | creds_grp.add_argument( 57 | "-t", "--session-token", 58 | help="The AWS session token to use for authentication. Generally " 59 | "required when using temporary credentials.") 60 | logger.debug("Creds group ready.") 61 | 62 | gen_grp = parser.add_argument_group(title="General arguments") 63 | gen_grp.add_argument( 64 | "-r", "--role-arn", 65 | help="The role to assume for console access, if needed.") 66 | gen_grp.add_argument( 67 | "-R", "--region", default=None, 68 | help="The AWS region you'd like the console link to refer to. " 69 | "If using -p, overrides the default region of the profile. ") 70 | gen_grp.add_argument( 71 | "-o", "--open", action="store_true", 72 | help="Open the generated link in your system's default browser.") 73 | gen_grp.add_argument( 74 | "-v", "--verbose", action="count", 75 | help="Verbosity, repeat for more verbose output (up to 3)") 76 | logger.debug("General group ready.") 77 | 78 | adv_grp = parser.add_argument_group(title="Advanced arguments") 79 | adv_grp.add_argument( 80 | "-eS", "--sts-endpoint", default=None, 81 | help="[advanced] The endpoint for connecting to STS, if connecting " 82 | "from behind a corporate proxy or an unknown partition. Expects " 83 | "a URL with a trailing slash. Overrides the URL based on -R." 84 | ) 85 | adv_grp.add_argument( 86 | "-eF", "--federation-endpoint", 87 | help="[advanced] The endpoint for console federation, if connecting " 88 | "from behind a corporate proxy or an unknown partition. Expects " 89 | "a URL to send federation requests to." 90 | ) 91 | adv_grp.add_argument( 92 | "-eC", "--console-endpoint", 93 | help="[advanced] The URL for console access, if connecting" 94 | "from behind a corporate proxy or an unknown partition. Expects " 95 | "a URL to forward the user to after obtaining their federation " 96 | "token." 97 | ) 98 | logger.debug("Advanced group ready.") 99 | 100 | logger.info("Parsing arguments...") 101 | if argv: 102 | args = parser.parse_args(argv) 103 | else: 104 | args = parser.parse_args([]) 105 | args_dict = vars(args) 106 | logger.debug("Arguments matrix: %s", 107 | str({k: bool(v) for k, v in args_dict.items()})) 108 | 109 | # Set up verbosity 110 | if args.verbose: 111 | cli_logger = logger 112 | logic_logger = logging.getLogger("aws_consoler.logic") 113 | if args.verbose == 1: 114 | cli_logger.setLevel(logging.INFO) 115 | logic_logger.setLevel(logging.INFO) 116 | if args.verbose >= 2: 117 | cli_logger.setLevel(logging.DEBUG) 118 | logic_logger.setLevel(logging.DEBUG) 119 | if args.verbose >= 3: 120 | logging.getLogger("boto3").setLevel(logging.DEBUG) 121 | logging.getLogger("botocore").setLevel(logging.DEBUG) 122 | logging.getLogger("urllib3").setLevel(logging.DEBUG) 123 | 124 | # Validate that we have good arguments 125 | # We should not have both a profile and credentials 126 | logger.info("Validating arguments...") 127 | if args.profile and (args.access_key_id or args.secret_access_key or 128 | args.session_token): 129 | parser.error("Profile cannot be combined with credential arguments.") 130 | # If we have a session token, we need an access key ID + secret access key 131 | if args.session_token and not (args.access_key_id and 132 | args.secret_access_key): 133 | parser.error("Session token must also have an access key ID/secret " 134 | "access key.") 135 | # If we have an access key ID or secret access key, we also need the other 136 | if bool(args.secret_access_key) != bool(args.access_key_id): 137 | parser.error("Access key ID and secret access key must be provided " 138 | "together.") 139 | 140 | # Arguments are valid, call our logic 141 | try: 142 | logger.info("Calling logic.") 143 | url = run(args) 144 | if args.open: 145 | logger.info("Opening browser.") 146 | webbrowser.open(url, new=2) 147 | else: 148 | print(url) 149 | except PermissionError as e: 150 | logger.critical(e) 151 | exit(13) # EACCES 152 | except HTTPError as e: 153 | logger.critical(e) 154 | exit(13) # EACCES 155 | except Exception as e: 156 | # TODO: better exception handling 157 | logger.critical(e) 158 | exit(1) 159 | 160 | 161 | if __name__ == "__main__": 162 | print(sys.argv) 163 | sys.exit(main(sys.argv[1:])) # pragma: no cover 164 | -------------------------------------------------------------------------------- /aws_consoler/logic.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import requests 4 | import boto3 5 | from botocore.exceptions import ClientError 6 | import argparse 7 | import urllib.parse 8 | import logging 9 | import re 10 | 11 | """Main module.""" 12 | 13 | 14 | def run(args: argparse.Namespace) -> str: 15 | """ 16 | Takes the arguments from the CLI and generates the link 17 | :param args: the namespace from the CLI 18 | :type args: argparse.Namespace 19 | :return: sign-in URL 20 | """ 21 | # Set up logging 22 | logger = logging.getLogger(__name__) 23 | 24 | # Set up the base session 25 | session: boto3.Session 26 | logger.debug("Establishing Boto3 session.") 27 | # If we have a profile, use that. 28 | if args.profile: 29 | logger.debug("Using CLI-provided profile.") 30 | session = boto3.Session(profile_name=args.profile, 31 | region_name=args.region) 32 | logger.info("Profile session using \"%s\" established.", args.profile) 33 | # Otherwise, use the command line arguments 34 | elif args.access_key_id: 35 | logger.debug("Using CLI-provided credentials.") 36 | session = boto3.Session(aws_access_key_id=args.access_key_id, 37 | aws_secret_access_key=args.secret_access_key, 38 | aws_session_token=args.session_token, 39 | region_name=args.region) 40 | logger.info("Session using credential variables established.") 41 | # Otherwise, let boto figure it out. 42 | else: 43 | logger.debug("No credentials detected, forwarding to Boto3.") 44 | session = boto3.Session(region_name=args.region) 45 | logger.info("Boto3 session established.") 46 | 47 | # Get to temporary credentials 48 | # If we have a role ARN supplied, start assuming them 49 | if args.role_arn: 50 | logger.debug("Role detected, setting up STS.") 51 | sts = session.client("sts", endpoint_url=args.sts_endpoint) 52 | logger.info("Assuming role \"%s\" via STS.", args.role_arn) 53 | resp = sts.assume_role(RoleArn=args.role_arn, 54 | RoleSessionName="aws_consoler") 55 | creds = resp["Credentials"] 56 | logger.debug("Role assumed, setting up session.") 57 | session = boto3.Session( 58 | aws_access_key_id=creds["AccessKeyId"], 59 | aws_secret_access_key=creds["SecretAccessKey"], 60 | aws_session_token=creds["SessionToken"]) 61 | logger.info("New role session established.") 62 | # If we are still a permanent IAM credential, use sts:GetFederationToken 63 | elif session.get_credentials().get_frozen_credentials() \ 64 | .access_key.startswith("AKIA"): 65 | sts = session.client("sts", endpoint_url=args.sts_endpoint) 66 | logger.warning("Creds still permanent, creating federated session.") 67 | # Effective access is calculated as the union of our permanent creds 68 | # and the policies supplied here. Use the AdministratorAccess policy 69 | # for the largest set of possible permissions. 70 | try: 71 | resp = sts.get_federation_token( 72 | Name="aws_consoler", 73 | PolicyArns=[ 74 | {"arn": "arn:aws:iam::aws:policy/AdministratorAccess"} 75 | ]) 76 | logger.debug("Federation session created, setting up session.") 77 | creds = resp["Credentials"] 78 | session = boto3.Session( 79 | aws_access_key_id=creds["AccessKeyId"], 80 | aws_secret_access_key=creds["SecretAccessKey"], 81 | aws_session_token=creds["SessionToken"]) 82 | logger.info("New federated session established.") 83 | except ClientError: 84 | message = "Error obtaining federation token from STS. Ensure " \ 85 | "the IAM user has sts:GetFederationToken permissions, " \ 86 | "or provide a role to assume. " 87 | raise PermissionError(message) 88 | 89 | # Check that our credentials are valid. 90 | sts = session.client("sts", endpoint_url=args.sts_endpoint) 91 | resp = sts.get_caller_identity() 92 | logger.info("Session valid, attempting to federate as %s.", resp["Arn"]) 93 | 94 | # TODO: Detect things like user session credentials here. 95 | 96 | # Get the partition-specific URLs. 97 | partition_metadata = _get_partition_endpoints(session.region_name) 98 | federation_endpoint = args.federation_endpoint if args.federation_endpoint \ 99 | else partition_metadata["federation"] 100 | console_endpoint = args.console_endpoint if args.console_endpoint\ 101 | else partition_metadata["console"] 102 | 103 | # Generate our signin link, given our temporary creds 104 | creds = session.get_credentials().get_frozen_credentials() 105 | logger.debug("Session credentials frozen.") 106 | json_creds = json.dumps( 107 | {"sessionId": creds.access_key, 108 | "sessionKey": creds.secret_key, 109 | "sessionToken": creds.token}) 110 | token_params = { 111 | "Action": "getSigninToken", 112 | # TODO: Customize duration for federation and sts:AssumeRole 113 | "SessionDuration": 43200, 114 | "Session": json_creds 115 | } 116 | logger.debug("Creating console federation token.") 117 | resp = requests.get(url=federation_endpoint, params=token_params) 118 | # Stacking AssumeRole sessions together will generate a 400 error here. 119 | try: 120 | resp.raise_for_status() 121 | except requests.exceptions.HTTPError as e: 122 | raise requests.exceptions.HTTPError( 123 | "Couldn't obtain federation token (trying to stack roles?): " 124 | + str(e)) 125 | 126 | fed_token = json.loads(resp.text)["SigninToken"] 127 | logger.debug("Federation token obtained, building URL.") 128 | console_params = {} 129 | if args.region: 130 | console_params["region"] = args.region 131 | login_params = { 132 | "Action": "login", 133 | "Issuer": "consoler.local", 134 | "Destination": console_endpoint + "?" 135 | + urllib.parse.urlencode(console_params), 136 | "SigninToken": fed_token 137 | } 138 | login_url = federation_endpoint + "?" \ 139 | + urllib.parse.urlencode(login_params) 140 | 141 | logger.info("URL generated!") 142 | return (login_url) 143 | 144 | 145 | def _get_partition_endpoints(region: str): 146 | # TODO: Implement boto/botocore#1715 when merged 147 | logger = logging.getLogger(__name__) 148 | 149 | # AWS China endpoints 150 | if re.match(r"^cn-\w+-\d+$", region): 151 | logger.info("Using AWS China partition.") 152 | return { 153 | "partition": "aws-cn", 154 | "console": "https://console.amazonaws.cn/console/home", 155 | "federation": "https://signin.amazonaws.cn/federation", 156 | } 157 | 158 | # AWS GovCloud endpoints 159 | if re.match(r"^us-gov-\w+-\d+$", region): 160 | logger.info("Using AWS GovCloud partition.") 161 | return { 162 | "partition": "aws-us-gov", 163 | "console": "https://console.amazonaws-us-gov.com/console/home", 164 | "federation": "https://signin.amazonaws-us-gov.com/federation" 165 | } 166 | 167 | # AWS ISO endpoints (guessing from suffixes in botocore's endpoints.json) 168 | if re.match(r"^us-iso-\w+-\d+$", region): 169 | logger.warning("Using undocumented AWS ISO partition, guessing URLs!") 170 | return { 171 | "partition": "aws-iso", 172 | "console": "https://console.c2s.ic.gov/console/home", 173 | "federation": "https://signin.c2s.ic.gov/federation" 174 | } 175 | 176 | # AWS ISOB endpoints (see above) 177 | if re.match(r"^us-isob-\w+-\d+$", region): 178 | logger.warning("Using undocumented AWS ISOB partition, guessing URLs!") 179 | return { 180 | "partition": "aws-iso-b", 181 | "console": "https://console.sc2s.sgov.gov/console/home", 182 | "federation": "https://signin.sc2s.sgov.gov/federation" 183 | } 184 | 185 | # Otherwise, we (should?) be using the default partition. 186 | if re.match(r"^(us|eu|ap|sa|ca|me)-\w+-\d+$", region): 187 | pass 188 | else: 189 | logger.warning("Could not detect partition! Using AWS Standard. " 190 | "If this is incorrect, consider using -eF and -eC.") 191 | return { 192 | "partition": "aws", 193 | "console": "https://console.aws.amazon.com/console/home", 194 | "federation": "https://signin.aws.amazon.com/federation" 195 | } 196 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = python -msphinx 7 | SPHINXPROJ = aws_consoler 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/authors.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../AUTHORS.rst 2 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # aws_consoler documentation build configuration file, created by 5 | # sphinx-quickstart on Fri Jun 9 13:47:02 2017. 6 | # 7 | # This file is execfile()d with the current directory set to its 8 | # containing dir. 9 | # 10 | # Note that not all possible configuration values are present in this 11 | # autogenerated file. 12 | # 13 | # All configuration values have a default; values that are commented out 14 | # serve to show the default. 15 | 16 | # If extensions (or modules to document with autodoc) are in another 17 | # directory, add these directories to sys.path here. If the directory is 18 | # relative to the documentation root, use os.path.abspath to make it 19 | # absolute, like shown here. 20 | # 21 | import os 22 | import sys 23 | sys.path.insert(0, os.path.abspath('..')) 24 | 25 | import aws_consoler 26 | 27 | # -- General configuration --------------------------------------------- 28 | 29 | # If your documentation needs a minimal Sphinx version, state it here. 30 | # 31 | # needs_sphinx = '1.0' 32 | 33 | # Add any Sphinx extension module names here, as strings. They can be 34 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 35 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] 36 | 37 | # Add any paths that contain templates here, relative to this directory. 38 | templates_path = ['_templates'] 39 | 40 | # The suffix(es) of source filenames. 41 | # You can specify multiple suffix as a list of string: 42 | # 43 | # source_suffix = ['.rst', '.md'] 44 | source_suffix = '.rst' 45 | 46 | # The master toctree document. 47 | master_doc = 'index' 48 | 49 | # General information about the project. 50 | project = u'AWS Consoler' 51 | copyright = u"2020, NetSPI" 52 | author = u"Ian Williams" 53 | 54 | # The version info for the project you're documenting, acts as replacement 55 | # for |version| and |release|, also used in various other places throughout 56 | # the built documents. 57 | # 58 | # The short X.Y version. 59 | version = aws_consoler.__version__ 60 | # The full version, including alpha/beta/rc tags. 61 | release = aws_consoler.__version__ 62 | 63 | # The language for content autogenerated by Sphinx. Refer to documentation 64 | # for a list of supported languages. 65 | # 66 | # This is also used if you do content translation via gettext catalogs. 67 | # Usually you set "language" from the command line for these cases. 68 | language = None 69 | 70 | # List of patterns, relative to source directory, that match files and 71 | # directories to ignore when looking for source files. 72 | # This patterns also effect to html_static_path and html_extra_path 73 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 74 | 75 | # The name of the Pygments (syntax highlighting) style to use. 76 | pygments_style = 'sphinx' 77 | 78 | # If true, `todo` and `todoList` produce output, else they produce nothing. 79 | todo_include_todos = False 80 | 81 | 82 | # -- Options for HTML output ------------------------------------------- 83 | 84 | # The theme to use for HTML and HTML Help pages. See the documentation for 85 | # a list of builtin themes. 86 | # 87 | html_theme = 'alabaster' 88 | 89 | # Theme options are theme-specific and customize the look and feel of a 90 | # theme further. For a list of options available for each theme, see the 91 | # documentation. 92 | # 93 | # html_theme_options = {} 94 | 95 | # Add any paths that contain custom static files (such as style sheets) here, 96 | # relative to this directory. They are copied after the builtin static files, 97 | # so a file named "default.css" will overwrite the builtin "default.css". 98 | html_static_path = ['_static'] 99 | 100 | 101 | # -- Options for HTMLHelp output --------------------------------------- 102 | 103 | # Output file base name for HTML help builder. 104 | htmlhelp_basename = 'aws_consolerdoc' 105 | 106 | 107 | # -- Options for LaTeX output ------------------------------------------ 108 | 109 | latex_elements = { 110 | # The paper size ('letterpaper' or 'a4paper'). 111 | # 112 | # 'papersize': 'letterpaper', 113 | 114 | # The font size ('10pt', '11pt' or '12pt'). 115 | # 116 | # 'pointsize': '10pt', 117 | 118 | # Additional stuff for the LaTeX preamble. 119 | # 120 | # 'preamble': '', 121 | 122 | # Latex figure (float) alignment 123 | # 124 | # 'figure_align': 'htbp', 125 | } 126 | 127 | # Grouping the document tree into LaTeX files. List of tuples 128 | # (source start file, target name, title, author, documentclass 129 | # [howto, manual, or own class]). 130 | latex_documents = [ 131 | (master_doc, 'aws_consoler.tex', 132 | u'AWS Consoler Documentation', 133 | u'Ian Williams', 'manual'), 134 | ] 135 | 136 | 137 | # -- Options for manual page output ------------------------------------ 138 | 139 | # One entry per manual page. List of tuples 140 | # (source start file, name, description, authors, manual section). 141 | man_pages = [ 142 | (master_doc, 'aws_consoler', 143 | u'AWS Consoler Documentation', 144 | [author], 1) 145 | ] 146 | 147 | 148 | # -- Options for Texinfo output ---------------------------------------- 149 | 150 | # Grouping the document tree into Texinfo files. List of tuples 151 | # (source start file, target name, title, author, 152 | # dir menu entry, description, category) 153 | texinfo_documents = [ 154 | (master_doc, 'aws_consoler', 155 | u'AWS Consoler Documentation', 156 | author, 157 | 'aws_consoler', 158 | 'One line description of project.', 159 | 'Miscellaneous'), 160 | ] 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /docs/contributing.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CONTRIBUTING.rst 2 | -------------------------------------------------------------------------------- /docs/history.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../HISTORY.rst 2 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to AWS Consoler's documentation! 2 | ======================================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :caption: Contents: 7 | 8 | readme 9 | installation 10 | usage 11 | modules 12 | contributing 13 | authors 14 | history 15 | 16 | Indices and tables 17 | ================== 18 | * :ref:`genindex` 19 | * :ref:`search` 20 | -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: shell 2 | 3 | ============ 4 | Installation 5 | ============ 6 | 7 | 8 | Stable release 9 | -------------- 10 | 11 | To install AWS Consoler, run this command in your terminal: 12 | 13 | .. code-block:: console 14 | 15 | $ pip install aws-consoler 16 | 17 | This is the preferred method to install AWS Consoler, as it will always install the most recent stable release. 18 | 19 | If you don't have `pip`_ installed, this `Python installation guide`_ can guide 20 | you through the process. 21 | 22 | .. _pip: https://pip.pypa.io 23 | .. _Python installation guide: http://docs.python-guide.org/en/latest/starting/installation/ 24 | 25 | 26 | From sources 27 | ------------ 28 | 29 | The sources for AWS Consoler can be downloaded from the `Github repo`_. 30 | 31 | You can either clone the public repository: 32 | 33 | .. code-block:: console 34 | 35 | $ git clone git://github.com/netspi/aws_consoler 36 | 37 | Or download the `tarball`_: 38 | 39 | .. code-block:: console 40 | 41 | $ curl -OJL https://github.com/netspi/aws_consoler/tarball/master 42 | 43 | Once you have a copy of the source, you can install it with: 44 | 45 | .. code-block:: console 46 | 47 | $ python setup.py install 48 | 49 | 50 | .. _Github repo: https://github.com/netspi/aws_consoler 51 | .. _tarball: https://github.com/netspi/aws_consoler/tarball/master 52 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=python -msphinx 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | set SPHINXPROJ=aws_consoler 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The Sphinx module was not found. Make sure you have Sphinx installed, 20 | echo.then set the SPHINXBUILD environment variable to point to the full 21 | echo.path of the 'sphinx-build' executable. Alternatively you may add the 22 | echo.Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /docs/readme.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../README.rst 2 | -------------------------------------------------------------------------------- /docs/usage.rst: -------------------------------------------------------------------------------- 1 | ===== 2 | Usage 3 | ===== 4 | 5 | To use AWS Consoler in a project:: 6 | 7 | import aws_consoler 8 | 9 | To use AWS Consoler on the command line, run the following for the full help output:: 10 | 11 | aws_consoler -h 12 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | argparse 2 | boto3 3 | requests 4 | -------------------------------------------------------------------------------- /requirements_dev.txt: -------------------------------------------------------------------------------- 1 | bump2version 2 | Sphinx 3 | twine 4 | 5 | -------------------------------------------------------------------------------- /requirements_test.txt: -------------------------------------------------------------------------------- 1 | pip 2 | wheel 3 | flake8 4 | tox 5 | coverage 6 | 7 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 1.1.0 3 | commit = True 4 | tag = True 5 | parse = 6 | (?P\d+)\.(?P\d+)\.(?P\d+) # major, minor and patch 7 | (?:\-(?P
(?:rc))\.(?P\d+))?        # pre-release
 8 | 	(?:\+(?P\d+))?                          # build metadata
 9 | serialize = 
10 | 	{major}.{minor}.{patch}-{pre}.{prenum}+{build}
11 | 	{major}.{minor}.{patch}-{pre}.{prenum}
12 | 	{major}.{minor}.{patch}+{build}
13 | 	{major}.{minor}.{patch}
14 | 
15 | [bumpversion:part:pre]
16 | optional_value = stable
17 | values = 
18 | 	rc
19 | 	stable
20 | 
21 | [bumpversion:part:prenum]
22 | first_value = 1
23 | 
24 | [bumpversion:part:build]
25 | 
26 | [bumpversion:file:setup.py]
27 | search = version='{current_version}'
28 | replace = version='{new_version}'
29 | 
30 | [bumpversion:file:aws_consoler/__init__.py]
31 | search = __version__ = '{current_version}'
32 | replace = __version__ = '{new_version}'
33 | 
34 | [bdist_wheel]
35 | universal = 1
36 | 
37 | [flake8]
38 | exclude = docs
39 | 
40 | [aliases]
41 | 


--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/env python
 2 | # -*- coding: utf-8 -*-
 3 | 
 4 | """The setup script."""
 5 | 
 6 | from setuptools import setup, find_packages
 7 | 
 8 | with open('README.rst') as readme_file:
 9 |     readme = readme_file.read()
10 | 
11 | with open('HISTORY.rst') as history_file:
12 |     history = history_file.read()
13 | 
14 | 
15 | def load_requirements(fname):
16 |     with open(fname) as f:
17 |         return f.read().strip().split('\n')
18 | 
19 | 
20 | requirements = load_requirements("requirements.txt")
21 | 
22 | setup_requirements = []
23 | 
24 | test_requirements = load_requirements("requirements_test.txt")
25 | 
26 | dev_requirements = test_requirements\
27 |                    + load_requirements("requirements_dev.txt")
28 | 
29 | setup(
30 |     author="Ian Williams",
31 |     author_email='ian.williams@netspi.com',
32 |     python_requires='>=3, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*',
33 |     classifiers=[
34 |         'Development Status :: 2 - Pre-Alpha',
35 |         'Intended Audience :: Developers',
36 |         'License :: OSI Approved :: BSD License',
37 |         'Natural Language :: English',
38 |         'Programming Language :: Python :: 3',
39 |         'Programming Language :: Python :: 3.5',
40 |         'Programming Language :: Python :: 3.6',
41 |         'Programming Language :: Python :: 3.7',
42 |         'Programming Language :: Python :: 3.8',
43 |     ],
44 |     description="A utility to convert your AWS CLI credentials into AWS "
45 |                 "console access.",
46 |     entry_points={
47 |         'console_scripts': [
48 |             'aws_consoler=aws_consoler.cli:main',
49 |         ],
50 |     },
51 |     extras_require={
52 |         "dev": dev_requirements,
53 |         "test": test_requirements
54 |     },
55 |     install_requires=requirements,
56 |     license="BSD license",
57 |     long_description=readme + '\n\n' + history,
58 |     include_package_data=True,
59 |     keywords='aws_consoler',
60 |     name='aws_consoler',
61 |     packages=find_packages(include=['aws_consoler', 'aws_consoler.*']),
62 |     setup_requires=setup_requirements,
63 |     test_suite='tests',
64 |     tests_require=test_requirements,
65 |     url='https://github.com/netspi/aws_consoler',
66 |     version='1.1.0',
67 |     zip_safe=True,
68 | )
69 | 


--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | 
3 | """Unit test package for aws_consoler."""
4 | 


--------------------------------------------------------------------------------
/tests/test_aws_consoler/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NetSPI/aws_consoler/cbd99010c248aef0f24afcbdf9219e85d36f5213/tests/test_aws_consoler/__init__.py


--------------------------------------------------------------------------------
/tests/test_aws_consoler/test_cli.py:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/env python
 2 | # -*- coding: utf-8 -*-
 3 | 
 4 | """Tests for `aws_consoler` CLI."""
 5 | 
 6 | 
 7 | import unittest
 8 | 
 9 | from aws_consoler import cli
10 | 
11 | 
12 | class TestCLI(unittest.TestCase):
13 |     """
14 |     Tests for `aws_consoler` package.
15 |     At the moment, this only includes tests for command-line arguments
16 |     """
17 | 
18 |     def setUp(self):
19 |         """Set up test fixtures, if any."""
20 |         pass
21 | 
22 |     def tearDown(self):
23 |         """Tear down test fixtures, if any."""
24 |         pass
25 | 
26 |     def test_000_help(self):
27 |         """Test no arguments to the CLI (expect help output)."""
28 |         with self.assertRaises(SystemExit) as e:
29 |             cli.main(["-h"])
30 |         self.assertEqual(e.exception.code, 0)
31 | 
32 |     def test_001_all_arguments(self):
33 |         """Test all arguments to the CLI (expect error)."""
34 |         with self.assertRaises(SystemExit) as e:
35 |             cli.main(["-p foo", "-a bar", "-s baz", "-t bul", "-r foo", "-R BAZ", "-o", "-v"])
36 |         self.assertEqual(e.exception.code, 2)
37 | 
38 |     def test_002_profile_and_creds(self):
39 |         """Test providing both a profile and credentials to the CLI."""
40 |         with self.assertRaises(SystemExit) as e:
41 |             cli.main(["-p foo", "-a bar", "-s baz", "-t bul"])
42 |         self.assertEqual(e.exception.code, 2)
43 | 
44 |     def test_003_partial_creds(self):
45 |         """Test providing only one credential argument to the CLI."""
46 |         with self.assertRaises(SystemExit) as e:
47 |             cli.main(["-a bar"])
48 |         self.assertEqual(e.exception.code, 2)
49 | 
50 |     def test_004_token_only(self):
51 |         """Test providing only a session token to the CLI."""
52 |         with self.assertRaises(SystemExit) as e:
53 |             cli.main(["-t bul"])
54 |         self.assertEqual(e.exception.code, 2)
55 | 
56 |     def test_005_logic_exception(self):
57 |         """Test malformed credentials to the CLI (passed in to logic)."""
58 |         with self.assertRaises(SystemExit) as e:
59 |             cli.main(["-a foo", "-s bar"])
60 |         self.assertEqual(e.exception.code, 1)
61 | 
62 | 


--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
 1 | [tox]
 2 | envlist = py36, py37, py38, flake8
 3 | 
 4 | [testenv:flake8]
 5 | basepython = python
 6 | deps = flake8
 7 | commands = flake8 aws_consoler
 8 | 
 9 | [testenv]
10 | setenv =
11 |     PYTHONPATH = {toxinidir}
12 | 
13 | commands = python setup.py test
14 | 


--------------------------------------------------------------------------------