Add x509_crl_info filter (#558)
* Add x509_crl_info filter. * Work around bugs in Ansible 2.9 and ansible-base 2.10.pull/562/head
parent
c08bae8308
commit
c173449c46
|
@ -0,0 +1,196 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright (c) 2022, Felix Fontein <felix@fontein.de>
|
||||||
|
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
name: x509_crl_info
|
||||||
|
short_description: Retrieve information from X.509 CRLs in PEM format
|
||||||
|
version_added: 2.10.0
|
||||||
|
author:
|
||||||
|
- Felix Fontein (@felixfontein)
|
||||||
|
description:
|
||||||
|
- Provided a X.509 crl in PEM format, retrieve information.
|
||||||
|
- This is a filter version of the M(community.crypto.x509_crl_info) module.
|
||||||
|
options:
|
||||||
|
_input:
|
||||||
|
description:
|
||||||
|
- The content of the X.509 CRL in PEM format.
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
list_revoked_certificates:
|
||||||
|
description:
|
||||||
|
- If set to C(false), the list of revoked certificates is not included in the result.
|
||||||
|
- This is useful when retrieving information on large CRL files. Enumerating all revoked
|
||||||
|
certificates can take some time, including serializing the result as JSON, sending it to
|
||||||
|
the Ansible controller, and decoding it again.
|
||||||
|
type: bool
|
||||||
|
default: true
|
||||||
|
version_added: 1.7.0
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.crypto.name_encoding
|
||||||
|
seealso:
|
||||||
|
- module: community.crypto.x509_crl_info
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: Show the Organization Name of the CRL's subject
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: >-
|
||||||
|
{{
|
||||||
|
(
|
||||||
|
lookup('ansible.builtin.file', '/path/to/cert.pem')
|
||||||
|
| community.crypto.x509_crl_info
|
||||||
|
).issuer.organizationName
|
||||||
|
}}
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
_value:
|
||||||
|
description:
|
||||||
|
- Information on the CRL.
|
||||||
|
type: dict
|
||||||
|
contains:
|
||||||
|
format:
|
||||||
|
description:
|
||||||
|
- Whether the CRL is in PEM format (C(pem)) or in DER format (C(der)).
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: pem
|
||||||
|
issuer:
|
||||||
|
description:
|
||||||
|
- The CRL's issuer.
|
||||||
|
- Note that for repeated values, only the last one will be returned.
|
||||||
|
- See I(name_encoding) for how IDNs are handled.
|
||||||
|
returned: success
|
||||||
|
type: dict
|
||||||
|
sample: {"organizationName": "Ansible", "commonName": "ca.example.com"}
|
||||||
|
issuer_ordered:
|
||||||
|
description: The CRL's issuer as an ordered list of tuples.
|
||||||
|
returned: success
|
||||||
|
type: list
|
||||||
|
elements: list
|
||||||
|
sample: [["organizationName", "Ansible"], ["commonName": "ca.example.com"]]
|
||||||
|
last_update:
|
||||||
|
description: The point in time from which this CRL can be trusted as ASN.1 TIME.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: '20190413202428Z'
|
||||||
|
next_update:
|
||||||
|
description: The point in time from which a new CRL will be issued and the client has to check for it as ASN.1 TIME.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: '20190413202428Z'
|
||||||
|
digest:
|
||||||
|
description: The signature algorithm used to sign the CRL.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: sha256WithRSAEncryption
|
||||||
|
revoked_certificates:
|
||||||
|
description: List of certificates to be revoked.
|
||||||
|
returned: success if I(list_revoked_certificates=true)
|
||||||
|
type: list
|
||||||
|
elements: dict
|
||||||
|
contains:
|
||||||
|
serial_number:
|
||||||
|
description: Serial number of the certificate.
|
||||||
|
type: int
|
||||||
|
sample: 1234
|
||||||
|
revocation_date:
|
||||||
|
description: The point in time the certificate was revoked as ASN.1 TIME.
|
||||||
|
type: str
|
||||||
|
sample: '20190413202428Z'
|
||||||
|
issuer:
|
||||||
|
description:
|
||||||
|
- The certificate's issuer.
|
||||||
|
- See I(name_encoding) for how IDNs are handled.
|
||||||
|
type: list
|
||||||
|
elements: str
|
||||||
|
sample: ["DNS:ca.example.org"]
|
||||||
|
issuer_critical:
|
||||||
|
description: Whether the certificate issuer extension is critical.
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
reason:
|
||||||
|
description:
|
||||||
|
- The value for the revocation reason extension.
|
||||||
|
- One of C(unspecified), C(key_compromise), C(ca_compromise), C(affiliation_changed), C(superseded),
|
||||||
|
C(cessation_of_operation), C(certificate_hold), C(privilege_withdrawn), C(aa_compromise), and
|
||||||
|
C(remove_from_crl).
|
||||||
|
type: str
|
||||||
|
sample: key_compromise
|
||||||
|
reason_critical:
|
||||||
|
description: Whether the revocation reason extension is critical.
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
invalidity_date:
|
||||||
|
description: |
|
||||||
|
The point in time it was known/suspected that the private key was compromised
|
||||||
|
or that the certificate otherwise became invalid as ASN.1 TIME.
|
||||||
|
type: str
|
||||||
|
sample: '20190413202428Z'
|
||||||
|
invalidity_date_critical:
|
||||||
|
description: Whether the invalidity date extension is critical.
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
'''
|
||||||
|
|
||||||
|
import base64
|
||||||
|
import binascii
|
||||||
|
|
||||||
|
from ansible.errors import AnsibleFilterError
|
||||||
|
from ansible.module_utils.six import string_types
|
||||||
|
from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
|
||||||
|
|
||||||
|
from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import (
|
||||||
|
OpenSSLObjectError,
|
||||||
|
)
|
||||||
|
|
||||||
|
from ansible_collections.community.crypto.plugins.module_utils.crypto.pem import (
|
||||||
|
identify_pem_format,
|
||||||
|
)
|
||||||
|
|
||||||
|
from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.crl_info import (
|
||||||
|
get_crl_info,
|
||||||
|
)
|
||||||
|
|
||||||
|
from ansible_collections.community.crypto.plugins.plugin_utils.filter_module import FilterModuleMock
|
||||||
|
|
||||||
|
|
||||||
|
def x509_crl_info_filter(data, name_encoding='ignore', list_revoked_certificates=True):
|
||||||
|
'''Extract information from X.509 PEM certificate.'''
|
||||||
|
if not isinstance(data, string_types):
|
||||||
|
raise AnsibleFilterError('The community.crypto.x509_crl_info input must be a text type, not %s' % type(data))
|
||||||
|
if not isinstance(name_encoding, string_types):
|
||||||
|
raise AnsibleFilterError('The name_encoding option must be of a text type, not %s' % type(name_encoding))
|
||||||
|
if not isinstance(list_revoked_certificates, bool):
|
||||||
|
raise AnsibleFilterError('The list_revoked_certificates option must be a boolean, not %s' % type(list_revoked_certificates))
|
||||||
|
name_encoding = to_native(name_encoding)
|
||||||
|
if name_encoding not in ('ignore', 'idna', 'unicode'):
|
||||||
|
raise AnsibleFilterError('The name_encoding option must be one of the values "ignore", "idna", or "unicode", not "%s"' % name_encoding)
|
||||||
|
|
||||||
|
data = to_bytes(data)
|
||||||
|
if not identify_pem_format(data):
|
||||||
|
try:
|
||||||
|
data = base64.b64decode(to_native(data))
|
||||||
|
except (binascii.Error, TypeError, ValueError, UnicodeEncodeError) as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
module = FilterModuleMock({'name_encoding': name_encoding})
|
||||||
|
try:
|
||||||
|
return get_crl_info(module, content=data, list_revoked_certificates=list_revoked_certificates)
|
||||||
|
except OpenSSLObjectError as exc:
|
||||||
|
raise AnsibleFilterError(to_native(exc))
|
||||||
|
|
||||||
|
|
||||||
|
class FilterModule(object):
|
||||||
|
'''Ansible jinja2 filters'''
|
||||||
|
|
||||||
|
def filters(self):
|
||||||
|
return {
|
||||||
|
'x509_crl_info': x509_crl_info_filter,
|
||||||
|
}
|
|
@ -50,6 +50,10 @@ notes:
|
||||||
They are all in UTC.
|
They are all in UTC.
|
||||||
seealso:
|
seealso:
|
||||||
- module: community.crypto.x509_crl
|
- module: community.crypto.x509_crl
|
||||||
|
- ref: community.crypto.x509_crl_info filter <ansible_collections.community.crypto.x509_crl_info_filter>
|
||||||
|
# - plugin: community.crypto.x509_crl_info
|
||||||
|
# plugin_type: filter
|
||||||
|
description: A filter variant of this module.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
EXAMPLES = r'''
|
EXAMPLES = r'''
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Copyright (c) Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
azp/generic/2
|
||||||
|
azp/posix/2
|
||||||
|
destructive
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
# Copyright (c) Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
- setup_openssl
|
||||||
|
- setup_remote_tmp_dir
|
|
@ -0,0 +1,346 @@
|
||||||
|
---
|
||||||
|
# Copyright (c) Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
- name: Create CRL 1
|
||||||
|
x509_crl:
|
||||||
|
path: '{{ remote_tmp_dir }}/ca-crl1.crl'
|
||||||
|
privatekey_path: '{{ remote_tmp_dir }}/ca.key'
|
||||||
|
issuer:
|
||||||
|
CN: Ansible
|
||||||
|
last_update: 20191013000000Z
|
||||||
|
next_update: 20191113000000Z
|
||||||
|
revoked_certificates:
|
||||||
|
- path: '{{ remote_tmp_dir }}/cert-1.pem'
|
||||||
|
revocation_date: 20191013000000Z
|
||||||
|
- path: '{{ remote_tmp_dir }}/cert-2.pem'
|
||||||
|
revocation_date: 20191013000000Z
|
||||||
|
reason: key_compromise
|
||||||
|
reason_critical: yes
|
||||||
|
invalidity_date: 20191012000000Z
|
||||||
|
- serial_number: 1234
|
||||||
|
revocation_date: 20191001000000Z
|
||||||
|
|
||||||
|
- name: Retrieve CRL 1 infos
|
||||||
|
set_fact:
|
||||||
|
crl_1_info_1: >-
|
||||||
|
{{ lookup('file', remote_tmp_dir ~ '/ca-crl1.crl') | community.crypto.x509_crl_info }}
|
||||||
|
|
||||||
|
- name: Retrieve CRL 1 infos
|
||||||
|
set_fact:
|
||||||
|
crl_1_info_2: >-
|
||||||
|
{{ lookup('file', remote_tmp_dir ~ '/ca-crl1.crl') | b64encode | community.crypto.x509_crl_info }}
|
||||||
|
|
||||||
|
- name: Validate CRL 1 info
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- crl_1_info_1.format == 'pem'
|
||||||
|
- crl_1_info_1.digest == 'ecdsa-with-SHA256'
|
||||||
|
- crl_1_info_1.issuer | length == 1
|
||||||
|
- crl_1_info_1.issuer.commonName == 'Ansible'
|
||||||
|
- crl_1_info_1.issuer_ordered | length == 1
|
||||||
|
- crl_1_info_1.last_update == '20191013000000Z'
|
||||||
|
- crl_1_info_1.next_update == '20191113000000Z'
|
||||||
|
- crl_1_info_1.revoked_certificates | length == 3
|
||||||
|
- crl_1_info_1.revoked_certificates[0].invalidity_date is none
|
||||||
|
- crl_1_info_1.revoked_certificates[0].invalidity_date_critical == false
|
||||||
|
- crl_1_info_1.revoked_certificates[0].issuer is none
|
||||||
|
- crl_1_info_1.revoked_certificates[0].issuer_critical == false
|
||||||
|
- crl_1_info_1.revoked_certificates[0].reason is none
|
||||||
|
- crl_1_info_1.revoked_certificates[0].reason_critical == false
|
||||||
|
- crl_1_info_1.revoked_certificates[0].revocation_date == '20191013000000Z'
|
||||||
|
- crl_1_info_1.revoked_certificates[0].serial_number == certificate_infos.results[0].serial_number
|
||||||
|
- crl_1_info_1.revoked_certificates[1].invalidity_date == '20191012000000Z'
|
||||||
|
- crl_1_info_1.revoked_certificates[1].invalidity_date_critical == false
|
||||||
|
- crl_1_info_1.revoked_certificates[1].issuer is none
|
||||||
|
- crl_1_info_1.revoked_certificates[1].issuer_critical == false
|
||||||
|
- crl_1_info_1.revoked_certificates[1].reason == 'key_compromise'
|
||||||
|
- crl_1_info_1.revoked_certificates[1].reason_critical == true
|
||||||
|
- crl_1_info_1.revoked_certificates[1].revocation_date == '20191013000000Z'
|
||||||
|
- crl_1_info_1.revoked_certificates[1].serial_number == certificate_infos.results[1].serial_number
|
||||||
|
- crl_1_info_1.revoked_certificates[2].invalidity_date is none
|
||||||
|
- crl_1_info_1.revoked_certificates[2].invalidity_date_critical == false
|
||||||
|
- crl_1_info_1.revoked_certificates[2].issuer is none
|
||||||
|
- crl_1_info_1.revoked_certificates[2].issuer_critical == false
|
||||||
|
- crl_1_info_1.revoked_certificates[2].reason is none
|
||||||
|
- crl_1_info_1.revoked_certificates[2].reason_critical == false
|
||||||
|
- crl_1_info_1.revoked_certificates[2].revocation_date == '20191001000000Z'
|
||||||
|
- crl_1_info_1.revoked_certificates[2].serial_number == 1234
|
||||||
|
- crl_1_info_1 == crl_1_info_2
|
||||||
|
|
||||||
|
- name: Recreate CRL 1 as DER file
|
||||||
|
x509_crl:
|
||||||
|
path: '{{ remote_tmp_dir }}/ca-crl1.crl'
|
||||||
|
privatekey_path: '{{ remote_tmp_dir }}/ca.key'
|
||||||
|
format: der
|
||||||
|
issuer:
|
||||||
|
CN: Ansible
|
||||||
|
last_update: 20191013000000Z
|
||||||
|
next_update: 20191113000000Z
|
||||||
|
revoked_certificates:
|
||||||
|
- path: '{{ remote_tmp_dir }}/cert-1.pem'
|
||||||
|
revocation_date: 20191013000000Z
|
||||||
|
- path: '{{ remote_tmp_dir }}/cert-2.pem'
|
||||||
|
revocation_date: 20191013000000Z
|
||||||
|
reason: key_compromise
|
||||||
|
reason_critical: yes
|
||||||
|
invalidity_date: 20191012000000Z
|
||||||
|
- serial_number: 1234
|
||||||
|
revocation_date: 20191001000000Z
|
||||||
|
|
||||||
|
- name: Read ca-crl1.crl
|
||||||
|
slurp:
|
||||||
|
src: "{{ remote_tmp_dir }}/ca-crl1.crl"
|
||||||
|
register: content
|
||||||
|
|
||||||
|
- name: Retrieve CRL 1 infos from DER (raw bytes)
|
||||||
|
set_fact:
|
||||||
|
crl_1_info_4: >-
|
||||||
|
{{ content.content | b64decode | community.crypto.x509_crl_info }}
|
||||||
|
# Ansible 2.9 and ansible-base 2.10 on Python 2 mangle bytes, so do not run this on these versions
|
||||||
|
when: ansible_version.string is version('2.11', '>=') or ansible_python.version.major > 2
|
||||||
|
|
||||||
|
- name: Retrieve CRL 1 infos from DER (Base64 encoded)
|
||||||
|
set_fact:
|
||||||
|
crl_1_info_5: >-
|
||||||
|
{{ content.content | community.crypto.x509_crl_info }}
|
||||||
|
|
||||||
|
- name: Validate CRL 1
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- crl_1_info_4 is not defined or crl_1_info_4.format == 'der'
|
||||||
|
- crl_1_info_5.format == 'der'
|
||||||
|
- crl_1_info_4 is not defined or crl_1_info_4 == crl_1_info_5
|
||||||
|
|
||||||
|
- name: Create CRL 2
|
||||||
|
x509_crl:
|
||||||
|
path: '{{ remote_tmp_dir }}/ca-crl2.crl'
|
||||||
|
privatekey_path: '{{ remote_tmp_dir }}/ca.key'
|
||||||
|
issuer_ordered:
|
||||||
|
- CN: Ansible
|
||||||
|
- CN: CRL
|
||||||
|
- countryName: US
|
||||||
|
- CN: Test
|
||||||
|
last_update: +0d
|
||||||
|
next_update: +0d
|
||||||
|
revoked_certificates:
|
||||||
|
- path: '{{ remote_tmp_dir }}/cert-2.pem'
|
||||||
|
reason: key_compromise
|
||||||
|
reason_critical: yes
|
||||||
|
invalidity_date: 20191012000000Z
|
||||||
|
ignore_timestamps: no
|
||||||
|
mode: update
|
||||||
|
return_content: yes
|
||||||
|
register: crl_2_change
|
||||||
|
|
||||||
|
- name: Retrieve CRL 2 infos
|
||||||
|
set_fact:
|
||||||
|
crl_2_info_1: >-
|
||||||
|
{{ lookup('file', remote_tmp_dir ~ '/ca-crl2.crl') | community.crypto.x509_crl_info(list_revoked_certificates=false) }}
|
||||||
|
|
||||||
|
- name: Create CRL 2 (changed order)
|
||||||
|
x509_crl:
|
||||||
|
path: '{{ remote_tmp_dir }}/ca-crl2.crl'
|
||||||
|
privatekey_path: '{{ remote_tmp_dir }}/ca.key'
|
||||||
|
issuer_ordered:
|
||||||
|
- CN: Ansible
|
||||||
|
- countryName: US
|
||||||
|
- CN: CRL
|
||||||
|
- CN: Test
|
||||||
|
last_update: +0d
|
||||||
|
next_update: +0d
|
||||||
|
revoked_certificates:
|
||||||
|
- path: '{{ remote_tmp_dir }}/cert-2.pem'
|
||||||
|
reason: key_compromise
|
||||||
|
reason_critical: yes
|
||||||
|
invalidity_date: 20191012000000Z
|
||||||
|
ignore_timestamps: true
|
||||||
|
mode: update
|
||||||
|
return_content: yes
|
||||||
|
register: crl_2_change_order
|
||||||
|
|
||||||
|
- name: Retrieve CRL 2 infos again
|
||||||
|
set_fact:
|
||||||
|
crl_2_info_2: >-
|
||||||
|
{{ lookup('file', remote_tmp_dir ~ '/ca-crl2.crl') | community.crypto.x509_crl_info(list_revoked_certificates=false) }}
|
||||||
|
|
||||||
|
- name: Validate CRL 2 info
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "'revoked_certificates' not in crl_2_info_1"
|
||||||
|
- >
|
||||||
|
crl_2_info_1.issuer_ordered == [
|
||||||
|
['commonName', 'Ansible'],
|
||||||
|
['commonName', 'CRL'],
|
||||||
|
['countryName', 'US'],
|
||||||
|
['commonName', 'Test'],
|
||||||
|
]
|
||||||
|
- >
|
||||||
|
crl_2_info_2.issuer_ordered == [
|
||||||
|
['commonName', 'Ansible'],
|
||||||
|
['countryName', 'US'],
|
||||||
|
['commonName', 'CRL'],
|
||||||
|
['commonName', 'Test'],
|
||||||
|
]
|
||||||
|
|
||||||
|
- name: Create CRL 3
|
||||||
|
x509_crl:
|
||||||
|
path: '{{ remote_tmp_dir }}/ca-crl3.crl'
|
||||||
|
privatekey_path: '{{ remote_tmp_dir }}/ca.key'
|
||||||
|
issuer:
|
||||||
|
CN: Ansible
|
||||||
|
last_update: +0d
|
||||||
|
next_update: +0d
|
||||||
|
revoked_certificates:
|
||||||
|
- serial_number: 1234
|
||||||
|
revocation_date: 20191001000000Z
|
||||||
|
# * cryptography < 2.1 strips username and password from URIs. To avoid problems, we do
|
||||||
|
# not pass usernames and passwords for URIs when the cryptography version is < 2.1.
|
||||||
|
# * Python 3.5 before 3.5.8 rc 1 has a bug in urllib.parse.urlparse() that results in an
|
||||||
|
# error if a Unicode netloc has a username or password included.
|
||||||
|
# (https://github.com/ansible-collections/community.crypto/pull/436#issuecomment-1101737134)
|
||||||
|
# This affects the Python 3.5 included in Ansible 2.9's default test container; to avoid
|
||||||
|
# this, we also do not pass usernames and passwords for Python 3.5.
|
||||||
|
issuer:
|
||||||
|
- "DNS:ca.example.org"
|
||||||
|
- "DNS:ffóò.ḃâŗ.çøṁ"
|
||||||
|
- "email:foo@ḃâŗ.çøṁ"
|
||||||
|
- "URI:https://{{ '' if cryptography_version.stdout is version('2.1', '<') or ansible_facts.python.version.minor == 5 else 'admin:hunter2@' }}ffóò.ḃâŗ.çøṁ/baz?foo=bar"
|
||||||
|
- "URI:https://{{ '' if cryptography_version.stdout is version('2.1', '<') or ansible_facts.python.version.minor == 5 else 'goo@' }}www.straße.de"
|
||||||
|
- "URI:https://straße.de:8080"
|
||||||
|
- "URI:http://gefäß.org"
|
||||||
|
- "URI:http://{{ '' if cryptography_version.stdout is version('2.1', '<') or ansible_facts.python.version.minor == 5 else 'a:b@' }}ä:1"
|
||||||
|
issuer_critical: true
|
||||||
|
register: crl_3
|
||||||
|
|
||||||
|
- name: Create CRL 3 (IDNA encoding)
|
||||||
|
x509_crl:
|
||||||
|
path: '{{ remote_tmp_dir }}/ca-crl3.crl'
|
||||||
|
privatekey_path: '{{ remote_tmp_dir }}/ca.key'
|
||||||
|
issuer:
|
||||||
|
CN: Ansible
|
||||||
|
last_update: +0d
|
||||||
|
next_update: +0d
|
||||||
|
revoked_certificates:
|
||||||
|
- serial_number: 1234
|
||||||
|
revocation_date: 20191001000000Z
|
||||||
|
issuer:
|
||||||
|
- "DNS:ca.example.org"
|
||||||
|
- "DNS:xn--ff-3jad.xn--2ca8uh37e.xn--7ca8a981n"
|
||||||
|
- "email:foo@xn--2ca8uh37e.xn--7ca8a981n"
|
||||||
|
- "URI:https://{{ '' if cryptography_version.stdout is version('2.1', '<') or ansible_facts.python.version.minor == 5 else 'admin:hunter2@' }}xn--ff-3jad.xn--2ca8uh37e.xn--7ca8a981n/baz?foo=bar"
|
||||||
|
- "URI:https://{{ '' if cryptography_version.stdout is version('2.1', '<') or ansible_facts.python.version.minor == 5 else 'goo@' }}www.xn--strae-oqa.de"
|
||||||
|
- "URI:https://xn--strae-oqa.de:8080"
|
||||||
|
- "URI:http://xn--gef-7kay.org"
|
||||||
|
- "URI:http://{{ '' if cryptography_version.stdout is version('2.1', '<') or ansible_facts.python.version.minor == 5 else 'a:b@' }}xn--4ca:1"
|
||||||
|
issuer_critical: true
|
||||||
|
ignore_timestamps: true
|
||||||
|
name_encoding: idna
|
||||||
|
register: crl_3_idna
|
||||||
|
|
||||||
|
- name: Create CRL 3 (Unicode encoding)
|
||||||
|
x509_crl:
|
||||||
|
path: '{{ remote_tmp_dir }}/ca-crl3.crl'
|
||||||
|
privatekey_path: '{{ remote_tmp_dir }}/ca.key'
|
||||||
|
issuer:
|
||||||
|
CN: Ansible
|
||||||
|
last_update: +0d
|
||||||
|
next_update: +0d
|
||||||
|
revoked_certificates:
|
||||||
|
- serial_number: 1234
|
||||||
|
revocation_date: 20191001000000Z
|
||||||
|
issuer:
|
||||||
|
- "DNS:ca.example.org"
|
||||||
|
- "DNS:ffóò.ḃâŗ.çøṁ"
|
||||||
|
- "email:foo@ḃâŗ.çøṁ"
|
||||||
|
- "URI:https://{{ '' if cryptography_version.stdout is version('2.1', '<') or ansible_facts.python.version.minor == 5 else 'admin:hunter2@' }}ffóò.ḃâŗ.çøṁ/baz?foo=bar"
|
||||||
|
- "URI:https://{{ '' if cryptography_version.stdout is version('2.1', '<') or ansible_facts.python.version.minor == 5 else 'goo@' }}www.straße.de"
|
||||||
|
- "URI:https://straße.de:8080"
|
||||||
|
- "URI:http://gefäß.org"
|
||||||
|
- "URI:http://{{ '' if cryptography_version.stdout is version('2.1', '<') or ansible_facts.python.version.minor == 5 else 'a:b@' }}ä:1"
|
||||||
|
issuer_critical: true
|
||||||
|
ignore_timestamps: true
|
||||||
|
name_encoding: unicode
|
||||||
|
register: crl_3_unicode
|
||||||
|
|
||||||
|
- name: Retrieve CRL 3 infos
|
||||||
|
set_fact:
|
||||||
|
crl_3_info: >-
|
||||||
|
{{ lookup('file', remote_tmp_dir ~ '/ca-crl3.crl') | community.crypto.x509_crl_info(list_revoked_certificates=true) }}
|
||||||
|
crl_3_info_idna: >-
|
||||||
|
{{ lookup('file', remote_tmp_dir ~ '/ca-crl3.crl') | community.crypto.x509_crl_info(list_revoked_certificates=true, name_encoding='idna') }}
|
||||||
|
crl_3_info_unicode: >-
|
||||||
|
{{ lookup('file', remote_tmp_dir ~ '/ca-crl3.crl') | community.crypto.x509_crl_info(list_revoked_certificates=true, name_encoding='unicode') }}
|
||||||
|
|
||||||
|
- name: Validate CRL 3 info
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- crl_3.revoked_certificates == crl_3_info.revoked_certificates
|
||||||
|
- crl_3_idna.revoked_certificates == crl_3_info_idna.revoked_certificates
|
||||||
|
- crl_3_unicode.revoked_certificates == crl_3_info_unicode.revoked_certificates
|
||||||
|
|
||||||
|
- name: Get invalid CRL info
|
||||||
|
set_fact:
|
||||||
|
result: >-
|
||||||
|
{{ [] | community.crypto.x509_crl_info }}
|
||||||
|
ignore_errors: true
|
||||||
|
register: output
|
||||||
|
|
||||||
|
- name: Check that task failed and error message is OK
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- output is failed
|
||||||
|
- output.msg is search("^The community.crypto.x509_crl_info input must be a text type, not <(?:class|type) 'list'>$")
|
||||||
|
|
||||||
|
- name: Get invalid CRL info
|
||||||
|
set_fact:
|
||||||
|
result: >-
|
||||||
|
{{ 'foo' | community.crypto.x509_crl_info }}
|
||||||
|
ignore_errors: true
|
||||||
|
register: output
|
||||||
|
|
||||||
|
- name: Check that task failed and error message is OK
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- output is failed
|
||||||
|
- output.msg is search("^Error while decoding CRL")
|
||||||
|
|
||||||
|
- name: Get invalid CRL info
|
||||||
|
set_fact:
|
||||||
|
result: >-
|
||||||
|
{{ 'foo' | community.crypto.x509_crl_info(name_encoding=[]) }}
|
||||||
|
ignore_errors: true
|
||||||
|
register: output
|
||||||
|
|
||||||
|
- name: Check that task failed and error message is OK
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- output is failed
|
||||||
|
- output.msg is search("^The name_encoding option must be of a text type, not <(?:class|type) 'list'>$")
|
||||||
|
|
||||||
|
- name: Get invalid name_encoding parameter
|
||||||
|
set_fact:
|
||||||
|
result: >-
|
||||||
|
{{ 'bar' | community.crypto.x509_crl_info(name_encoding='foo') }}
|
||||||
|
ignore_errors: true
|
||||||
|
register: output
|
||||||
|
|
||||||
|
- name: Check that task failed and error message is OK
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- output is failed
|
||||||
|
- output.msg is search("^The name_encoding option must be one of the values \"ignore\", \"idna\", or \"unicode\", not \"foo\"$")
|
||||||
|
|
||||||
|
- name: Get invalid list_revoked_certificates parameter
|
||||||
|
set_fact:
|
||||||
|
result: >-
|
||||||
|
{{ 'bar' | community.crypto.x509_crl_info(list_revoked_certificates=[]) }}
|
||||||
|
ignore_errors: true
|
||||||
|
register: output
|
||||||
|
|
||||||
|
- name: Check that task failed and error message is OK
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- output is failed
|
||||||
|
- output.msg is search("^The list_revoked_certificates option must be a boolean, not <(?:class|type) 'list'>$")
|
|
@ -0,0 +1,91 @@
|
||||||
|
---
|
||||||
|
# Copyright (c) Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
####################################################################
|
||||||
|
# WARNING: These are designed specifically for Ansible tests #
|
||||||
|
# and should not be used as examples of how to write Ansible roles #
|
||||||
|
####################################################################
|
||||||
|
|
||||||
|
- name: Make sure the Python idna library is installed
|
||||||
|
pip:
|
||||||
|
name: idna
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
certificates:
|
||||||
|
- name: ca
|
||||||
|
subject:
|
||||||
|
commonName: Ansible
|
||||||
|
is_ca: yes
|
||||||
|
- name: ca-2
|
||||||
|
subject:
|
||||||
|
commonName: Ansible Other CA
|
||||||
|
is_ca: yes
|
||||||
|
- name: cert-1
|
||||||
|
subject_alt_name:
|
||||||
|
- DNS:ansible.com
|
||||||
|
- name: cert-2
|
||||||
|
subject_alt_name:
|
||||||
|
- DNS:example.com
|
||||||
|
- name: cert-3
|
||||||
|
subject_alt_name:
|
||||||
|
- DNS:example.org
|
||||||
|
- IP:1.2.3.4
|
||||||
|
- name: cert-4
|
||||||
|
subject_alt_name:
|
||||||
|
- DNS:test.ansible.com
|
||||||
|
- DNS:b64.ansible.com
|
||||||
|
|
||||||
|
- name: Generate private keys
|
||||||
|
openssl_privatekey:
|
||||||
|
path: '{{ remote_tmp_dir }}/{{ item.name }}.key'
|
||||||
|
type: ECC
|
||||||
|
curve: secp256r1
|
||||||
|
loop: "{{ certificates }}"
|
||||||
|
|
||||||
|
- name: Generate CSRs
|
||||||
|
openssl_csr:
|
||||||
|
path: '{{ remote_tmp_dir }}/{{ item.name }}.csr'
|
||||||
|
privatekey_path: '{{ remote_tmp_dir }}/{{ item.name }}.key'
|
||||||
|
subject: "{{ item.subject | default(omit) }}"
|
||||||
|
subject_alt_name: "{{ item.subject_alt_name | default(omit) }}"
|
||||||
|
basic_constraints: "{{ 'CA:TRUE' if item.is_ca | default(false) else omit }}"
|
||||||
|
use_common_name_for_san: no
|
||||||
|
loop: "{{ certificates }}"
|
||||||
|
|
||||||
|
- name: Generate CA certificates
|
||||||
|
x509_certificate:
|
||||||
|
path: '{{ remote_tmp_dir }}/{{ item.name }}.pem'
|
||||||
|
csr_path: '{{ remote_tmp_dir }}/{{ item.name }}.csr'
|
||||||
|
privatekey_path: '{{ remote_tmp_dir }}/{{ item.name }}.key'
|
||||||
|
provider: selfsigned
|
||||||
|
loop: "{{ certificates }}"
|
||||||
|
when: item.is_ca | default(false)
|
||||||
|
|
||||||
|
- name: Generate other certificates
|
||||||
|
x509_certificate:
|
||||||
|
path: '{{ remote_tmp_dir }}/{{ item.name }}.pem'
|
||||||
|
csr_path: '{{ remote_tmp_dir }}/{{ item.name }}.csr'
|
||||||
|
provider: ownca
|
||||||
|
ownca_path: '{{ remote_tmp_dir }}/ca.pem'
|
||||||
|
ownca_privatekey_path: '{{ remote_tmp_dir }}/ca.key'
|
||||||
|
loop: "{{ certificates }}"
|
||||||
|
when: not (item.is_ca | default(false))
|
||||||
|
|
||||||
|
- name: Get certificate infos
|
||||||
|
x509_certificate_info:
|
||||||
|
path: '{{ remote_tmp_dir }}/{{ item }}.pem'
|
||||||
|
loop:
|
||||||
|
- cert-1
|
||||||
|
- cert-2
|
||||||
|
- cert-3
|
||||||
|
- cert-4
|
||||||
|
register: certificate_infos
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Running tests
|
||||||
|
include_tasks: impl.yml
|
||||||
|
|
||||||
|
when: cryptography_version.stdout is version('1.2', '>=')
|
Loading…
Reference in New Issue