Enable validation of subkeys in rpm key module (#83716)

* Enable validation of subkeys in rpm key module

A gpg subkey may change while the primary key remains the same. Due to
this behavior, there are situations where validation of the primary gpg
key fingerprint is not sufficient because the desired target is actually
the gpg subkey. This change allows the user to validate against either
the fingerprint of the primary gpg key or its subkey.

Signed-off-by: Kellin <kellin@retromud.org>

* Improve tests, add multi-fingerprint

- Improve tests to cover all cases
- add multi fingerprint validation

Signed-off-by: Kellin <kellin@retromud.org>
pull/82681/merge
Kellin 4 months ago committed by GitHub
parent 7b74de069c
commit 0d6b034103
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,4 @@
---
minor_changes:
- rpm_key - allow validation of gpg key with a subkey fingerprint
- rpm_key - enable gpg validation that requires presence of multiple fingerprints

@ -40,7 +40,8 @@ options:
description:
- The long-form fingerprint of the key being imported.
- This will be used to verify the specified key.
type: str
type: list
elements: str
version_added: 2.9
extends_documentation_fragment:
- action_common_attributes
@ -73,6 +74,13 @@ EXAMPLES = '''
ansible.builtin.rpm_key:
key: /path/to/RPM-GPG-KEY.dag.txt
fingerprint: EBC6 E12C 62B1 C734 026B 2122 A20E 5214 6B8D 79E6
- name: Verify the key, using multiple fingerprints, before import
ansible.builtin.rpm_key:
key: /path/to/RPM-GPG-KEY.dag.txt
fingerprint:
- EBC6 E12C 62B1 C734 026B 2122 A20E 5214 6B8D 79E6
- 19B7 913E 6284 8E3F 4D78 D6B4 ECD9 1AB2 2EB6 8D86
'''
RETURN = r'''#'''
@ -105,8 +113,12 @@ class RpmKey(object):
state = module.params['state']
key = module.params['key']
fingerprint = module.params['fingerprint']
fingerprints = set()
if fingerprint:
fingerprint = fingerprint.replace(' ', '').upper()
if not isinstance(fingerprint, list):
fingerprint = [fingerprint]
fingerprints = set(f.replace(' ', '').upper() for f in fingerprint)
self.gpg = self.module.get_bin_path('gpg')
if not self.gpg:
@ -131,11 +143,12 @@ class RpmKey(object):
else:
if not keyfile:
self.module.fail_json(msg="When importing a key, a valid file must be given")
if fingerprint:
has_fingerprint = self.getfingerprint(keyfile)
if fingerprint != has_fingerprint:
if fingerprints:
keyfile_fingerprints = self.getfingerprints(keyfile)
if not fingerprints.issubset(keyfile_fingerprints):
self.module.fail_json(
msg="The specified fingerprint, '%s', does not match the key fingerprint '%s'" % (fingerprint, has_fingerprint)
msg=("The specified fingerprint, '%s', "
"does not match any key fingerprints in '%s'") % (fingerprints, keyfile_fingerprints)
)
self.import_key(keyfile)
if should_cleanup_keyfile:
@ -183,11 +196,15 @@ class RpmKey(object):
self.module.fail_json(msg="Unexpected gpg output")
def getfingerprint(self, keyfile):
def getfingerprints(self, keyfile):
stdout, stderr = self.execute_command([
self.gpg, '--no-tty', '--batch', '--with-colons',
'--fixed-list-mode', '--with-fingerprint', keyfile
'--fixed-list-mode', '--import', '--import-options', 'show-only',
'--dry-run', keyfile
])
fingerprints = set()
for line in stdout.splitlines():
line = line.strip()
if line.startswith('fpr:'):
@ -199,7 +216,10 @@ class RpmKey(object):
#
# "fpr :: Fingerprint (fingerprint is in field 10)"
#
return line.split(':')[9]
fingerprints.add(line.split(':')[9])
if fingerprints:
return fingerprints
self.module.fail_json(msg="Unexpected gpg output")
@ -239,7 +259,7 @@ def main():
argument_spec=dict(
state=dict(type='str', default='present', choices=['absent', 'present']),
key=dict(type='str', required=True, no_log=False),
fingerprint=dict(type='str'),
fingerprint=dict(type='list', elements='str'),
validate_certs=dict(type='bool', default=True),
),
supports_check_mode=True,

@ -161,7 +161,7 @@
that:
- result is success
- result is not changed
- "'does not match the key fingerprint' in result.msg"
- "'does not match any key fingerprints' in result.msg"
- name: Issue 20325 - Verify fingerprint of key, valid fingerprint
rpm_key:
@ -187,6 +187,67 @@
- result is success
- result is not changed
# Reset to test subkey validation
- name: remove all keys from key ring
shell: "rpm -q gpg-pubkey | xargs rpm -e"
- name: Verify fingerprint of subkey, valid fingerprint
rpm_key:
key: https://ci-files.testing.ansible.com/test/integration/targets/rpm_key/RPM-GPG-KEY.dag
fingerprint: 19B7 913E 6284 8E3F 4D78 D6B4 ECD9 1AB2 2EB6 8D86
register: result
- name: Assert Verify fingerprint of key, valid fingerprint
assert:
that:
- result is success
- result is changed
- name: Verify fingerprint of subkey, valid fingerprint - Idempotent check
rpm_key:
key: https://ci-files.testing.ansible.com/test/integration/targets/rpm_key/RPM-GPG-KEY.dag
fingerprint: 19B7 913E 6284 8E3F 4D78 D6B4 ECD9 1AB2 2EB6 8D86
register: result
- name: Assert Verify fingerprint of subkey, valid fingerprint - Idempotent check
assert:
that:
- result is success
- result is not changed
# Reset to test multi-key validation
- name: remove all keys from key ring
shell: "rpm -q gpg-pubkey | xargs rpm -e"
- name: Verify fingerprint of primary and subkey, valid fingerprint
rpm_key:
key: https://ci-files.testing.ansible.com/test/integration/targets/rpm_key/RPM-GPG-KEY.dag
fingerprint:
- 19B7 913E 6284 8E3F 4D78 D6B4 ECD9 1AB2 2EB6 8D86
- EBC6 E12C 62B1 C734 026B 2122 A20E 5214 6B8D 79E6
register: result
- name: Assert Verify fingerprint of primary and subkey, valid fingerprint
assert:
that:
- result is success
- result is changed
- name: Verify fingerprint of primary and subkey, valid fingerprint - Idempotent check
rpm_key:
key: https://ci-files.testing.ansible.com/test/integration/targets/rpm_key/RPM-GPG-KEY.dag
fingerprint:
- 19B7 913E 6284 8E3F 4D78 D6B4 ECD9 1AB2 2EB6 8D86
- EBC6 E12C 62B1 C734 026B 2122 A20E 5214 6B8D 79E6
register: result
- name: Assert Verify fingerprint of primary and subkey, valid fingerprint - Idempotent check
assert:
that:
- result is success
- result is not changed
#
# Cleanup
#

Loading…
Cancel
Save