Skip to content

Commit

Permalink
Add gpg_fingerprint lookup.
Browse files Browse the repository at this point in the history
  • Loading branch information
felixfontein committed Jul 15, 2023
1 parent 54b2163 commit f056b71
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 0 deletions.
72 changes: 72 additions & 0 deletions plugins/lookup/gpg_fingerprint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2023, Felix Fontein <[email protected]>
# 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 = """
name: gpg_fingerprint
short_description: Retrieve a GPG fingerprint from a GPG public or private key file
author: Felix Fontein (@felixfontein)
version_added: 2.15.0
description:
- "Takes the input lists and returns a list with elements that are lists, dictionaries,
or template expressions which evaluate to lists or dicts, composed of the elements of
the input evaluated lists and dictionaries."
options:
_terms:
description:
- A path to a GPG public or private key.
type: path
required: true
"""

EXAMPLES = """
- name: Show fingerprint of GPG public key
ansible.builtin.debug:
msg: "{{ lookup('community.crypto.gpg_fingerprint', '/path/to/public_key.gpg') }}"
"""

RETURN = """
_value:
description:
- The fingerprint of the provided public or private GPG key.
- The list as entry for every path provided.
type: list
elements: string
"""

from subprocess import Popen, PIPE

from ansible.plugins.lookup import LookupBase
from ansible.errors import AnsibleLookupError
from ansible.module_utils.common.text.converters import to_native


class LookupModule(LookupBase):
def get_fingerprint(self, path):
command = ['gpg', '--with-colons', '--import-options', 'show-only', '--import', path]
p = Popen(command, shell=False, cwd=self._loader.get_basedir(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
stdout, stderr = p.communicate()
if p.returncode != 0:
raise AnsibleLookupError('Running {cmd} yielded return code {rc} with stdout: "{stdout}" and stderr: "{stderr}")'.format(
cmd=command,
rc=p.returncode,
stdout=stdout,
stderr=stderr,
))
lines = to_native(stdout).splitlines(False)
for line in lines:
if line.startswith('fpr:'):
return line.split(':')[9]
raise AnsibleLookupError('Cannot extract fingerprint for {path} from stdout "{stdout}"'.format(path=path, stdout=stdout))

def run(self, terms, variables=None, **kwargs):
self.set_options(direct=kwargs)

result = []
for path in terms:
result.append(self.get_fingerprint(path))
return result
6 changes: 6 additions & 0 deletions tests/integration/targets/lookup_gpg_fingerprint/aliases
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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

dependencies:
- setup_remote_tmp_dir
- setup_gnupg
57 changes: 57 additions & 0 deletions tests/integration/targets/lookup_gpg_fingerprint/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
# 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: 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: [email protected]
Expire-Date: 0
%commit
%echo done
register: result

- name: Extract fingerprint
ansible.builtin.shell: gpg --homedir "{{ remote_tmp_dir }}" --with-colons --fingerprint [email protected] | grep '^fpr:'
register: fingerprints

- name: Show fingerprints
ansible.builtin.debug:
msg: "{{ fingerprints.stdout_lines | map('split', ':') }}"

- name: Export public key
ansible.builtin.command: gpg --homedir "{{ remote_tmp_dir }}" --export --armor [email protected]
register: public_key

- name: Export private key
ansible.builtin.command: gpg --homedir "{{ remote_tmp_dir }}" --export-secret-key --armor [email protected]
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]
7 changes: 7 additions & 0 deletions tests/integration/targets/setup_gnupg/meta/main.yml
Original file line number Diff line number Diff line change
@@ -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
18 changes: 18 additions & 0 deletions tests/integration/targets/setup_gnupg/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
# 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: Include distribution specific variables
ansible.builtin.include_vars: '{{ lookup("ansible.builtin.first_found", params) }}'
vars:
params:
files:
- '{{ ansible_facts.os_family }}.yml'
- default.yml
paths:
- '{{ role_path }}/vars'

- name: Install GnuPG
ansible.builtin.package:
name: '{{ gnupg_package_name }}'
6 changes: 6 additions & 0 deletions tests/integration/targets/setup_gnupg/vars/Alpine.yml
Original file line number Diff line number Diff line change
@@ -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

gnupg_package_name: gpg
6 changes: 6 additions & 0 deletions tests/integration/targets/setup_gnupg/vars/RedHat.yml
Original file line number Diff line number Diff line change
@@ -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

gnupg_package_name: gnupg2
6 changes: 6 additions & 0 deletions tests/integration/targets/setup_gnupg/vars/default.yml
Original file line number Diff line number Diff line change
@@ -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

gnupg_package_name: gnupg

0 comments on commit f056b71

Please sign in to comment.