acme_* modules: support private key passprases (#207)

* Support private key passprases.

* Use c.c modules for key generation, add first passphrase tests.

* Some more passphrase tests.
This commit is contained in:
Felix Fontein
2021-03-21 17:53:20 +01:00
committed by GitHub
parent 5d32937321
commit e85554827f
16 changed files with 190 additions and 64 deletions

View File

@@ -88,6 +88,12 @@ options:
- "Mutually exclusive with C(new_account_key_src)."
- "Required if C(new_account_key_src) is not used and state is C(changed_key)."
type: str
new_account_key_passphrase:
description:
- Phassphrase to use to decode the new account key.
- "B(Note:) this is not supported by the C(openssl) backend, only by the C(cryptography) backend."
type: str
version_added: 1.6.0
external_account_binding:
description:
- Allows to provide external account binding data during account creation.
@@ -183,6 +189,7 @@ def main():
contact=dict(type='list', elements='str', default=[]),
new_account_key_src=dict(type='path'),
new_account_key_content=dict(type='str', no_log=True),
new_account_key_passphrase=dict(type='str', no_log=True),
external_account_binding=dict(type='dict', options=dict(
kid=dict(type='str', required=True),
alg=dict(type='str', required=True, choices=['HS256', 'HS384', 'HS512']),
@@ -272,7 +279,8 @@ def main():
try:
new_key_data = client.parse_key(
module.params.get('new_account_key_src'),
module.params.get('new_account_key_content')
module.params.get('new_account_key_content'),
passphrase=module.params.get('new_account_key_passphrase'),
)
except KeyParsingError as e:
raise ModuleFailException("Error while parsing new account key: {msg}".format(msg=e.msg))

View File

@@ -54,7 +54,6 @@ options:
private keys in PEM format can be used as well."
- "Mutually exclusive with C(account_key_content)."
- "Required if C(account_key_content) is not used."
type: path
account_key_content:
description:
- "Content of the ACME account RSA or Elliptic Curve key."
@@ -69,7 +68,6 @@ options:
temporary file. It can still happen that it is written to disk by
Ansible in the process of moving the module with its argument to
the node where it is executed."
type: str
private_key_src:
description:
- "Path to the certificate's private key."
@@ -91,6 +89,12 @@ options:
Ansible in the process of moving the module with its argument to
the node where it is executed."
type: str
private_key_passphrase:
description:
- Phassphrase to use to decode the certificate's private key.
- "B(Note:) this is not supported by the C(openssl) backend, only by the C(cryptography) backend."
type: str
version_added: 1.6.0
revoke_reason:
description:
- "One of the revocation reasonCodes defined in
@@ -146,6 +150,7 @@ def main():
argument_spec.update(dict(
private_key_src=dict(type='path'),
private_key_content=dict(type='str', no_log=True),
private_key_passphrase=dict(type='str', no_log=True),
certificate=dict(type='path', required=True),
revoke_reason=dict(type='int'),
))
@@ -184,9 +189,10 @@ def main():
private_key_content = module.params.get('private_key_content')
# Revoke certificate
if private_key or private_key_content:
passphrase = module.params['private_key_passphrase']
# Step 1: load and parse private key
try:
private_key_data = client.parse_key(private_key, private_key_content)
private_key_data = client.parse_key(private_key, private_key_content, passphrase=passphrase)
except KeyParsingError as e:
raise ModuleFailException("Error while parsing private key: {msg}".format(msg=e.msg))
# Step 2: sign revokation request with private key

View File

@@ -52,6 +52,11 @@ options:
- "Content of the private key to use for this challenge certificate."
- "Mutually exclusive with C(private_key_src)."
type: str
private_key_passphrase:
description:
- Phassphrase to use to decode the private key.
type: str
version_added: 1.6.0
notes:
- Does not support C(check_mode).
'''
@@ -187,6 +192,7 @@ def main():
challenge_data=dict(type='dict', required=True),
private_key_src=dict(type='path'),
private_key_content=dict(type='str', no_log=True),
private_key_passphrase=dict(type='str', no_log=True),
),
required_one_of=(
['private_key_src', 'private_key_content'],
@@ -205,12 +211,16 @@ def main():
# Get hold of private key
private_key_content = module.params.get('private_key_content')
private_key_passphrase = module.params.get('private_key_passphrase')
if private_key_content is None:
private_key_content = read_file(module.params['private_key_src'])
else:
private_key_content = to_bytes(private_key_content)
try:
private_key = cryptography.hazmat.primitives.serialization.load_pem_private_key(private_key_content, password=None, backend=_cryptography_backend)
private_key = cryptography.hazmat.primitives.serialization.load_pem_private_key(
private_key_content,
password=to_bytes(private_key_passphrase) if private_key_passphrase is not None else None,
backend=_cryptography_backend)
except Exception as e:
raise ModuleFailException('Error while loading private key: {0}'.format(e))