Skip to content

Commit

Permalink
Updated usage chapter, examples; fixed error
Browse files Browse the repository at this point in the history
Signed-off-by: Andreas Maier <andreas.r.maier@gmx.de>
  • Loading branch information
andy-maier committed Mar 29, 2021
1 parent 62d1406 commit 26b317c
Show file tree
Hide file tree
Showing 11 changed files with 120 additions and 122 deletions.
80 changes: 46 additions & 34 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,7 @@ shown in the previous section:
password: mypass2
The vault file must have one top-level property named ``secrets``. Below
that are properties that represent the servers or services. For the sake of
simplicity, we only talk about servers from now on.
that are properties that represent the servers (or services).

The server items are identified by nicknames (``myserver1`` and ``myserver2``
in the example above) and can have an arbitrary user-defined set of properties
Expand All @@ -191,57 +190,70 @@ Here is another example that defines the server secrets as URL and API key
url: https://9.10.11.12/myservice
api_key: mykey2
Because the server definition file has user-defined properties for each
server entry, and the structure of the server entries in the vault file
is user-defined, there is a choice of which information is put into which
file. For example, the host property from the previous examples could have
been moved into the server definition file as a user-defined property,
since usually it is not really a secret.

The vault file can be encrypted or decrypted using the ``easy-vault`` command
that is part of the
`easy-vault package <https://easy-vault.readthedocs.io/en/latest/>`_

The vault file can be in the encrypted state or in clear text when the
**secure-server-access** library functions are accessing it.
**secure-server-access** library functions are accessing it. It is recommended
to always have it in the encrypted state and to decrypt it only for the period
of time while it is edited.


.. _`Accessing the secrets in a program`:
.. _`Example usage`:

Accessing the secrets in a program
----------------------------------
Example usage
-------------

The following Python code demonstrates the use case of a command line utility
that prompts for the vault password if needed and stores that password in the
keyring facility of the local system for future use, using the
`keyring Python package`_:
This section describes how a program would use the example server definition
file and vault file from the previous sections to get to all the information
that is needed to access the server.

.. code-block:: python
import getpass
import keyring
from secure_server_access import Vault, NotFound
from secure_server_access import VaultFile, VaultFileException, \
ServerDefinitionFile, ServerDefinitionFileException
vault_file = 'vault.yml' # Path name of Ansible vault file
server_nick = 'myserver1' # Nickname of server in Ansible vault file
# Some parameters that typically would be inout to the program:
vault_file = 'examples/vault.yml' # Path name of vault file
srvdef_file = 'examples/srvdef.yml' # Path name of server definition file
nickname = 'mygroup1' # Nickname of server or group
keyring_service = 'myprogram' # Some unique service name within your keyring
keyring_username = 'vault'
try:
sdf = ServerDefinitionFile(srvdef_file)
except ServerDefinitionFileException as exc:
print("Error: {}".format(exc))
return 1
password = keyring.get_password(keyring_service, keyring_username)
if password is None:
password = getpass.getpass("Password for Ansible vault file {fn}:".
format(fn=vault_file))
keyring.set_password(keyring_service, keyring_username, password)
sd_list = sdf.list_servers(nickname)
# Open the vault and access the entry for a server
vault = Vault(vault_file, password)
try:
vault_server = vault.get_server(server_nick)
except NotFound as exc:
# Handle server nickname not found
. . .
vault = VaultFile(vault_file)
except VaultFileException as exc:
print("Error: {}".format(exc))
return 1
session = MySession( # A fictitious session class
host=vault_server['host'],
username=vault_server['username'],
password=vault_server['password'])
for sd in sd_list:
nick = sd.nickname
secrets = vault.get_secrets(nick)
# Do something in the server session
. . .
host=secrets['host'],
username=secrets['username']
password=secrets['password']
print("Server {n}: host={h}, username={u}, password=********".
format(n=nick, h=host, u=username))
# A fictitious session class
session = MySession(host, username, password)
. . .
The use case where a Python test program using the `pytest Python package`_
needs access to servers is best handled by using the `Pytest fixture`_ provided
Expand Down
13 changes: 0 additions & 13 deletions examples/approach2/ssa.yml

This file was deleted.

35 changes: 0 additions & 35 deletions examples/approach2/test_workflow.yml

This file was deleted.

16 changes: 0 additions & 16 deletions examples/approach2/vault.yml

This file was deleted.

55 changes: 55 additions & 0 deletions examples/process_servers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/usr/bin/env python
"""
Example script that processes the servers of a server or grou nickname.
"""

import sys
import os
from pprint import pprint
import easy_vault

from secure_server_access import VaultFile, VaultFileException, \
ServerDefinitionFile, ServerDefinitionFileException


def main():
"""Main function"""

if len(sys.argv) < 4:
print("Usage: {} vaultfile srvdeffile nickname".format(sys.argv[0]))
sys.exit(2)

vault_file = sys.argv[1]
srvdef_file = sys.argv[2]
nickname = sys.argv[3]

try:
sdf = ServerDefinitionFile(srvdef_file)
except ServerDefinitionFileException as exc:
print("Error: {}".format(exc))
return 1

sd_list = sdf.list_servers(nickname)

try:
vault = VaultFile(vault_file)
except VaultFileException as exc:
print("Error: {}".format(exc))
return 1

for sd in sd_list:
nick = sd.nickname
secrets = vault.get_secrets(nick)

host=secrets['host'],
username=secrets['username']
password=secrets['password']

print("Server {n}: host={h}, username={u}, password=********".
format(n=nick, h=host, u=username))

return 0


if __name__ == '__main__':
sys.exit(main())
7 changes: 1 addition & 6 deletions scripts/show_secrets.py → examples/show_vault.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python
"""
Test script that shows the content of a vault file.
Example script that shows the content of a vault file.
"""

import sys
Expand All @@ -20,11 +20,6 @@ def main():

vault_file = sys.argv[1]

# if not os.path.exists(vault_file):
# print("Error: Vault file does not exist: {fn}".
# format(fn=vault_file))
# return 1

try:
vault = VaultFile(vault_file)
except (easy_vault.EasyVaultException, VaultFileException) as exc:
Expand Down
1 change: 0 additions & 1 deletion examples/ssa.yml → examples/srvdef.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
---
# Example server definition file for secure-server-access package.

servers:
Expand Down
11 changes: 5 additions & 6 deletions examples/vault.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
---
# Example vault file for secure-server-access package.

secrets:

myserver1:
host: "10.11.12.13"
username: myusername
password: mypassword
username: myuser1
password: mypass1

myserver2:
host: "9.11.12.13"
username: myusername
password: mypassword
host: "9.10.11.12"
username: myuser2
password: mypass2
10 changes: 3 additions & 7 deletions secure_server_access/_srvdef.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class ServerDefinition(object):
"""
Represents a single server definition from a server definition file.
Example for a server definition in a server definition file:
Example for a server definition item in a server definition file:
.. code-block:: yaml
Expand All @@ -32,19 +32,15 @@ class ServerDefinition(object):
contact_name: "John Doe"
access_via: "VPN to dev network"
user_defined: # user-defined part
host: "10.11.12.13"
username: myusername
password: mypassword
stuff:
- morestuff1
stuff: morestuff
"""

def __init__(self, nickname, server_dict):
self._nickname = nickname
self._description = server_dict['description']
self._contact_name = server_dict.get('contact_name', None)
self._access_via = server_dict.get('access_via', None)
self._user_defined = server_dict['user_defined']
self._user_defined = server_dict.get('user_defined', None)

def __repr__(self):
return "ServerDefinition(" \
Expand Down
12 changes: 9 additions & 3 deletions tests/unittest/test_srvdef.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@
None, None, True
),
(
"Omitted required parameter: user_defined",
"Omitted optional parameter: user_defined",
dict(
init_args=(),
init_kwargs=dict(
Expand All @@ -158,9 +158,15 @@
'access_via': 'my vpn',
},
),
exp_attrs=None,
exp_attrs={
'nickname': 'myserver',
'description': 'my description',
'contact_name': 'my contact',
'access_via': 'my vpn',
'user_defined': None,
},
),
KeyError, None, True
None, None, True
),
]

Expand Down
2 changes: 1 addition & 1 deletion tests/unittest/test_srvdef_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from ..utils.simplified_test_function import simplified_test_function


TEST_SDF_FILEPATH = 'examples/ssa.yml'
TEST_SDF_FILEPATH = 'examples/srvdef.yml'

TESTCASES_SDF_INIT = [

Expand Down

0 comments on commit 26b317c

Please sign in to comment.