updated formating+documentation and added ability to specify multiple subkeys

pull/743/head
Austin Lucas Lake 2024-05-02 03:35:05 -07:00
parent 422a248e9b
commit af9571495b
No known key found for this signature in database
GPG Key ID: 6A37FA54CFCFA4DB
1 changed files with 186 additions and 180 deletions

View File

@ -15,7 +15,7 @@ author: "Austin Lucas Lake (@austinlucaslake)"
short_description: Generate or delete GPG private and public keys short_description: Generate or delete GPG private and public keys
version_added: 2.20.0 version_added: 2.20.0
description: description:
- "This module allows one to generate or delete OpenSSH private and public keys using GnuPG (gpg)." - "This module allows one to generate or delete GPG private and public keys using GnuPG (gpg)."
requirements: requirements:
- gpg >= 2.1 - gpg >= 2.1
extends_documentation_fragment: extends_documentation_fragment:
@ -36,59 +36,56 @@ options:
choices: [ present, absent ] choices: [ present, absent ]
key_type: key_type:
description: description:
- "Specifies the type of key to create. - Specifies the type of key to create.
Supported key types are V(RSA), V(DSA), V(ECDSA), V(EDDSA), and V(ECDH)."
type: str type: str
choices: ['RSA', 'DSA', 'ECDSA', 'EDDSA', 'ECDH'] choices: ['RSA', 'DSA', 'ECDSA', 'EDDSA']
key_length: key_length:
description: description:
- For non-ECC keys, this specifies the number of bits in the key to create. - For non-ECC keys, this specifies the number of bits in the key to create.
- For RSA keys, the minimum is V(1024), the maximum is V(4096), and the default is V(3072). - For RSA keys, the minimum is V(1024), the maximum is V(4096), and the default is V(3072).
- For DSA keys, the minimum is V(768), the maximum is V(3072), and the default is V(2048). - For DSA keys, the minimum is V(768), the maximum is V(3072), and the default is V(2048).
- Invalid values will automatically be saturated in the afforemented ranges for each respective key. - As per gpg's behavior, values below the allowed ranges will be set to the respective defaults, and those above the allowed ranges will saturate at the maximum.
- For ECC keys, this parameter will be ignored. - For ECC keys, this parameter will be ignored.
type: int type: int
key_curve: key_curve:
description: description:
- For ECC keys, this specifies the curve used to generate the keys. - For ECC keys, this specifies the curve used to generate the keys.
- Supported key curves are V(cv25519), V(nistp256), V(nistp384), V(nistp521), V(brainpoolP256r1), V(brainpoolP384r1), V(brainpoolP512r1), and V(secp256k1). - EDDSA keys only support the V(ed25519) curve and they can only be generate using said curve.
- EDDSA keys can only be used with V(cv25519). - For ECDSA keys, the default is V(brainpoolP512r1).
- Only EDDSA and ECDH keys support V(cv25519), and for both, V(cv25519) is the default.
- For ECDSA and ECDH, the default is V(brainpoolP512r1).
- For non-ECC keys, this parameter with be ignored. - For non-ECC keys, this parameter with be ignored.
type: str type: str
choices: ['cv25519', 'nistp256', 'nistp384', 'nistp521', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1', 'secp256k1'] choices: ['nistp256', 'nistp384', 'nistp521', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1', 'secp256k1', 'ed25519']
key_usage: key_usage:
description: description:
- Specifies usage(s) for key. - Specifies usage(s) for key.
- Support usages are V(encrypt), V(sign), V(auth), V(cert).
- V(cert) is given to all primary keys regardess, however can be used to only give V(vert) usage to a key. - V(cert) is given to all primary keys regardess, however can be used to only give V(vert) usage to a key.
- If not usage is specified, the valid usages for the given key type with be assigned. - If not usage is specified, the valid usages for the given key type with be assigned.
- If O(state) is V(absent), this parameter is ignored. - If O(state) is V(absent), this parameter is ignored.
type: list type: list
elements: str elements: str
choices: ['encrypt', 'sign', 'auth', 'cert'] choices: ['encrypt', 'sign', 'auth', 'cert']
subkey_type: subkeys:
description: description:
- Similar to O(key_type), but also supports V(ELG). - List of subkeys with their own respective key types, lengths, curves, and usages.
type: str - Similar to O(key_type), O(key_length), O(key_curve), and (key_usage).
default: EDDSA - Supports ECDH and ELG keys.
choices: ['RSA', 'DSA', 'ECDSA', 'EDDSA', 'ECDH', 'ELG'] - For both ECDH and ELG keys, the only supported usage is V(encrypt).
subkey_length: - For ECDH keys, the default curve is V(brainpoolP512r1).
description: - ECDH keys also support the V(cv25519) curve.
- Similar to O(key_length). - For ELG keys, the minimum length is V(1024) bits, the maximum length is V(4096) bits, and the default length is V(3072) bits.
- For ELG keys, the minimum is V(1024), the maximum is V(4096), and the default is V(3072)."
type: int type: list
subkey_curve: elements: dict
description: options:
- "Similar to O(key_curve)" subkey_type:
type: str type: str
choices: ['cv25519', 'nistp256', 'nistp384', 'nistp521', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1', 'secp256k1'] subkey_length:
key_usage: type: int
description: subkey_curve:
- Similar to O(key_usage), but does not support V(cert). type: str
type: list[str] subkey_usage:
choices: ['encrypt', 'sign', 'auth', 'cert'] type: list
elements: str
name: name:
description: description:
- Specifies a name for the key. - Specifies a name for the key.
@ -104,38 +101,34 @@ options:
passphrase: passphrase:
description: description:
- Passphrase used to decrypt an existing private key or encrypt a newly generated private key. - Passphrase used to decrypt an existing private key or encrypt a newly generated private key.
- If O(state) is V(absent), this parameter is ignored. - If O(state=absent), this parameter is ignored.
type: str type: str
fingerprints: fingerprints:
description: description:
- Specifies keys to match against. - Specifies keys to match against.
- Provided fingerprints will take priority over user-id "V(name) (V(comment)) <V(email)>". - Provided fingerprints will take priority over user-id "O(name) (O(comment)) <O(email)>".
- If O(state) is V(absent), keys with the provided fingerprints will be deleted if found. - If O(state=absent), keys with the provided fingerprints will be deleted if found.
type: list[str] type: list
elements: str
keyserver: keyserver:
description: description:
- Specifies keyserver to upload key to. - Specifies keyserver to upload key to.
- If O(state) is V(absent), this parameter will be ignored. - If O(state=absent), this parameter will be ignored.
type: str type: str
transient_key: transient_key:
description: description:
- Allows key generation to use a faster, but less secure random number generator. - Allows key generation to use a faster, but less secure random number generator.
type: bool type: bool
default: False default: False
return_fingerprints:
description:
- Allows for the return of fingerprint(s) for newly created or deleted keys(s)
type: bool
default: False
''' '''
EXAMPLES = ''' EXAMPLES = '''
- name: Generate the default GPG keypair (Ed25519) - name: Generate the default GPG keypair
community.crypto.gpg_keypair: community.crypto.gpg_keypair:
- name: Generate the default GPG keypair with a passphrase - name: Generate the default GPG keypair with a passphrase
community.crypto.gpg_keypair: community.crypto.gpg_keypair:
passphrase: super_secret_password passphrase: {{ passphrase }}
- name: Generate a RSA GPG keypair with the default RSA size (2048 bits) - name: Generate a RSA GPG keypair with the default RSA size (2048 bits)
community.crypto.gpg_keypair: community.crypto.gpg_keypair:
@ -149,49 +142,42 @@ EXAMPLES = '''
- name: Generate an ECC GPG keypair - name: Generate an ECC GPG keypair
community.crypto.gpg_keypair: community.crypto.gpg_keypair:
key_type: EDDSA key_type: EDDSA
key_curve: cv25519 key_curve: ed25519
- name: Generate a GPG keypair and with a subkey: - name: Generate a GPG keypair and with a subkey:
community.crypto.gpg_keypair: community.crypto.gpg_keypair:
subkey_type: ECDH subkeys:
subkey_curve: cv25519 - { subkey_type: ECDH, subkey_curve: cv25519 }
- name: Generate a GPG keypair with custom user-id: - name: Generate a GPG keypair with custom user-id:
community.crypto.gpg_keypair: community.crypto.gpg_keypair:
name: Your Name name: name
comment: Interesting comment. comment: comment
email: example@email.com email: name@email.com
- name: Generate a GPG keypair and return fingerprint of new key
community.crypto.gpg_keypair:
return_fingerprints: true
register: gpg_keys
- name: Delete GPG keypair(s) matching a specified user-id: - name: Delete GPG keypair(s) matching a specified user-id:
community.crypto.gpg_keypair: community.crypto.gpg_keypair:
state: abscent state: absent
name: Your Name name: name
comment: Interesting comment. comment: comment
email: example@email.com email: name@email.com
- name: Delete GPG keypair(s) matching a specified fingerprint: - name: Delete a GPG keypair matching a specified fingerprint:
community.crypto.gpg_keypair: community.crypto.gpg_keypair:
state: abscent state: abscent
fingerprints: fingerprints:
- ABC123... - ABC123...
''' '''
RETURN = ''' RETURN = '''
size: changed:
description: Size (in bits) of the SSH private key. description: Indicates if changes were made to GPG keyring.
returned: changed or success type: bool
type: int sample: True
sample: 4096
fingerprints: fingerprints:
description: Fingerprint(s) of newly created or deleted key(s) description: Fingerprint(s) of newly created or matched key(s).
return: changed and O(return_fingerprints=true) type: list
type: list[str] elements: str
sample: [ ABC123... ] sample: [ ABC123... ]
''' '''
@ -204,144 +190,154 @@ from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.crypto.plugins.module_utils.gnupg.cli import GPGError from ansible_collections.community.crypto.plugins.module_utils.gnupg.cli import GPGError
from ansible_collections.community.crypto.plugins.plugin_utils.gnupg import GPGError from ansible_collections.community.crypto.plugins.plugin_utils.gnupg import GPGError
def validate_params(params):
if params['override'] and params['present'] and not (params['fingerprint'] or params['name'] or params['comment'] or params['email']): def validate_key(key_type, key_length, key_curve, key_usage, key_name = 'primary key'):
raise GPGError, 'To override existing keys, please provide any combination of the `fingerprint`, `name`, `comment`, and `email` parameters.' if key_type == 'EDDSA':
keys = ['key'] if key_curve and key_curve != 'ed25519':
if params['subkey_type']: raise GPGError('Invalid curve for {} {}.'.format(key_type, key_name))
keys.append('subkey') elif:
for key in keys: raise GPGError('No curve provided for {} {}.'.format(key_type, key_name))
if params[f'{key}_type'] == 'EDDSA': elif key_usage and key_usage not in list(itertools.combinations(['sign', 'auth'])):
if not params[f'{key}_usage']: params[f'{key}_usage'] = ['sign', 'auth'] raise GPGError('Invalid usage for {} {}.'.format(key_type, key_name))
elif params[f'{key}_usage'] not in list(itertools.combinations(['sign', 'auth'])): elif key_type == 'ECDH':
raise GPGError, f'Invalid {key}_usage for {params[f"{key}_type"]} {key}.' if key_name = 'primary key':
if not params[f'{key}_curve'] or params[f'{key}_curve'] == 'cv25519': raise GPGError('Invalid type for {}.'.format(key_name))
params[f'{key}_curve'] = 'ed25519' elif key_usage and key_usage != ['encrypt']:
elif params[f'{key}_curve'] != 'cv25519': raise GPGError('Invalid usage for {} {}.'.format(key_type, key_name))
raise GPGError, f'Invalid {key}_curve for {params[f"{key}_type"]} {key}.' elif not key_curve:
elif params[f'{key}_type'] == 'ECDH': raise GPGError('No curve provided for {} {}.'.format(key_type, key_name))
if not params[f'{key}_usage']: params[f'{key}_usage'] = ['encrypt'] elif key_type == 'ECDSA':
elif params[f'{key}_usage'] != ['encrypt']: if key_curve and key_curve not in ['nistp256', 'nistp384', 'nistp521', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1', 'secp256k1']:
raise GPGError, f'Invalid {key}_usage for {params[f"{key}_type"]} {key}.' raise GPGError('Invalid curve for {} {}.'.format(key_type, key_name))
if not params[f'{key}_curve']: params[f'{key}_curve'] = 'cv25519' elif not key_curve:
elif params[f'{key}_curve'] != 'cv25519': raise GPGError('No curve provided for {} {}.'.format(key_type, key_name))
raise GPGError, f'Invalid {key}_curve for {params[f"{key}_type"]} {key}.' elif key_usage and key_usage not in list(itertools.combinations(['sign', 'auth'])):
elif params[f'{key}_type'] == 'ECDSA': raise GPGError('Invalid usage for {} {}.'.format(key_type, key_name))
if not params[f'{key}_usage']: params[f'{key}_usage'] = ['sign', 'auth'] elif key_type == 'RSA':
elif params[f'{key}_usage'] not in list(itertools.combinations(['sign', 'auth'])): if key_usage and key_usage not in list(itertools.combinatios(['ecrypt', 'sign', 'auth'])):
raise GPGError, f'Invalid {key}_usage for {params[f"{key}_type"]} {key}.' raise GPGError('Invalid usage for {} {}.'.format(key_type, key_name))
if not params[f'{key}_curve']: params[f'{key}_curve'] = 'brainpoolp521r1' elif key_type == 'DSA':
elif params[f'{key}_curve'] not in ['nistp256', 'nistp384', 'nistp521', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1', 'secp256k1']: if key_usage and key_usage not in list(itertools.combinations(['sign', 'auth'])):
raise GPGError, f'Invalid {key}_curve for {params[f"{key}_type"]} {key}.' raise GPGError('Invalid usage for {} {}.'.format(key_type, key_name))
elif params[f'{key}_type'] == 'RSA': elif key_type == 'ELG':
if not params[f'{key}_usage']: params = ['ecrypt', 'sign', 'auth'] if key_name == 'primary key':
elif not params[f'{key}_usage'] not in list(itertools.combinatios(['ecrypt', 'sign', 'auth'])): raise GPGError('Invalid type for {}.'.format(key_name))
raise GPGError, f'Invalid {key}_usage for {params[f"{key}_type"]} {key}.' elif key_usage != ['encrypt']:
if not params[f'{key}_length']: params[f'{key}_length'] = 3072 raise GPGError('Invalid usage for {} {}.'.format(key_type, key_name))
elif not 1024 <= params[f'{key}_length'] < 4096:
params[f'{key}_length'] = min(max(params[f'{key}_length'], 1024), 4096)
elif params[f'{key}_type'] == 'DSA': def validate_params(params):
if not params[f'{key}_usage']: params[f'{key}_usage'] = ['sign', 'auth'] validate_key(params['key_type'], params['key_length'], params['key_curve'], params['key_usage'])
elif params[f'{key}_usage'] not in list(itertools.combinations(['sign', 'auth'])): for index, subkey in enumerate(params['subkeys']):
raise GPGError, f'Invalid {key}_usage for {params[f"{key}_type"]} {key}.' validate_key(subkey['subkey_type'], subkey['subkey_length'], subkey['subkey_curve'], subkey['subkey_usage'], ('subkey #{}').format(index+1))
if not params[f'{key}_length']: params[f'{key}_length'] = 2048
elif not 768 <= params[f'{key}_length'] < 3072:
params[f'{key}_length'] = min(max(params[f'{key}_length'], 768), 3072)
elif params[f'{key}_type'] == 'ELG':
if params[f'{key}_type'] == params['key_type']:
raise GPGError, f'Invalid algorithm for {key}_type parameter.'
if not params[f'{key}_usage']: params[f'{key}_usage'] = ['encrypt']
elif params[f'{key}_usage'] != ['encrypt']:
raise GPGError, f'Invalid {key}_iusage for {params[f"{key}_type"]} {key}.'
if not params[f'{key}_length']: params[f'{key}_length'] = 3072
elif not 1024 <= params[f'{key}_length'] < 4096:
params[f'{key}_length'] = min(max(params[f'{key}_length'], 1024), 4096)
def list_matching_keys(name, comment, email, fingerprint): def list_matching_keys(name, comment, email, fingerprint):
user_id = "" user_id = ''
if params['name']: if params['name']:
user_id += f'{params["name"]} ' user_id += '{} '.format(params["name"])
if params['comment']: if params['comment']:
user_id += f'({params["comment"]}) ' user_id += '({}) '.format(params["comment"])
if params['email']: if params['email']:
user_id += f'<{params["email"]}>' user_id += '<{}>'.format(params["email"])
if user_id: if user_id:
user_id = f'"{user_id.strip()}"' user_id = '"{}"'.format(user_id.strip())
if user_id or fingerprints: if user_id or fingerprints:
_, stdout, _ = gpg_runner.run_command(['gpg', '--batch', '--list-secret-keys', f'{*fingerprints if fingerprints else user_id}']) _, stdout, _ = gpg_runner.run_command(['gpg', '--batch', '--list-secret-keys', '{}'.format(*fingerprints if fingerprints else user_id)])
lines = stdout.split('\n') lines = stdout.split('\n')
matching_keys = [line.strip() for line in lines if line.strip().isalnum()] matching_keys = [line.strip() for line in lines if line.strip().isalnum()]
for key in matching_keys:
# TODO: match based on key_type, key_usage, key_curve, and subkeys
pass
return matching_keys return matching_keys
return [] return []
def delete_keypair(gpg_runner, matching_keys, check_mode): def delete_keypair(gpg_runner, matching_keys, check_mode):
if matching_keys: if matching_keys:
gpg_runner.run_command([ gpg_runner.run_command([
f'{"dry-run" if check_mode else ""}', '--dry-run' if check_mode else '',
'--batch', '--batch',
'--yes', '--yes',
'--delete-secret-and-public-key', '--delete-secret-and-public-key',
*matching_keys *matching_keys
], check_rc=True) ], check_rc=True)
if params['return_fingerprints']: return dict(changed=True, fingerprints=matching_keys)
return dict(changed=True, fingerprints=matching_keys)
return dict(changed=True, fingerprints=[])
return dict(changed=False, fingerprints=[]) return dict(changed=False, fingerprints=[])
def add_subkey(gpg_runner, fingerprint, subkey_index, subkey_type, subkey_length, subkey_curve, subkey_usage, subkey_index):
if subkey_type in ['RSA', 'DSA'. 'ELG']:
algo = '{}'.format(subkey_type.lower())
if subkey_length:
algo += str(subkey_length)
elif subkey_curve:
algo = subkey_curve
else:
algo = None
gpg_runner.run_command([
'--batch', '--quick-add-key', fingerprint, algo if algo else 'default', *usage, expire_date if expire_date else 0
])
else:
raise GPGError('No algorithm applied for subkey #{}'.format(subkey_index+1))
def generate_keypair(gpg_runner, params, matching_keys, check_mode): def generate_keypair(gpg_runner, params, matching_keys, check_mode):
if matching_keys: if matching_keys:
if params['return_fingerprints']: return dict(changed=False, fingerprints=matching_keys)
return dict(changed=False, fingerprints=matching_keys)
return dict(change=False, fingerprints=[])
parameters = f"""<<EOF parameters = '''<<EOF
Key-Type: {params['key_type']} {}
Key-Length: {params['key_type']} {}
Key-Curve: {params['key_curve']} {}
{f''' {}
Subkey-Type: {params["subkey_type"]} {}
Subkey-Length: {params["subkey_type"]} {}
Subkey-Curve: {params["subkey_curve"]} {}
''' if params['subkey_type'] else ''} {}
Expire-Date: {params['expire_date']} {}
{f'Name-Real: {params["name"]}' if params['name'] else ''} {}
{f'Name-Comment: {params["comment"]}' if params['comment'] else ''}
{f'Name-Email: {params["email"]}' if params['email'] else ''}
{f'Passphrase: {params["passphrase"]}' if params['passphrase'] else '%no-protection'}
{f'Keyserver: {params["keyserver"]}' if params['keyserver'] else ''}
{'%transient-key' if params['transient_key'] else ''}
{'%dry-run' if check_mode or not params['force'] else ''}
%commit %commit
EOF EOF
""" '''.format(
'Key-Type: {}'.format(params['key_type'] if params['key_type'] else 'default'),
'Key-Length: {}'.format(params['key_length']) if params['key_length'] else '',
'Key-Curve: {}'.format(params['key_curve']) if params['key_curve'] else '',
'Expire-Date: {}'.format(params['expire_date']) if params['expire_date'] else '',
'Name-Real: {}'.format(params['name']) if params['name'] else '',
'Name-Comment: {}'.format(params['comment']) if params['comment'] else '',
'Name-Email: {}'.format(params['email']) if params['email'] else '',
'Passphrase: {}'.format(params['passphrase']) if params['passphrase'] else '%no-protection',
'Keyserver: {}'.format(params['keyserver']) if params['keyserver'] else '',
'%transient-key' if params['transient_key'] else ''
)
dummy, stdout, dummy2 = gpg_runner.run_command([ _, stdout, _ = gpg_runner.run_command([
f'{"dry-run" if check_mode else ""}', '--dry-run' if check_mode else '',
'--batch', '--batch',
'--log-file', '--log-file',
'/dev/stdout', '/dev/stdout',
'--gen-key', '--gen-key',
f'{parameters}' parameters
]) ])
if params['return_fingerprints']: fingerprint = re.search(r"([a-zA-Z0-9]*)\.rev", stdout)
fingerprints = []
fingerprint = re.search(r"([a-zA-Z0-9]*)\.rev", stdout) for index, subkey in enumerate(params['subkeys']):
if fingerprint: add_subkey(gpg_runner, fingerprint, index, subkey['subkey_type'], subkey['subkey_length'], subkey['subkey_curve'], subkey['subkey_usage'])
fingerprints.append(fingerprint)
return dict(changed=True, fingerprints=fingerprints) return dict(changed=True, fingerprints=[fingerprint])
return dict(changed=True, fingerprints=[])
def run_module(params, check_mode = False): def run_module(params, check_mode = False):
validate_params(params) validate_params(params)
gpg_runner = PluginGPGRunner() gpg_runner = PluginGPGRunner()
matching_keys = list_matching_keys( matching_keys = list_matching_keys(
params["name"], params['name'],
params["comment"], params['comment'],
params["email"], params['email'],
params["fingerprints"] params['fingerprints']
) )
if params['state'] = present: if params['state'] = present:
result = generate_keypair(gpg_runner, params, matching_keys, check_mode) result = generate_keypair(gpg_runner, params, matching_keys, check_mode)
@ -349,30 +345,39 @@ def run_module(params, check_mode = False):
result = delete_keypair(gpg_runner, matching_keys, check_mode) result = delete_keypair(gpg_runner, matching_keys, check_mode)
return result return result
def main(): def main():
key_types = ['RSA', 'DSA', 'ECDH', 'ECDSA', 'EDDSA', 'ELG'] key_types = ['RSA', 'DSA', 'ECDSA', 'EDDSA', 'ECDH', 'ELG']
key_curves = ['cv25519', 'nistp256', 'nistp384', 'nistp521', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1', 'secp256k1'] key_curves = ['nistp256', 'nistp384', 'nistp521', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1', 'secp256k1', 'ed25519', 'cv25519']
key_usages = ['encrypt', 'sign', 'auth', 'cert'] key_usages = ['encrypt', 'sign', 'auth', 'cert']
module = AnsibleModule( module = AnsibleModule(
argument_spec= argument_spec=dict(
state=dict(type='str', default='present', choices=['present', 'absent']), state=dict(type='str', default='present', choices=['present', 'absent']),
key_type=dict(type='str', choices=key_types[:-1]), key_type=dict(type='str', choices=key_types[:-2]),
key_curve=dict(type='str', choices=key_curves), key_length=dict(type='int'),
key_usage=dict(type='str', choices=key_usages), key_curve=dict(type='str', choices=key_curves[:-1]),
subkey_type=dict(type='str', choices=key_types), key_usage=dict(type='list', elements='str', choices=key_usages),
subkey_curve=dict(type='str', choices=key_curves), subkeys=dict(type='list', elements='dict', options=dict(
subkey_usage=dict(type='str', choices=key_usages[:-1]), subkey_type=dict(type='str', choices=key_types),
subkey_length=dict(type='int'),
subkey_curve=dict(type='str', choices=key_curves),
subkey_usage=dict(type='list', elements='str', choices=key_usages[:-1])
)),
name=dict(type='str', default=None), name=dict(type='str', default=None),
comment=dict(type='str', default=None), comment=dict(type='str', default=None),
email=dict(type='str', default=None), email=dict(type='str', default=None),
passphrase=dict(type='str', default=None), passphrase=dict(type='str', default=None, no_log=True),
fingerprints=dict(type='str', default=None, no_log=True), fingerprints=dict(type='list', elements='str', default=None, no_log=True),
keyserver=dict(type='str', default=None) keyserver=dict(type='str', default=None),
transient_key=dict(type='bool', default=False), transient_key=dict(type='bool', default=False)
return_fingerprints=dict(type='bool', default=False)
), ),
supports_check_mode=True supports_check_mode=True,
required_if=[
['state', 'present', ['name', 'comment', 'email']],
['state', 'absent', ['name', 'comment', 'email', 'fingerprints']]
]
) )
try: try:
@ -383,5 +388,6 @@ def main():
except Exception as e: except Exception as e:
module.fail_json(e) module.fail_json(e)
if __name__ == '__main__': if __name__ == '__main__':
main() main()