mirror of
https://github.com/ansible-collections/community.crypto.git
synced 2026-05-06 13:22:58 +00:00
Refactor x509_certificate module, add x509_certificate_pipe module (#135)
* Move documentation to doc fragment. * Prepare module backends. * Linting. * Fix comments. * First shot at actually moving code. * Forgot SKI check. * Remove unused imports. * Improve check mode. * Fix 'returned'. * Move csr_* checks. * Explicitly specify parameter. * Add x509_certificate_pipe module. * Update other seealsos. * Forgot to remove doc fragment. * Adjust to work with macOS 10.15. * Update plugins/module_utils/crypto/module_backends/certificate_entrust.py Co-authored-by: Chris Trufan <31186388+ctrufan@users.noreply.github.com> * Add changelog fragments for entrust bugfix and module refactorings. * Restore old behavior of Entrust backend when existing certificate cannot be parsed. * Update plugins/modules/x509_certificate_pipe.py Co-authored-by: Chris Trufan <31186388+ctrufan@users.noreply.github.com> * Remove Entrust provider from x509_certificate_pipe for now. * Add own CA tests. * One more fix for Entrust provider, when csr_content is used. * Update plugins/modules/x509_certificate_pipe.py Co-authored-by: Chris Trufan <31186388+ctrufan@users.noreply.github.com> * Fix another broken example. * Revert "Remove Entrust provider from x509_certificate_pipe for now." This reverts commit 6ee5d7d4f99f0fe2218276a2d3f1f38b676c29b9. * ci_complete * Apply suggestions from code review Co-authored-by: MarkusTeufelberger <mteufelberger@mgit.at> * Improve example. * Improve readability of example, add another one. * Extend descriptions of csr_* for selfsigned. * Improve documentation. * Move deprecation message up. * Explain empty choices. Co-authored-by: Chris Trufan <31186388+ctrufan@users.noreply.github.com> Co-authored-by: MarkusTeufelberger <mteufelberger@mgit.at>
This commit is contained in:
@@ -53,6 +53,7 @@ options:
|
||||
|
||||
seealso:
|
||||
- module: community.crypto.openssl_csr
|
||||
- module: community.crypto.openssl_csr_pipe
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
|
||||
@@ -40,7 +40,7 @@ EXAMPLES = r'''
|
||||
- debug:
|
||||
var: result.csr
|
||||
|
||||
- name: Generate an OpenSSL Certificate Signing Request with an inline key
|
||||
- name: Generate an OpenSSL Certificate Signing Request with an inline CSR
|
||||
community.crypto.openssl_csr:
|
||||
content: "{{ lookup('file', '/etc/ssl/csr/www.ansible.com.csr') }}"
|
||||
privatekey_content: "{{ private_key_content }}"
|
||||
@@ -48,7 +48,7 @@ EXAMPLES = r'''
|
||||
register: result
|
||||
- name: Store CSR
|
||||
ansible.builtin.copy:
|
||||
path: /etc/ssl/csr/www.ansible.com.csr
|
||||
dest: /etc/ssl/csr/www.ansible.com.csr
|
||||
content: "{{ result.csr }}"
|
||||
when: result is changed
|
||||
'''
|
||||
@@ -111,7 +111,7 @@ name_constraints_excluded:
|
||||
sample: ['email:.com']
|
||||
csr:
|
||||
description: The (current or generated) CSR's content.
|
||||
returned: if I(state) is C(present)
|
||||
returned: changed or success
|
||||
type: str
|
||||
'''
|
||||
|
||||
|
||||
@@ -92,10 +92,13 @@ extends_documentation_fragment:
|
||||
- files
|
||||
seealso:
|
||||
- module: community.crypto.x509_certificate
|
||||
- module: community.crypto.x509_certificate_pipe
|
||||
- module: community.crypto.openssl_csr
|
||||
- module: community.crypto.openssl_csr_pipe
|
||||
- module: community.crypto.openssl_dhparam
|
||||
- module: community.crypto.openssl_pkcs12
|
||||
- module: community.crypto.openssl_privatekey
|
||||
- module: community.crypto.openssl_privatekey_pipe
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -74,6 +74,7 @@ notes:
|
||||
They are all in UTC.
|
||||
seealso:
|
||||
- module: community.crypto.x509_certificate
|
||||
- module: community.crypto.x509_certificate_pipe
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
|
||||
206
plugins/modules/x509_certificate_pipe.py
Normal file
206
plugins/modules/x509_certificate_pipe.py
Normal file
@@ -0,0 +1,206 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: (c) 2016-2017, Yanis Guenane <yanis+ansible@guenane.org>
|
||||
# Copyright: (c) 2017, Markus Teufelberger <mteufelberger+ansible@mgit.at>
|
||||
# Copyright: (2) 2020, Felix Fontein <felix@fontein.de>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: x509_certificate_pipe
|
||||
short_description: Generate and/or check OpenSSL certificates
|
||||
version_added: 1.3.0
|
||||
description:
|
||||
- It implements a notion of provider (ie. C(selfsigned), C(ownca), C(entrust))
|
||||
for your certificate.
|
||||
- "Please note that the module regenerates an existing certificate if it doesn't match the module's
|
||||
options, or if it seems to be corrupt. If you are concerned that this could overwrite
|
||||
your existing certificate, consider using the I(backup) option."
|
||||
author:
|
||||
- Yanis Guenane (@Spredzy)
|
||||
- Markus Teufelberger (@MarkusTeufelberger)
|
||||
- Felix Fontein (@felixfontein)
|
||||
options:
|
||||
provider:
|
||||
description:
|
||||
- Name of the provider to use to generate/retrieve the OpenSSL certificate.
|
||||
- "The C(entrust) provider requires credentials for the
|
||||
L(Entrust Certificate Services,https://www.entrustdatacard.com/products/categories/ssl-certificates) (ECS) API."
|
||||
type: str
|
||||
choices: [ entrust, ownca, selfsigned ]
|
||||
required: true
|
||||
|
||||
content:
|
||||
description:
|
||||
- The existing certificate.
|
||||
type: str
|
||||
|
||||
seealso:
|
||||
- module: community.crypto.x509_certificate
|
||||
|
||||
extends_documentation_fragment:
|
||||
- community.crypto.module_certificate
|
||||
- community.crypto.module_certificate.backend_entrust_documentation
|
||||
- community.crypto.module_certificate.backend_ownca_documentation
|
||||
- community.crypto.module_certificate.backend_selfsigned_documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Generate a Self Signed OpenSSL certificate
|
||||
community.crypto.x509_certificate_pipe:
|
||||
provider: selfsigned
|
||||
privatekey_path: /etc/ssl/private/ansible.com.pem
|
||||
csr_path: /etc/ssl/csr/ansible.com.csr
|
||||
register: result
|
||||
- ansible.builtin.debug:
|
||||
var: result.certificate
|
||||
|
||||
# In the following example, both CSR and certificate file are stored on the
|
||||
# machine where ansible-playbook is executed, while the OwnCA data (certificate,
|
||||
# private key) are stored on the remote machine.
|
||||
|
||||
- name: (1/2) Generate an OpenSSL Certificate with the CSR provided inline
|
||||
community.crypto.x509_certificate_pipe:
|
||||
provider: ownca
|
||||
content: "{{ lookup('file', '/etc/ssl/csr/www.ansible.com.crt') }}"
|
||||
csr_content: "{{ lookup('file', '/etc/ssl/csr/www.ansible.com.csr') }}"
|
||||
ownca_cert: /path/to/ca_cert.crt
|
||||
ownca_privatekey: /path/to/ca_cert.key
|
||||
ownca_privatekey_passphrase: hunter2
|
||||
register: result
|
||||
|
||||
- name: (2/2) Store certificate
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/ssl/csr/www.ansible.com.crt
|
||||
content: "{{ result.certificate }}"
|
||||
delegate_to: localhost
|
||||
when: result is changed
|
||||
|
||||
# In the following example, the certificate from another machine is signed by
|
||||
# our OwnCA whose private key and certificate are only available on this
|
||||
# machine (where ansible-playbook is executed), without having to write
|
||||
# the certificate file to disk on localhost. The CSR could have been
|
||||
# provided by community.crypto.openssl_csr_pipe earlier, or also have been
|
||||
# read from the remote machine.
|
||||
|
||||
- name: (1/3) Read certificate's contents from remote machine
|
||||
ansible.builtin.slurp:
|
||||
src: /etc/ssl/csr/www.ansible.com.crt
|
||||
register: certificate_content
|
||||
|
||||
- name: (2/3) Generate an OpenSSL Certificate with the CSR provided inline
|
||||
community.crypto.x509_certificate_pipe:
|
||||
provider: ownca
|
||||
content: "{{ certificate_content.content | b64decode }}"
|
||||
csr_content: "{{ the_csr }}"
|
||||
ownca_cert: /path/to/ca_cert.crt
|
||||
ownca_privatekey: /path/to/ca_cert.key
|
||||
ownca_privatekey_passphrase: hunter2
|
||||
delegate_to: localhost
|
||||
register: result
|
||||
|
||||
- name: (3/3) Store certificate
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/ssl/csr/www.ansible.com.crt
|
||||
content: "{{ result.certificate }}"
|
||||
when: result is changed
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
certificate:
|
||||
description: The (current or generated) certificate's content.
|
||||
returned: changed or success
|
||||
type: str
|
||||
'''
|
||||
|
||||
|
||||
import os
|
||||
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.certificate import (
|
||||
select_backend,
|
||||
get_certificate_argument_spec,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.certificate_entrust import (
|
||||
EntrustCertificateProvider,
|
||||
add_entrust_provider_to_argument_spec,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.certificate_ownca import (
|
||||
OwnCACertificateProvider,
|
||||
add_ownca_provider_to_argument_spec,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.certificate_selfsigned import (
|
||||
SelfSignedCertificateProvider,
|
||||
add_selfsigned_provider_to_argument_spec,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import (
|
||||
OpenSSLObjectError,
|
||||
)
|
||||
|
||||
|
||||
class GenericCertificate(object):
|
||||
"""Retrieve a certificate using the given module backend."""
|
||||
def __init__(self, module, module_backend):
|
||||
self.check_mode = module.check_mode
|
||||
self.module_backend = module_backend
|
||||
self.changed = False
|
||||
if module.params['content'] is not None:
|
||||
self.module_backend.set_existing(module.params['content'].encode('utf-8'))
|
||||
|
||||
def generate(self, module):
|
||||
if self.module_backend.needs_regeneration():
|
||||
if not self.check_mode:
|
||||
self.module_backend.generate_certificate()
|
||||
self.changed = True
|
||||
|
||||
def dump(self, check_mode=False):
|
||||
result = self.module_backend.dump(include_certificate=True)
|
||||
result.update({
|
||||
'changed': self.changed,
|
||||
})
|
||||
return result
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = get_certificate_argument_spec()
|
||||
argument_spec.argument_spec['provider']['required'] = True
|
||||
add_entrust_provider_to_argument_spec(argument_spec)
|
||||
add_ownca_provider_to_argument_spec(argument_spec)
|
||||
add_selfsigned_provider_to_argument_spec(argument_spec)
|
||||
argument_spec.argument_spec.update(dict(
|
||||
content=dict(type='str'),
|
||||
))
|
||||
module = argument_spec.create_ansible_module(
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
try:
|
||||
provider = module.params['provider']
|
||||
provider_map = {
|
||||
'entrust': EntrustCertificateProvider,
|
||||
'ownca': OwnCACertificateProvider,
|
||||
'selfsigned': SelfSignedCertificateProvider,
|
||||
}
|
||||
|
||||
backend = module.params['select_crypto_backend']
|
||||
module_backend = select_backend(module, backend, provider_map[provider]())
|
||||
certificate = GenericCertificate(module, module_backend)
|
||||
certificate.generate(module)
|
||||
result = certificate.dump()
|
||||
module.exit_json(**result)
|
||||
except OpenSSLObjectError as exc:
|
||||
module.fail_json(msg=to_native(exc))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user