-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add support for systemd creds encrypt/decrypt (#9383)
* add support for systemd creds encrypt/decrypt Signed-off-by: Thomas Sjögren <[email protected]> * add __metaclass__ Signed-off-by: Thomas Sjögren <[email protected]> * Python 2.7 issues Signed-off-by: Thomas Sjögren <[email protected]> * update version_added and ci test aliases Signed-off-by: Thomas Sjögren <[email protected]> * switch to container Signed-off-by: Thomas Sjögren <[email protected]> * run tests in docker as well Signed-off-by: Thomas Sjögren <[email protected]> * move tasks into tasks/ Signed-off-by: Thomas Sjögren <[email protected]> * no need to call echo Signed-off-by: Thomas Sjögren <[email protected]> * lint and add become: Signed-off-by: Thomas Sjögren <[email protected]> * dont append a newline Signed-off-by: Thomas Sjögren <[email protected]> * don't clean newlines Signed-off-by: Thomas Sjögren <[email protected]> * only use module name Signed-off-by: Thomas Sjögren <[email protected]> * clean Signed-off-by: Thomas Sjögren <[email protected]> * change msg to value Signed-off-by: Thomas Sjögren <[email protected]> * add return values Signed-off-by: Thomas Sjögren <[email protected]> * update attributes and description Signed-off-by: Thomas Sjögren <[email protected]> * Update plugins/modules/systemd_creds_decrypt.py Co-authored-by: Felix Fontein <[email protected]> * set newline default Signed-off-by: Thomas Sjögren <[email protected]> * Update plugins/modules/systemd_creds_encrypt.py Co-authored-by: Alexei Znamensky <[email protected]> * Update plugins/modules/systemd_creds_encrypt.py Co-authored-by: Alexei Znamensky <[email protected]> * Update plugins/modules/systemd_creds_encrypt.py Co-authored-by: Alexei Znamensky <[email protected]> * update required and spelling Signed-off-by: Thomas Sjögren <[email protected]> * use single backslash Signed-off-by: Thomas Sjögren <[email protected]> --------- Signed-off-by: Thomas Sjögren <[email protected]> Co-authored-by: Felix Fontein <[email protected]> Co-authored-by: Alexei Znamensky <[email protected]> (cherry picked from commit 482a90e)
- Loading branch information
1 parent
98a956a
commit 1cc4431
Showing
7 changed files
with
445 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
#!/usr/bin/python | ||
# -*- coding: utf-8 -*- | ||
|
||
# Copyright (c) 2024, Ansible Project | ||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
# SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
from __future__ import absolute_import, division, print_function | ||
|
||
__metaclass__ = type | ||
|
||
DOCUMENTATION = r""" | ||
module: systemd_creds_decrypt | ||
short_description: C(systemd)'s C(systemd-creds decrypt) plugin | ||
description: | ||
- This module decrypts input using C(systemd)'s C(systemd-creds decrypt). | ||
author: | ||
- Thomas Sjögren (@konstruktoid) | ||
version_added: '10.2.0' | ||
extends_documentation_fragment: | ||
- community.general.attributes | ||
attributes: | ||
check_mode: | ||
support: full | ||
details: | ||
- This action does not modify state. | ||
diff_mode: | ||
support: N/A | ||
details: | ||
- This action does not modify state. | ||
options: | ||
name: | ||
description: | ||
- The credential name to validate the embedded credential name. | ||
type: str | ||
required: false | ||
newline: | ||
description: | ||
- Whether to add a trailing newline character to the end of the output, | ||
if not present. | ||
type: bool | ||
required: false | ||
default: false | ||
secret: | ||
description: | ||
- The secret to decrypt. | ||
type: str | ||
required: true | ||
timestamp: | ||
description: | ||
- The timestamp to use to validate the V(not-after) timestamp that | ||
was used during encryption. | ||
- Takes a timestamp specification in the format described in | ||
V(systemd.time(7\)). | ||
type: str | ||
required: false | ||
transcode: | ||
description: | ||
- Whether to transcode the output before returning it. | ||
type: str | ||
choices: [ base64, unbase64, hex, unhex ] | ||
required: false | ||
user: | ||
description: | ||
- A user name or numeric UID when decrypting from a specific user context. | ||
- If set to the special string V(self) it sets the user to the user | ||
of the calling process. | ||
- Requires C(systemd) 256 or later. | ||
type: str | ||
required: false | ||
notes: | ||
- C(systemd-creds) requires C(systemd) 250 or later. | ||
""" | ||
|
||
EXAMPLES = """ | ||
- name: Decrypt secret | ||
community.general.systemd_creds_decrypt: | ||
name: db | ||
secret: "WhQZht+JQJax1aZemmGLxmAAAA..." | ||
register: decrypted_secret | ||
- name: Print the decrypted secret | ||
ansible.builtin.debug: | ||
msg: "{{ decrypted_secret }}" | ||
""" | ||
|
||
RETURN = r""" | ||
value: | ||
description: | ||
- The decrypted secret. | ||
- Note that Ansible only supports returning UTF-8 encoded strings. | ||
If the decrypted secret is binary data, or a string encoded in another | ||
way, use O(transcode=base64) or O(transcode=hex) to circument this | ||
restriction. You then need to decode the data when using it, for | ||
example using the P(ansible.builtin.b64decode#filter) filter. | ||
type: str | ||
returned: always | ||
sample: "access_token" | ||
""" | ||
|
||
|
||
from ansible.module_utils.basic import AnsibleModule | ||
|
||
|
||
def main(): | ||
"""Decrypt secret using systemd-creds.""" | ||
module = AnsibleModule( | ||
argument_spec=dict( | ||
name=dict(type="str", required=False), | ||
newline=dict(type="bool", required=False, default=False), | ||
secret=dict(type="str", required=True, no_log=True), | ||
timestamp=dict(type="str", required=False), | ||
transcode=dict( | ||
type="str", | ||
choices=["base64", "unbase64", "hex", "unhex"], | ||
required=False, | ||
), | ||
user=dict(type="str", required=False), | ||
), | ||
supports_check_mode=True, | ||
) | ||
|
||
cmd = module.get_bin_path("systemd-creds", required=True) | ||
|
||
name = module.params["name"] | ||
newline = module.params["newline"] | ||
secret = module.params["secret"] | ||
timestamp = module.params["timestamp"] | ||
transcode = module.params["transcode"] | ||
user = module.params["user"] | ||
|
||
decrypt_cmd = [cmd, "decrypt"] | ||
if name: | ||
decrypt_cmd.append("--name=" + name) | ||
else: | ||
decrypt_cmd.append("--name=") | ||
decrypt_cmd.append("--newline=" + ("yes" if newline else "no")) | ||
if timestamp: | ||
decrypt_cmd.append("--timestamp=" + timestamp) | ||
if transcode: | ||
decrypt_cmd.append("--transcode=" + transcode) | ||
if user: | ||
decrypt_cmd.append("--uid=" + user) | ||
decrypt_cmd.extend(["-", "-"]) | ||
|
||
rc, stdout, stderr = module.run_command(decrypt_cmd, data=secret, binary_data=True) | ||
|
||
module.exit_json( | ||
changed=False, | ||
value=stdout, | ||
rc=rc, | ||
stderr=stderr, | ||
) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
#!/usr/bin/python | ||
|
||
# Copyright (c) 2024, Ansible Project | ||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
# SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
from __future__ import absolute_import, division, print_function | ||
|
||
__metaclass__ = type | ||
|
||
|
||
DOCUMENTATION = r""" | ||
module: systemd_creds_encrypt | ||
short_description: C(systemd)'s C(systemd-creds encrypt) plugin | ||
description: | ||
- This module encrypts input using C(systemd)'s C(systemd-creds encrypt). | ||
author: | ||
- Thomas Sjögren (@konstruktoid) | ||
version_added: '10.2.0' | ||
extends_documentation_fragment: | ||
- community.general.attributes | ||
attributes: | ||
check_mode: | ||
support: full | ||
details: | ||
- This action does not modify state. | ||
diff_mode: | ||
support: N/A | ||
details: | ||
- This action does not modify state. | ||
options: | ||
name: | ||
description: | ||
- The credential name to embed in the encrypted credential data. | ||
type: str | ||
required: false | ||
not_after: | ||
description: | ||
- The time when the credential shall not be used anymore. | ||
- Takes a timestamp specification in the format described in | ||
V(systemd.time(7\)). | ||
type: str | ||
required: false | ||
pretty: | ||
description: | ||
- Pretty print the output so that it may be pasted directly into a | ||
unit file. | ||
type: bool | ||
required: false | ||
default: false | ||
secret: | ||
description: | ||
- The secret to encrypt. | ||
type: str | ||
required: true | ||
timestamp: | ||
description: | ||
- The timestamp to embed into the encrypted credential. | ||
- Takes a timestamp specification in the format described in | ||
V(systemd.time(7\)). | ||
type: str | ||
required: false | ||
user: | ||
description: | ||
- A user name or numeric UID to encrypt the credential for. | ||
- If set to the special string V(self) it sets the user to the user | ||
of the calling process. | ||
- Requires C(systemd) 256 or later. | ||
type: str | ||
required: false | ||
notes: | ||
- C(systemd-creds) requires C(systemd) 250 or later. | ||
""" | ||
|
||
EXAMPLES = """ | ||
- name: Encrypt secret | ||
become: true | ||
community.general.systemd_creds_encrypt: | ||
name: db | ||
not_after: +48hr | ||
secret: access_token | ||
register: encrypted_secret | ||
- name: Print the encrypted secret | ||
ansible.builtin.debug: | ||
msg: "{{ encrypted_secret }}" | ||
""" | ||
|
||
RETURN = r""" | ||
value: | ||
description: The Base64 encoded encrypted secret. | ||
type: str | ||
returned: always | ||
sample: "WhQZht+JQJax1aZemmGLxmAAAA..." | ||
""" | ||
|
||
from ansible.module_utils.basic import AnsibleModule | ||
|
||
|
||
def main(): | ||
"""Encrypt secret using systemd-creds.""" | ||
module = AnsibleModule( | ||
argument_spec=dict( | ||
name=dict(type="str", required=False), | ||
not_after=dict(type="str", required=False), | ||
pretty=dict(type="bool", default=False), | ||
secret=dict(type="str", required=True, no_log=True), | ||
timestamp=dict(type="str", required=False), | ||
user=dict(type="str", required=False), | ||
), | ||
supports_check_mode=True, | ||
) | ||
|
||
cmd = module.get_bin_path("systemd-creds", required=True) | ||
|
||
name = module.params["name"] | ||
not_after = module.params["not_after"] | ||
pretty = module.params["pretty"] | ||
secret = module.params["secret"] | ||
timestamp = module.params["timestamp"] | ||
user = module.params["user"] | ||
|
||
encrypt_cmd = [cmd, "encrypt"] | ||
if name: | ||
encrypt_cmd.append("--name=" + name) | ||
else: | ||
encrypt_cmd.append("--name=") | ||
if not_after: | ||
encrypt_cmd.append("--not-after=" + not_after) | ||
if pretty: | ||
encrypt_cmd.append("--pretty") | ||
if timestamp: | ||
encrypt_cmd.append("--timestamp=" + timestamp) | ||
if user: | ||
encrypt_cmd.append("--uid=" + user) | ||
encrypt_cmd.extend(["-", "-"]) | ||
|
||
rc, stdout, stderr = module.run_command(encrypt_cmd, data=secret, binary_data=True) | ||
|
||
module.exit_json( | ||
changed=False, | ||
value=stdout, | ||
rc=rc, | ||
stderr=stderr, | ||
) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Copyright (c) Ansible Project | ||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
# SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
needs/root | ||
|
||
azp/posix/1 | ||
skip/aix | ||
skip/freebsd | ||
skip/osx | ||
skip/macos |
58 changes: 58 additions & 0 deletions
58
tests/integration/targets/systemd_creds_decrypt/tasks/main.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
--- | ||
# Copyright (c) Ansible Project | ||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
# SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
- name: Test systemd_creds_decrypt | ||
when: | ||
- ansible_systemd.version is defined | ||
- ansible_systemd.version | int >= 250 | ||
block: | ||
- name: Encrypt secret | ||
become: true | ||
systemd_creds_encrypt: | ||
name: api | ||
not_after: +48hr | ||
secret: access_token | ||
register: encrypted_api_secret | ||
|
||
- name: Print the encrypted secret | ||
ansible.builtin.debug: | ||
msg: "{{ encrypted_api_secret }}" | ||
|
||
- name: Decrypt secret | ||
community.general.systemd_creds_decrypt: | ||
name: api | ||
newline: false | ||
secret: "{{ encrypted_api_secret.value }}" | ||
register: decrypted_secret | ||
|
||
- name: Print the decrypted secret | ||
ansible.builtin.debug: | ||
msg: "{{ decrypted_secret }}" | ||
|
||
- name: Assert that the decrypted secret is the same as the original secret | ||
ansible.builtin.assert: | ||
that: | ||
- decrypted_secret.value == 'access_token' | ||
fail_msg: "Decrypted secret is not the same as the original secret" | ||
success_msg: "Decrypted secret is the same as the original secret" | ||
|
||
- name: Decrypt secret into hex | ||
community.general.systemd_creds_decrypt: | ||
name: api | ||
newline: false | ||
secret: "{{ encrypted_api_secret.value }}" | ||
transcode: hex | ||
register: decrypted_secret_hex | ||
|
||
- name: Print the trancoded decrypted secret | ||
ansible.builtin.debug: | ||
msg: "{{ decrypted_secret_hex }}" | ||
|
||
- name: Assert that the decrypted secret is the same as the original secret | ||
ansible.builtin.assert: | ||
that: | ||
- decrypted_secret_hex.value == '6163636573735f746f6b656e' | ||
fail_msg: "Decrypted secret is not the same as the original secret" | ||
success_msg: "Decrypted secret is the same as the original secret" |
Oops, something went wrong.