Compare commits

...

39 Commits
v0.6.0 ... main

Author SHA1 Message Date
Victor Zemtsov b633a57fc3
Merge pull request #51 from MichaelEllnebrand/deprecated-configuration-setting
Deprecated Configuration Setting
2024-04-25 09:42:56 +03:00
Michael Ellnebrand acb07e8335
Deprecated Configuration Setting
The configuration setting COLLECTIONS_PATHS was deprecated in Ansible 2.19, see: https://docs.ansible.com/ansible/latest/reference_appendices/config.html#collections-paths
2024-04-21 19:57:33 +02:00
Victor Zemtsov c1ecea1fb5 Fix version 2023-06-11 23:22:15 +03:00
Victor Zemtsov 6be989a0d3 Fix DEPRECATION WARNING 2023-06-11 23:21:43 +03:00
Victor Zemtsov ab6d3a8228 Fix example 2023-06-11 23:14:43 +03:00
Victor Zemtsov 61a8f39081 Merge branch 'advanova-main' 2023-06-11 23:13:29 +03:00
Markus Heberling 1988cb62a6 Dereference field references 2023-06-01 08:23:12 +02:00
Victor Zemtsov dd97f8a830 Fix version to 0.7.4 2023-02-10 02:19:03 +03:00
Victor Zemtsov 8259d85305 Merge branch 'jpmens-attachment_new' 2023-02-10 01:04:44 +03:00
Victor Zemtsov 02fc763fd5 Merge branch 'attachment_new' of github.com:jpmens/ansible-keepass into jpmens-attachment_new 2023-02-10 01:02:58 +03:00
Victor Zemtsov 47ebe2e6dd Fix #46 custom_properties - long chain are truncated 2023-02-10 00:55:32 +03:00
Jan-Piet Mens 808391953c support kdbx key file for attachment extraction
the lookup plugin supports using a key file, but the module didn't.
  This small patch adds support for specifying a key file for
  accessing the kdbx file.
2023-01-25 20:53:46 +01:00
Victor Zemtsov 237f3a0da5 Fix version to 0.7.3 2023-01-10 08:43:58 +03:00
Victor Zemtsov 5ec13cdee3 Fix typo 2023-01-10 08:38:08 +03:00
Victor Zemtsov 625be39764 Fix lint errors 2023-01-10 08:34:20 +03:00
Victor Zemtsov 37309942d9 Merge branch 'add_environment_variables' of github.com:tabacha/ansible-keepass into tabacha-add_environment_variables 2023-01-10 08:11:56 +03:00
Victor Zemtsov 6db523cedb Merge branch 'develop' 2023-01-10 08:02:02 +03:00
Victor Zemtsov 9bcd8ce6a7 Merge branch 'tabacha-fix_path_to_python' into develop 2023-01-10 07:58:56 +03:00
Sven Anders 6ca6efde8a Add Bash/Shell environment variables for better ci integration 2023-01-06 15:57:09 +01:00
Sven Anders ee68122d74 use sys.executable as path to python, this helps if use use a venv for ansible 2023-01-06 14:48:35 +01:00
Victor Zemtsov 107fb09a1a Fix #34 KeePass: socket connection failed when used in parallel 2022-11-09 11:47:02 +03:00
Victor Zemtsov ac84c3ccbc Add playbook to tests/parallel 2022-11-09 11:27:36 +03:00
Victor Zemtsov 5c247f921b Fix tests/parallel group_vars 2022-11-09 11:25:34 +03:00
Victor Zemtsov ee4aba14df Add tests/parallel 2022-11-03 14:12:05 +03:00
Victor Zemtsov affcf5e950 Merge branch 'main' into develop 2022-10-22 14:09:37 +03:00
Victor Zemtsov f55e4d84d6 Fix #33 Password shall not be mandatory for opening the db 2022-10-22 13:44:40 +03:00
Victor Zemtsov e9392a54e3 Add Dockerfile for run examples 2022-09-02 15:45:39 +03:00
Victor Zemtsov c622672bab Fix README 2022-08-20 14:47:07 +03:00
Victor Zemtsov ae19f7c2c5 Fix collection metadata
The 'license' and 'license_file' keys are mutually exclusive
2022-08-20 14:35:37 +03:00
Victor Zemtsov 655b343e03 Merge branch 'jimisola-feature/update_docs' into develop 2022-08-20 14:28:43 +03:00
Victor Zemtsov a61cc8dd80 Fix .gitignore 2022-08-20 14:18:51 +03:00
Victor Zemtsov 05576cca7d Rename /doc to /docs 2022-08-20 14:12:57 +03:00
Victor Zemtsov 0a523d7fdf Merge branch 'feature/update_docs' of github.com:jimisola/ansible-keepass into jimisola-feature/update_docs 2022-08-20 14:05:53 +03:00
Victor Zemtsov bdc8febd7e Merge branch 'jimisola-feature/attachment_to_file' into develop 2022-08-20 13:54:12 +03:00
Victor Zemtsov dd935327e7 Fix version 2022-08-20 13:43:39 +03:00
Victor Zemtsov de1d72afe0 Linting 2022-08-20 13:29:57 +03:00
Jimisola Laursen 10f4a191fe docs: Update docs and refactor doc to docs 2022-08-15 00:57:21 +02:00
Jimisola Laursen ef15128536 Merge branch 'main' into feature/attachment_to_file 2022-08-15 00:41:06 +02:00
Jimisola Laursen 26422700ab feat: Adds module attachment w/ example 2022-08-15 00:29:10 +02:00
43 changed files with 626 additions and 49 deletions

4
.gitignore vendored
View File

@ -105,4 +105,6 @@ venv.bak/
# mypy
.mypy_cache/
.idea
.idea
/docs/examples/attachment*
/*.tar.gz

View File

@ -1,15 +1,14 @@
# Ansible KeePass Lookup Plugin
This collection provides a plugin that allows to read data from KeePass file (modifying is not supported)
This collection provides plugins that allows to read data from KeePass file (modifying is not supported)
## How it works
The plugin opens a UNIX socket with decrypted KeePass file.
For performance reasons, decryption occurs only once at socket startup,
The lookup plugin opens a UNIX socket with decrypted KeePass file.
For performance reasons, decryption occurs only once at socket startup,
and the KeePass file remains decrypted as long as the socket is open.
The UNIX socket file is stored in a temporary folder according to OS.
## Installation
Requirements: `python 3`, `pykeepass==4.0.3`
@ -21,17 +20,38 @@ Requirements: `python 3`, `pykeepass==4.0.3`
## Variables
- `keepass_dbx` - path to KeePass file
- `keepass_psw` - password
- `keepass_key` - *Optional*. Path to keyfile
- `keepass_ttl` - *Optional*. Socket TTL (will be closed automatically when not used).
- `keepass_psw` - *Optional*. Password (required if `keepass_key` is not set)
- `keepass_key` - *Optional*. Path to keyfile (required if `keepass_psw` is not set)
- `keepass_ttl` - *Optional*. Socket TTL (will be closed automatically when not used).
Default 60 seconds.
## Environment Variables
If you want to use ansible-keepass with continuous integration, it could be helpful not to use ansible variables but Shell environment variables.
- `ANSIBLE_KEEPASS_PSW` Password
- `ANSIBLE_KEEPASS_KEY` Path to keyfile
- `ANSIBLE_KEEPASS_TTL` Socket TTL
- `ANSIBLE_KEEPASS_SOCKET` Path to Keepass Socket
The environment variables will only be used, if no ansible variable is set.
You can than start the socket in another background process like this
```sh
export ANSIBLE_KEEPASS_PSW=mySecret
export ANSIBLE_KEEPASS_SOCKET=/home/build/.my-ansible-sock.${CI_JOB_ID}
export ANSIBLE_TTL=600 # 10 Minutes
/home/build/ansible-pyenv/bin/python3 /home/build/.ansible/roles/ansible_collections/viczem/keepass/plugins/lookup/keepass.py /path-to/my-keepass.kdbx &
ansible-playbook -v playbook1.yml
ansible-playbook -v playbook2.yml
```
## Usage
`ansible-doc -t lookup keepass` to get description of the plugin
> **WARNING**: For security reasons, do not store KeePass passwords in plain text.
> **WARNING**: For security reasons, do not store KeePass passwords in plain text.
Use `ansible-vault encrypt_string` to encrypt it and use it like below
# file: group_vars/all
@ -41,11 +61,26 @@ Use `ansible-vault encrypt_string` to encrypt it and use it like below
$ANSIBLE_VAULT;1.1;AES256
...encrypted password...
### Example
### Examples
More examples see in [/docs/examples](/docs/examples).
#### Lookup
ansible_user : "{{ lookup('viczem.keepass.keepass', 'path/to/entry', 'username') }}"
ansible_become_pass : "{{ lookup('viczem.keepass.keepass', 'path/to/entry', 'password') }}"
custom_field : "{{ lookup('viczem.keepass.keepass', 'path/to/entry', 'custom_properties', 'a_custom_property_name') }}"
attachment : "{{ lookup('viczem.keepass.keepass', 'path/to/entry', 'attachments', 'a_file_name') }}"
More examples see in [/doc/examples](/doc/examples).
#### Module
- name: "Export file: attachment.txt"
viczem.keepass.attachment:
database: "{{ keepass_dbx }}"
password: "{{ keepass_psw }}"
entrypath: example/attachments
attachment: "attachment.txt"
dest: "{{ keepass_attachment_1_name }}"
## Contributing
See [/docs/contributing](docs/contributing).

View File

@ -1,5 +0,0 @@
# Example
`ansible-playbook example-playbook.yml --ask-vault-pass -vvv`
Password: `spamham`

Binary file not shown.

View File

@ -0,0 +1,29 @@
# Contributing
1. Create ansible.cfg in cloned directory:
```
[defaults]
COLLECTIONS_PATH = ./collections
```
2. Create requirements.yml in cloned directory:
```
---
collections:
- name: namespace.collection_name
source: /where/is/your/clone
type: dir
```
3. To install the collection _locally_ in your cloned directory, just install it through ansible-galaxy
```shell
rm -rf ./collections && ansible-galaxy install -r requirements.yml
```
Note: Any change on your clone imply to reinstall the collection.
Tip: You can place a ansible.cfg with `COLLECTIONS_PATH = ../../collections` in the examples dictory if you want to run the example on local collection in your cloned directory.

10
docs/examples/README.md Normal file
View File

@ -0,0 +1,10 @@
# Example
`ansible-playbook example-playbook.yml --ask-vault-pass -vvv`
Password: `spamham`
## Docker
`DOCKER_BUILDKIT=1 docker-compose up --build`

View File

@ -11,7 +11,8 @@
slash_url: "{{ lookup('viczem.keepass.keepass', 'slash\\/group/slash\\/title', 'url') }}"
pork_custom_property: "{{ lookup('viczem.keepass.keepass', 'example/pork', 'custom_properties', 'pork_custom_property')}}"
attachment: "{{ lookup('viczem.keepass.keepass', 'example/pork', 'attachments', 'test.txt')}}"
keepass_attachment_1_name: "attachment_1.txt"
keepass_attachment_2_name: "attachment_2.zip"
tasks:
- debug:
@ -33,4 +34,22 @@
- debug:
msg: "fetch entry: '/slash\\/group/slash\\/title'; username: '{{ slash_login }}'; url: '{{ slash_url }}'"
- debug: "{{ lookup('viczem.keepass.keepass', 'close') }}"
- debug:
msg: "close {{ lookup('viczem.keepass.keepass', 'close') }}"
- name: "Export file: {{ keepass_attachment_1_name }}"
viczem.keepass.attachment:
database: "{{ keepass_dbx }}"
password: "{{ keepass_psw }}"
entrypath: example/attachments
attachment: "{{ keepass_attachment_1_name }}"
dest: "{{ keepass_attachment_1_name }}"
- name: "Export file: {{ keepass_attachment_2_name }}"
viczem.keepass.attachment:
database: "{{ keepass_dbx }}"
password: "{{ keepass_psw }}"
entrypath: example/attachments
attachment: "{{ keepass_attachment_2_name }}"
dest: "{{ keepass_attachment_2_name }}"
mode: 0600

BIN
docs/examples/example.kdbx Normal file

Binary file not shown.

View File

@ -8,7 +8,7 @@ namespace: viczem
name: keepass
# The version of the collection. Must be compatible with semantic versioning
version: 0.6.0
version: 0.7.5
# The path to the Markdown (.md) readme file. This path is relative to the root of the collection
readme: README.md
@ -21,11 +21,7 @@ authors:
### OPTIONAL but strongly recommended
# A short summary description of the collection
description: The collection provides a lookup plugin that allow to read data from KeePass file.
# Either a single license or a list of licenses for content inside of a collection. Ansible Galaxy currently only
# accepts L(SPDX,https://spdx.org/licenses/) licenses. This key is mutually exclusive with 'license_file'
license: []
description: The collection provides plugins that allow to read data from KeePass file.
# The path to the license file for the collection. This path is relative to the root of the collection. This key is
# mutually exclusive with 'license'
@ -36,6 +32,7 @@ license_file: 'LICENSE'
tags:
- keepass
- lookup
- module
- plugin
# Collections that this collection requires to be installed for it to be usable. The key of the dict is the

View File

@ -3,6 +3,7 @@ __metaclass__ = type
import argparse
import getpass
import hashlib
import fcntl
import os
import re
import socket
@ -21,7 +22,7 @@ from pykeepass.exceptions import CredentialsError
DOCUMENTATION = """
lookup: keepass
author: Victor Zemtsov <viczem.dev@gmail.com>
version_added: '0.6.0'
version_added: '0.7.5'
short_description: Fetching data from KeePass file
description:
- This lookup returns a value of a property of a KeePass entry
@ -71,26 +72,37 @@ class LookupModule(LookupBase):
# Check key file (optional)
var_key = self._var(variables_.get("keepass_key", ""))
if not var_key and "ANSIBLE_KEEPASS_KEY_FILE" in os.environ:
var_key = os.environ.get('ANSIBLE_KEEPASS_KEY_FILE')
if var_key:
var_key = os.path.realpath(os.path.expanduser(os.path.expandvars(var_key)))
if not os.path.isfile(var_key):
raise AnsibleError("KeePass: '%s' is not found" % var_key)
# Check password (required)
# Check password (optional)
var_psw = self._var(variables_.get("keepass_psw", ""))
if not var_psw:
raise AnsibleError("KeePass: 'keepass_psw' is not set")
if not var_psw and "ANSIBLE_KEEPASS_PSW" in os.environ:
var_psw = os.environ.get('ANSIBLE_KEEPASS_PSW')
if not var_key and not var_psw:
raise AnsibleError("KeePass: 'keepass_psw' and/or 'keepass_key' is not set")
# TTL of keepass socket (optional, default: 60 seconds)
var_ttl = self._var(str(variables_.get("keepass_ttl", "60")))
default_ttl = "60"
if "ANSIBLE_KEEPASS_TTL" in os.environ:
default_ttl = os.environ.get("ANSIBLE_KEEPASS_TTL")
var_ttl = self._var(str(variables_.get("keepass_ttl", default_ttl)))
socket_path = _keepass_socket_path(var_dbx)
lock_file_ = socket_path + ".lock"
if not os.path.isfile(lock_file_):
try:
os.open(lock_file_, os.O_RDWR)
except FileNotFoundError:
cmd = [
"/usr/bin/env",
"python3",
sys.executable,
os.path.abspath(__file__),
var_dbx,
socket_path,
@ -121,7 +133,6 @@ class LookupModule(LookupBase):
if resp[1] == "0":
success = True
else:
sock.send(_rq("close"))
raise AnsibleError("KeePass: wrong dbx password")
sock.close()
break
@ -136,6 +147,7 @@ class LookupModule(LookupBase):
if len(terms) == 1 and terms[0] in ("quit", "exit", "close"):
self._send(socket_path, terms[0], [])
return []
else:
# Fetching data from the keepass socket
return self._send(socket_path, "fetch", terms)
@ -153,7 +165,14 @@ class LookupModule(LookupBase):
display.vvv("KeePass: %s %s" % (cmd, terms))
sock.send(_rq(cmd, *terms))
resp = sock.recv(1024).decode().splitlines()
data = b''
while True:
_ = sock.recv(1024)
data += _
if len(_) < 1024:
break
resp = data.decode().splitlines()
resp_len = len(resp)
if resp_len == 0:
raise AnsibleError("KeePass: '%s' result is empty" % cmd)
@ -189,7 +208,6 @@ def _keepass_socket(kdbx, kdbx_key, sock_path, ttl=60, kdbx_password=None):
"""
tmp_files = []
try:
os.umask(0o177)
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s:
s.bind(sock_path)
s.listen(1)
@ -229,16 +247,20 @@ def _keepass_socket(kdbx, kdbx_key, sock_path, ttl=60, kdbx_password=None):
# CMD: password
if kp is None:
if arg_len == 0:
conn.send(_resp("password", 1))
break
if cmd == "password" and arg[0]:
if cmd == "password" and arg_len > 0:
kp = PyKeePass(kdbx, arg[0], kdbx_key)
conn.send(_resp("password", 0))
break
elif cmd == "password" and kdbx_key:
kp = PyKeePass(kdbx, None, kdbx_key)
conn.send(_resp("password", 0))
break
else:
conn.send(_resp("password", 1))
break
elif cmd == "password":
conn.send(_resp("password", 0))
break
# CMD: fetch
# Read data from decrypted KeePass file
@ -348,7 +370,7 @@ def _keepass_socket(kdbx, kdbx_key, sock_path, ttl=60, kdbx_password=None):
)
)
break
conn.send(_resp("fetch", 0, getattr(entry, prop)))
conn.send(_resp("fetch", 0, entry.deref(prop)))
except CredentialsError:
print("%s failed to decrypt" % kdbx)
sys.exit(1)
@ -395,6 +417,9 @@ def _resp(cmd, status_code, payload=""):
def _keepass_socket_path(dbx_path):
# UNIX socket path for a dbx (supported multiple dbx)
if "ANSIBLE_KEEPASS_SOCKET" in os.environ:
return os.environ.get('ANSIBLE_KEEPASS_SOCKET')
# else:
tempdir = tempfile.gettempdir()
if not os.access(tempdir, os.W_OK):
raise AnsibleError("KeePass: no write permissions to '%s'" % tempdir)
@ -403,6 +428,20 @@ def _keepass_socket_path(dbx_path):
return "%s/ansible-keepass-%s.sock" % (tempdir, suffix[:8])
def lock(kdbx_sock_path):
fd = os.open(kdbx_sock_path + ".lock", os.O_RDWR | os.O_CREAT | os.O_TRUNC)
try:
# The LOCK_EX means that only one process can hold the lock
# The LOCK_NB means that the fcntl.flock() is not blocking
# https://docs.python.org/3/library/fcntl.html#fcntl.flock
fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
except (IOError, OSError):
return None
return fd
if __name__ == "__main__":
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument("kdbx", type=str)
@ -412,24 +451,29 @@ if __name__ == "__main__":
arg_parser.add_argument("--ask-pass", action="store_true")
args = arg_parser.parse_args()
kdbx = os.path.realpath(os.path.expanduser(os.path.expandvars(args.kdbx)))
arg_kdbx = os.path.realpath(os.path.expanduser(os.path.expandvars(args.kdbx)))
if args.key:
key = os.path.realpath(os.path.expanduser(os.path.expandvars(args.key)))
arg_key = os.path.realpath(os.path.expanduser(os.path.expandvars(args.key)))
else:
key = None
arg_key = None
if args.kdbx_sock:
kdbx_sock = args.kdbx_sock
arg_kdbx_sock = args.kdbx_sock
else:
kdbx_sock = _keepass_socket_path(kdbx)
arg_kdbx_sock = _keepass_socket_path(arg_kdbx)
password = None
if args.ask_pass:
password = getpass.getpass("Password: ")
if isinstance(password, bytes):
password = password.decode(sys.stdin.encoding)
elif "ANSIBLE_KEEPASS_PSW" in os.environ:
password = os.environ.get('ANSIBLE_KEEPASS_PSW')
lock_file = kdbx_sock + ".lock"
if not os.path.isfile(lock_file):
open(lock_file, "a").close()
_keepass_socket(kdbx, key, kdbx_sock, args.ttl, password)
arg_ttl = args.ttl
if arg_ttl is None and "ANSIBLE_KEEPASS_TTL" in os.environ:
arg_ttl = os.environ.get('ANSIBLE_KEEPASS_TTL')
os.umask(0o177)
if lock(arg_kdbx_sock):
_keepass_socket(arg_kdbx, arg_key, arg_kdbx_sock, arg_ttl, password)

View File

@ -0,0 +1,204 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2022, Jimisola Laursen <jimisola@jimisola.com>
# Copyright: (c) 2022, LFV <www.lfv.se>
__metaclass__ = type
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.basic import missing_required_lib
from ansible.module_utils._text import to_bytes, to_native
import os
import tempfile
LIB_IMP_ERR = None
try:
from pykeepass import PyKeePass
HAS_LIB = True
except Exception:
HAS_LIB = False
LIB_IMP_ERR = traceback.format_exc()
DOCUMENTATION = r"""
---
module: attachment
author:
- Jimisola Laursen (@lfvjimisola)
- Jimisola Laursen (@jimisola)
short_description: Exports KeePass attachments
description:
- This module will export an attachment in a KeePass entry to a file.
version_added: "0.1.0"
extends_documentation_fragment:
- files
- action_common_attributes
requirements:
- pykeepass
options:
database:
description: Path to KeePass database file
required: true
type: str
password:
description: Password for KeePass database file
required: true
type: str
entrypath:
description: Path to KeePass entry containing the attachment that should be exported
required: true
type: str
attachment:
description: Name of attachment that should be exported
required: true
type: str
dest:
description: Absolute path where the file should be exported to
required: true
type: str
attributes:
check_mode:
support: none
diff_mode:
support: none
platform:
platforms: posix
"""
EXAMPLES = r"""
# Export a file
- name: Export a file from KeePass
keepass:
database: database.kdbx
password: somepassword
path: "group/subgroup/entry"
attachment: somefile.txt
dest: somefile_exported.txt
"""
RETURN = r""" # """
def check_file_attrs(module, result, diff):
changed, msg = result["changed"], result["msg"]
file_args = module.load_file_common_arguments(module.params)
if module.set_fs_attributes_if_different(file_args, False, diff=diff):
if changed:
msg += " and "
changed = True
msg += "ownership, perms or SE linux context changed"
result["changed"] = changed
result["msg"] = msg
return result
def export_attachment(module, result):
try:
# load database
kp = PyKeePass(
module.params["database"],
password=module.params["password"],
keyfile=module.params["keyfile"])
entrypath = module.params["entrypath"]
dest = module.params["dest"]
attachment = module.params["attachment"]
# find entry
kp_entry = kp.find_entries(path=entrypath.split("/"), first=True)
if kp_entry is None:
module.fail_json(msg="Entry '{0}' not found".format(entrypath))
kp_attachment = None
for item in kp_entry.attachments:
if item.filename == attachment:
kp_attachment = item
if kp_attachment is None:
module.fail_json(
msg="Entry '{0}' does not contain attachment '{1}'".format(
entrypath, attachment
)
)
b_data = kp_attachment.binary
tmpfd, tmpfile = tempfile.mkstemp()
f = os.fdopen(tmpfd, "wb")
f.write(b_data)
f.close()
module.atomic_move(
tmpfile,
to_native(
os.path.realpath(to_bytes(dest, errors="surrogate_or_strict")),
errors="surrogate_or_strict",
),
unsafe_writes=module.params["unsafe_writes"],
)
result["changed"] = True
result["msg"] = "attachment '{0}' exported to file '{1}'".format(
module.params["attachment"], dest
)
except Exception as e:
result["msg"] = "Module viczem.keepass.attachment failed: {0}".format(e)
module.fail_json(**result)
attr_diff = None
result = check_file_attrs(module, result, attr_diff)
module.exit_json(**result, diff=attr_diff)
def main():
module_args = dict(
database=dict(type="str", required=True),
password=dict(type="str", no_log=True, required=True),
keyfile=dict(type="str", no_log=True, required=False),
entrypath=dict(type="str", required=True),
attachment=dict(type="str", required=True),
dest=dict(type="path", required=True),
)
module = AnsibleModule(
argument_spec=module_args,
add_file_common_args=True,
)
if not HAS_LIB:
module.fail_json(msg=missing_required_lib("pykeepass"), exception=LIB_IMP_ERR)
result = dict(
changed=False,
)
dest = module.params["dest"]
b_dest = to_bytes(dest, errors="surrogate_or_strict")
if os.path.isdir(b_dest):
module.fail_json(rc=256, msg="Destination {0} is a directory!".format(dest))
export_attachment(module, result)
if __name__ == "__main__":
main()

Binary file not shown.

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<KeyFile>
<Meta>
<Version>2.0</Version>
</Meta>
<Key>
<Data Hash="95ED5C71">
8810353D 83453EDC 2266A931 A0A073F9
54B90B68 1E341EF4 6B47729B F42DBE0A
</Data>
</Key>
</KeyFile>

View File

@ -0,0 +1,2 @@
[test]
127.0.0.1 keepass_dbx=./ansible.kdbx keepass_key=./ansible.keyx keepass_ttl=3

View File

@ -0,0 +1,11 @@
---
- name: test-keepass-keyfile-only
hosts: test
connection: local
vars:
test_username: "{{ lookup('viczem.keepass.keepass', 'test', 'username') }}"
test_password: "{{ lookup('viczem.keepass.keepass', 'test', 'password') }}"
tasks:
- debug:
msg: "fetch entry: '/test'; username: '{{ test_username }}'; password: '{{ test_password }}'"

View File

@ -0,0 +1,2 @@
#!/bin/sh
ansible-playbook -i hosts.ini -vvvv playbook.yml

Binary file not shown.

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<KeyFile>
<Meta>
<Version>2.0</Version>
</Meta>
<Key>
<Data Hash="E13D7CBE">
D7A7EA4F D6DCBFD7 B2DFE21C E89FFBB0
B203AAA5 4A32C405 D6C1B3CA B69C40BF
</Data>
</Key>
</KeyFile>

View File

@ -0,0 +1,2 @@
[test]
127.0.0.1 keepass_dbx=./ansible.kdbx keepass_psw=spamham keepass_key=./ansible.keyx keepass_ttl=3

View File

@ -0,0 +1,11 @@
---
- name: test-keepass-keyfile-only
hosts: test
connection: local
vars:
test_username: "{{ lookup('viczem.keepass.keepass', 'test', 'username') }}"
test_password: "{{ lookup('viczem.keepass.keepass', 'test', 'password') }}"
tasks:
- debug:
msg: "fetch entry: '/test'; username: '{{ test_username }}'; password: '{{ test_password }}'"

View File

@ -0,0 +1,2 @@
#!/bin/sh
ansible-playbook -i hosts.ini -vvvv playbook.yml

Binary file not shown.

View File

@ -0,0 +1,2 @@
[test]
127.0.0.1 keepass_dbx=./ansible.kdbx keepass_psw=spamham keepass_ttl=3

View File

@ -0,0 +1,11 @@
---
- name: test-keepass-keyfile-only
hosts: test
connection: local
vars:
test_username: "{{ lookup('viczem.keepass.keepass', 'test', 'username') }}"
test_password: "{{ lookup('viczem.keepass.keepass', 'test', 'password') }}"
tasks:
- debug:
msg: "fetch entry: '/test'; username: '{{ test_username }}'; password: '{{ test_password }}'"

View File

@ -0,0 +1,2 @@
#!/bin/sh
ansible-playbook -i hosts.ini -vvvv playbook.yml

View File

@ -0,0 +1,3 @@
[defaults]
host_key_checking = False
inventory = ./inventory.ini

BIN
tests/parallel/ansible.kdbx Normal file

Binary file not shown.

11
tests/parallel/clear.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/sh
ssh-keygen -R 172.24.2.1
ssh-keygen -R 172.24.2.2
ssh-keygen -R 172.24.2.3
ssh-keygen -R 172.24.2.4
ssh-keygen -R 172.24.2.5
cd ./docker || exit
docker-compose down
docker rmi ansible-keepass-test-1 ansible-keepass-test-2 ansible-keepass-test-3 ansible-keepass-test-4 ansible-keepass-test-5

View File

@ -0,0 +1,7 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACCW034btEPrMzPe4xNKw02O70DhQr+EOnwz0vqNNqUgtAAAAJjHR3u1x0d7
tQAAAAtzc2gtZWQyNTUxOQAAACCW034btEPrMzPe4xNKw02O70DhQr+EOnwz0vqNNqUgtA
AAAEBnKHslpVj1lBKjreOmPTIhd5mPgl3jaCHlEleLVmSfd5bTfhu0Q+szM97jE0rDTY7v
QOFCv4Q6fDPS+o02pSC0AAAAE2V4YW1wbGVAZXhhbXBsZS5jb20BAg==
-----END OPENSSH PRIVATE KEY-----

View File

@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJbTfhu0Q+szM97jE0rDTY7vQOFCv4Q6fDPS+o02pSC0 example@example.com

View File

@ -0,0 +1,25 @@
FROM alpine:3.16
ARG USERNAME
ARG PASSWORD
RUN apk add --update --no-cache sudo openssh python3 \
&& cd /etc/ssh && ssh-keygen -A \
&& echo "PubkeyAuthentication yes" >> /etc/ssh/sshd_config \
&& echo "PermitRootLogin no" >> /etc/ssh/sshd_config \
&& echo "PasswordAuthentication no" >> /etc/ssh/sshd_config \
&& echo '%wheel ALL=(ALL) ALL' > /etc/sudoers.d/wheel
RUN adduser -D $USERNAME -G wheel \
&& echo $USERNAME:$PASSWORD | chpasswd \
&& mkdir -p /home/$USERNAME/.ssh \
&& chmod go-w /home/$USERNAME \
&& chmod 700 /home/$USERNAME/.ssh \
&& chown $USERNAME -R /home/$USERNAME/.ssh
COPY --chmod=600 --chown=$USERNAME .ssh/id_ed25519.pub /home/$USERNAME/.ssh/authorized_keys
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]

View File

@ -0,0 +1,13 @@
## UP test servers
```sh
DOCKER_BUILDKIT=1 docker-compose build
docker-compose up -d
```
## DOWN test servers
```sh
docker-compose down
docker rmi ansible-keepass-test-1 ansible-keepass-test-2 ansible-keepass-test-3 ansible-keepass-test-4 ansible-keepass-test-5
```

View File

@ -0,0 +1,65 @@
version: "3"
services:
ansible-keepass-test-1:
build:
context: .
args:
USERNAME: user1
PASSWORD: password1
image: "ansible-keepass-test-1:latest"
networks:
ansible-net:
ipv4_address: 172.24.2.1
ansible-keepass-test-2:
build:
context: .
args:
USERNAME: user2
PASSWORD: password2
image: "ansible-keepass-test-2:latest"
networks:
ansible-net:
ipv4_address: 172.24.2.2
ansible-keepass-test-3:
build:
context: .
args:
USERNAME: user3
PASSWORD: password3
image: "ansible-keepass-test-3:latest"
networks:
ansible-net:
ipv4_address: 172.24.2.3
ansible-keepass-test-4:
build:
context: .
args:
USERNAME: user4
PASSWORD: password4
image: "ansible-keepass-test-4:latest"
networks:
ansible-net:
ipv4_address: 172.24.2.4
ansible-keepass-test-5:
build:
context: .
args:
USERNAME: user5
PASSWORD: password5
image: "ansible-keepass-test-5:latest"
networks:
ansible-net:
ipv4_address: 172.24.2.5
networks:
ansible-net:
driver: bridge
ipam:
driver: default
config:
- subnet: "172.24.2.0/16"

View File

@ -0,0 +1,2 @@
ansible_user : "{{ lookup('viczem.keepass.keepass', 'srv-1', 'username') }}"
ansible_become_pass : "{{ lookup('viczem.keepass.keepass', 'srv-1', 'password') }}"

View File

@ -0,0 +1,3 @@
ansible_host : 172.24.2.2
ansible_user : "{{ lookup('viczem.keepass.keepass', 'srv-2', 'username') }}"
ansible_become_pass : "{{ lookup('viczem.keepass.keepass', 'srv-2', 'password') }}"

View File

@ -0,0 +1,3 @@
ansible_host : 172.24.2.3
ansible_user : "{{ lookup('viczem.keepass.keepass', 'srv-3', 'username') }}"
ansible_become_pass : "{{ lookup('viczem.keepass.keepass', 'srv-3', 'password') }}"

View File

@ -0,0 +1,3 @@
ansible_host : 172.24.2.4
ansible_user : "{{ lookup('viczem.keepass.keepass', 'srv-4', 'username') }}"
ansible_become_pass : "{{ lookup('viczem.keepass.keepass', 'srv-4', 'password') }}"

View File

@ -0,0 +1,3 @@
ansible_host : 172.24.2.5
ansible_user : "{{ lookup('viczem.keepass.keepass', 'srv-5', 'username') }}"
ansible_become_pass : "{{ lookup('viczem.keepass.keepass', 'srv-5', 'password') }}"

View File

@ -0,0 +1,5 @@
keepass_dbx: ./ansible.kdbx
keepass_psw: spamham
keepass_ttl: 3
ansible_ssh_private_key_file: ./docker/.ssh/id_ed25519

View File

@ -0,0 +1,14 @@
[SRV1]
srv-1 ansible_host=172.24.2.1
[SRV2]
srv-2 ansible_host=172.24.2.2
[SRV3]
srv-3 ansible_host=172.24.2.3
[SRV4]
srv-4 ansible_host=172.24.2.4
[SRV5]
srv-5 ansible_host=172.24.2.5

View File

@ -0,0 +1,12 @@
---
- name: Parallel
hosts: all
tasks:
- ansible.builtin.ping:
- name: pause to emulate long time operation (greater than keepass_ttl)
pause:
seconds: 5
- ansible.builtin.ping:

3
tests/parallel/run.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
# ansible all -m ping
ansible-playbook playbook.yml -f5