rpm_key - add fingerprint parameter (#58373)
This parameter can be used to verify keys before they are imported by providing the long form fingerprint of the key.
This commit is contained in:
parent
d2ccf90610
commit
580b013837
2 changed files with 86 additions and 6 deletions
|
@ -17,7 +17,7 @@ DOCUMENTATION = '''
|
||||||
---
|
---
|
||||||
module: rpm_key
|
module: rpm_key
|
||||||
author:
|
author:
|
||||||
- Hector Acosta (@hacosta) <hector.acosta@gazzang.com>
|
- Hector Acosta (@hacosta) <hector.acosta@gazzang.com>
|
||||||
short_description: Adds or removes a gpg key from the rpm db
|
short_description: Adds or removes a gpg key from the rpm db
|
||||||
description:
|
description:
|
||||||
- Adds or removes (rpm --import) a gpg key to your rpm database.
|
- Adds or removes (rpm --import) a gpg key to your rpm database.
|
||||||
|
@ -25,7 +25,8 @@ version_added: "1.3"
|
||||||
options:
|
options:
|
||||||
key:
|
key:
|
||||||
description:
|
description:
|
||||||
- Key that will be modified. Can be a url, a file, or a keyid if the key already exists in the database.
|
- Key that will be modified. Can be a url, a file on the managed node, or a keyid if the key
|
||||||
|
already exists in the database.
|
||||||
required: true
|
required: true
|
||||||
state:
|
state:
|
||||||
description:
|
description:
|
||||||
|
@ -34,10 +35,16 @@ options:
|
||||||
choices: [ absent, present ]
|
choices: [ absent, present ]
|
||||||
validate_certs:
|
validate_certs:
|
||||||
description:
|
description:
|
||||||
- If C(no) and the C(key) is a url starting with https, SSL certificates will not be validated. This should only be used
|
- If C(no) and the C(key) is a url starting with https, SSL certificates will not be validated.
|
||||||
on personally controlled sites using self-signed certificates.
|
- This should only be used on personally controlled sites using self-signed certificates.
|
||||||
type: bool
|
type: bool
|
||||||
default: 'yes'
|
default: 'yes'
|
||||||
|
fingerprint:
|
||||||
|
description:
|
||||||
|
- The long-form fingerprint of the key being imported.
|
||||||
|
- This will be used to verify the specified key.
|
||||||
|
type: str
|
||||||
|
version_added: 2.9
|
||||||
'''
|
'''
|
||||||
|
|
||||||
EXAMPLES = '''
|
EXAMPLES = '''
|
||||||
|
@ -55,6 +62,11 @@ EXAMPLES = '''
|
||||||
- rpm_key:
|
- rpm_key:
|
||||||
state: absent
|
state: absent
|
||||||
key: DEADB33F
|
key: DEADB33F
|
||||||
|
|
||||||
|
# Verify the key, using a fingerprint, before import
|
||||||
|
- rpm_key:
|
||||||
|
key: /path/to/RPM-GPG-KEY.dag.txt
|
||||||
|
fingerprint: EBC6 E12C 62B1 C734 026B 2122 A20E 5214 6B8D 79E6
|
||||||
'''
|
'''
|
||||||
import re
|
import re
|
||||||
import os.path
|
import os.path
|
||||||
|
@ -83,6 +95,9 @@ class RpmKey(object):
|
||||||
self.rpm = self.module.get_bin_path('rpm', True)
|
self.rpm = self.module.get_bin_path('rpm', True)
|
||||||
state = module.params['state']
|
state = module.params['state']
|
||||||
key = module.params['key']
|
key = module.params['key']
|
||||||
|
fingerprint = module.params['fingerprint']
|
||||||
|
if fingerprint:
|
||||||
|
fingerprint = fingerprint.replace(' ', '').upper()
|
||||||
|
|
||||||
self.gpg = self.module.get_bin_path('gpg')
|
self.gpg = self.module.get_bin_path('gpg')
|
||||||
if not self.gpg:
|
if not self.gpg:
|
||||||
|
@ -107,6 +122,12 @@ class RpmKey(object):
|
||||||
else:
|
else:
|
||||||
if not keyfile:
|
if not keyfile:
|
||||||
self.module.fail_json(msg="When importing a key, a valid file must be given")
|
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:
|
||||||
|
self.module.fail_json(
|
||||||
|
msg="The specified fingerprint, '%s', does not match the key fingerprint '%s'" % (fingerprint, has_fingerprint)
|
||||||
|
)
|
||||||
self.import_key(keyfile)
|
self.import_key(keyfile)
|
||||||
if should_cleanup_keyfile:
|
if should_cleanup_keyfile:
|
||||||
self.module.cleanup(keyfile)
|
self.module.cleanup(keyfile)
|
||||||
|
@ -153,6 +174,26 @@ class RpmKey(object):
|
||||||
|
|
||||||
self.module.fail_json(msg="Unexpected gpg output")
|
self.module.fail_json(msg="Unexpected gpg output")
|
||||||
|
|
||||||
|
def getfingerprint(self, keyfile):
|
||||||
|
stdout, stderr = self.execute_command([
|
||||||
|
self.gpg, '--no-tty', '--batch', '--with-colons',
|
||||||
|
'--fixed-list-mode', '--with-fingerprint', keyfile
|
||||||
|
])
|
||||||
|
for line in stdout.splitlines():
|
||||||
|
line = line.strip()
|
||||||
|
if line.startswith('fpr:'):
|
||||||
|
# As mentioned here,
|
||||||
|
#
|
||||||
|
# https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob_plain;f=doc/DETAILS
|
||||||
|
#
|
||||||
|
# The description of the `fpr` field says
|
||||||
|
#
|
||||||
|
# "fpr :: Fingerprint (fingerprint is in field 10)"
|
||||||
|
#
|
||||||
|
return line.split(':')[9]
|
||||||
|
|
||||||
|
self.module.fail_json(msg="Unexpected gpg output")
|
||||||
|
|
||||||
def is_keyid(self, keystr):
|
def is_keyid(self, keystr):
|
||||||
"""Verifies if a key, as provided by the user is a keyid"""
|
"""Verifies if a key, as provided by the user is a keyid"""
|
||||||
return re.match('(0x)?[0-9a-f]{8}', keystr, flags=re.IGNORECASE)
|
return re.match('(0x)?[0-9a-f]{8}', keystr, flags=re.IGNORECASE)
|
||||||
|
@ -189,6 +230,7 @@ def main():
|
||||||
argument_spec=dict(
|
argument_spec=dict(
|
||||||
state=dict(type='str', default='present', choices=['absent', 'present']),
|
state=dict(type='str', default='present', choices=['absent', 'present']),
|
||||||
key=dict(type='str', required=True),
|
key=dict(type='str', required=True),
|
||||||
|
fingerprint=dict(type='str'),
|
||||||
validate_certs=dict(type='bool', default=True),
|
validate_certs=dict(type='bool', default=True),
|
||||||
),
|
),
|
||||||
supports_check_mode=True,
|
supports_check_mode=True,
|
||||||
|
|
|
@ -138,6 +138,44 @@
|
||||||
assert:
|
assert:
|
||||||
that: "'rsa sha1 (md5) pgp md5 OK' in sl_check.stdout or 'digests signatures OK' in sl_check.stdout"
|
that: "'rsa sha1 (md5) pgp md5 OK' in sl_check.stdout or 'digests signatures OK' in sl_check.stdout"
|
||||||
|
|
||||||
|
- name: Issue 20325 - Verify fingerprint of key, invalid fingerprint - EXPECTED FAILURE
|
||||||
|
rpm_key:
|
||||||
|
key: https://ansible-ci-files.s3.amazonaws.com/test/integration/targets/rpm_key/RPM-GPG-KEY.dag
|
||||||
|
fingerprint: 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111
|
||||||
|
register: result
|
||||||
|
failed_when: result is success
|
||||||
|
|
||||||
|
- name: Issue 20325 - Assert Verify fingerprint of key, invalid fingerprint
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result is success
|
||||||
|
- result is not changed
|
||||||
|
- "'does not match the key fingerprint' in result.msg"
|
||||||
|
|
||||||
|
- name: Issue 20325 - Verify fingerprint of key, valid fingerprint
|
||||||
|
rpm_key:
|
||||||
|
key: https://ansible-ci-files.s3.amazonaws.com/test/integration/targets/rpm_key/RPM-GPG-KEY.dag
|
||||||
|
fingerprint: EBC6 E12C 62B1 C734 026B 2122 A20E 5214 6B8D 79E6
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Issue 20325 - Assert Verify fingerprint of key, valid fingerprint
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result is success
|
||||||
|
- result is changed
|
||||||
|
|
||||||
|
- name: Issue 20325 - Verify fingerprint of key, valid fingerprint - Idempotent check
|
||||||
|
rpm_key:
|
||||||
|
key: https://ansible-ci-files.s3.amazonaws.com/test/integration/targets/rpm_key/RPM-GPG-KEY.dag
|
||||||
|
fingerprint: EBC6 E12C 62B1 C734 026B 2122 A20E 5214 6B8D 79E6
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Issue 20325 - Assert Verify fingerprint of key, valid fingerprint - Idempotent check
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result is success
|
||||||
|
- result is not changed
|
||||||
|
|
||||||
#
|
#
|
||||||
# Cleanup
|
# Cleanup
|
||||||
#
|
#
|
||||||
|
|
Loading…
Reference in a new issue