1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

openssl_*: Allow user to specify privatekey passphrase

Allow a user to specify the privatekey passphrase when dealing with
openssl modules.
This commit is contained in:
Yanis Guenane 2017-07-19 12:02:29 +02:00 committed by Toshio Kuratomi
parent a260063ffd
commit f40db199aa
4 changed files with 66 additions and 12 deletions

View file

@ -26,12 +26,14 @@ except ImportError:
import hashlib import hashlib
def get_fingerprint(path): def get_fingerprint(path, passphrase):
"""Generate the fingerprint of the public key. """ """Generate the fingerprint of the public key. """
fingerprint = {} fingerprint = {}
privatekey = crypto.load_privatekey(crypto.FILETYPE_PEM, open(path, 'r').read()) privatekey = crypto.load_privatekey(crypto.FILETYPE_PEM,
open(path, 'rb').read(),
passphrase)
try: try:
publickey = crypto.dump_publickey(crypto.FILETYPE_ASN1, privatekey) publickey = crypto.dump_publickey(crypto.FILETYPE_ASN1, privatekey)

View file

@ -50,6 +50,11 @@ options:
required: true required: true
description: description:
- Path to the privatekey to use when signing the certificate signing request - Path to the privatekey to use when signing the certificate signing request
privatekey_passphrase:
required: false
description:
- The passphrase for the privatekey.
version_added: "2.4"
version: version:
required: false required: false
default: 3 default: 3
@ -114,6 +119,14 @@ EXAMPLES = '''
privatekey_path: /etc/ssl/private/ansible.com.pem privatekey_path: /etc/ssl/private/ansible.com.pem
commonName: www.ansible.com commonName: www.ansible.com
# Generate an OpenSSL Certificate Signing Request with a
# passphrase protected private key
- openssl_csr:
path: /etc/ssl/csr/www.ansible.com.csr
privatekey_path: /etc/ssl/private/ansible.com.pem
privatekey_passphrase: ansible
commonName: www.ansible.com
# Generate an OpenSSL Certificate Signing Request with Subject information # Generate an OpenSSL Certificate Signing Request with Subject information
- openssl_csr: - openssl_csr:
path: /etc/ssl/csr/www.ansible.com.csr path: /etc/ssl/csr/www.ansible.com.csr
@ -183,6 +196,7 @@ class CertificateSigningRequest(object):
self.subjectAltName = module.params['subjectAltName'] self.subjectAltName = module.params['subjectAltName']
self.path = module.params['path'] self.path = module.params['path']
self.privatekey_path = module.params['privatekey_path'] self.privatekey_path = module.params['privatekey_path']
self.privatekey_passphrase = module.params['privatekey_passphrase']
self.version = module.params['version'] self.version = module.params['version']
self.changed = True self.changed = True
self.request = None self.request = None
@ -218,8 +232,9 @@ class CertificateSigningRequest(object):
req.add_extensions([crypto.X509Extension(b"subjectAltName", False, self.subjectAltName.encode('ascii'))]) req.add_extensions([crypto.X509Extension(b"subjectAltName", False, self.subjectAltName.encode('ascii'))])
privatekey_content = open(self.privatekey_path).read() privatekey_content = open(self.privatekey_path).read()
self.privatekey = crypto.load_privatekey(crypto.FILETYPE_PEM, privatekey_content) self.privatekey = crypto.load_privatekey(crypto.FILETYPE_PEM,
privatekey_content,
self.privatekey_passphrase)
req.set_pubkey(self.privatekey) req.set_pubkey(self.privatekey)
req.sign(self.privatekey, self.digest) req.sign(self.privatekey, self.digest)
self.request = req self.request = req
@ -267,6 +282,7 @@ def main():
state=dict(default='present', choices=['present', 'absent'], type='str'), state=dict(default='present', choices=['present', 'absent'], type='str'),
digest=dict(default='sha256', type='str'), digest=dict(default='sha256', type='str'),
privatekey_path=dict(require=True, type='path'), privatekey_path=dict(require=True, type='path'),
privatekey_passphrase=dict(type='str', no_log=True),
version=dict(default='3', type='int'), version=dict(default='3', type='int'),
force=dict(default=False, type='bool'), force=dict(default=False, type='bool'),
subjectAltName=dict(aliases=['subjectAltName'], type='str'), subjectAltName=dict(aliases=['subjectAltName'], type='str'),

View file

@ -62,14 +62,30 @@ options:
required: true required: true
description: description:
- Name of the file in which the generated TLS/SSL private key will be written. It will have 0600 mode. - Name of the file in which the generated TLS/SSL private key will be written. It will have 0600 mode.
passphrase:
required: false
description:
- The passphrase for the private key.
version_added: "2.4"
cipher:
required: false
description:
- The cipher to encrypt the private key. (cipher can be found by running `openssl list-cipher-algorithms`)
version_added: "2.4"
''' '''
EXAMPLES = ''' EXAMPLES = '''
# Generate an OpenSSL private key with the default values (4096 bits, RSA) # Generate an OpenSSL private key with the default values (4096 bits, RSA)
# and no public key
- openssl_privatekey: - openssl_privatekey:
path: /etc/ssl/private/ansible.com.pem path: /etc/ssl/private/ansible.com.pem
# Generate an OpenSSL private key with the default values (4096 bits, RSA)
# and a passphrase
- openssl_privatekey:
path: /etc/ssl/private/ansible.com.pem
passphrase: ansible
cipher: aes256
# Generate an OpenSSL private key with a different size (2048 bits) # Generate an OpenSSL private key with a different size (2048 bits)
- openssl_privatekey: - openssl_privatekey:
path: /etc/ssl/private/ansible.com.pem path: /etc/ssl/private/ansible.com.pem
@ -145,13 +161,14 @@ class PrivateKey(object):
self.type = module.params['type'] self.type = module.params['type']
self.force = module.params['force'] self.force = module.params['force']
self.path = module.params['path'] self.path = module.params['path']
self.passphrase = module.params['passphrase']
self.cipher = module.params['cipher']
self.mode = module.params['mode'] self.mode = module.params['mode']
self.changed = True self.changed = True
self.privatekey = None self.privatekey = None
self.fingerprint = {} self.fingerprint = {}
self.check_mode = module.check_mode self.check_mode = module.check_mode
def generate(self, module): def generate(self, module):
"""Generate a keypair.""" """Generate a keypair."""
@ -173,7 +190,11 @@ class PrivateKey(object):
os.O_WRONLY | os.O_CREAT | os.O_TRUNC, os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
self.mode) self.mode)
os.write(privatekey_file, crypto.dump_privatekey(crypto.FILETYPE_PEM, self.privatekey)) extras = {}
if self.cipher and self.passphrase:
extras = {'cipher': self.cipher, 'passphrase': self.passphrase}
os.write(privatekey_file, crypto.dump_privatekey(crypto.FILETYPE_PEM, self.privatekey, **extras))
os.close(privatekey_file) os.close(privatekey_file)
except IOError as exc: except IOError as exc:
self.remove() self.remove()
@ -181,12 +202,11 @@ class PrivateKey(object):
else: else:
self.changed = False self.changed = False
self.fingerprint = get_fingerprint(self.path) self.fingerprint = get_fingerprint(self.path, self.passphrase)
file_args = module.load_file_common_arguments(module.params) file_args = module.load_file_common_arguments(module.params)
if module.set_fs_attributes_if_different(file_args, False): if module.set_fs_attributes_if_different(file_args, False):
self.changed = True self.changed = True
def remove(self): def remove(self):
"""Remove the private key from the filesystem.""" """Remove the private key from the filesystem."""
@ -198,7 +218,6 @@ class PrivateKey(object):
else: else:
self.changed = False self.changed = False
def dump(self): def dump(self):
"""Serialize the object into a dictionary.""" """Serialize the object into a dictionary."""
@ -222,9 +241,12 @@ def main():
type=dict(default='RSA', choices=['RSA', 'DSA'], type='str'), type=dict(default='RSA', choices=['RSA', 'DSA'], type='str'),
force=dict(default=False, type='bool'), force=dict(default=False, type='bool'),
path=dict(required=True, type='path'), path=dict(required=True, type='path'),
passphrase=dict(type='str', no_log=True),
cipher=dict(type='str'),
), ),
supports_check_mode = True, supports_check_mode = True,
add_file_common_args = True, add_file_common_args = True,
required_together=[['cipher', 'passphrase']],
) )
if not pyopenssl_found: if not pyopenssl_found:

View file

@ -62,6 +62,11 @@ options:
required: true required: true
description: description:
- Path to the TLS/SSL private key from which to generate the public key. - Path to the TLS/SSL private key from which to generate the public key.
privatekey_passphrase:
required: false
description:
- The passphrase for the privatekey.
version_added: "2.4"
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -76,6 +81,13 @@ EXAMPLES = '''
privatekey_path: /etc/ssl/private/ansible.com.pem privatekey_path: /etc/ssl/private/ansible.com.pem
format: OpenSSH format: OpenSSH
# Generate an OpenSSL public key with a passphrase protected
# private key
- openssl_publickey:
path: /etc/ssl/public/ansible.com.pem
privatekey_path: /etc/ssl/private/ansible.com.pem
privatekey_passphrase: ansible
# Force regenerate an OpenSSL public key if it already exists # Force regenerate an OpenSSL public key if it already exists
- openssl_publickey: - openssl_publickey:
path: /etc/ssl/public/ansible.com.pem path: /etc/ssl/public/ansible.com.pem
@ -150,6 +162,7 @@ class PublicKey(object):
self.name = os.path.basename(module.params['path']) self.name = os.path.basename(module.params['path'])
self.path = module.params['path'] self.path = module.params['path']
self.privatekey_path = module.params['privatekey_path'] self.privatekey_path = module.params['privatekey_path']
self.privatekey_passphrase = module.params['privatekey_passphrase']
self.privatekey = None self.privatekey = None
self.changed = True self.changed = True
self.fingerprint = {} self.fingerprint = {}
@ -164,7 +177,7 @@ class PublicKey(object):
if self.format == 'OpenSSH': if self.format == 'OpenSSH':
key = crypto_serialization.load_pem_private_key(privatekey_content, key = crypto_serialization.load_pem_private_key(privatekey_content,
password=None, password=self.privatekey_passphrase,
backend=default_backend()) backend=default_backend())
publickey_content = key.public_key().public_bytes( publickey_content = key.public_key().public_bytes(
crypto_serialization.Encoding.OpenSSH, crypto_serialization.Encoding.OpenSSH,
@ -190,7 +203,7 @@ class PublicKey(object):
self.changed = False self.changed = False
file_args = module.load_file_common_arguments(module.params) file_args = module.load_file_common_arguments(module.params)
self.fingerprint = get_fingerprint(self.privatekey_path) self.fingerprint = get_fingerprint(self.privatekey_path, self.privatekey_passphrase)
if module.set_fs_attributes_if_different(file_args, False): if module.set_fs_attributes_if_different(file_args, False):
self.changed = True self.changed = True
@ -228,6 +241,7 @@ def main():
path=dict(required=True, type='path'), path=dict(required=True, type='path'),
privatekey_path=dict(type='path'), privatekey_path=dict(type='path'),
format=dict(type='str', choices=['PEM', 'OpenSSH'], default='PEM'), format=dict(type='str', choices=['PEM', 'OpenSSH'], default='PEM'),
privatekey_passphrase=dict(type='path', no_log=True),
), ),
supports_check_mode = True, supports_check_mode = True,
add_file_common_args = True, add_file_common_args = True,