Skip to content

Commit

Permalink
Release (#4)
Browse files Browse the repository at this point in the history
* removed un-neceesary import

* added test for keyring

* version 0.6.0

* testing keyring

* added ubuntu scripts

* added root

* removed ubuntu

* don't test keyring with ubuntu

* version 0.6.0, toml update

* removed special ubuntu workflow

* tidied up README.MD

* black linted

* new coveralls addition

* set env var

* changed path

* new plugins

* downgrade coveralls

* try this

* new one

* new release

* downgraded coveralls

* new Readme

* version 0.6.1

* corrected bug tracker
  • Loading branch information
keithrozario committed Nov 21, 2020
1 parent ab16936 commit 9776a14
Show file tree
Hide file tree
Showing 16 changed files with 416 additions and 247 deletions.
11 changes: 8 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,13 @@ jobs:
- name: Poetry test
env:
CREDENTIALS_FILE_CONTENTS : ${{ secrets.AWS_CREDENTIALS_FILE_CONTENTS }}
run: poetry run pytest -s -x .


working-directory: ./tests
run: poetry run pytest . --cov ../mentaws --cov-report term-missing -vv

- name: Update Test Coverage
if: github.ref == 'refs/heads/release' && contains(matrix.os, 'mac')
env:
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
working-directory: ./tests
run: poetry run coveralls

14 changes: 14 additions & 0 deletions README.MD
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@

# mentaws (moMENTary AWS tokens)

Stay Fresh!

[![Coverage Status](https://coveralls.io/repos/github/keithrozario/mentaws/badge.svg?branch=release)](https://coveralls.io/github/keithrozario/mentaws?branch=release) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/keithrozario/mentaws.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/keithrozario/mentaws/context:python)

[![Python 3.6](https://img.shields.io/badge/python-3.6-blue.svg)](https://www.python.org/downloads/release/python-360/)
[![Python 3.7](https://img.shields.io/badge/python-3.7-blue.svg)](https://www.python.org/downloads/release/python-370/)
[![Python 3.8](https://img.shields.io/badge/python-3.8-blue.svg)](https://www.python.org/downloads/release/python-380/)

## Introduction

mentaws (rhymes with jaws, and sounds like the candy) replaces your aws credentials file with fresh temporary tokens, while keeping your long lived AWS secret keys encrypted.
Expand Down Expand Up @@ -90,6 +97,13 @@ For the encryption we use the [pyca/cryptography](https://cryptography.io/en/lat
We store the randomly generated key in your macOS keychain using keyring, this has one limitation, namely:

* Any Python script or application can access secrets created by keyring from that same Python executable without the operating system prompting the user for a password. **To cause any specific secret to prompt for a password every time it is accessed, locate the credential using the Keychain Access application, and in the Access Control settings, remove Python from the list of allowed applications.**

Although, on my machine with macOS Catalina installed, I do get prompted once for every sensitive mentaws operation.

## Warning

This project is still in beta, and work with all AWS features, use at your own risk.

## Limitation

Because of the way tokens work, any operation on iam, e.g. iam:GetRole, will fail with mentaws because we do not use MFA for the authorization.
2 changes: 1 addition & 1 deletion mentaws/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.6.0"
__version__ = "0.6.1"
20 changes: 9 additions & 11 deletions mentaws/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,22 @@
"creds_file_name": "credentials",
"encryption_key_name": "encryption_key",
"config_file_name": "config", # AWS config name
"Darwin": {
"aws_directory": "/Users/{user_name}/.aws",
},
"Linux": {
"aws_directory": "/home/{user_name}/.aws",
},
"Windows": {
"aws_directory": "{user_profile}\\.aws",
},
"Darwin": {"aws_directory": "/Users/{user_name}/.aws",},
"Linux": {"aws_directory": "/home/{user_name}/.aws",},
"Windows": {"aws_directory": "{user_profile}\\.aws",},
}

refresh_message = """
You're all fresh 😎
"""

unsetup_message = """So long, farewell, auf Wiedersehen, goodbye 😢"""
setup_message = """mentaws successfully setup, run mentaws refresh to get fresh tokens"""
already_setup_message = "It looks like mentaws is already setup, use mentaws refresh or mentaws list"
setup_message = (
"""mentaws successfully setup, run mentaws refresh to get fresh tokens"""
)
already_setup_message = (
"It looks like mentaws is already setup, use mentaws refresh or mentaws list"
)


def get_platform_config() -> dict:
Expand Down
32 changes: 18 additions & 14 deletions mentaws/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ def setup():


@main.command()
@click.option('--profiles', '-p',
help='Comma separated list of profiles to refresh (e.g. profile1,profile2)',
default=""
@click.option(
"--profiles",
"-p",
help="Comma separated list of profiles to refresh (e.g. profile1,profile2)",
default="",
)
def refresh(profiles: str = ""):
"""
Expand Down Expand Up @@ -83,21 +85,23 @@ def refresh(profiles: str = ""):


@main.command()
@click.option('--profiles', '-p',
help='Comma separated list of profiles to remove (e.g. profile1,profile2)',
required=True
@click.option(
"--profiles",
"-p",
help="Comma separated list of profiles to remove (e.g. profile1,profile2)",
required=True,
)
@click.confirmation_option(prompt=f'Deleting a profile is irreversible, are you sure?')
def remove(profiles: str="") -> bool:
@click.confirmation_option(prompt=f"Deleting a profile is irreversible, are you sure?")
def remove(profiles: str = "") -> bool:
"""
Removes an AWS profile from mentaws [REQUIRES -p option].
"""
profiles_list = profiles.split(",")

for profile_name in profiles_list:
if operations.check_profile_in_db(profile_name):
operations.remove_profile_from_db(profile_name)
safe_print(f"Profile {profile_name} was deleted")
operations.remove_profile_from_db(profile_name)
safe_print(f"Profile {profile_name} was deleted")
else:
safe_print(f"Profile {profile_name} not found")

Expand Down Expand Up @@ -131,7 +135,7 @@ def status() -> List[dict]:
safe_print(f" {section:<30}-{' '*24}No Token Expiry")
temp = {"profile": section}
profiles.append(temp)

safe_print("")

return profiles
Expand All @@ -156,13 +160,13 @@ def unsetup() -> bool:
for key in temp_config[profile]:
if temp_config[profile][key] == "":
del temp_config[profile][key]

operations.write_creds_file(config=temp_config, replace=True)
mentaws_db_path = operations.remove_mentaws_db()

safe_print(f"{mentaws_db_path} has been been deleted, it's like we were never here")
safe_print(mentaws_config.unsetup_message)

return True


Expand All @@ -178,4 +182,4 @@ def safe_print(print_string: str) -> None:
except UnicodeEncodeError:
print(print_string.encode("ascii", "ignore").decode("ascii"))

return None
return None
15 changes: 7 additions & 8 deletions mentaws/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,22 +92,23 @@ def get_plaintext_credentials(profiles: str = "", all: bool = False) -> List[dic
conn.row_factory = sqlite3.Row
db = conn.cursor()


# Get all profiles in DB
try:
# Select all profiles (even those without creds)
if all:
db.execute(f"SELECT * FROM {table_name} ORDER BY profile")
# Select only profiles with creds
elif len(profiles) == 0:
db.execute(f"SELECT * FROM {table_name} WHERE aws_access_key_id != '' ORDER BY profile")
db.execute(
f"SELECT * FROM {table_name} WHERE aws_access_key_id != '' ORDER BY profile"
)
else:
profile_list = profiles.split(",")
# Select only one profile
if len(profile_list) == 1:
db.execute(
f"SELECT * FROM {table_name} WHERE profile = ? AND aws_access_key_id != '' ORDER BY profile",
(profile_list[0],)
(profile_list[0],),
)
# Select a list of profiles
else:
Expand Down Expand Up @@ -151,12 +152,11 @@ def write_creds_file(config: ConfigParser, replace: bool = True):
**Future addition**
replace: if True, replaces entire credentials file. If False, only over-writes existing sections
"""

creds = ConfigParser()

if not replace:
creds.read(filenames=[creds_file_path], encoding="utf-8")


creds.read_dict(configparser_to_dict(config))
with open(creds_file_path, "w") as creds_file:
Expand Down Expand Up @@ -221,7 +221,6 @@ def write_creds_to_db(creds: ConfigParser) -> List[str]:
temp_profile["other_options"] = json.dumps(other_options)
rows_to_write.append(temp_profile)


# append with encrypted keys, we do it this way, so that one call can be made to cryptographic operations, and retrieve the secret key once!
# This reduces the number of times the user has to enter the keychain password
encrypted_keys = encrypt_keys(
Expand Down Expand Up @@ -296,10 +295,10 @@ def creds_file_contents() -> ConfigParser:


def remove_mentaws_db() -> str:

try:
os.remove(mentaws_db_path)
except OSError:
pass

return config["database_file"]
return config["database_file"]
Loading

0 comments on commit 9776a14

Please sign in to comment.