Allow to run x509_certificate selfsigned provider without providing a CSR (#129)
* Allow to run x509_certificate selfsigned provider without providing a CSR. * Add missing prefixes (unrelated).pull/131/head
parent
b32adcce78
commit
fd7871ae7d
|
@ -0,0 +1,2 @@
|
|||
minor_changes:
|
||||
- "x509_certificate - for the ``selfsigned`` provider, a CSR is not required anymore. If no CSR is provided, the module behaves as if a minimal CSR which only contains the public key has been provided (https://github.com/ansible-collections/community.crypto/issues/32, https://github.com/ansible-collections/community.crypto/pull/129)."
|
|
@ -87,13 +87,13 @@ options:
|
|||
csr_path:
|
||||
description:
|
||||
- Path to the Certificate Signing Request (CSR) used to generate this certificate.
|
||||
- This is not required in C(assertonly) mode.
|
||||
- This is not required in C(assertonly) or C(selfsigned) mode.
|
||||
- This is mutually exclusive with I(csr_content).
|
||||
type: path
|
||||
csr_content:
|
||||
description:
|
||||
- Content of the Certificate Signing Request (CSR) used to generate this certificate.
|
||||
- This is not required in C(assertonly) mode.
|
||||
- This is not required in C(assertonly) or C(selfsigned) mode.
|
||||
- This is mutually exclusive with I(csr_path).
|
||||
type: str
|
||||
version_added: '1.0.0'
|
||||
|
@ -1144,7 +1144,7 @@ class SelfSignedCertificateCryptography(Certificate):
|
|||
self.version = module.params['selfsigned_version']
|
||||
self.serial_number = x509.random_serial_number()
|
||||
|
||||
if self.csr_content is None and not os.path.exists(self.csr_path):
|
||||
if self.csr_path is not None and not os.path.exists(self.csr_path):
|
||||
raise CertificateError(
|
||||
'The certificate signing request file {0} does not exist'.format(self.csr_path)
|
||||
)
|
||||
|
@ -1153,11 +1153,6 @@ class SelfSignedCertificateCryptography(Certificate):
|
|||
'The private key file {0} does not exist'.format(self.privatekey_path)
|
||||
)
|
||||
|
||||
self.csr = load_certificate_request(
|
||||
path=self.csr_path,
|
||||
content=self.csr_content,
|
||||
backend=self.backend
|
||||
)
|
||||
self._module = module
|
||||
|
||||
try:
|
||||
|
@ -1170,6 +1165,28 @@ class SelfSignedCertificateCryptography(Certificate):
|
|||
except OpenSSLBadPassphraseError as exc:
|
||||
module.fail_json(msg=to_native(exc))
|
||||
|
||||
if self.csr_path is not None or self.csr_content is not None:
|
||||
self.csr = load_certificate_request(
|
||||
path=self.csr_path,
|
||||
content=self.csr_content,
|
||||
backend=self.backend
|
||||
)
|
||||
else:
|
||||
# Create empty CSR on the fly
|
||||
csr = cryptography.x509.CertificateSigningRequestBuilder()
|
||||
csr = csr.subject_name(cryptography.x509.Name([]))
|
||||
digest = None
|
||||
if cryptography_key_needs_digest_for_signing(self.privatekey):
|
||||
digest = self.digest
|
||||
if digest is None:
|
||||
self.module.fail_json(msg='Unsupported digest "{0}"'.format(module.params['selfsigned_digest']))
|
||||
try:
|
||||
self.csr = csr.sign(self.privatekey, digest, default_backend())
|
||||
except TypeError as e:
|
||||
if str(e) == 'Algorithm must be a registered hash algorithm.' and digest is None:
|
||||
self.module.fail_json(msg='Signing with Ed25519 and Ed448 keys requires cryptography 2.8 or newer.')
|
||||
raise
|
||||
|
||||
if cryptography_key_needs_digest_for_signing(self.privatekey):
|
||||
if self.digest is None:
|
||||
raise CertificateError(
|
||||
|
@ -1179,14 +1196,6 @@ class SelfSignedCertificateCryptography(Certificate):
|
|||
self.digest = None
|
||||
|
||||
def generate(self, module):
|
||||
if self.privatekey_content is None and not os.path.exists(self.privatekey_path):
|
||||
raise CertificateError(
|
||||
'The private key %s does not exist' % self.privatekey_path
|
||||
)
|
||||
if self.csr_content is None and not os.path.exists(self.csr_path):
|
||||
raise CertificateError(
|
||||
'The certificate signing request file %s does not exist' % self.csr_path
|
||||
)
|
||||
if not self.check(module, perms_required=False) or self.force:
|
||||
try:
|
||||
cert_builder = x509.CertificateBuilder()
|
||||
|
@ -1285,7 +1294,7 @@ class SelfSignedCertificate(Certificate):
|
|||
self.version = module.params['selfsigned_version']
|
||||
self.serial_number = generate_serial_number()
|
||||
|
||||
if self.csr_content is None and not os.path.exists(self.csr_path):
|
||||
if self.csr_path is not None and not os.path.exists(self.csr_path):
|
||||
raise CertificateError(
|
||||
'The certificate signing request file {0} does not exist'.format(self.csr_path)
|
||||
)
|
||||
|
@ -1294,10 +1303,6 @@ class SelfSignedCertificate(Certificate):
|
|||
'The private key file {0} does not exist'.format(self.privatekey_path)
|
||||
)
|
||||
|
||||
self.csr = load_certificate_request(
|
||||
path=self.csr_path,
|
||||
content=self.csr_content,
|
||||
)
|
||||
try:
|
||||
self.privatekey = load_privatekey(
|
||||
path=self.privatekey_path,
|
||||
|
@ -1307,18 +1312,18 @@ class SelfSignedCertificate(Certificate):
|
|||
except OpenSSLBadPassphraseError as exc:
|
||||
module.fail_json(msg=str(exc))
|
||||
|
||||
if self.csr_path is not None or self.csr_content is not None:
|
||||
self.csr = load_certificate_request(
|
||||
path=self.csr_path,
|
||||
content=self.csr_content,
|
||||
)
|
||||
else:
|
||||
# Create empty CSR on the fly
|
||||
self.csr = crypto.X509Req()
|
||||
self.csr.set_pubkey(self.privatekey)
|
||||
self.csr.sign(self.privatekey, self.digest)
|
||||
|
||||
def generate(self, module):
|
||||
|
||||
if self.privatekey_content is None and not os.path.exists(self.privatekey_path):
|
||||
raise CertificateError(
|
||||
'The private key %s does not exist' % self.privatekey_path
|
||||
)
|
||||
|
||||
if self.csr_content is None and not os.path.exists(self.csr_path):
|
||||
raise CertificateError(
|
||||
'The certificate signing request file %s does not exist' % self.csr_path
|
||||
)
|
||||
|
||||
if not self.check(module, perms_required=False) or self.force:
|
||||
cert = crypto.X509()
|
||||
cert.set_serial_number(self.serial_number)
|
||||
|
@ -2666,8 +2671,8 @@ def main():
|
|||
certificate = CertificateAbsent(module)
|
||||
|
||||
else:
|
||||
if module.params['provider'] != 'assertonly' and module.params['csr_path'] is None and module.params['csr_content'] is None:
|
||||
module.fail_json(msg='csr_path or csr_content is required when provider is not assertonly')
|
||||
if module.params['provider'] not in ('assertonly', 'selfsigned') and module.params['csr_path'] is None and module.params['csr_content'] is None:
|
||||
module.fail_json(msg='csr_path or csr_content is required when provider is not assertonly or selfsigned')
|
||||
|
||||
base_dir = os.path.dirname(module.params['path']) or '.'
|
||||
if not os.path.isdir(base_dir):
|
||||
|
|
|
@ -245,11 +245,11 @@
|
|||
ignore_errors: yes
|
||||
register: passphrase_error_3
|
||||
|
||||
- name: Create broken certificate
|
||||
- name: (OwnCA, {{select_crypto_backend}}) Create broken certificate
|
||||
copy:
|
||||
dest: "{{ output_dir }}/ownca_broken.pem"
|
||||
content: "broken"
|
||||
- name: Regenerate broken cert
|
||||
- name: (OwnCA, {{select_crypto_backend}}) Regenerate broken cert
|
||||
x509_certificate:
|
||||
path: '{{ output_dir }}/ownca_broken.pem'
|
||||
csr_path: '{{ output_dir }}/csr_ecc.csr'
|
||||
|
|
|
@ -10,6 +10,36 @@
|
|||
cipher: auto
|
||||
select_crypto_backend: cryptography
|
||||
|
||||
- name: (Selfsigned, {{select_crypto_backend}}) Generate selfsigned certificate without CSR
|
||||
x509_certificate:
|
||||
path: '{{ output_dir }}/cert_no_csr.pem'
|
||||
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||
provider: selfsigned
|
||||
selfsigned_digest: sha256
|
||||
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||
return_content: yes
|
||||
register: selfsigned_certificate_no_csr
|
||||
|
||||
- name: (Selfsigned, {{select_crypto_backend}}) Generate selfsigned certificate without CSR - idempotency
|
||||
x509_certificate:
|
||||
path: '{{ output_dir }}/cert_no_csr.pem'
|
||||
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||
provider: selfsigned
|
||||
selfsigned_digest: sha256
|
||||
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||
return_content: yes
|
||||
register: selfsigned_certificate_no_csr_idempotence
|
||||
|
||||
- name: (Selfsigned, {{select_crypto_backend}}) Generate selfsigned certificate without CSR (check mode)
|
||||
x509_certificate:
|
||||
path: '{{ output_dir }}/cert_no_csr.pem'
|
||||
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||
provider: selfsigned
|
||||
selfsigned_digest: sha256
|
||||
select_crypto_backend: '{{ select_crypto_backend }}'
|
||||
check_mode: yes
|
||||
register: selfsigned_certificate_no_csr_idempotence_check
|
||||
|
||||
- name: (Selfsigned, {{select_crypto_backend}}) Generate CSR
|
||||
openssl_csr:
|
||||
path: '{{ output_dir }}/csr.csr'
|
||||
|
@ -250,11 +280,11 @@
|
|||
ignore_errors: yes
|
||||
register: passphrase_error_3
|
||||
|
||||
- name: Create broken certificate
|
||||
- name: (Selfsigned, {{select_crypto_backend}}) Create broken certificate
|
||||
copy:
|
||||
dest: "{{ output_dir }}/cert_broken.pem"
|
||||
content: "broken"
|
||||
- name: Regenerate broken cert
|
||||
- name: (Selfsigned, {{select_crypto_backend}}) Regenerate broken cert
|
||||
x509_certificate:
|
||||
path: '{{ output_dir }}/cert_broken.pem'
|
||||
csr_path: '{{ output_dir }}/csr_ecc.csr'
|
||||
|
|
|
@ -3,6 +3,40 @@
|
|||
shell: 'openssl rsa -noout -modulus -in {{ output_dir }}/privatekey.pem'
|
||||
register: privatekey_modulus
|
||||
|
||||
- name: (Selfsigned validation, {{select_crypto_backend}}) Validate behavior for no CSR
|
||||
assert:
|
||||
that:
|
||||
- selfsigned_certificate_no_csr is changed
|
||||
- selfsigned_certificate_no_csr_idempotence is not changed
|
||||
- selfsigned_certificate_no_csr_idempotence_check is not changed
|
||||
|
||||
- name: (Selfsigned validation, {{select_crypto_backend}}) Validate certificate with no CSR (test - certificate modulus)
|
||||
shell: 'openssl x509 -noout -modulus -in {{ output_dir }}/cert_no_csr.pem'
|
||||
register: cert_modulus
|
||||
|
||||
- name: (Selfsigned validation, {{select_crypto_backend}}) Validate certificate with no CSR (test - certficate version == default == 3)
|
||||
shell: 'openssl x509 -noout -in {{ output_dir}}/cert_no_csr.pem -text | grep "Version" | sed "s/.*: \(.*\) .*/\1/g"'
|
||||
register: cert_version
|
||||
|
||||
- name: (Selfsigned validation, {{select_crypto_backend}}) Validate certificate with no CSR (assert)
|
||||
assert:
|
||||
that:
|
||||
- cert_modulus.stdout == privatekey_modulus.stdout
|
||||
- cert_version.stdout == '3'
|
||||
|
||||
- name: (Selfsigned validation, {{select_crypto_backend}}) Validate certificate with no CSR idempotence
|
||||
assert:
|
||||
that:
|
||||
- selfsigned_certificate_no_csr.serial_number == selfsigned_certificate_no_csr_idempotence.serial_number
|
||||
- selfsigned_certificate_no_csr.notBefore == selfsigned_certificate_no_csr_idempotence.notBefore
|
||||
- selfsigned_certificate_no_csr.notAfter == selfsigned_certificate_no_csr_idempotence.notAfter
|
||||
|
||||
- name: (Selfsigned validation, {{select_crypto_backend}}) Validate data retrieval with no CSR
|
||||
assert:
|
||||
that:
|
||||
- selfsigned_certificate_no_csr.certificate == lookup('file', output_dir ~ '/cert_no_csr.pem', rstrip=False)
|
||||
- selfsigned_certificate_no_csr.certificate == selfsigned_certificate_no_csr_idempotence.certificate
|
||||
|
||||
- name: (Selfsigned validation, {{select_crypto_backend}}) Validate certificate (test - certificate modulus)
|
||||
shell: 'openssl x509 -noout -modulus -in {{ output_dir }}/cert.pem'
|
||||
register: cert_modulus
|
||||
|
|
Loading…
Reference in New Issue