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:
Felix Fontein
2023-08-02 11:16:34 +02:00
committed by GitHub
parent 5e630ffe78
commit ba456c5eaf
20 changed files with 545 additions and 0 deletions

View 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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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,
}

View 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

View 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

View 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

View 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

View 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

View 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

View 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