mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
new provider: ownca (#35840)
This commit is contained in:
parent
c4a6bce69f
commit
b61b113fb9
6 changed files with 473 additions and 119 deletions
|
@ -24,9 +24,11 @@ version_added: "2.4"
|
||||||
short_description: Generate and/or check OpenSSL certificates
|
short_description: Generate and/or check OpenSSL certificates
|
||||||
description:
|
description:
|
||||||
- "This module allows one to (re)generate OpenSSL certificates. It implements a notion
|
- "This module allows one to (re)generate OpenSSL certificates. It implements a notion
|
||||||
of provider (ie. C(selfsigned), C(acme), C(assertonly)) for your certificate.
|
of provider (ie. C(selfsigned), C(ownca), C(acme), C(assertonly)) for your certificate.
|
||||||
The 'assertonly' provider is intended for use cases where one is only interested in
|
The 'assertonly' provider is intended for use cases where one is only interested in
|
||||||
checking properties of a supplied certificate.
|
checking properties of a supplied certificate.
|
||||||
|
The 'ownca' provider is intended for generate OpenSSL certificate signed with your own
|
||||||
|
CA (Certificate Authority) certificate (self-signed certificate).
|
||||||
Many properties that can be specified in this module are for validation of an
|
Many properties that can be specified in this module are for validation of an
|
||||||
existing or newly generated certificate. The proper place to specify them, if you
|
existing or newly generated certificate. The proper place to specify them, if you
|
||||||
want to receive a certificate with these properties is a CSR (Certificate Signing Request).
|
want to receive a certificate with these properties is a CSR (Certificate Signing Request).
|
||||||
|
@ -48,7 +50,7 @@ options:
|
||||||
|
|
||||||
provider:
|
provider:
|
||||||
required: true
|
required: true
|
||||||
choices: [ 'selfsigned', 'assertonly', 'acme' ]
|
choices: [ 'selfsigned', 'ownca', 'assertonly', 'acme' ]
|
||||||
description:
|
description:
|
||||||
- Name of the provider to use to generate/retrieve the OpenSSL certificate.
|
- Name of the provider to use to generate/retrieve the OpenSSL certificate.
|
||||||
The C(assertonly) provider will not generate files and fail if the certificate file is missing.
|
The C(assertonly) provider will not generate files and fail if the certificate file is missing.
|
||||||
|
@ -94,6 +96,45 @@ options:
|
||||||
If this value is not specified, certificate will stop being valid 10 years from now.
|
If this value is not specified, certificate will stop being valid 10 years from now.
|
||||||
aliases: [ selfsigned_notAfter ]
|
aliases: [ selfsigned_notAfter ]
|
||||||
|
|
||||||
|
ownca_path:
|
||||||
|
description:
|
||||||
|
- Remote absolute path of the CA (Certificate Authority) certificate.
|
||||||
|
version_added: "2.7"
|
||||||
|
|
||||||
|
ownca_privatekey_path:
|
||||||
|
description:
|
||||||
|
- Path to the CA (Certificate Authority) private key to use when signing the certificate.
|
||||||
|
version_added: "2.7"
|
||||||
|
|
||||||
|
ownca_privatekey_passphrase:
|
||||||
|
description:
|
||||||
|
- The passphrase for the I(ownca_privatekey_path).
|
||||||
|
version_added: "2.7"
|
||||||
|
|
||||||
|
ownca_digest:
|
||||||
|
default: "sha256"
|
||||||
|
description:
|
||||||
|
- Digest algorithm to be used for the C(ownca) certificate.
|
||||||
|
version_added: "2.7"
|
||||||
|
|
||||||
|
ownca_version:
|
||||||
|
default: 3
|
||||||
|
description:
|
||||||
|
- Version of the C(ownca) certificate. Nowadays it should almost always be C(3).
|
||||||
|
version_added: "2.7"
|
||||||
|
|
||||||
|
ownca_not_before:
|
||||||
|
description:
|
||||||
|
- The timestamp at which the certificate starts being valid. The timestamp is formatted as an ASN.1 TIME.
|
||||||
|
If this value is not specified, certificate will start being valid from now.
|
||||||
|
version_added: "2.7"
|
||||||
|
|
||||||
|
ownca_not_after:
|
||||||
|
description:
|
||||||
|
- The timestamp at which the certificate stops being valid. The timestamp is formatted as an ASN.1 TIME.
|
||||||
|
If this value is not specified, certificate will stop being valid 10 years from now.
|
||||||
|
version_added: "2.7"
|
||||||
|
|
||||||
acme_accountkey_path:
|
acme_accountkey_path:
|
||||||
description:
|
description:
|
||||||
- Path to the accountkey for the C(acme) provider
|
- Path to the accountkey for the C(acme) provider
|
||||||
|
@ -209,6 +250,9 @@ extends_documentation_fragment: files
|
||||||
notes:
|
notes:
|
||||||
- All ASN.1 TIME values should be specified following the YYYYMMDDHHMMSSZ pattern.
|
- All ASN.1 TIME values should be specified following the YYYYMMDDHHMMSSZ pattern.
|
||||||
Date specified should be UTC. Minutes and seconds are mandatory.
|
Date specified should be UTC. Minutes and seconds are mandatory.
|
||||||
|
- For security reason, when you use C(ownca) provider, you should NOT run M(openssl_certificate) on
|
||||||
|
a target machine, but on a dedicated CA machine. It is recommended not to store the CA private key
|
||||||
|
on the target machine. Once signed, the certificate can be moved to the target machine.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
@ -220,6 +264,14 @@ EXAMPLES = '''
|
||||||
csr_path: /etc/ssl/csr/ansible.com.csr
|
csr_path: /etc/ssl/csr/ansible.com.csr
|
||||||
provider: selfsigned
|
provider: selfsigned
|
||||||
|
|
||||||
|
- name: Generate an OpenSSL certificate signed with your own CA certificate
|
||||||
|
openssl_certificate:
|
||||||
|
path: /etc/ssl/crt/ansible.com.crt
|
||||||
|
csr_path: /etc/ssl/csr/ansible.com.csr
|
||||||
|
ownca_path: /etc/ssl/crt/ansible_CA.crt
|
||||||
|
ownca_privatekey_path: /etc/ssl/private/ansible_CA.pem
|
||||||
|
provider: ownca
|
||||||
|
|
||||||
- name: Generate a Let's Encrypt Certificate
|
- name: Generate a Let's Encrypt Certificate
|
||||||
openssl_certificate:
|
openssl_certificate:
|
||||||
path: /etc/ssl/crt/ansible.com.crt
|
path: /etc/ssl/crt/ansible.com.crt
|
||||||
|
@ -381,6 +433,7 @@ class Certificate(crypto_utils.OpenSSLObject):
|
||||||
self.csr_path = module.params['csr_path']
|
self.csr_path = module.params['csr_path']
|
||||||
self.cert = None
|
self.cert = None
|
||||||
self.privatekey = None
|
self.privatekey = None
|
||||||
|
self.csr = None
|
||||||
self.module = module
|
self.module = module
|
||||||
|
|
||||||
def check(self, module, perms_required=True):
|
def check(self, module, perms_required=True):
|
||||||
|
@ -399,6 +452,24 @@ class Certificate(crypto_utils.OpenSSLObject):
|
||||||
except OpenSSL.SSL.Error:
|
except OpenSSL.SSL.Error:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def _validate_csr():
|
||||||
|
try:
|
||||||
|
self.csr.verify(self.cert.get_pubkey())
|
||||||
|
except OpenSSL.crypto.Error:
|
||||||
|
return False
|
||||||
|
if self.csr.get_subject() != self.cert.get_subject():
|
||||||
|
return False
|
||||||
|
csr_extensions = self.csr.get_extensions()
|
||||||
|
cert_extension_count = self.cert.get_extension_count()
|
||||||
|
if len(csr_extensions) != cert_extension_count:
|
||||||
|
return False
|
||||||
|
for extension_number in range(0, cert_extension_count):
|
||||||
|
cert_extension = self.cert.get_extension(extension_number)
|
||||||
|
csr_extension = filter(lambda extension: extension.get_short_name() == cert_extension.get_short_name(), csr_extensions)
|
||||||
|
if cert_extension.get_data() != list(csr_extension)[0].get_data():
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
if not state_and_perms:
|
if not state_and_perms:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -411,6 +482,11 @@ class Certificate(crypto_utils.OpenSSLObject):
|
||||||
)
|
)
|
||||||
return _validate_privatekey()
|
return _validate_privatekey()
|
||||||
|
|
||||||
|
if self.csr_path:
|
||||||
|
self.csr = crypto_utils.load_certificate_request(self.csr_path)
|
||||||
|
if not _validate_csr():
|
||||||
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -502,6 +578,105 @@ class SelfSignedCertificate(Certificate):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class OwnCACertificate(Certificate):
|
||||||
|
"""Generate the own CA certificate."""
|
||||||
|
|
||||||
|
def __init__(self, module):
|
||||||
|
super(OwnCACertificate, self).__init__(module)
|
||||||
|
self.notBefore = module.params['ownca_not_before']
|
||||||
|
self.notAfter = module.params['ownca_not_after']
|
||||||
|
self.digest = module.params['ownca_digest']
|
||||||
|
self.version = module.params['ownca_version']
|
||||||
|
self.serial_number = randint(1000, 99999)
|
||||||
|
self.ca_cert_path = module.params['ownca_path']
|
||||||
|
self.ca_privatekey_path = module.params['ownca_privatekey_path']
|
||||||
|
self.ca_privatekey_passphrase = module.params['ownca_privatekey_passphrase']
|
||||||
|
self.csr = crypto_utils.load_certificate_request(self.csr_path)
|
||||||
|
self.ca_cert = crypto_utils.load_certificate(self.ca_cert_path)
|
||||||
|
self.ca_privatekey = crypto_utils.load_privatekey(
|
||||||
|
self.ca_privatekey_path, self.ca_privatekey_passphrase
|
||||||
|
)
|
||||||
|
|
||||||
|
def generate(self, module):
|
||||||
|
|
||||||
|
if not os.path.exists(self.ca_cert_path):
|
||||||
|
raise CertificateError(
|
||||||
|
'The CA certificate %s does not exist' % self.ca_cert_path
|
||||||
|
)
|
||||||
|
|
||||||
|
if not os.path.exists(self.ca_privatekey_path):
|
||||||
|
raise CertificateError(
|
||||||
|
'The CA private key %s does not exist' % self.ca_privatekey_path
|
||||||
|
)
|
||||||
|
|
||||||
|
if 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)
|
||||||
|
if self.notBefore:
|
||||||
|
cert.set_notBefore(self.notBefore.encode())
|
||||||
|
else:
|
||||||
|
cert.gmtime_adj_notBefore(0)
|
||||||
|
if self.notAfter:
|
||||||
|
cert.set_notAfter(self.notAfter.encode())
|
||||||
|
else:
|
||||||
|
# If no NotAfter specified, expire in
|
||||||
|
# 10 years. 315360000 is 10 years in seconds.
|
||||||
|
cert.gmtime_adj_notAfter(315360000)
|
||||||
|
cert.set_subject(self.csr.get_subject())
|
||||||
|
cert.set_issuer(self.ca_cert.get_subject())
|
||||||
|
cert.set_version(self.version - 1)
|
||||||
|
cert.set_pubkey(self.csr.get_pubkey())
|
||||||
|
cert.add_extensions(self.csr.get_extensions())
|
||||||
|
|
||||||
|
cert.sign(self.ca_privatekey, self.digest)
|
||||||
|
self.cert = cert
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(self.path, 'wb') as cert_file:
|
||||||
|
cert_file.write(crypto.dump_certificate(crypto.FILETYPE_PEM, self.cert))
|
||||||
|
except EnvironmentError as exc:
|
||||||
|
raise CertificateError(exc)
|
||||||
|
|
||||||
|
self.changed = True
|
||||||
|
|
||||||
|
file_args = module.load_file_common_arguments(module.params)
|
||||||
|
if module.set_fs_attributes_if_different(file_args, False):
|
||||||
|
self.changed = True
|
||||||
|
|
||||||
|
def dump(self, check_mode=False):
|
||||||
|
|
||||||
|
result = {
|
||||||
|
'changed': self.changed,
|
||||||
|
'filename': self.path,
|
||||||
|
'privatekey': self.privatekey_path,
|
||||||
|
'csr': self.csr_path,
|
||||||
|
'ca_cert': self.ca_cert_path,
|
||||||
|
'ca_privatekey': self.ca_privatekey_path
|
||||||
|
}
|
||||||
|
|
||||||
|
if check_mode:
|
||||||
|
now = datetime.datetime.utcnow()
|
||||||
|
ten = now.replace(now.year + 10)
|
||||||
|
result.update({
|
||||||
|
'notBefore': self.notBefore if self.notBefore else now.strftime("%Y%m%d%H%M%SZ"),
|
||||||
|
'notAfter': self.notAfter if self.notAfter else ten.strftime("%Y%m%d%H%M%SZ"),
|
||||||
|
'serial_number': self.serial_number,
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
result.update({
|
||||||
|
'notBefore': self.cert.get_notBefore(),
|
||||||
|
'notAfter': self.cert.get_notAfter(),
|
||||||
|
'serial_number': self.cert.get_serial_number(),
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
class AssertOnlyCertificate(Certificate):
|
class AssertOnlyCertificate(Certificate):
|
||||||
"""validate the supplied certificate."""
|
"""validate the supplied certificate."""
|
||||||
|
|
||||||
|
@ -805,7 +980,7 @@ def main():
|
||||||
argument_spec=dict(
|
argument_spec=dict(
|
||||||
state=dict(type='str', choices=['present', 'absent'], default='present'),
|
state=dict(type='str', choices=['present', 'absent'], default='present'),
|
||||||
path=dict(type='path', required=True),
|
path=dict(type='path', required=True),
|
||||||
provider=dict(type='str', choices=['selfsigned', 'assertonly', 'acme']),
|
provider=dict(type='str', choices=['selfsigned', 'ownca', 'assertonly', 'acme']),
|
||||||
force=dict(type='bool', default=False,),
|
force=dict(type='bool', default=False,),
|
||||||
csr_path=dict(type='path'),
|
csr_path=dict(type='path'),
|
||||||
|
|
||||||
|
@ -837,6 +1012,15 @@ def main():
|
||||||
selfsigned_notBefore=dict(type='str', aliases=['selfsigned_not_before']),
|
selfsigned_notBefore=dict(type='str', aliases=['selfsigned_not_before']),
|
||||||
selfsigned_notAfter=dict(type='str', aliases=['selfsigned_not_after']),
|
selfsigned_notAfter=dict(type='str', aliases=['selfsigned_not_after']),
|
||||||
|
|
||||||
|
# provider: ownca
|
||||||
|
ownca_path=dict(type='path'),
|
||||||
|
ownca_privatekey_path=dict(type='path'),
|
||||||
|
ownca_privatekey_passphrase=dict(type='path', no_log=True),
|
||||||
|
ownca_digest=dict(type='str', default='sha256'),
|
||||||
|
ownca_version=dict(type='int', default='3'),
|
||||||
|
ownca_not_before=dict(type='str'),
|
||||||
|
ownca_not_after=dict(type='str'),
|
||||||
|
|
||||||
# provider: acme
|
# provider: acme
|
||||||
acme_accountkey_path=dict(type='path'),
|
acme_accountkey_path=dict(type='path'),
|
||||||
acme_challenge_path=dict(type='path'),
|
acme_challenge_path=dict(type='path'),
|
||||||
|
@ -848,7 +1032,7 @@ def main():
|
||||||
|
|
||||||
if not pyopenssl_found:
|
if not pyopenssl_found:
|
||||||
module.fail_json(msg='The python pyOpenSSL library is required')
|
module.fail_json(msg='The python pyOpenSSL library is required')
|
||||||
if module.params['provider'] in ['selfsigned', 'assertonly']:
|
if module.params['provider'] in ['selfsigned', 'ownca', 'assertonly']:
|
||||||
try:
|
try:
|
||||||
getattr(crypto.X509Req, 'get_extensions')
|
getattr(crypto.X509Req, 'get_extensions')
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
@ -867,6 +1051,8 @@ def main():
|
||||||
certificate = SelfSignedCertificate(module)
|
certificate = SelfSignedCertificate(module)
|
||||||
elif provider == 'acme':
|
elif provider == 'acme':
|
||||||
certificate = AcmeCertificate(module)
|
certificate = AcmeCertificate(module)
|
||||||
|
elif provider == 'ownca':
|
||||||
|
certificate = OwnCACertificate(module)
|
||||||
else:
|
else:
|
||||||
certificate = AssertOnlyCertificate(module)
|
certificate = AssertOnlyCertificate(module)
|
||||||
|
|
||||||
|
|
|
@ -1,120 +1,7 @@
|
||||||
- block:
|
- block:
|
||||||
- name: Generate privatekey
|
|
||||||
openssl_privatekey:
|
|
||||||
path: '{{ output_dir }}/privatekey.pem'
|
|
||||||
|
|
||||||
- name: Generate CSR
|
- import_tasks: selfsigned.yml
|
||||||
openssl_csr:
|
|
||||||
path: '{{ output_dir }}/csr.csr'
|
|
||||||
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
|
||||||
subject:
|
|
||||||
commonName: www.example.com
|
|
||||||
|
|
||||||
- name: Generate selfsigned certificate
|
- import_tasks: ownca.yml
|
||||||
openssl_certificate:
|
|
||||||
path: '{{ output_dir }}/cert.pem'
|
|
||||||
csr_path: '{{ output_dir }}/csr.csr'
|
|
||||||
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
|
||||||
provider: selfsigned
|
|
||||||
selfsigned_digest: sha256
|
|
||||||
register: selfsigned_certificate
|
|
||||||
|
|
||||||
- name: Generate selfsigned certificate
|
|
||||||
openssl_certificate:
|
|
||||||
path: '{{ output_dir }}/cert.pem'
|
|
||||||
csr_path: '{{ output_dir }}/csr.csr'
|
|
||||||
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
|
||||||
provider: selfsigned
|
|
||||||
selfsigned_digest: sha256
|
|
||||||
register: selfsigned_certificate_idempotence
|
|
||||||
|
|
||||||
- name: Generate selfsigned certificate (check mode)
|
|
||||||
openssl_certificate:
|
|
||||||
path: '{{ output_dir }}/cert.pem'
|
|
||||||
csr_path: '{{ output_dir }}/csr.csr'
|
|
||||||
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
|
||||||
provider: selfsigned
|
|
||||||
selfsigned_digest: sha256
|
|
||||||
check_mode: yes
|
|
||||||
|
|
||||||
- name: Check selfsigned certificate
|
|
||||||
openssl_certificate:
|
|
||||||
path: '{{ output_dir }}/cert.pem'
|
|
||||||
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
|
||||||
provider: assertonly
|
|
||||||
has_expired: False
|
|
||||||
version: 3
|
|
||||||
signature_algorithms:
|
|
||||||
- sha256WithRSAEncryption
|
|
||||||
- sha256WithECDSAEncryption
|
|
||||||
subject:
|
|
||||||
commonName: www.example.com
|
|
||||||
|
|
||||||
- name: Generate selfsigned v2 certificate
|
|
||||||
openssl_certificate:
|
|
||||||
path: '{{ output_dir }}/cert_v2.pem'
|
|
||||||
csr_path: '{{ output_dir }}/csr.csr'
|
|
||||||
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
|
||||||
provider: selfsigned
|
|
||||||
selfsigned_digest: sha256
|
|
||||||
selfsigned_version: 2
|
|
||||||
|
|
||||||
- name: Generate privatekey2
|
|
||||||
openssl_privatekey:
|
|
||||||
path: '{{ output_dir }}/privatekey2.pem'
|
|
||||||
|
|
||||||
- name: Generate CSR2
|
|
||||||
openssl_csr:
|
|
||||||
subject:
|
|
||||||
CN: www.example.com
|
|
||||||
C: US
|
|
||||||
ST: California
|
|
||||||
L: Los Angeles
|
|
||||||
O: ACME Inc.
|
|
||||||
OU:
|
|
||||||
- Roadrunner pest control
|
|
||||||
- Pyrotechnics
|
|
||||||
path: '{{ output_dir }}/csr2.csr'
|
|
||||||
privatekey_path: '{{ output_dir }}/privatekey2.pem'
|
|
||||||
keyUsage:
|
|
||||||
- digitalSignature
|
|
||||||
extendedKeyUsage:
|
|
||||||
- ipsecUser
|
|
||||||
- biometricInfo
|
|
||||||
|
|
||||||
- name: Generate selfsigned certificate2
|
|
||||||
openssl_certificate:
|
|
||||||
path: '{{ output_dir }}/cert2.pem'
|
|
||||||
csr_path: '{{ output_dir }}/csr2.csr'
|
|
||||||
privatekey_path: '{{ output_dir }}/privatekey2.pem'
|
|
||||||
provider: selfsigned
|
|
||||||
selfsigned_digest: sha256
|
|
||||||
|
|
||||||
- name: Check selfsigned certificate2
|
|
||||||
openssl_certificate:
|
|
||||||
path: '{{ output_dir }}/cert2.pem'
|
|
||||||
privatekey_path: '{{ output_dir }}/privatekey2.pem'
|
|
||||||
provider: assertonly
|
|
||||||
has_expired: False
|
|
||||||
version: 3
|
|
||||||
signature_algorithms:
|
|
||||||
- sha256WithRSAEncryption
|
|
||||||
- sha256WithECDSAEncryption
|
|
||||||
subject:
|
|
||||||
commonName: www.example.com
|
|
||||||
C: US
|
|
||||||
ST: California
|
|
||||||
L: Los Angeles
|
|
||||||
O: ACME Inc.
|
|
||||||
OU:
|
|
||||||
- Roadrunner pest control
|
|
||||||
- Pyrotechnics
|
|
||||||
keyUsage:
|
|
||||||
- digitalSignature
|
|
||||||
extendedKeyUsage:
|
|
||||||
- ipsecUser
|
|
||||||
- biometricInfo
|
|
||||||
|
|
||||||
- import_tasks: ../tests/validate.yml
|
|
||||||
|
|
||||||
when: pyopenssl_version.stdout is version('0.15', '>=')
|
when: pyopenssl_version.stdout is version('0.15', '>=')
|
||||||
|
|
116
test/integration/targets/openssl_certificate/tasks/ownca.yml
Normal file
116
test/integration/targets/openssl_certificate/tasks/ownca.yml
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
- name: Generate CA privatekey
|
||||||
|
openssl_privatekey:
|
||||||
|
path: '{{ output_dir }}/ca_privatekey.pem'
|
||||||
|
|
||||||
|
- name: Generate CA CSR
|
||||||
|
openssl_csr:
|
||||||
|
path: '{{ output_dir }}/ca_csr.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/ca_privatekey.pem'
|
||||||
|
subject:
|
||||||
|
commonName: Example CA
|
||||||
|
|
||||||
|
- name: Generate selfsigned CA certificate
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/ca_cert.pem'
|
||||||
|
csr_path: '{{ output_dir }}/ca_csr.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/ca_privatekey.pem'
|
||||||
|
provider: selfsigned
|
||||||
|
selfsigned_digest: sha256
|
||||||
|
|
||||||
|
- name: Generate ownca certificate
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/ownca_cert.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
ownca_path: '{{ output_dir }}/ca_cert.pem'
|
||||||
|
ownca_privatekey_path: '{{ output_dir }}/ca_privatekey.pem'
|
||||||
|
provider: ownca
|
||||||
|
ownca_digest: sha256
|
||||||
|
register: ownca_certificate
|
||||||
|
|
||||||
|
- name: Generate ownca certificate
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/ownca_cert.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
ownca_path: '{{ output_dir }}/ca_cert.pem'
|
||||||
|
ownca_privatekey_path: '{{ output_dir }}/ca_privatekey.pem'
|
||||||
|
provider: ownca
|
||||||
|
ownca_digest: sha256
|
||||||
|
register: ownca_certificate_idempotence
|
||||||
|
|
||||||
|
- name: Generate ownca certificate (check mode)
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/ownca_cert.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
ownca_path: '{{ output_dir }}/ca_cert.pem'
|
||||||
|
ownca_privatekey_path: '{{ output_dir }}/ca_privatekey.pem'
|
||||||
|
provider: ownca
|
||||||
|
ownca_digest: sha256
|
||||||
|
check_mode: yes
|
||||||
|
|
||||||
|
- name: Check ownca certificate
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/ownca_cert.pem'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
provider: assertonly
|
||||||
|
has_expired: False
|
||||||
|
version: 3
|
||||||
|
signature_algorithms:
|
||||||
|
- sha256WithRSAEncryption
|
||||||
|
- sha256WithECDSAEncryption
|
||||||
|
subject:
|
||||||
|
commonName: www.example.com
|
||||||
|
issuer:
|
||||||
|
commonName: Example CA
|
||||||
|
|
||||||
|
- name: Generate ownca v2 certificate
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/ownca_cert_v2.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
ownca_path: '{{ output_dir }}/ca_cert.pem'
|
||||||
|
ownca_privatekey_path: '{{ output_dir }}/ca_privatekey.pem'
|
||||||
|
provider: ownca
|
||||||
|
ownca_digest: sha256
|
||||||
|
ownca_version: 2
|
||||||
|
|
||||||
|
- name: Generate ownca certificate2
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/ownca_cert2.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr2.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey2.pem'
|
||||||
|
ownca_path: '{{ output_dir }}/ca_cert.pem'
|
||||||
|
ownca_privatekey_path: '{{ output_dir }}/ca_privatekey.pem'
|
||||||
|
provider: ownca
|
||||||
|
ownca_digest: sha256
|
||||||
|
|
||||||
|
- name: Check ownca certificate2
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/ownca_cert2.pem'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey2.pem'
|
||||||
|
provider: assertonly
|
||||||
|
has_expired: False
|
||||||
|
version: 3
|
||||||
|
signature_algorithms:
|
||||||
|
- sha256WithRSAEncryption
|
||||||
|
- sha256WithECDSAEncryption
|
||||||
|
subject:
|
||||||
|
commonName: www.example.com
|
||||||
|
C: US
|
||||||
|
ST: California
|
||||||
|
L: Los Angeles
|
||||||
|
O: ACME Inc.
|
||||||
|
OU:
|
||||||
|
- Roadrunner pest control
|
||||||
|
- Pyrotechnics
|
||||||
|
keyUsage:
|
||||||
|
- digitalSignature
|
||||||
|
extendedKeyUsage:
|
||||||
|
- ipsecUser
|
||||||
|
- biometricInfo
|
||||||
|
issuer:
|
||||||
|
commonName: Example CA
|
||||||
|
|
||||||
|
- import_tasks: ../tests/validate_ownca.yml
|
|
@ -0,0 +1,117 @@
|
||||||
|
- name: Generate privatekey
|
||||||
|
openssl_privatekey:
|
||||||
|
path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
|
||||||
|
- name: Generate CSR
|
||||||
|
openssl_csr:
|
||||||
|
path: '{{ output_dir }}/csr.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
subject:
|
||||||
|
commonName: www.example.com
|
||||||
|
|
||||||
|
- name: Generate selfsigned certificate
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/cert.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
provider: selfsigned
|
||||||
|
selfsigned_digest: sha256
|
||||||
|
register: selfsigned_certificate
|
||||||
|
|
||||||
|
- name: Generate selfsigned certificate
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/cert.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
provider: selfsigned
|
||||||
|
selfsigned_digest: sha256
|
||||||
|
register: selfsigned_certificate_idempotence
|
||||||
|
|
||||||
|
- name: Generate selfsigned certificate (check mode)
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/cert.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
provider: selfsigned
|
||||||
|
selfsigned_digest: sha256
|
||||||
|
check_mode: yes
|
||||||
|
|
||||||
|
- name: Check selfsigned certificate
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/cert.pem'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
provider: assertonly
|
||||||
|
has_expired: False
|
||||||
|
version: 3
|
||||||
|
signature_algorithms:
|
||||||
|
- sha256WithRSAEncryption
|
||||||
|
- sha256WithECDSAEncryption
|
||||||
|
subject:
|
||||||
|
commonName: www.example.com
|
||||||
|
|
||||||
|
- name: Generate selfsigned v2 certificate
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/cert_v2.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey.pem'
|
||||||
|
provider: selfsigned
|
||||||
|
selfsigned_digest: sha256
|
||||||
|
selfsigned_version: 2
|
||||||
|
|
||||||
|
- name: Generate privatekey2
|
||||||
|
openssl_privatekey:
|
||||||
|
path: '{{ output_dir }}/privatekey2.pem'
|
||||||
|
|
||||||
|
- name: Generate CSR2
|
||||||
|
openssl_csr:
|
||||||
|
subject:
|
||||||
|
CN: www.example.com
|
||||||
|
C: US
|
||||||
|
ST: California
|
||||||
|
L: Los Angeles
|
||||||
|
O: ACME Inc.
|
||||||
|
OU:
|
||||||
|
- Roadrunner pest control
|
||||||
|
- Pyrotechnics
|
||||||
|
path: '{{ output_dir }}/csr2.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey2.pem'
|
||||||
|
keyUsage:
|
||||||
|
- digitalSignature
|
||||||
|
extendedKeyUsage:
|
||||||
|
- ipsecUser
|
||||||
|
- biometricInfo
|
||||||
|
|
||||||
|
- name: Generate selfsigned certificate2
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/cert2.pem'
|
||||||
|
csr_path: '{{ output_dir }}/csr2.csr'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey2.pem'
|
||||||
|
provider: selfsigned
|
||||||
|
selfsigned_digest: sha256
|
||||||
|
|
||||||
|
- name: Check selfsigned certificate2
|
||||||
|
openssl_certificate:
|
||||||
|
path: '{{ output_dir }}/cert2.pem'
|
||||||
|
privatekey_path: '{{ output_dir }}/privatekey2.pem'
|
||||||
|
provider: assertonly
|
||||||
|
has_expired: False
|
||||||
|
version: 3
|
||||||
|
signature_algorithms:
|
||||||
|
- sha256WithRSAEncryption
|
||||||
|
- sha256WithECDSAEncryption
|
||||||
|
subject:
|
||||||
|
commonName: www.example.com
|
||||||
|
C: US
|
||||||
|
ST: California
|
||||||
|
L: Los Angeles
|
||||||
|
O: ACME Inc.
|
||||||
|
OU:
|
||||||
|
- Roadrunner pest control
|
||||||
|
- Pyrotechnics
|
||||||
|
keyUsage:
|
||||||
|
- digitalSignature
|
||||||
|
extendedKeyUsage:
|
||||||
|
- ipsecUser
|
||||||
|
- biometricInfo
|
||||||
|
|
||||||
|
- import_tasks: ../tests/validate_selfsigned.yml
|
|
@ -0,0 +1,48 @@
|
||||||
|
- name: Validate ownca certificate (test - verify CA)
|
||||||
|
shell: 'openssl verify -CAfile {{ output_dir }}/ca_cert.pem {{ output_dir }}/ownca_cert.pem | sed "s/.*: \(.*\)/\1/g"'
|
||||||
|
register: ownca_verify_ca
|
||||||
|
|
||||||
|
- name: Validate ownca certificate (test - ownca certificate modulus)
|
||||||
|
shell: 'openssl x509 -noout -modulus -in {{ output_dir }}/ownca_cert.pem'
|
||||||
|
register: ownca_cert_modulus
|
||||||
|
|
||||||
|
- name: Validate ownca certificate (test - ownca issuer value)
|
||||||
|
shell: 'openssl x509 -noout -in {{ output_dir}}/ownca_cert.pem -text | grep "Issuer" | sed "s/.*: \(.*\)/\1/g"'
|
||||||
|
register: ownca_cert_issuer
|
||||||
|
|
||||||
|
- name: Validate ownca certificate (test - ownca certficate version == default == 3)
|
||||||
|
shell: 'openssl x509 -noout -in {{ output_dir}}/ownca_cert.pem -text | grep "Version" | sed "s/.*: \(.*\) .*/\1/g"'
|
||||||
|
register: ownca_cert_version
|
||||||
|
|
||||||
|
- name: Validate ownca certificate (assert)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- ownca_verify_ca.stdout == 'OK'
|
||||||
|
- ownca_cert_modulus.stdout == privatekey_modulus.stdout
|
||||||
|
- ownca_cert_version.stdout == '3'
|
||||||
|
- ownca_cert_issuer.stdout == 'CN=Example CA'
|
||||||
|
|
||||||
|
- name: Validate ownca certificate idempotence
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- ownca_certificate.serial_number == ownca_certificate_idempotence.serial_number
|
||||||
|
- ownca_certificate.notBefore == ownca_certificate_idempotence.notBefore
|
||||||
|
- ownca_certificate.notAfter == ownca_certificate_idempotence.notAfter
|
||||||
|
|
||||||
|
- name: Validate ownca certificate v2 (test - ownca certificate version == 2)
|
||||||
|
shell: 'openssl x509 -noout -in {{ output_dir}}/ownca_cert_v2.pem -text | grep "Version" | sed "s/.*: \(.*\) .*/\1/g"'
|
||||||
|
register: ownca_cert_v2_version
|
||||||
|
|
||||||
|
- name: Validate ownca certificate version 2 (assert)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- ownca_cert_v2_version.stdout == '2'
|
||||||
|
|
||||||
|
- name: Validate ownca certificate2 (test - ownca certificate modulus)
|
||||||
|
shell: 'openssl x509 -noout -modulus -in {{ output_dir }}/ownca_cert2.pem'
|
||||||
|
register: ownca_cert2_modulus
|
||||||
|
|
||||||
|
- name: Validate ownca certificate2 (assert)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- ownca_cert2_modulus.stdout == privatekey2_modulus.stdout
|
Loading…
Reference in a new issue