mirror of
https://github.com/ansible-collections/community.crypto.git
synced 2026-05-07 13:53:06 +00:00
Add gpg_fingerprint lookup and filter (#639)
* Add gpg_fingerprint lookup. * Work around problems on some CI targets. * Use get_bin_path to find the gpg executable. Document that we need it. * Improve and test error handling. * Refactor (potentially) common code to module_utils and plugin_utils. This will be useful to create a filter version of this, and further lookups, filters, and modules. * Do not create a keyring when there isn't one. * Fixups. * Fix description. * More fixes for lookup. * Also add a gpg_fingerprint filter. * Improve formulation. Co-authored-by: Sandra McCann <samccann@redhat.com> --------- Co-authored-by: Sandra McCann <samccann@redhat.com>
This commit is contained in:
6
tests/integration/targets/filter_gpg_fingerprint/aliases
Normal file
6
tests/integration/targets/filter_gpg_fingerprint/aliases
Normal file
@@ -0,0 +1,6 @@
|
||||
# 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
|
||||
|
||||
azp/posix/2
|
||||
destructive
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
# 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
|
||||
|
||||
dependencies:
|
||||
- prepare_jinja2_compat
|
||||
- setup_remote_tmp_dir
|
||||
- setup_gnupg
|
||||
@@ -0,0 +1,80 @@
|
||||
---
|
||||
# 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: Run tests if GPG is available
|
||||
when: has_gnupg
|
||||
block:
|
||||
- name: Create GPG key
|
||||
ansible.builtin.command:
|
||||
cmd: gpg --homedir "{{ remote_tmp_dir }}" --batch --generate-key
|
||||
stdin: |
|
||||
%echo Generating a basic OpenPGP key
|
||||
%no-ask-passphrase
|
||||
%no-protection
|
||||
Key-Type: RSA
|
||||
Key-Length: 4096
|
||||
Name-Real: Foo Bar
|
||||
Name-Email: foo@bar.com
|
||||
Expire-Date: 0
|
||||
%commit
|
||||
%echo done
|
||||
register: result
|
||||
|
||||
- name: Extract fingerprint
|
||||
ansible.builtin.shell: gpg --homedir "{{ remote_tmp_dir }}" --with-colons --fingerprint foo@bar.com | grep '^fpr:'
|
||||
register: fingerprints
|
||||
|
||||
- name: Show fingerprints
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ fingerprints.stdout_lines | map('split', ':') | list }}"
|
||||
|
||||
- name: Export public key
|
||||
ansible.builtin.command: gpg --homedir "{{ remote_tmp_dir }}" --export --armor foo@bar.com
|
||||
register: public_key
|
||||
|
||||
- name: Export private key
|
||||
ansible.builtin.command: gpg --homedir "{{ remote_tmp_dir }}" --export-secret-key --armor foo@bar.com
|
||||
register: private_key
|
||||
|
||||
- name: Gather fingerprints
|
||||
ansible.builtin.set_fact:
|
||||
public_key_fingerprint: "{{ public_key.stdout | community.crypto.gpg_fingerprint }}"
|
||||
private_key_fingerprint: "{{ private_key.stdout | community.crypto.gpg_fingerprint }}"
|
||||
|
||||
- name: Check whether fingerprints match
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- public_key_fingerprint == (fingerprints.stdout_lines[0] | split(':'))[9]
|
||||
- private_key_fingerprint == (fingerprints.stdout_lines[0] | split(':'))[9]
|
||||
|
||||
- name: Error scenario - wrong input type
|
||||
ansible.builtin.set_fact:
|
||||
failing_result: "{{ 42 | community.crypto.gpg_fingerprint }}"
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: Check result
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- result is failed
|
||||
- >-
|
||||
'The input for the community.crypto.gpg_fingerprint filter must be a string; got ' in result.msg
|
||||
- >-
|
||||
'int' in result.msg
|
||||
|
||||
- name: Error scenario - garbage input
|
||||
ansible.builtin.set_fact:
|
||||
failing_result: "{{ 'garbage' | community.crypto.gpg_fingerprint }}"
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: Check result
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- result is failed
|
||||
- >-
|
||||
'Running ' in result.msg
|
||||
- >-
|
||||
('/gpg --no-keyring --with-colons --import-options show-only --import /dev/stdin yielded return code ') in result.msg
|
||||
6
tests/integration/targets/lookup_gpg_fingerprint/aliases
Normal file
6
tests/integration/targets/lookup_gpg_fingerprint/aliases
Normal file
@@ -0,0 +1,6 @@
|
||||
# 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
|
||||
|
||||
azp/posix/2
|
||||
destructive
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
# 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
|
||||
|
||||
dependencies:
|
||||
- prepare_jinja2_compat
|
||||
- setup_remote_tmp_dir
|
||||
- setup_gnupg
|
||||
@@ -0,0 +1,93 @@
|
||||
---
|
||||
# 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: Run tests if GPG is available
|
||||
when: has_gnupg
|
||||
block:
|
||||
- name: Create GPG key
|
||||
ansible.builtin.command:
|
||||
cmd: gpg --homedir "{{ remote_tmp_dir }}" --batch --generate-key
|
||||
stdin: |
|
||||
%echo Generating a basic OpenPGP key
|
||||
%no-ask-passphrase
|
||||
%no-protection
|
||||
Key-Type: RSA
|
||||
Key-Length: 4096
|
||||
Name-Real: Foo Bar
|
||||
Name-Email: foo@bar.com
|
||||
Expire-Date: 0
|
||||
%commit
|
||||
%echo done
|
||||
register: result
|
||||
|
||||
- name: Extract fingerprint
|
||||
ansible.builtin.shell: gpg --homedir "{{ remote_tmp_dir }}" --with-colons --fingerprint foo@bar.com | grep '^fpr:'
|
||||
register: fingerprints
|
||||
|
||||
- name: Show fingerprints
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ fingerprints.stdout_lines | map('split', ':') | list }}"
|
||||
|
||||
- name: Export public key
|
||||
ansible.builtin.command: gpg --homedir "{{ remote_tmp_dir }}" --export --armor foo@bar.com
|
||||
register: public_key
|
||||
|
||||
- name: Export private key
|
||||
ansible.builtin.command: gpg --homedir "{{ remote_tmp_dir }}" --export-secret-key --armor foo@bar.com
|
||||
register: private_key
|
||||
|
||||
- name: Write public key to disk
|
||||
ansible.builtin.copy:
|
||||
dest: "{{ remote_tmp_dir }}/public-key"
|
||||
content: "{{ public_key.stdout }}"
|
||||
|
||||
- name: Write private key to disk
|
||||
ansible.builtin.copy:
|
||||
dest: "{{ remote_tmp_dir }}/private-key"
|
||||
content: "{{ private_key.stdout }}"
|
||||
|
||||
- name: Gather fingerprints
|
||||
ansible.builtin.set_fact:
|
||||
public_key_fingerprint: "{{ lookup('community.crypto.gpg_fingerprint', remote_tmp_dir ~ '/public-key') }}"
|
||||
private_key_fingerprint: "{{ lookup('community.crypto.gpg_fingerprint', remote_tmp_dir ~ '/private-key') }}"
|
||||
|
||||
- name: Check whether fingerprints match
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- public_key_fingerprint == (fingerprints.stdout_lines[0] | split(':'))[9]
|
||||
- private_key_fingerprint == (fingerprints.stdout_lines[0] | split(':'))[9]
|
||||
|
||||
- name: Error scenario - file does not exist
|
||||
ansible.builtin.set_fact:
|
||||
failing_result: "{{ lookup('community.crypto.gpg_fingerprint', remote_tmp_dir ~ '/does-not-exist') }}"
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: Check result
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- result is failed
|
||||
- >-
|
||||
(remote_tmp_dir ~ '/does-not-exist does not exist') in result.msg
|
||||
|
||||
- name: Write garbage to disk
|
||||
ansible.builtin.copy:
|
||||
dest: "{{ remote_tmp_dir }}/garbage"
|
||||
content: gargabe
|
||||
|
||||
- name: Error scenario - file contains garbage
|
||||
ansible.builtin.set_fact:
|
||||
failing_result: "{{ lookup('community.crypto.gpg_fingerprint', remote_tmp_dir ~ '/garbage') }}"
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: Check result
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- result is failed
|
||||
- >-
|
||||
'Running ' in result.msg
|
||||
- >-
|
||||
('/gpg --no-keyring --with-colons --import-options show-only --import ' ~ remote_tmp_dir ~ '/garbage yielded return code ') in result.msg
|
||||
@@ -0,0 +1,20 @@
|
||||
# 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
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
# Added in ansible-core 2.11
|
||||
def compatibility_split_filter(text, by_what):
|
||||
return text.split(by_what)
|
||||
|
||||
|
||||
class FilterModule:
|
||||
''' Jinja2 compat filters '''
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'split': compatibility_split_filter,
|
||||
}
|
||||
7
tests/integration/targets/setup_gnupg/meta/main.yml
Normal file
7
tests/integration/targets/setup_gnupg/meta/main.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
# 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
|
||||
|
||||
dependencies:
|
||||
- setup_pkg_mgr
|
||||
30
tests/integration/targets/setup_gnupg/tasks/main.yml
Normal file
30
tests/integration/targets/setup_gnupg/tasks/main.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
# 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: Print distribution specific data
|
||||
ansible.builtin.debug:
|
||||
msg: |
|
||||
Distribution: {{ ansible_facts.distribution }}
|
||||
Distribution version: {{ ansible_facts.distribution_version }}
|
||||
Distribution major version: {{ ansible_facts.distribution_major_version }}
|
||||
OS family: {{ ansible_facts.os_family }}
|
||||
|
||||
- name: Include distribution specific variables
|
||||
ansible.builtin.include_vars: '{{ lookup("ansible.builtin.first_found", params) }}'
|
||||
vars:
|
||||
params:
|
||||
files:
|
||||
- '{{ ansible_facts.distribution }}-{{ ansible_facts.distribution_version }}.yml'
|
||||
- '{{ ansible_facts.distribution }}-{{ ansible_facts.distribution_major_version }}.yml'
|
||||
- '{{ ansible_facts.distribution }}.yml'
|
||||
- '{{ ansible_facts.os_family }}.yml'
|
||||
- default.yml
|
||||
paths:
|
||||
- '{{ role_path }}/vars'
|
||||
|
||||
- name: Install GnuPG
|
||||
ansible.builtin.package:
|
||||
name: '{{ gnupg_package_name }}'
|
||||
when: has_gnupg
|
||||
8
tests/integration/targets/setup_gnupg/vars/Alpine.yml
Normal file
8
tests/integration/targets/setup_gnupg/vars/Alpine.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
# 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
|
||||
|
||||
# Alpine 3.12 should have GnuPG, but for some reason installing it fails...
|
||||
has_gnupg: "{{ ansible_facts.distribution_version is version('3.13', '>=') }}"
|
||||
gnupg_package_name: gpg
|
||||
7
tests/integration/targets/setup_gnupg/vars/CentOS-6.yml
Normal file
7
tests/integration/targets/setup_gnupg/vars/CentOS-6.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
# 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
|
||||
|
||||
has_gnupg: false
|
||||
# The GnuPG version included with CentOS 6 is too old, it doesn't understand --generate-key
|
||||
7
tests/integration/targets/setup_gnupg/vars/Darwin.yml
Normal file
7
tests/integration/targets/setup_gnupg/vars/Darwin.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
# 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
|
||||
|
||||
# TODO Homebrew currently isn't happy when running as root, so assume we don't have GnuPG
|
||||
has_gnupg: false
|
||||
7
tests/integration/targets/setup_gnupg/vars/RedHat.yml
Normal file
7
tests/integration/targets/setup_gnupg/vars/RedHat.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
# 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
|
||||
|
||||
has_gnupg: true
|
||||
gnupg_package_name: gnupg2
|
||||
7
tests/integration/targets/setup_gnupg/vars/default.yml
Normal file
7
tests/integration/targets/setup_gnupg/vars/default.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
# 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
|
||||
|
||||
has_gnupg: true
|
||||
gnupg_package_name: gnupg
|
||||
@@ -1,4 +1,5 @@
|
||||
.azure-pipelines/scripts/publish-codecov.py replace-urlopen
|
||||
plugins/lookup/gpg_fingerprint.py validate-modules:invalid-documentation
|
||||
plugins/modules/openssl_csr_info.py validate-modules:invalid-documentation
|
||||
plugins/modules/openssl_privatekey_info.py validate-modules:invalid-documentation
|
||||
plugins/modules/openssl_publickey_info.py validate-modules:invalid-documentation
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
.azure-pipelines/scripts/publish-codecov.py replace-urlopen
|
||||
plugins/lookup/gpg_fingerprint.py validate-modules:invalid-documentation
|
||||
plugins/modules/openssl_csr_info.py validate-modules:invalid-documentation
|
||||
plugins/modules/openssl_privatekey_info.py validate-modules:invalid-documentation
|
||||
plugins/modules/openssl_publickey_info.py validate-modules:invalid-documentation
|
||||
|
||||
Reference in New Issue
Block a user