mirror of
https://github.com/ansible-collections/community.crypto.git
synced 2026-03-26 21:33:25 +00:00
Remove Entrust modules and certificate providers (#900)
* Remove Entrust modules and certificate providers. * Add more information on Entrust removal. * Remove Entrust content from ignore.txt files. * Work around bug in ansible-test.
This commit is contained in:
@@ -1,8 +0,0 @@
|
|||||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
@@ -106,6 +106,6 @@ This collection is primarily licensed and distributed as a whole under the GNU G
|
|||||||
|
|
||||||
See [LICENSES/GPL-3.0-or-later.txt](https://github.com/ansible-collections/community.crypto/blob/main/COPYING) for the full text.
|
See [LICENSES/GPL-3.0-or-later.txt](https://github.com/ansible-collections/community.crypto/blob/main/COPYING) for the full text.
|
||||||
|
|
||||||
Parts of the collection are licensed under the [Apache 2.0 license](https://github.com/ansible-collections/community.crypto/blob/main/LICENSES/Apache-2.0.txt) (`plugins/module_utils/_crypto/_obj2txt.py` and `plugins/module_utils/_crypto/_objects_data.py`), the [BSD 2-Clause license](https://github.com/ansible-collections/community.crypto/blob/main/LICENSES/BSD-2-Clause.txt) (`plugins/module_utils/_ecs/api.py`), the [BSD 3-Clause license](https://github.com/ansible-collections/community.crypto/blob/main/LICENSES/BSD-3-Clause.txt) (`plugins/module_utils/_crypto/_obj2txt.py`). This only applies to vendored files in ``plugins/module_utils/`` and to the ECS module utils.
|
Parts of the collection are licensed under the [Apache 2.0 license](https://github.com/ansible-collections/community.crypto/blob/main/LICENSES/Apache-2.0.txt) (`plugins/module_utils/_crypto/_obj2txt.py` and `plugins/module_utils/_crypto/_objects_data.py`) and the [BSD 3-Clause license](https://github.com/ansible-collections/community.crypto/blob/main/LICENSES/BSD-3-Clause.txt) (`plugins/module_utils/_crypto/_obj2txt.py`). This only applies to vendored files in ``plugins/module_utils/``.
|
||||||
|
|
||||||
All files have a machine readable `SDPX-License-Identifier:` comment denoting its respective license(s) or an equivalent entry in an accompanying `.license` file. Only changelog fragments (which will not be part of a release) are covered by a blanket statement in `REUSE.toml`. This conforms to the [REUSE specification](https://reuse.software/spec/).
|
All files have a machine readable `SDPX-License-Identifier:` comment denoting its respective license(s) or an equivalent entry in an accompanying `.license` file. Only changelog fragments (which will not be part of a release) are covered by a blanket statement in `REUSE.toml`. This conforms to the [REUSE specification](https://reuse.software/spec/).
|
||||||
|
|||||||
6
changelogs/fragments/900-remove-entrust.yml
Normal file
6
changelogs/fragments/900-remove-entrust.yml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
removed_features:
|
||||||
|
- "All Entrust content is being removed since the Entrust service in currently being sunsetted after the sale of Entrust's Public Certificates Business to Sectigo; see `the announcement with key dates <https://www.entrust.com/tls-certificate-information-center>`__ and `the migration brief for customers <https://www.sectigo.com/uploads/resources/EOL_Migration-Brief-End-Customer.pdf>`__ for details. Since this process will be completed in 2025, we decided to remove all Entrust content from community.general 3.0.0 (https://github.com/ansible-collections/community.crypto/issues/895, https://github.com/ansible-collections/community.crypto/pull/901)."
|
||||||
|
- "ecs_certificate - the module has been removed. Please use community.crypto 2.x.y if you need this module (https://github.com/ansible-collections/community.crypto/pull/900)."
|
||||||
|
- "ecs_domain - the module has been removed. Please use community.crypto 2.x.y if you need this module (https://github.com/ansible-collections/community.crypto/pull/900)."
|
||||||
|
- "x509_certificate - the ``entrust`` provider has been removed. Please use community.crypto 2.x.y if you need this provider (https://github.com/ansible-collections/community.crypto/pull/900)."
|
||||||
|
- "x509_certificate_pipe - the ``entrust`` provider has been removed. Please use community.crypto 2.x.y if you need this provider (https://github.com/ansible-collections/community.crypto/pull/900)."
|
||||||
@@ -20,6 +20,14 @@ action_groups:
|
|||||||
|
|
||||||
plugin_routing:
|
plugin_routing:
|
||||||
modules:
|
modules:
|
||||||
|
ecs_certificate:
|
||||||
|
tombstone:
|
||||||
|
removal_version: 3.0.0
|
||||||
|
warning_text: The 'community.crypto.ecs_certificate' module has been removed due to the upcoming sunsetting of the ECS service. Please use community.crypto 2.x.y to continue using this module
|
||||||
|
ecs_domain:
|
||||||
|
tombstone:
|
||||||
|
removal_version: 3.0.0
|
||||||
|
warning_text: The 'community.crypto.ecs_domain' module has been removed due to the upcoming sunsetting of the ECS service. Please use community.crypto 2.x.y to continue using this module.
|
||||||
acme_account_facts:
|
acme_account_facts:
|
||||||
tombstone:
|
tombstone:
|
||||||
removal_version: 2.0.0
|
removal_version: 2.0.0
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
# Copyright (c), Entrust Datacard Corporation, 2019
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# Note that this doc fragment is **PRIVATE** to the collection. It can have breaking changes at any time.
|
|
||||||
# Do not use this from other collections or standalone plugins/modules!
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
class ModuleDocFragment:
|
|
||||||
|
|
||||||
# Plugin options for Entrust Certificate Services (ECS) credentials
|
|
||||||
DOCUMENTATION = r"""
|
|
||||||
options:
|
|
||||||
entrust_api_user:
|
|
||||||
description:
|
|
||||||
- The username for authentication to the Entrust Certificate Services (ECS) API.
|
|
||||||
type: str
|
|
||||||
required: true
|
|
||||||
entrust_api_key:
|
|
||||||
description:
|
|
||||||
- The key (password) for authentication to the Entrust Certificate Services (ECS) API.
|
|
||||||
type: str
|
|
||||||
required: true
|
|
||||||
entrust_api_client_cert_path:
|
|
||||||
description:
|
|
||||||
- The path to the client certificate used to authenticate to the Entrust Certificate Services (ECS) API.
|
|
||||||
type: path
|
|
||||||
required: true
|
|
||||||
entrust_api_client_cert_key_path:
|
|
||||||
description:
|
|
||||||
- The path to the key for the client certificate used to authenticate to the Entrust Certificate Services (ECS) API.
|
|
||||||
type: path
|
|
||||||
required: true
|
|
||||||
entrust_api_specification_path:
|
|
||||||
description:
|
|
||||||
- The path to the specification file defining the Entrust Certificate Services (ECS) API configuration.
|
|
||||||
- You can use this to keep a local copy of the specification to avoid downloading it every time the module is used.
|
|
||||||
type: path
|
|
||||||
default: https://cloud.entrust.net/EntrustCloud/documentation/cms-api-2.1.0.yaml
|
|
||||||
requirements:
|
|
||||||
- "PyYAML >= 3.11"
|
|
||||||
"""
|
|
||||||
@@ -132,91 +132,6 @@ options:
|
|||||||
default: https://acme-v02.api.letsencrypt.org/directory
|
default: https://acme-v02.api.letsencrypt.org/directory
|
||||||
"""
|
"""
|
||||||
|
|
||||||
BACKEND_ENTRUST_DOCUMENTATION = r"""
|
|
||||||
options:
|
|
||||||
entrust_cert_type:
|
|
||||||
description:
|
|
||||||
- Specify the type of certificate requested.
|
|
||||||
- This is only used by the V(entrust) provider.
|
|
||||||
type: str
|
|
||||||
default: STANDARD_SSL
|
|
||||||
choices: [STANDARD_SSL, ADVANTAGE_SSL, UC_SSL, EV_SSL, WILDCARD_SSL, PRIVATE_SSL, PD_SSL, CDS_ENT_LITE, CDS_ENT_PRO, SMIME_ENT]
|
|
||||||
|
|
||||||
entrust_requester_email:
|
|
||||||
description:
|
|
||||||
- The email of the requester of the certificate (for tracking purposes).
|
|
||||||
- This is only used by the V(entrust) provider.
|
|
||||||
- This is required if the provider is V(entrust).
|
|
||||||
type: str
|
|
||||||
|
|
||||||
entrust_requester_name:
|
|
||||||
description:
|
|
||||||
- The name of the requester of the certificate (for tracking purposes).
|
|
||||||
- This is only used by the V(entrust) provider.
|
|
||||||
- This is required if the provider is V(entrust).
|
|
||||||
type: str
|
|
||||||
|
|
||||||
entrust_requester_phone:
|
|
||||||
description:
|
|
||||||
- The phone number of the requester of the certificate (for tracking purposes).
|
|
||||||
- This is only used by the V(entrust) provider.
|
|
||||||
- This is required if the provider is V(entrust).
|
|
||||||
type: str
|
|
||||||
|
|
||||||
entrust_api_user:
|
|
||||||
description:
|
|
||||||
- The username for authentication to the Entrust Certificate Services (ECS) API.
|
|
||||||
- This is only used by the V(entrust) provider.
|
|
||||||
- This is required if the provider is V(entrust).
|
|
||||||
type: str
|
|
||||||
|
|
||||||
entrust_api_key:
|
|
||||||
description:
|
|
||||||
- The key (password) for authentication to the Entrust Certificate Services (ECS) API.
|
|
||||||
- This is only used by the V(entrust) provider.
|
|
||||||
- This is required if the provider is V(entrust).
|
|
||||||
type: str
|
|
||||||
|
|
||||||
entrust_api_client_cert_path:
|
|
||||||
description:
|
|
||||||
- The path to the client certificate used to authenticate to the Entrust Certificate Services (ECS) API.
|
|
||||||
- This is only used by the V(entrust) provider.
|
|
||||||
- This is required if the provider is V(entrust).
|
|
||||||
type: path
|
|
||||||
|
|
||||||
entrust_api_client_cert_key_path:
|
|
||||||
description:
|
|
||||||
- The path to the private key of the client certificate used to authenticate to the Entrust Certificate Services (ECS) API.
|
|
||||||
- This is only used by the V(entrust) provider.
|
|
||||||
- This is required if the provider is V(entrust).
|
|
||||||
type: path
|
|
||||||
|
|
||||||
entrust_not_after:
|
|
||||||
description:
|
|
||||||
- The point in time at which the certificate stops being valid.
|
|
||||||
- Time can be specified either as relative time or as an absolute timestamp.
|
|
||||||
- A valid absolute time format is C(ASN.1 TIME) such as V(2019-06-18).
|
|
||||||
- A valid relative time format is V([+-]timespec) where timespec can be an integer + C([w | d | h | m | s]), such as V(+365d) or V(+32w1d2h)).
|
|
||||||
- Time will always be interpreted as UTC.
|
|
||||||
- Note that only the date (day, month, year) is supported for specifying the expiry date of the issued certificate.
|
|
||||||
- The full date-time is adjusted to EST (GMT -5:00) before issuance, which may result in a certificate with an expiration date one day
|
|
||||||
earlier than expected if a relative time is used.
|
|
||||||
- The minimum certificate lifetime is 90 days, and maximum is three years.
|
|
||||||
- If this value is not specified, the certificate will stop being valid 365 days the date of issue.
|
|
||||||
- This is only used by the V(entrust) provider.
|
|
||||||
- Please note that this value is B(not) covered by the O(ignore_timestamps) option.
|
|
||||||
type: str
|
|
||||||
default: +365d
|
|
||||||
|
|
||||||
entrust_api_specification_path:
|
|
||||||
description:
|
|
||||||
- The path to the specification file defining the Entrust Certificate Services (ECS) API configuration.
|
|
||||||
- You can use this to keep a local copy of the specification to avoid downloading it every time the module is used.
|
|
||||||
- This is only used by the V(entrust) provider.
|
|
||||||
type: path
|
|
||||||
default: https://cloud.entrust.net/EntrustCloud/documentation/cms-api-2.1.0.yaml
|
|
||||||
"""
|
|
||||||
|
|
||||||
BACKEND_OWNCA_DOCUMENTATION = r"""
|
BACKEND_OWNCA_DOCUMENTATION = r"""
|
||||||
description:
|
description:
|
||||||
- The V(ownca) provider is intended for generating an OpenSSL certificate signed with your own
|
- The V(ownca) provider is intended for generating an OpenSSL certificate signed with your own
|
||||||
|
|||||||
@@ -1,297 +0,0 @@
|
|||||||
# Copyright (c) 2016-2017, Yanis Guenane <yanis+ansible@guenane.org>
|
|
||||||
# Copyright (c) 2017, Markus Teufelberger <mteufelberger+ansible@mgit.at>
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# Note that this module util is **PRIVATE** to the collection. It can have breaking changes at any time.
|
|
||||||
# Do not use this from other collections or standalone plugins/modules!
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import datetime
|
|
||||||
import os
|
|
||||||
import typing as t
|
|
||||||
|
|
||||||
from ansible.module_utils.common.text.converters import to_bytes, to_text
|
|
||||||
from ansible_collections.community.crypto.plugins.module_utils._crypto.cryptography_support import (
|
|
||||||
CRYPTOGRAPHY_TIMEZONE,
|
|
||||||
get_not_valid_after,
|
|
||||||
)
|
|
||||||
from ansible_collections.community.crypto.plugins.module_utils._crypto.module_backends.certificate import (
|
|
||||||
CertificateBackend,
|
|
||||||
CertificateError,
|
|
||||||
CertificateProvider,
|
|
||||||
)
|
|
||||||
from ansible_collections.community.crypto.plugins.module_utils._crypto.support import (
|
|
||||||
load_certificate,
|
|
||||||
)
|
|
||||||
from ansible_collections.community.crypto.plugins.module_utils._ecs.api import (
|
|
||||||
ECSClient,
|
|
||||||
RestOperationException,
|
|
||||||
SessionConfigurationException,
|
|
||||||
)
|
|
||||||
from ansible_collections.community.crypto.plugins.module_utils._time import (
|
|
||||||
get_now_datetime,
|
|
||||||
get_relative_time_option,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if t.TYPE_CHECKING:
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible_collections.community.crypto.plugins.module_utils._argspec import (
|
|
||||||
ArgumentSpec,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
from cryptography.x509.oid import NameOID
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class EntrustCertificateBackend(CertificateBackend):
|
|
||||||
def __init__(self, *, module: AnsibleModule) -> None:
|
|
||||||
super().__init__(module=module)
|
|
||||||
self.trackingId = None
|
|
||||||
self.notAfter = get_relative_time_option(
|
|
||||||
module.params["entrust_not_after"],
|
|
||||||
input_name="entrust_not_after",
|
|
||||||
with_timezone=CRYPTOGRAPHY_TIMEZONE,
|
|
||||||
)
|
|
||||||
self.cert_bytes: bytes | None = None
|
|
||||||
|
|
||||||
if self.csr_content is None:
|
|
||||||
if self.csr_path is None:
|
|
||||||
raise CertificateError(
|
|
||||||
"csr_path or csr_content is required for entrust provider"
|
|
||||||
)
|
|
||||||
if not os.path.exists(self.csr_path):
|
|
||||||
raise CertificateError(
|
|
||||||
f"The certificate signing request file {self.csr_path} does not exist"
|
|
||||||
)
|
|
||||||
|
|
||||||
self._ensure_csr_loaded()
|
|
||||||
if self.csr is None:
|
|
||||||
raise CertificateError("CSR not provided")
|
|
||||||
|
|
||||||
# ECS API defaults to using the validated organization tied to the account.
|
|
||||||
# We want to always force behavior of trying to use the organization provided in the CSR.
|
|
||||||
# To that end we need to parse out the organization from the CSR.
|
|
||||||
self.csr_org = None
|
|
||||||
csr_subject_orgs = self.csr.subject.get_attributes_for_oid(
|
|
||||||
NameOID.ORGANIZATION_NAME
|
|
||||||
)
|
|
||||||
if len(csr_subject_orgs) == 1:
|
|
||||||
self.csr_org = csr_subject_orgs[0].value
|
|
||||||
elif len(csr_subject_orgs) > 1:
|
|
||||||
self.module.fail_json(
|
|
||||||
msg=(
|
|
||||||
"Entrust provider does not currently support multiple validated organizations. Multiple organizations found in "
|
|
||||||
f"Subject DN: '{self.csr.subject}'. "
|
|
||||||
)
|
|
||||||
)
|
|
||||||
# If no organization in the CSR, explicitly tell ECS that it should be blank in issued cert, not defaulted to
|
|
||||||
# organization tied to the account.
|
|
||||||
if self.csr_org is None:
|
|
||||||
self.csr_org = ""
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.ecs_client = ECSClient(
|
|
||||||
entrust_api_user=self.module.params["entrust_api_user"],
|
|
||||||
entrust_api_key=self.module.params["entrust_api_key"],
|
|
||||||
entrust_api_cert=self.module.params["entrust_api_client_cert_path"],
|
|
||||||
entrust_api_cert_key=self.module.params[
|
|
||||||
"entrust_api_client_cert_key_path"
|
|
||||||
],
|
|
||||||
entrust_api_specification_path=self.module.params[
|
|
||||||
"entrust_api_specification_path"
|
|
||||||
],
|
|
||||||
)
|
|
||||||
except SessionConfigurationException as e:
|
|
||||||
module.fail_json(msg=f"Failed to initialize Entrust Provider: {e}")
|
|
||||||
|
|
||||||
def generate_certificate(self) -> None:
|
|
||||||
"""(Re-)Generate certificate."""
|
|
||||||
body = {}
|
|
||||||
|
|
||||||
# Read the CSR that was generated for us
|
|
||||||
if self.csr_content is not None:
|
|
||||||
# csr_content contains bytes
|
|
||||||
body["csr"] = to_text(self.csr_content)
|
|
||||||
else:
|
|
||||||
assert self.csr_path is not None
|
|
||||||
with open(self.csr_path, "r", encoding="utf-8") as csr_file:
|
|
||||||
body["csr"] = csr_file.read()
|
|
||||||
|
|
||||||
body["certType"] = self.module.params["entrust_cert_type"]
|
|
||||||
|
|
||||||
# Handle expiration (30 days if not specified)
|
|
||||||
expiry = self.notAfter
|
|
||||||
if not expiry:
|
|
||||||
gmt_now = get_now_datetime(with_timezone=CRYPTOGRAPHY_TIMEZONE)
|
|
||||||
expiry = gmt_now + datetime.timedelta(days=365)
|
|
||||||
|
|
||||||
expiry_iso3339 = expiry.strftime("%Y-%m-%dT%H:%M:%S.00Z")
|
|
||||||
body["certExpiryDate"] = expiry_iso3339
|
|
||||||
body["org"] = self.csr_org
|
|
||||||
body["tracking"] = {
|
|
||||||
"requesterName": self.module.params["entrust_requester_name"],
|
|
||||||
"requesterEmail": self.module.params["entrust_requester_email"],
|
|
||||||
"requesterPhone": self.module.params["entrust_requester_phone"],
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
result = self.ecs_client.NewCertRequest( # type: ignore[attr-defined] # pylint: disable=no-member
|
|
||||||
Body=body
|
|
||||||
)
|
|
||||||
self.trackingId = result.get("trackingId")
|
|
||||||
except RestOperationException as e:
|
|
||||||
self.module.fail_json(
|
|
||||||
msg=f"Failed to request new certificate from Entrust Certificate Services (ECS): {e.message}"
|
|
||||||
)
|
|
||||||
|
|
||||||
self.cert_bytes = to_bytes(result.get("endEntityCert"))
|
|
||||||
self.cert = load_certificate(
|
|
||||||
path=None,
|
|
||||||
content=self.cert_bytes,
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_certificate_data(self) -> bytes:
|
|
||||||
"""Return bytes for self.cert."""
|
|
||||||
if self.cert_bytes is None:
|
|
||||||
raise AssertionError("Contract violation: cert_bytes not set")
|
|
||||||
return self.cert_bytes
|
|
||||||
|
|
||||||
def needs_regeneration(
|
|
||||||
self,
|
|
||||||
*,
|
|
||||||
not_before: datetime.datetime | None = None,
|
|
||||||
not_after: datetime.datetime | None = None,
|
|
||||||
) -> bool:
|
|
||||||
parent_check = super().needs_regeneration()
|
|
||||||
|
|
||||||
try:
|
|
||||||
cert_details = self._get_cert_details()
|
|
||||||
except RestOperationException as e:
|
|
||||||
self.module.fail_json(
|
|
||||||
msg=f"Failed to get status of existing certificate from Entrust Certificate Services (ECS): {e.message}."
|
|
||||||
)
|
|
||||||
|
|
||||||
# Always issue a new certificate if the certificate is expired, suspended or revoked
|
|
||||||
status = cert_details.get("status", False)
|
|
||||||
if status in ("EXPIRED", "SUSPENDED", "REVOKED"):
|
|
||||||
return True
|
|
||||||
|
|
||||||
# If the requested cert type was specified and it is for a different certificate type than the initial certificate, a new one is needed
|
|
||||||
if (
|
|
||||||
self.module.params["entrust_cert_type"]
|
|
||||||
and cert_details.get("certType")
|
|
||||||
and self.module.params["entrust_cert_type"] != cert_details.get("certType")
|
|
||||||
):
|
|
||||||
return True
|
|
||||||
|
|
||||||
return parent_check
|
|
||||||
|
|
||||||
def _get_cert_details(self) -> dict[str, t.Any]:
|
|
||||||
cert_details: dict[str, t.Any] = {}
|
|
||||||
try:
|
|
||||||
self._ensure_existing_certificate_loaded()
|
|
||||||
except Exception:
|
|
||||||
return cert_details
|
|
||||||
if self.existing_certificate:
|
|
||||||
serial_number = f"{self.existing_certificate.serial_number:X}"
|
|
||||||
expiry = get_not_valid_after(self.existing_certificate)
|
|
||||||
|
|
||||||
# get some information about the expiry of this certificate
|
|
||||||
expiry_iso3339 = expiry.strftime("%Y-%m-%dT%H:%M:%S.00Z")
|
|
||||||
cert_details["expiresAfter"] = expiry_iso3339
|
|
||||||
|
|
||||||
# If a trackingId is not already defined (from the result of a generate)
|
|
||||||
# use the serial number to identify the tracking Id
|
|
||||||
if self.trackingId is None and serial_number is not None:
|
|
||||||
cert_results = self.ecs_client.GetCertificates( # type: ignore[attr-defined] # pylint: disable=no-member
|
|
||||||
serialNumber=serial_number
|
|
||||||
).get(
|
|
||||||
"certificates", {}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Finding 0 or more than 1 result is a very unlikely use case, it simply means we cannot perform additional checks
|
|
||||||
# on the 'state' as returned by Entrust Certificate Services (ECS). The general certificate validity is
|
|
||||||
# still checked as it is in the rest of the module.
|
|
||||||
if len(cert_results) == 1:
|
|
||||||
self.trackingId = cert_results[0].get("trackingId")
|
|
||||||
|
|
||||||
if self.trackingId is not None:
|
|
||||||
cert_details.update(
|
|
||||||
self.ecs_client.GetCertificate( # pylint: disable=no-member
|
|
||||||
trackingId=self.trackingId
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return cert_details
|
|
||||||
|
|
||||||
|
|
||||||
class EntrustCertificateProvider(CertificateProvider):
|
|
||||||
def validate_module_args(self, module: AnsibleModule) -> None:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def create_backend(self, module: AnsibleModule) -> EntrustCertificateBackend:
|
|
||||||
return EntrustCertificateBackend(module=module)
|
|
||||||
|
|
||||||
|
|
||||||
def add_entrust_provider_to_argument_spec(argument_spec: ArgumentSpec) -> None:
|
|
||||||
argument_spec.argument_spec["provider"]["choices"].append("entrust")
|
|
||||||
argument_spec.argument_spec.update(
|
|
||||||
{
|
|
||||||
"entrust_cert_type": {
|
|
||||||
"type": "str",
|
|
||||||
"default": "STANDARD_SSL",
|
|
||||||
"choices": [
|
|
||||||
"STANDARD_SSL",
|
|
||||||
"ADVANTAGE_SSL",
|
|
||||||
"UC_SSL",
|
|
||||||
"EV_SSL",
|
|
||||||
"WILDCARD_SSL",
|
|
||||||
"PRIVATE_SSL",
|
|
||||||
"PD_SSL",
|
|
||||||
"CDS_ENT_LITE",
|
|
||||||
"CDS_ENT_PRO",
|
|
||||||
"SMIME_ENT",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"entrust_requester_email": {"type": "str"},
|
|
||||||
"entrust_requester_name": {"type": "str"},
|
|
||||||
"entrust_requester_phone": {"type": "str"},
|
|
||||||
"entrust_api_user": {"type": "str"},
|
|
||||||
"entrust_api_key": {"type": "str", "no_log": True},
|
|
||||||
"entrust_api_client_cert_path": {"type": "path"},
|
|
||||||
"entrust_api_client_cert_key_path": {"type": "path", "no_log": True},
|
|
||||||
"entrust_api_specification_path": {
|
|
||||||
"type": "path",
|
|
||||||
"default": "https://cloud.entrust.net/EntrustCloud/documentation/cms-api-2.1.0.yaml",
|
|
||||||
},
|
|
||||||
"entrust_not_after": {"type": "str", "default": "+365d"},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
argument_spec.required_if.append(
|
|
||||||
(
|
|
||||||
"provider",
|
|
||||||
"entrust",
|
|
||||||
[
|
|
||||||
"entrust_requester_email",
|
|
||||||
"entrust_requester_name",
|
|
||||||
"entrust_requester_phone",
|
|
||||||
"entrust_api_user",
|
|
||||||
"entrust_api_key",
|
|
||||||
"entrust_api_client_cert_path",
|
|
||||||
"entrust_api_client_cert_key_path",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
|
||||||
"EntrustCertificateBackend",
|
|
||||||
"EntrustCertificateProvider",
|
|
||||||
"add_entrust_provider_to_argument_spec",
|
|
||||||
)
|
|
||||||
@@ -1,421 +0,0 @@
|
|||||||
# This code is part of Ansible, but is an independent component.
|
|
||||||
# This particular file snippet, and this file snippet only, is licensed under the
|
|
||||||
# Modified BSD License. Modules you write using this snippet, which is embedded
|
|
||||||
# dynamically by Ansible, still belong to the author of the module, and may assign
|
|
||||||
# their own license to the complete work.
|
|
||||||
#
|
|
||||||
# Copyright (c), Entrust Datacard Corporation, 2019
|
|
||||||
# Simplified BSD License (see LICENSES/BSD-2-Clause.txt or https://opensource.org/licenses/BSD-2-Clause)
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
|
|
||||||
# Note that this module util is **PRIVATE** to the collection. It can have breaking changes at any time.
|
|
||||||
# Do not use this from other collections or standalone plugins/modules!
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import traceback
|
|
||||||
import typing as t
|
|
||||||
from urllib.error import HTTPError
|
|
||||||
from urllib.parse import urlencode
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import missing_required_lib
|
|
||||||
from ansible.module_utils.common.text.converters import to_text
|
|
||||||
from ansible.module_utils.urls import Request
|
|
||||||
|
|
||||||
|
|
||||||
if t.TYPE_CHECKING:
|
|
||||||
_P = t.ParamSpec("_P")
|
|
||||||
|
|
||||||
|
|
||||||
YAML_IMP_ERR = None
|
|
||||||
try:
|
|
||||||
import yaml
|
|
||||||
except ImportError:
|
|
||||||
YAML_FOUND = False
|
|
||||||
YAML_IMP_ERR = traceback.format_exc()
|
|
||||||
else:
|
|
||||||
YAML_FOUND = True
|
|
||||||
|
|
||||||
valid_file_format = re.compile(r".*(\.)(yml|yaml|json)$")
|
|
||||||
|
|
||||||
|
|
||||||
def ecs_client_argument_spec() -> dict[str, t.Any]:
|
|
||||||
return {
|
|
||||||
"entrust_api_user": {"type": "str", "required": True},
|
|
||||||
"entrust_api_key": {"type": "str", "required": True, "no_log": True},
|
|
||||||
"entrust_api_client_cert_path": {"type": "path", "required": True},
|
|
||||||
"entrust_api_client_cert_key_path": {
|
|
||||||
"type": "path",
|
|
||||||
"required": True,
|
|
||||||
"no_log": True,
|
|
||||||
},
|
|
||||||
"entrust_api_specification_path": {
|
|
||||||
"type": "path",
|
|
||||||
"default": "https://cloud.entrust.net/EntrustCloud/documentation/cms-api-2.1.0.yaml",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class SessionConfigurationException(Exception):
|
|
||||||
"""Raised if we cannot configure a session with the API"""
|
|
||||||
|
|
||||||
|
|
||||||
class RestOperationException(Exception):
|
|
||||||
"""Encapsulate a REST API error"""
|
|
||||||
|
|
||||||
def __init__(self, error: dict[str, t.Any]) -> None:
|
|
||||||
self.status = to_text(error.get("status", None))
|
|
||||||
self.errors = [to_text(err.get("message")) for err in error.get("errors", {})]
|
|
||||||
self.message = " ".join(self.errors)
|
|
||||||
|
|
||||||
|
|
||||||
def generate_docstring(operation_spec: dict[str, t.Any]) -> str:
|
|
||||||
"""Generate a docstring for an operation defined in operation_spec (swagger)"""
|
|
||||||
# Description of the operation
|
|
||||||
docs = operation_spec.get("description", "No Description")
|
|
||||||
docs += "\n\n"
|
|
||||||
|
|
||||||
# Parameters of the operation
|
|
||||||
parameters = operation_spec.get("parameters", [])
|
|
||||||
if len(parameters) != 0:
|
|
||||||
docs += "\tArguments:\n\n"
|
|
||||||
for parameter in parameters:
|
|
||||||
req = "Required" if parameter.get("required", False) else "Not Required"
|
|
||||||
docs += f"{parameter.get('name')} ({parameter.get('type', 'No Type')}:{req}): {parameter.get('description')}\n"
|
|
||||||
|
|
||||||
return docs
|
|
||||||
|
|
||||||
|
|
||||||
_T = t.TypeVar("_T")
|
|
||||||
_R = t.TypeVar("_R")
|
|
||||||
|
|
||||||
|
|
||||||
def bind(
|
|
||||||
instance: _T,
|
|
||||||
method: t.Callable[t.Concatenate[_T, _P], _R],
|
|
||||||
operation_spec: dict[str, str],
|
|
||||||
) -> t.Callable[_P, _R]:
|
|
||||||
def binding_scope_fn(*args, **kwargs) -> _R:
|
|
||||||
return method(instance, *args, **kwargs)
|
|
||||||
|
|
||||||
# Make sure we do not confuse users; add the proper name and documentation to the function.
|
|
||||||
# Users can use !help(<function>) to get help on the function from interactive python or pdb
|
|
||||||
operation_name = operation_spec["operationId"].split("Using")[0]
|
|
||||||
binding_scope_fn.__name__ = str(operation_name)
|
|
||||||
binding_scope_fn.__doc__ = generate_docstring(operation_spec)
|
|
||||||
|
|
||||||
return binding_scope_fn
|
|
||||||
|
|
||||||
|
|
||||||
class RestOperation:
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
session: "ECSSession",
|
|
||||||
uri: str,
|
|
||||||
method: str,
|
|
||||||
parameters: dict | None = None,
|
|
||||||
) -> None:
|
|
||||||
self.session = session
|
|
||||||
self.method = method
|
|
||||||
if parameters is None:
|
|
||||||
self.parameters = {}
|
|
||||||
else:
|
|
||||||
self.parameters = parameters
|
|
||||||
self.url = (
|
|
||||||
f"https://{session._spec.get('host')}{session._spec.get('basePath')}{uri}"
|
|
||||||
)
|
|
||||||
|
|
||||||
def restmethod(self, *args, **kwargs) -> t.Any:
|
|
||||||
"""Do the hard work of making the request here"""
|
|
||||||
|
|
||||||
# gather named path parameters and do substitution on the URL
|
|
||||||
body_parameters: dict[str, t.Any] | None
|
|
||||||
if self.parameters:
|
|
||||||
path_parameters = {}
|
|
||||||
body_parameters = {}
|
|
||||||
query_parameters = {}
|
|
||||||
for x in self.parameters:
|
|
||||||
expected_location = x.get("in")
|
|
||||||
key_name = x.get("name", None)
|
|
||||||
key_value = kwargs.get(key_name, None)
|
|
||||||
if expected_location == "path" and key_name and key_value:
|
|
||||||
path_parameters.update({key_name: key_value})
|
|
||||||
elif expected_location == "body" and key_name and key_value:
|
|
||||||
body_parameters.update({key_name: key_value})
|
|
||||||
elif expected_location == "query" and key_name and key_value:
|
|
||||||
query_parameters.update({key_name: key_value})
|
|
||||||
|
|
||||||
if len(body_parameters.keys()) >= 1:
|
|
||||||
body_parameters = body_parameters.get(list(body_parameters.keys())[0])
|
|
||||||
else:
|
|
||||||
body_parameters = None
|
|
||||||
else:
|
|
||||||
path_parameters = {}
|
|
||||||
query_parameters = {}
|
|
||||||
body_parameters = None
|
|
||||||
|
|
||||||
# This will fail if we have not set path parameters with a KeyError
|
|
||||||
url = self.url.format(**path_parameters)
|
|
||||||
if query_parameters:
|
|
||||||
# modify the URL to add path parameters
|
|
||||||
url = url + "?" + urlencode(query_parameters)
|
|
||||||
|
|
||||||
try:
|
|
||||||
if body_parameters:
|
|
||||||
body_parameters_json = json.dumps(body_parameters)
|
|
||||||
response = self.session.request.open(
|
|
||||||
method=self.method, url=url, data=body_parameters_json
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
response = self.session.request.open(method=self.method, url=url)
|
|
||||||
except HTTPError as e:
|
|
||||||
# An HTTPError has the same methods available as a valid response from request.open
|
|
||||||
response = e
|
|
||||||
|
|
||||||
# Return the result if JSON and success ({} for empty responses)
|
|
||||||
# Raise an exception if there was a failure.
|
|
||||||
try:
|
|
||||||
result_code = response.getcode()
|
|
||||||
result = json.loads(response.read())
|
|
||||||
except ValueError:
|
|
||||||
result = {}
|
|
||||||
|
|
||||||
if result or result == {}:
|
|
||||||
if result_code and result_code < 400:
|
|
||||||
return result
|
|
||||||
raise RestOperationException(result)
|
|
||||||
|
|
||||||
# Raise a generic RestOperationException if this fails
|
|
||||||
raise RestOperationException(
|
|
||||||
{"status": result_code, "errors": [{"message": "REST Operation Failed"}]}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Resource:
|
|
||||||
"""Implement basic CRUD operations against a path."""
|
|
||||||
|
|
||||||
def __init__(self, session: "ECSSession") -> None:
|
|
||||||
self.session = session
|
|
||||||
self.parameters: dict[str, t.Any] = {}
|
|
||||||
|
|
||||||
for url in session._spec.get("paths").keys():
|
|
||||||
methods = session._spec.get("paths").get(url)
|
|
||||||
for method in methods.keys():
|
|
||||||
operation_spec = methods.get(method)
|
|
||||||
operation_name = operation_spec.get("operationId", None)
|
|
||||||
parameters = operation_spec.get("parameters")
|
|
||||||
|
|
||||||
if not operation_name:
|
|
||||||
if method.lower() == "post":
|
|
||||||
operation_name = "Create"
|
|
||||||
elif method.lower() == "get":
|
|
||||||
operation_name = "Get"
|
|
||||||
elif method.lower() == "put":
|
|
||||||
operation_name = "Update"
|
|
||||||
elif method.lower() == "delete":
|
|
||||||
operation_name = "Delete"
|
|
||||||
elif method.lower() == "patch":
|
|
||||||
operation_name = "Patch"
|
|
||||||
else:
|
|
||||||
raise SessionConfigurationException(
|
|
||||||
f"Invalid REST method type {method}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Get the non-parameter parts of the URL and append to the operation name
|
|
||||||
# e.g /application/version -> GetApplicationVersion
|
|
||||||
# e.g. /application/{id} -> GetApplication
|
|
||||||
# This may lead to duplicates, which we must prevent.
|
|
||||||
operation_name += (
|
|
||||||
re.sub(r"{(.*)}", "", url)
|
|
||||||
.replace("/", " ")
|
|
||||||
.title()
|
|
||||||
.replace(" ", "")
|
|
||||||
)
|
|
||||||
operation_spec["operationId"] = operation_name
|
|
||||||
|
|
||||||
op = RestOperation(session, url, method, parameters)
|
|
||||||
setattr(self, operation_name, bind(self, op.restmethod, operation_spec))
|
|
||||||
|
|
||||||
|
|
||||||
# Session to encapsulate the connection parameters of the module_utils Request object, the api spec, etc
|
|
||||||
class ECSSession:
|
|
||||||
def __init__(self, name: str, **kwargs) -> None:
|
|
||||||
"""
|
|
||||||
Initialize our session
|
|
||||||
"""
|
|
||||||
|
|
||||||
self._set_config(name, **kwargs)
|
|
||||||
|
|
||||||
def client(self) -> Resource:
|
|
||||||
resource = Resource(self)
|
|
||||||
return resource
|
|
||||||
|
|
||||||
def _set_config(self, name: str, **kwargs) -> None:
|
|
||||||
headers = {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"Connection": "keep-alive",
|
|
||||||
}
|
|
||||||
self.request = Request(headers=headers, timeout=60)
|
|
||||||
|
|
||||||
configurators = [self._read_config_vars]
|
|
||||||
for configurator in configurators:
|
|
||||||
self._config = configurator(name, **kwargs)
|
|
||||||
if self._config:
|
|
||||||
break
|
|
||||||
if self._config is None:
|
|
||||||
raise SessionConfigurationException("No Configuration Found.")
|
|
||||||
|
|
||||||
# set up auth if passed
|
|
||||||
entrust_api_user: str | None = self.get_config("entrust_api_user")
|
|
||||||
entrust_api_key: str | None = self.get_config("entrust_api_key")
|
|
||||||
if entrust_api_user and entrust_api_key:
|
|
||||||
self.request.url_username = entrust_api_user
|
|
||||||
self.request.url_password = entrust_api_key
|
|
||||||
else:
|
|
||||||
raise SessionConfigurationException("User and key must be provided.")
|
|
||||||
|
|
||||||
# set up client certificate if passed (support all-in one or cert + key)
|
|
||||||
entrust_api_cert: str | None = self.get_config("entrust_api_cert")
|
|
||||||
entrust_api_cert_key: str | None = self.get_config("entrust_api_cert_key")
|
|
||||||
if entrust_api_cert:
|
|
||||||
self.request.client_cert = entrust_api_cert
|
|
||||||
if entrust_api_cert_key:
|
|
||||||
self.request.client_key = entrust_api_cert_key
|
|
||||||
else:
|
|
||||||
raise SessionConfigurationException(
|
|
||||||
"Client certificate for authentication to the API must be provided."
|
|
||||||
)
|
|
||||||
|
|
||||||
# set up the spec
|
|
||||||
entrust_api_specification_path = self.get_config(
|
|
||||||
"entrust_api_specification_path"
|
|
||||||
)
|
|
||||||
if not isinstance(entrust_api_specification_path, str):
|
|
||||||
raise SessionConfigurationException(
|
|
||||||
"entrust_api_specification_path must be a string."
|
|
||||||
)
|
|
||||||
|
|
||||||
if not entrust_api_specification_path.startswith("http") and not os.path.isfile(
|
|
||||||
entrust_api_specification_path
|
|
||||||
):
|
|
||||||
raise SessionConfigurationException(
|
|
||||||
f"OpenAPI specification was not found at location {entrust_api_specification_path}."
|
|
||||||
)
|
|
||||||
if not valid_file_format.match(entrust_api_specification_path):
|
|
||||||
raise SessionConfigurationException(
|
|
||||||
"OpenAPI specification filename must end in .json, .yml or .yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
self.verify = True
|
|
||||||
|
|
||||||
if entrust_api_specification_path.startswith("http"):
|
|
||||||
try:
|
|
||||||
http_response = Request().open(
|
|
||||||
method="GET", url=entrust_api_specification_path
|
|
||||||
)
|
|
||||||
http_response_contents = http_response.read()
|
|
||||||
if entrust_api_specification_path.endswith(".json"):
|
|
||||||
self._spec = json.load(http_response_contents)
|
|
||||||
elif entrust_api_specification_path.endswith(
|
|
||||||
".yml"
|
|
||||||
) or entrust_api_specification_path.endswith(".yaml"):
|
|
||||||
self._spec = yaml.safe_load(http_response_contents)
|
|
||||||
except HTTPError as e:
|
|
||||||
raise SessionConfigurationException(
|
|
||||||
f"Error downloading specification from address '{entrust_api_specification_path}', received error code '{e.getcode()}'"
|
|
||||||
) from e
|
|
||||||
else:
|
|
||||||
with open(entrust_api_specification_path, "rb") as f:
|
|
||||||
if ".json" in entrust_api_specification_path:
|
|
||||||
self._spec = json.load(f)
|
|
||||||
elif (
|
|
||||||
".yml" in entrust_api_specification_path
|
|
||||||
or ".yaml" in entrust_api_specification_path
|
|
||||||
):
|
|
||||||
self._spec = yaml.safe_load(f)
|
|
||||||
|
|
||||||
def get_config(self, item: str) -> t.Any | None:
|
|
||||||
return self._config.get(item, None)
|
|
||||||
|
|
||||||
def _read_config_vars(self, name: str, **kwargs) -> dict[str, t.Any]:
|
|
||||||
"""Read configuration from variables passed to the module."""
|
|
||||||
config = {}
|
|
||||||
|
|
||||||
entrust_api_specification_path = kwargs.get("entrust_api_specification_path")
|
|
||||||
if not entrust_api_specification_path or (
|
|
||||||
not entrust_api_specification_path.startswith("http")
|
|
||||||
and not os.path.isfile(entrust_api_specification_path)
|
|
||||||
):
|
|
||||||
raise SessionConfigurationException(
|
|
||||||
f"Parameter provided for entrust_api_specification_path of value '{entrust_api_specification_path}'"
|
|
||||||
" was not a valid file path or HTTPS address."
|
|
||||||
)
|
|
||||||
|
|
||||||
for required_file in ["entrust_api_cert", "entrust_api_cert_key"]:
|
|
||||||
file_path = kwargs.get(required_file)
|
|
||||||
if not file_path or not os.path.isfile(file_path):
|
|
||||||
raise SessionConfigurationException(
|
|
||||||
f"Parameter provided for {required_file} of value '{file_path}' was not a valid file path."
|
|
||||||
)
|
|
||||||
|
|
||||||
for required_var in ["entrust_api_user", "entrust_api_key"]:
|
|
||||||
if not kwargs.get(required_var):
|
|
||||||
raise SessionConfigurationException(
|
|
||||||
f"Parameter provided for {required_var} was missing."
|
|
||||||
)
|
|
||||||
|
|
||||||
config["entrust_api_cert"] = kwargs.get("entrust_api_cert")
|
|
||||||
config["entrust_api_cert_key"] = kwargs.get("entrust_api_cert_key")
|
|
||||||
config["entrust_api_specification_path"] = kwargs.get(
|
|
||||||
"entrust_api_specification_path"
|
|
||||||
)
|
|
||||||
config["entrust_api_user"] = kwargs.get("entrust_api_user")
|
|
||||||
config["entrust_api_key"] = kwargs.get("entrust_api_key")
|
|
||||||
|
|
||||||
return config
|
|
||||||
|
|
||||||
|
|
||||||
def ECSClient(
|
|
||||||
entrust_api_user: str | None = None,
|
|
||||||
entrust_api_key: str | None = None,
|
|
||||||
entrust_api_cert: str | None = None,
|
|
||||||
entrust_api_cert_key: str | None = None,
|
|
||||||
entrust_api_specification_path: str | None = None,
|
|
||||||
) -> Resource:
|
|
||||||
"""Create an ECS client"""
|
|
||||||
|
|
||||||
if not YAML_FOUND:
|
|
||||||
raise SessionConfigurationException(
|
|
||||||
missing_required_lib("PyYAML") # TODO: pass `exception=YAML_IMP_ERR`
|
|
||||||
)
|
|
||||||
|
|
||||||
if entrust_api_specification_path is None:
|
|
||||||
entrust_api_specification_path = (
|
|
||||||
"https://cloud.entrust.net/EntrustCloud/documentation/cms-api-2.1.0.yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Not functionally necessary with current uses of this module_util, but better to be explicit for future use cases
|
|
||||||
entrust_api_user = to_text(entrust_api_user)
|
|
||||||
entrust_api_key = to_text(entrust_api_key)
|
|
||||||
entrust_api_cert_key = to_text(entrust_api_cert_key)
|
|
||||||
entrust_api_specification_path = to_text(entrust_api_specification_path)
|
|
||||||
|
|
||||||
return ECSSession(
|
|
||||||
"ecs",
|
|
||||||
entrust_api_user=entrust_api_user,
|
|
||||||
entrust_api_key=entrust_api_key,
|
|
||||||
entrust_api_cert=entrust_api_cert,
|
|
||||||
entrust_api_cert_key=entrust_api_cert_key,
|
|
||||||
entrust_api_specification_path=entrust_api_specification_path,
|
|
||||||
).client()
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
|
||||||
"ecs_client_argument_spec",
|
|
||||||
"SessionConfigurationException",
|
|
||||||
"RestOperationException",
|
|
||||||
"ECSClient",
|
|
||||||
)
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,481 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
# Copyright 2019 Entrust Datacard Corporation.
|
|
||||||
# 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 annotations
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = r"""
|
|
||||||
module: ecs_domain
|
|
||||||
author:
|
|
||||||
- Chris Trufan (@ctrufan)
|
|
||||||
version_added: '1.0.0'
|
|
||||||
short_description: Request validation of a domain with the Entrust Certificate Services (ECS) API
|
|
||||||
description:
|
|
||||||
- Request validation or re-validation of a domain with the Entrust Certificate Services (ECS) API.
|
|
||||||
- Requires credentials for the L(Entrust Certificate Services,https://www.entrustdatacard.com/products/categories/ssl-certificates)
|
|
||||||
(ECS) API.
|
|
||||||
- If the domain is already in the validation process, no new validation will be requested, but the validation data (if applicable)
|
|
||||||
will be returned.
|
|
||||||
- If the domain is already in the validation process but the O(verification_method) specified is different than the current
|
|
||||||
O(verification_method), the O(verification_method) will be updated and validation data (if applicable) will be returned.
|
|
||||||
- If the domain is an active, validated domain, the return value of C(changed) will be false, unless RV(domain_status=EXPIRED),
|
|
||||||
in which case a re-validation will be performed.
|
|
||||||
- If O(verification_method=dns), details about the required DNS entry will be specified in the return parameters RV(dns_contents),
|
|
||||||
RV(dns_location), and RV(dns_resource_type).
|
|
||||||
- If O(verification_method=web_server), details about the required file details will be specified in the return parameters
|
|
||||||
RV(file_contents) and RV(file_location).
|
|
||||||
- If O(verification_method=email), the email address(es) that the validation email(s) were sent to will be in the return
|
|
||||||
parameter RV(emails). This is purely informational. For domains requested using this module, this will always be a list
|
|
||||||
of size 1.
|
|
||||||
notes:
|
|
||||||
- There is a small delay (typically about 5 seconds, but can be as long as 60 seconds) before obtaining the random values
|
|
||||||
when requesting a validation while O(verification_method=dns) or O(verification_method=web_server). Be aware of that if
|
|
||||||
doing many domain validation requests.
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- community.crypto._attributes
|
|
||||||
- community.crypto._ecs_credential
|
|
||||||
attributes:
|
|
||||||
check_mode:
|
|
||||||
support: none
|
|
||||||
diff_mode:
|
|
||||||
support: none
|
|
||||||
idempotent:
|
|
||||||
support: partial
|
|
||||||
details:
|
|
||||||
- Under which conditions the module is idempotent still needs to be determined.
|
|
||||||
If you are using this module and have more information, please contribute to
|
|
||||||
the documentation!
|
|
||||||
options:
|
|
||||||
client_id:
|
|
||||||
description:
|
|
||||||
- The client ID to request the domain be associated with.
|
|
||||||
- If no client ID is specified, the domain will be added under the primary client with ID of 1.
|
|
||||||
type: int
|
|
||||||
default: 1
|
|
||||||
domain_name:
|
|
||||||
description:
|
|
||||||
- The domain name to be verified or reverified.
|
|
||||||
type: str
|
|
||||||
required: true
|
|
||||||
verification_method:
|
|
||||||
description:
|
|
||||||
- The verification method to be used to prove control of the domain.
|
|
||||||
- If O(verification_method=email) and the value O(verification_email) is specified, that value is used for the email
|
|
||||||
validation. If O(verification_email) is not provided, the first value present in WHOIS data will be used. An email
|
|
||||||
will be sent to the address in O(verification_email) with instructions on how to verify control of the domain.
|
|
||||||
- If O(verification_method=dns), the value RV(dns_contents) must be stored in location RV(dns_location), with a DNS
|
|
||||||
record type of RV(dns_resource_type). To prove domain ownership, update your DNS records so the text string returned
|
|
||||||
by RV(dns_contents) is available at RV(dns_location).
|
|
||||||
- If O(verification_method=web_server), the contents of return value RV(file_contents) must be made available on a web
|
|
||||||
server accessible at location RV(file_location).
|
|
||||||
- If O(verification_method=manual), the domain will be validated with a manual process. This is not recommended.
|
|
||||||
type: str
|
|
||||||
choices: ['dns', 'email', 'manual', 'web_server']
|
|
||||||
required: true
|
|
||||||
verification_email:
|
|
||||||
description:
|
|
||||||
- Email address to be used to verify domain ownership.
|
|
||||||
- 'Email address must be either an email address present in the WHOIS data for O(domain_name), or one of the following
|
|
||||||
constructed emails: admin@O(domain_name), administrator@O(domain_name), webmaster@O(domain_name), hostmaster@O(domain_name),
|
|
||||||
postmaster@O(domain_name).'
|
|
||||||
- Note that if O(domain_name) includes subdomains, the top level domain should be used. For example, if requesting validation
|
|
||||||
of example1.ansible.com, or test.example2.ansible.com, and you want to use the "admin" preconstructed name, the email
|
|
||||||
address should be admin@ansible.com.
|
|
||||||
- If using the email values from the WHOIS data for the domain or its top level namespace, they must be exact matches.
|
|
||||||
- If O(verification_method=email) but O(verification_email) is not provided, the first email address found in WHOIS
|
|
||||||
data for the domain will be used.
|
|
||||||
- To verify domain ownership, domain owner must follow the instructions in the email they receive.
|
|
||||||
- Only allowed if O(verification_method=email).
|
|
||||||
type: str
|
|
||||||
seealso:
|
|
||||||
- module: community.crypto.x509_certificate
|
|
||||||
description: Can be used to request certificates from ECS, with O(community.crypto.x509_certificate#module:provider=entrust).
|
|
||||||
- module: community.crypto.ecs_certificate
|
|
||||||
description: Can be used to request a Certificate from ECS using a verified domain.
|
|
||||||
"""
|
|
||||||
|
|
||||||
EXAMPLES = r"""
|
|
||||||
---
|
|
||||||
- name: Request domain validation using email validation for client ID of 2.
|
|
||||||
community.crypto.ecs_domain:
|
|
||||||
domain_name: ansible.com
|
|
||||||
client_id: 2
|
|
||||||
verification_method: email
|
|
||||||
verification_email: admin@ansible.com
|
|
||||||
entrust_api_user: apiusername
|
|
||||||
entrust_api_key: a^lv*32!cd9LnT
|
|
||||||
entrust_api_client_cert_path: /etc/ssl/entrust/ecs-client.crt
|
|
||||||
entrust_api_client_cert_key_path: /etc/ssl/entrust/ecs-client.key
|
|
||||||
|
|
||||||
- name: Request domain validation using DNS. If domain is already valid, request revalidation if expires within 90 days
|
|
||||||
community.crypto.ecs_domain:
|
|
||||||
domain_name: ansible.com
|
|
||||||
verification_method: dns
|
|
||||||
entrust_api_user: apiusername
|
|
||||||
entrust_api_key: a^lv*32!cd9LnT
|
|
||||||
entrust_api_client_cert_path: /etc/ssl/entrust/ecs-client.crt
|
|
||||||
entrust_api_client_cert_key_path: /etc/ssl/entrust/ecs-client.key
|
|
||||||
|
|
||||||
- name: Request domain validation using web server validation, and revalidate if fewer than 60 days remaining of EV eligibility.
|
|
||||||
community.crypto.ecs_domain:
|
|
||||||
domain_name: ansible.com
|
|
||||||
verification_method: web_server
|
|
||||||
entrust_api_user: apiusername
|
|
||||||
entrust_api_key: a^lv*32!cd9LnT
|
|
||||||
entrust_api_client_cert_path: /etc/ssl/entrust/ecs-client.crt
|
|
||||||
entrust_api_client_cert_key_path: /etc/ssl/entrust/ecs-client.key
|
|
||||||
|
|
||||||
- name: Request domain validation using manual validation.
|
|
||||||
community.crypto.ecs_domain:
|
|
||||||
domain_name: ansible.com
|
|
||||||
verification_method: manual
|
|
||||||
entrust_api_user: apiusername
|
|
||||||
entrust_api_key: a^lv*32!cd9LnT
|
|
||||||
entrust_api_client_cert_path: /etc/ssl/entrust/ecs-client.crt
|
|
||||||
entrust_api_client_cert_key_path: /etc/ssl/entrust/ecs-client.key
|
|
||||||
"""
|
|
||||||
|
|
||||||
RETURN = r"""
|
|
||||||
domain_status:
|
|
||||||
description: Status of the current domain. Will be one of V(APPROVED), V(DECLINED), V(CANCELLED), V(INITIAL_VERIFICATION),
|
|
||||||
V(DECLINED), V(CANCELLED), V(RE_VERIFICATION), V(EXPIRED), V(EXPIRING).
|
|
||||||
returned: changed or success
|
|
||||||
type: str
|
|
||||||
sample: APPROVED
|
|
||||||
verification_method:
|
|
||||||
description: Verification method used to request the domain validation. If C(changed) will be the same as O(verification_method)
|
|
||||||
input parameter.
|
|
||||||
returned: changed or success
|
|
||||||
type: str
|
|
||||||
sample: dns
|
|
||||||
file_location:
|
|
||||||
description: The location that ECS will be expecting to be able to find the file for domain verification, containing the
|
|
||||||
contents of RV(file_contents).
|
|
||||||
returned: O(verification_method) is V(web_server)
|
|
||||||
type: str
|
|
||||||
sample: http://ansible.com/.well-known/pki-validation/abcd.txt
|
|
||||||
file_contents:
|
|
||||||
description: The contents of the file that ECS will be expecting to find at RV(file_location).
|
|
||||||
returned: O(verification_method) is V(web_server)
|
|
||||||
type: str
|
|
||||||
sample: AB23CD41432522FF2526920393982FAB
|
|
||||||
emails:
|
|
||||||
description:
|
|
||||||
- The list of emails used to request validation of this domain.
|
|
||||||
- Domains requested using this module will only have a list of size 1.
|
|
||||||
returned: O(verification_method) is V(email)
|
|
||||||
type: list
|
|
||||||
sample: [admin@ansible.com, administrator@ansible.com]
|
|
||||||
dns_location:
|
|
||||||
description: The location that ECS will be expecting to be able to find the DNS entry for domain verification, containing
|
|
||||||
the contents of RV(dns_contents).
|
|
||||||
returned: changed and if O(verification_method) is V(dns)
|
|
||||||
type: str
|
|
||||||
sample: _pki-validation.ansible.com
|
|
||||||
dns_contents:
|
|
||||||
description: The value that ECS will be expecting to find in the DNS record located at RV(dns_location).
|
|
||||||
returned: changed and if O(verification_method) is V(dns)
|
|
||||||
type: str
|
|
||||||
sample: AB23CD41432522FF2526920393982FAB
|
|
||||||
dns_resource_type:
|
|
||||||
description: The type of resource record that ECS will be expecting for the DNS record located at RV(dns_location).
|
|
||||||
returned: changed and if O(verification_method) is V(dns)
|
|
||||||
type: str
|
|
||||||
sample: TXT
|
|
||||||
client_id:
|
|
||||||
description: Client ID that the domain belongs to. If the input value O(client_id) is specified, this will always be the
|
|
||||||
same as O(client_id).
|
|
||||||
returned: changed or success
|
|
||||||
type: int
|
|
||||||
sample: 1
|
|
||||||
ov_eligible:
|
|
||||||
description: Whether the domain is eligible for submission of "OV" certificates. Will never be V(false) if RV(ev_eligible)
|
|
||||||
is V(true).
|
|
||||||
returned: success and RV(domain_status) is V(APPROVED), V(RE_VERIFICATION), V(EXPIRING), or V(EXPIRED).
|
|
||||||
type: bool
|
|
||||||
sample: true
|
|
||||||
ov_days_remaining:
|
|
||||||
description: The number of days the domain remains eligible for submission of "OV" certificates. Will never be less than
|
|
||||||
the value of RV(ev_days_remaining).
|
|
||||||
returned: success and RV(ov_eligible) is V(true) and RV(domain_status) is V(APPROVED), V(RE_VERIFICATION) or V(EXPIRING).
|
|
||||||
type: int
|
|
||||||
sample: 129
|
|
||||||
ev_eligible:
|
|
||||||
description: Whether the domain is eligible for submission of "EV" certificates. Will never be V(true) if RV(ov_eligible)
|
|
||||||
is V(false).
|
|
||||||
returned: success and RV(domain_status) is V(APPROVED), V(RE_VERIFICATION) or V(EXPIRING), or V(EXPIRED).
|
|
||||||
type: bool
|
|
||||||
sample: true
|
|
||||||
ev_days_remaining:
|
|
||||||
description: The number of days the domain remains eligible for submission of "EV" certificates. Will never be greater than
|
|
||||||
the value of RV(ov_days_remaining).
|
|
||||||
returned: success and RV(ev_eligible) is V(true) and RV(domain_status) is V(APPROVED), V(RE_VERIFICATION) or V(EXPIRING).
|
|
||||||
type: int
|
|
||||||
sample: 94
|
|
||||||
"""
|
|
||||||
|
|
||||||
import datetime
|
|
||||||
import time
|
|
||||||
import typing as t
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible_collections.community.crypto.plugins.module_utils._ecs.api import (
|
|
||||||
ECSClient,
|
|
||||||
RestOperationException,
|
|
||||||
SessionConfigurationException,
|
|
||||||
ecs_client_argument_spec,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@t.overload
|
|
||||||
def calculate_days_remaining(expiry_date: str) -> int: ...
|
|
||||||
|
|
||||||
|
|
||||||
@t.overload
|
|
||||||
def calculate_days_remaining(expiry_date: str | None) -> int | None: ...
|
|
||||||
|
|
||||||
|
|
||||||
def calculate_days_remaining(expiry_date: str | None) -> int | None:
|
|
||||||
days_remaining = None
|
|
||||||
if expiry_date is not None:
|
|
||||||
expiry_datetime = datetime.datetime.strptime(expiry_date, "%Y-%m-%dT%H:%M:%SZ")
|
|
||||||
days_remaining = (expiry_datetime - datetime.datetime.now()).days
|
|
||||||
return days_remaining
|
|
||||||
|
|
||||||
|
|
||||||
class EcsDomain:
|
|
||||||
"""
|
|
||||||
Entrust Certificate Services domain class.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, module: AnsibleModule) -> None:
|
|
||||||
self.changed = False
|
|
||||||
self.domain_status = None
|
|
||||||
self.verification_method = None
|
|
||||||
self.file_location = None
|
|
||||||
self.file_contents = None
|
|
||||||
self.dns_location = None
|
|
||||||
self.dns_contents = None
|
|
||||||
self.dns_resource_type = None
|
|
||||||
self.emails = None
|
|
||||||
self.ov_eligible: bool | None = None
|
|
||||||
self.ov_days_remaining: int | None = None
|
|
||||||
self.ev_eligible: bool | None = None
|
|
||||||
self.ev_days_remaining: int | None = None
|
|
||||||
# Note that verification_method is the 'current' verification
|
|
||||||
# method of the domain, we'll use module.params when requesting a new
|
|
||||||
# one, in case the verification method has changed.
|
|
||||||
self.verification_method = None
|
|
||||||
self.client_id: str | None = None
|
|
||||||
|
|
||||||
# Instantiate the ECS client and then try a no-op connection to verify credentials are valid
|
|
||||||
try:
|
|
||||||
self.ecs_client = ECSClient(
|
|
||||||
entrust_api_user=module.params["entrust_api_user"],
|
|
||||||
entrust_api_key=module.params["entrust_api_key"],
|
|
||||||
entrust_api_cert=module.params["entrust_api_client_cert_path"],
|
|
||||||
entrust_api_cert_key=module.params["entrust_api_client_cert_key_path"],
|
|
||||||
entrust_api_specification_path=module.params[
|
|
||||||
"entrust_api_specification_path"
|
|
||||||
],
|
|
||||||
)
|
|
||||||
except SessionConfigurationException as e:
|
|
||||||
module.fail_json(msg=f"Failed to initialize Entrust Provider: {e}")
|
|
||||||
try:
|
|
||||||
self.ecs_client.GetAppVersion() # type: ignore[attr-defined] # pylint: disable=no-member
|
|
||||||
except RestOperationException as e:
|
|
||||||
module.fail_json(
|
|
||||||
msg=f"Please verify credential information. Received exception when testing ECS connection: {e.message}"
|
|
||||||
)
|
|
||||||
|
|
||||||
def set_domain_details(self, domain_details: dict[str, t.Any]) -> None:
|
|
||||||
if domain_details.get("verificationMethod"):
|
|
||||||
self.verification_method = domain_details["verificationMethod"].lower()
|
|
||||||
self.domain_status = domain_details["verificationStatus"]
|
|
||||||
self.ov_eligible = domain_details.get("ovEligible")
|
|
||||||
self.ov_days_remaining = calculate_days_remaining(
|
|
||||||
domain_details.get("ovExpiry")
|
|
||||||
)
|
|
||||||
self.ev_eligible = domain_details.get("evEligible")
|
|
||||||
self.ev_days_remaining = calculate_days_remaining(
|
|
||||||
domain_details.get("evExpiry")
|
|
||||||
)
|
|
||||||
self.client_id = domain_details["clientId"]
|
|
||||||
|
|
||||||
if self.verification_method == "dns" and domain_details.get("dnsMethod"):
|
|
||||||
self.dns_location = domain_details["dnsMethod"]["recordDomain"]
|
|
||||||
self.dns_resource_type = domain_details["dnsMethod"]["recordType"]
|
|
||||||
self.dns_contents = domain_details["dnsMethod"]["recordValue"]
|
|
||||||
elif self.verification_method == "web_server" and domain_details.get(
|
|
||||||
"webServerMethod"
|
|
||||||
):
|
|
||||||
self.file_location = domain_details["webServerMethod"]["fileLocation"]
|
|
||||||
self.file_contents = domain_details["webServerMethod"]["fileContents"]
|
|
||||||
elif self.verification_method == "email" and domain_details.get("emailMethod"):
|
|
||||||
self.emails = domain_details["emailMethod"]
|
|
||||||
|
|
||||||
def check(self, module: AnsibleModule) -> bool:
|
|
||||||
try:
|
|
||||||
domain_details = self.ecs_client.GetDomain( # type: ignore[attr-defined] # pylint: disable=no-member
|
|
||||||
clientId=module.params["client_id"], domain=module.params["domain_name"]
|
|
||||||
)
|
|
||||||
self.set_domain_details(domain_details)
|
|
||||||
if self.domain_status not in (
|
|
||||||
"APPROVED",
|
|
||||||
"INITIAL_VERIFICATION",
|
|
||||||
"RE_VERIFICATION",
|
|
||||||
):
|
|
||||||
return False
|
|
||||||
|
|
||||||
# If domain verification is in process, we want to return the random values and treat it as a valid.
|
|
||||||
if self.domain_status in ("INITIAL_VERIFICATION", "RE_VERIFICATION"):
|
|
||||||
# Unless the verification method has changed, in which case we need to do a reverify request.
|
|
||||||
if self.verification_method != module.params["verification_method"]:
|
|
||||||
return False
|
|
||||||
|
|
||||||
if self.domain_status == "EXPIRING":
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
except RestOperationException:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def request_domain(self, module: AnsibleModule) -> None:
|
|
||||||
if not self.check(module):
|
|
||||||
body = {}
|
|
||||||
|
|
||||||
body["verificationMethod"] = module.params["verification_method"].upper()
|
|
||||||
if module.params["verification_method"] == "email":
|
|
||||||
emailMethod = {}
|
|
||||||
if module.params["verification_email"]:
|
|
||||||
emailMethod["emailSource"] = "SPECIFIED"
|
|
||||||
emailMethod["email"] = module.params["verification_email"]
|
|
||||||
else:
|
|
||||||
emailMethod["emailSource"] = "INCLUDE_WHOIS"
|
|
||||||
body["emailMethod"] = emailMethod
|
|
||||||
# Only populate domain name in body if it is not an existing domain
|
|
||||||
if not self.domain_status:
|
|
||||||
body["domainName"] = module.params["domain_name"]
|
|
||||||
try:
|
|
||||||
if not self.domain_status:
|
|
||||||
self.ecs_client.AddDomain( # type: ignore[attr-defined] # pylint: disable=no-member
|
|
||||||
clientId=module.params["client_id"], Body=body
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self.ecs_client.ReverifyDomain( # type: ignore[attr-defined] # pylint: disable=no-member
|
|
||||||
clientId=module.params["client_id"],
|
|
||||||
domain=module.params["domain_name"],
|
|
||||||
Body=body,
|
|
||||||
)
|
|
||||||
|
|
||||||
time.sleep(5)
|
|
||||||
result = self.ecs_client.GetDomain( # type: ignore[attr-defined] # pylint: disable=no-member
|
|
||||||
clientId=module.params["client_id"],
|
|
||||||
domain=module.params["domain_name"],
|
|
||||||
)
|
|
||||||
|
|
||||||
# It takes a bit of time before the random values are available
|
|
||||||
if (
|
|
||||||
module.params["verification_method"] == "dns"
|
|
||||||
or module.params["verification_method"] == "web_server"
|
|
||||||
):
|
|
||||||
for _i in range(4):
|
|
||||||
# Check both that random values are now available, and that they're different than were populated by previous 'check'
|
|
||||||
if module.params["verification_method"] == "dns":
|
|
||||||
if (
|
|
||||||
result.get("dnsMethod")
|
|
||||||
and result["dnsMethod"]["recordValue"]
|
|
||||||
!= self.dns_contents
|
|
||||||
):
|
|
||||||
break
|
|
||||||
elif module.params["verification_method"] == "web_server":
|
|
||||||
if (
|
|
||||||
result.get("webServerMethod")
|
|
||||||
and result["webServerMethod"]["fileContents"]
|
|
||||||
!= self.file_contents
|
|
||||||
):
|
|
||||||
break
|
|
||||||
time.sleep(10)
|
|
||||||
result = self.ecs_client.GetDomain( # type: ignore[attr-defined] # pylint: disable=no-member
|
|
||||||
clientId=module.params["client_id"],
|
|
||||||
domain=module.params["domain_name"],
|
|
||||||
)
|
|
||||||
self.changed = True
|
|
||||||
self.set_domain_details(result)
|
|
||||||
except RestOperationException as e:
|
|
||||||
module.fail_json(
|
|
||||||
msg=f"Failed to request domain validation from Entrust (ECS) {e.message}"
|
|
||||||
)
|
|
||||||
|
|
||||||
def dump(self) -> dict[str, t.Any]:
|
|
||||||
result: dict[str, t.Any] = {
|
|
||||||
"changed": self.changed,
|
|
||||||
"client_id": self.client_id,
|
|
||||||
"domain_status": self.domain_status,
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.verification_method:
|
|
||||||
result["verification_method"] = self.verification_method
|
|
||||||
if self.ov_eligible is not None:
|
|
||||||
result["ov_eligible"] = self.ov_eligible
|
|
||||||
if self.ov_days_remaining:
|
|
||||||
result["ov_days_remaining"] = self.ov_days_remaining
|
|
||||||
if self.ev_eligible is not None:
|
|
||||||
result["ev_eligible"] = self.ev_eligible
|
|
||||||
if self.ev_days_remaining:
|
|
||||||
result["ev_days_remaining"] = self.ev_days_remaining
|
|
||||||
if self.emails:
|
|
||||||
result["emails"] = self.emails
|
|
||||||
|
|
||||||
if self.verification_method == "dns":
|
|
||||||
result["dns_location"] = self.dns_location
|
|
||||||
result["dns_contents"] = self.dns_contents
|
|
||||||
result["dns_resource_type"] = self.dns_resource_type
|
|
||||||
elif self.verification_method == "web_server":
|
|
||||||
result["file_location"] = self.file_location
|
|
||||||
result["file_contents"] = self.file_contents
|
|
||||||
elif self.verification_method == "email":
|
|
||||||
result["emails"] = self.emails
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def ecs_domain_argument_spec() -> dict[str, dict[str, t.Any]]:
|
|
||||||
return {
|
|
||||||
"client_id": {"type": "int", "default": 1},
|
|
||||||
"domain_name": {"type": "str", "required": True},
|
|
||||||
"verification_method": {
|
|
||||||
"type": "str",
|
|
||||||
"required": True,
|
|
||||||
"choices": ["dns", "email", "manual", "web_server"],
|
|
||||||
},
|
|
||||||
"verification_email": {"type": "str"},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> t.NoReturn:
|
|
||||||
ecs_argument_spec = ecs_client_argument_spec()
|
|
||||||
ecs_argument_spec.update(ecs_domain_argument_spec())
|
|
||||||
module = AnsibleModule(
|
|
||||||
argument_spec=ecs_argument_spec,
|
|
||||||
supports_check_mode=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
if (
|
|
||||||
module.params["verification_email"]
|
|
||||||
and module.params["verification_method"] != "email"
|
|
||||||
):
|
|
||||||
module.fail_json(
|
|
||||||
msg=f'The verification_email field is invalid when verification_method="{module.params["verification_method"]}".'
|
|
||||||
)
|
|
||||||
|
|
||||||
domain = EcsDomain(module)
|
|
||||||
domain.request_domain(module)
|
|
||||||
result = domain.dump()
|
|
||||||
module.exit_json(**result)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -11,7 +11,7 @@ DOCUMENTATION = r"""
|
|||||||
module: x509_certificate
|
module: x509_certificate
|
||||||
short_description: Generate and/or check OpenSSL certificates
|
short_description: Generate and/or check OpenSSL certificates
|
||||||
description:
|
description:
|
||||||
- It implements a notion of provider (one of V(selfsigned), V(ownca), V(acme), and V(entrust)) for your certificate.
|
- It implements a notion of provider (one of V(selfsigned), V(ownca), and V(acme)) for your certificate.
|
||||||
- Please note that the module regenerates existing certificate if it does not match the module's options, or if it seems
|
- Please note that the module regenerates existing certificate if it does not 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 O(backup)
|
to be corrupt. If you are concerned that this could overwrite your existing certificate, consider using the O(backup)
|
||||||
option.
|
option.
|
||||||
@@ -29,7 +29,6 @@ extends_documentation_fragment:
|
|||||||
- community.crypto._attributes.files
|
- community.crypto._attributes.files
|
||||||
- community.crypto._module_certificate
|
- community.crypto._module_certificate
|
||||||
- community.crypto._module_certificate.backend_acme_documentation
|
- community.crypto._module_certificate.backend_acme_documentation
|
||||||
- community.crypto._module_certificate.backend_entrust_documentation
|
|
||||||
- community.crypto._module_certificate.backend_ownca_documentation
|
- community.crypto._module_certificate.backend_ownca_documentation
|
||||||
- community.crypto._module_certificate.backend_selfsigned_documentation
|
- community.crypto._module_certificate.backend_selfsigned_documentation
|
||||||
attributes:
|
attributes:
|
||||||
@@ -56,11 +55,10 @@ options:
|
|||||||
- Name of the provider to use to generate/retrieve the OpenSSL certificate. Please see the examples on how to emulate
|
- Name of the provider to use to generate/retrieve the OpenSSL certificate. Please see the examples on how to emulate
|
||||||
it with M(community.crypto.x509_certificate_info), M(community.crypto.openssl_csr_info), M(community.crypto.openssl_privatekey_info)
|
it with M(community.crypto.x509_certificate_info), M(community.crypto.openssl_csr_info), M(community.crypto.openssl_privatekey_info)
|
||||||
and M(ansible.builtin.assert).
|
and M(ansible.builtin.assert).
|
||||||
- The V(entrust) provider was added for Ansible 2.9 and requires credentials for the
|
|
||||||
L(Entrust Certificate Services,https://www.entrustdatacard.com/products/categories/ssl-certificates) (ECS) API.
|
|
||||||
- Required if O(state) is V(present).
|
- Required if O(state) is V(present).
|
||||||
|
- The V(entrust) provider has been removed from community.crypto 3.0.0 due to sunsetting of the ECS API.
|
||||||
type: str
|
type: str
|
||||||
choices: [acme, entrust, ownca, selfsigned]
|
choices: [acme, ownca, selfsigned]
|
||||||
|
|
||||||
return_content:
|
return_content:
|
||||||
description:
|
description:
|
||||||
@@ -125,21 +123,6 @@ EXAMPLES = r"""
|
|||||||
acme_challenge_path: /etc/ssl/challenges/ansible.com/
|
acme_challenge_path: /etc/ssl/challenges/ansible.com/
|
||||||
force: true
|
force: true
|
||||||
|
|
||||||
- name: Generate an Entrust certificate via the Entrust Certificate Services (ECS) API
|
|
||||||
community.crypto.x509_certificate:
|
|
||||||
path: /etc/ssl/crt/ansible.com.crt
|
|
||||||
csr_path: /etc/ssl/csr/ansible.com.csr
|
|
||||||
provider: entrust
|
|
||||||
entrust_requester_name: Jo Doe
|
|
||||||
entrust_requester_email: jdoe@ansible.com
|
|
||||||
entrust_requester_phone: 555-555-5555
|
|
||||||
entrust_cert_type: STANDARD_SSL
|
|
||||||
entrust_api_user: apiusername
|
|
||||||
entrust_api_key: a^lv*32!cd9LnT
|
|
||||||
entrust_api_client_cert_path: /etc/ssl/entrust/ecs-client.crt
|
|
||||||
entrust_api_client_cert_key_path: /etc/ssl/entrust/ecs-key.crt
|
|
||||||
entrust_api_specification_path: /etc/ssl/entrust/api-docs/cms-api-2.1.0.yaml
|
|
||||||
|
|
||||||
# The following example shows how to emulate the behavior of the removed
|
# The following example shows how to emulate the behavior of the removed
|
||||||
# "assertonly" provider with the x509_certificate_info, openssl_csr_info,
|
# "assertonly" provider with the x509_certificate_info, openssl_csr_info,
|
||||||
# openssl_privatekey_info and assert modules:
|
# openssl_privatekey_info and assert modules:
|
||||||
@@ -237,10 +220,6 @@ from ansible_collections.community.crypto.plugins.module_utils._crypto.module_ba
|
|||||||
AcmeCertificateProvider,
|
AcmeCertificateProvider,
|
||||||
add_acme_provider_to_argument_spec,
|
add_acme_provider_to_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 (
|
from ansible_collections.community.crypto.plugins.module_utils._crypto.module_backends.certificate_ownca import (
|
||||||
OwnCACertificateProvider,
|
OwnCACertificateProvider,
|
||||||
add_ownca_provider_to_argument_spec,
|
add_ownca_provider_to_argument_spec,
|
||||||
@@ -362,7 +341,6 @@ class GenericCertificate(OpenSSLObject):
|
|||||||
def main() -> t.NoReturn:
|
def main() -> t.NoReturn:
|
||||||
argument_spec = get_certificate_argument_spec()
|
argument_spec = get_certificate_argument_spec()
|
||||||
add_acme_provider_to_argument_spec(argument_spec)
|
add_acme_provider_to_argument_spec(argument_spec)
|
||||||
add_entrust_provider_to_argument_spec(argument_spec)
|
|
||||||
add_ownca_provider_to_argument_spec(argument_spec)
|
add_ownca_provider_to_argument_spec(argument_spec)
|
||||||
add_selfsigned_provider_to_argument_spec(argument_spec)
|
add_selfsigned_provider_to_argument_spec(argument_spec)
|
||||||
argument_spec.argument_spec.update(
|
argument_spec.argument_spec.update(
|
||||||
@@ -407,12 +385,10 @@ def main() -> t.NoReturn:
|
|||||||
provider_map: dict[
|
provider_map: dict[
|
||||||
str,
|
str,
|
||||||
type[AcmeCertificateProvider]
|
type[AcmeCertificateProvider]
|
||||||
| type[EntrustCertificateProvider]
|
|
||||||
| type[OwnCACertificateProvider]
|
| type[OwnCACertificateProvider]
|
||||||
| type[SelfSignedCertificateProvider],
|
| type[SelfSignedCertificateProvider],
|
||||||
] = {
|
] = {
|
||||||
"acme": AcmeCertificateProvider,
|
"acme": AcmeCertificateProvider,
|
||||||
"entrust": EntrustCertificateProvider,
|
|
||||||
"ownca": OwnCACertificateProvider,
|
"ownca": OwnCACertificateProvider,
|
||||||
"selfsigned": SelfSignedCertificateProvider,
|
"selfsigned": SelfSignedCertificateProvider,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ module: x509_certificate_pipe
|
|||||||
short_description: Generate and/or check OpenSSL certificates
|
short_description: Generate and/or check OpenSSL certificates
|
||||||
version_added: 1.3.0
|
version_added: 1.3.0
|
||||||
description:
|
description:
|
||||||
- It implements a notion of provider (one of V(selfsigned), V(ownca), V(entrust)) for your certificate.
|
- It implements a notion of provider (one of V(selfsigned) and V(ownca)) for your certificate.
|
||||||
author:
|
author:
|
||||||
- Yanis Guenane (@Spredzy)
|
- Yanis Guenane (@Spredzy)
|
||||||
- Markus Teufelberger (@MarkusTeufelberger)
|
- Markus Teufelberger (@MarkusTeufelberger)
|
||||||
@@ -21,7 +21,6 @@ author:
|
|||||||
extends_documentation_fragment:
|
extends_documentation_fragment:
|
||||||
- community.crypto._attributes
|
- community.crypto._attributes
|
||||||
- community.crypto._module_certificate
|
- community.crypto._module_certificate
|
||||||
- community.crypto._module_certificate.backend_entrust_documentation
|
|
||||||
- community.crypto._module_certificate.backend_ownca_documentation
|
- community.crypto._module_certificate.backend_ownca_documentation
|
||||||
- community.crypto._module_certificate.backend_selfsigned_documentation
|
- community.crypto._module_certificate.backend_selfsigned_documentation
|
||||||
attributes:
|
attributes:
|
||||||
@@ -33,10 +32,9 @@ options:
|
|||||||
provider:
|
provider:
|
||||||
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 V(entrust) provider requires credentials for the L(Entrust Certificate Services,
|
- The V(entrust) provider has been removed from community.crypto 3.0.0 due to sunsetting of the ECS API.
|
||||||
https://www.entrustdatacard.com/products/categories/ssl-certificates) (ECS) API.
|
|
||||||
type: str
|
type: str
|
||||||
choices: [entrust, ownca, selfsigned]
|
choices: [ownca, selfsigned]
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
content:
|
content:
|
||||||
@@ -127,10 +125,6 @@ from ansible_collections.community.crypto.plugins.module_utils._crypto.module_ba
|
|||||||
get_certificate_argument_spec,
|
get_certificate_argument_spec,
|
||||||
select_backend,
|
select_backend,
|
||||||
)
|
)
|
||||||
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 (
|
from ansible_collections.community.crypto.plugins.module_utils._crypto.module_backends.certificate_ownca import (
|
||||||
OwnCACertificateProvider,
|
OwnCACertificateProvider,
|
||||||
add_ownca_provider_to_argument_spec,
|
add_ownca_provider_to_argument_spec,
|
||||||
@@ -178,7 +172,6 @@ class GenericCertificate:
|
|||||||
def main() -> t.NoReturn:
|
def main() -> t.NoReturn:
|
||||||
argument_spec = get_certificate_argument_spec()
|
argument_spec = get_certificate_argument_spec()
|
||||||
argument_spec.argument_spec["provider"]["required"] = True
|
argument_spec.argument_spec["provider"]["required"] = True
|
||||||
add_entrust_provider_to_argument_spec(argument_spec)
|
|
||||||
add_ownca_provider_to_argument_spec(argument_spec)
|
add_ownca_provider_to_argument_spec(argument_spec)
|
||||||
add_selfsigned_provider_to_argument_spec(argument_spec)
|
add_selfsigned_provider_to_argument_spec(argument_spec)
|
||||||
argument_spec.argument_spec.update(
|
argument_spec.argument_spec.update(
|
||||||
@@ -194,11 +187,8 @@ def main() -> t.NoReturn:
|
|||||||
provider = module.params["provider"]
|
provider = module.params["provider"]
|
||||||
provider_map: dict[
|
provider_map: dict[
|
||||||
str,
|
str,
|
||||||
type[EntrustCertificateProvider]
|
type[OwnCACertificateProvider] | type[SelfSignedCertificateProvider],
|
||||||
| type[OwnCACertificateProvider]
|
|
||||||
| type[SelfSignedCertificateProvider],
|
|
||||||
] = {
|
] = {
|
||||||
"entrust": EntrustCertificateProvider,
|
|
||||||
"ownca": OwnCACertificateProvider,
|
"ownca": OwnCACertificateProvider,
|
||||||
"selfsigned": SelfSignedCertificateProvider,
|
"selfsigned": SelfSignedCertificateProvider,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
# 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
|
|
||||||
|
|
||||||
# Not enabled due to lack of access to test environments. May be enabled using custom integration_config.yml
|
|
||||||
# Example integation_config.yml
|
|
||||||
# ---
|
|
||||||
# entrust_api_user:
|
|
||||||
# entrust_api_key:
|
|
||||||
# entrust_api_client_cert_path: /var/integration-testing/publicCert.pem
|
|
||||||
# entrust_api_client_cert_key_path: /var/integration-testing/privateKey.pem
|
|
||||||
# entrust_api_ip_address: 127.0.0.1
|
|
||||||
# entrust_cloud_ip_address: 127.0.0.1
|
|
||||||
# # Used for certificate path validation of QA environments - we chose not to support disabling path validation ever.
|
|
||||||
# cacerts_bundle_path_local: /var/integration-testing/cacerts
|
|
||||||
|
|
||||||
### WARNING: This test will update HOSTS file and CERTIFICATE STORE of target host, in order to be able to validate
|
|
||||||
# to a QA environment. ###
|
|
||||||
unsupported
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
---
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# defaults file for test_ecs_certificate
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
---
|
|
||||||
# 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:
|
|
||||||
- prepare_tests
|
|
||||||
- setup_openssl
|
|
||||||
@@ -1,222 +0,0 @@
|
|||||||
---
|
|
||||||
# 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 #
|
|
||||||
####################################################################
|
|
||||||
|
|
||||||
## Verify that integration_config was specified
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- entrust_api_user is defined
|
|
||||||
- entrust_api_key is defined
|
|
||||||
- entrust_api_ip_address is defined
|
|
||||||
- entrust_cloud_ip_address is defined
|
|
||||||
- entrust_api_client_cert_path is defined or entrust_api_client_cert_contents is defined
|
|
||||||
- entrust_api_client_cert_key_path is defined or entrust_api_client_cert_key_contents
|
|
||||||
- cacerts_bundle_path_local is defined
|
|
||||||
|
|
||||||
## SET UP TEST ENVIRONMENT ########################################################################
|
|
||||||
- name: copy the files needed for verifying test server certificate to the host
|
|
||||||
copy:
|
|
||||||
src: '{{ cacerts_bundle_path_local }}/'
|
|
||||||
dest: '{{ cacerts_bundle_path }}'
|
|
||||||
|
|
||||||
- name: Update the CA certificates for our QA certs (collection may need updating if new QA environments used)
|
|
||||||
command: c_rehash {{ cacerts_bundle_path }}
|
|
||||||
|
|
||||||
- name: Update hosts file
|
|
||||||
lineinfile:
|
|
||||||
path: /etc/hosts
|
|
||||||
state: present
|
|
||||||
regexp: 'api.entrust.net$'
|
|
||||||
line: '{{ entrust_api_ip_address }} api.entrust.net'
|
|
||||||
|
|
||||||
- name: Update hosts file
|
|
||||||
lineinfile:
|
|
||||||
path: /etc/hosts
|
|
||||||
state: present
|
|
||||||
regexp: 'cloud.entrust.net$'
|
|
||||||
line: '{{ entrust_cloud_ip_address }} cloud.entrust.net'
|
|
||||||
|
|
||||||
- name: Clear out the temporary directory for storing the API connection information
|
|
||||||
file:
|
|
||||||
path: '{{ tmpdir_path }}'
|
|
||||||
state: absent
|
|
||||||
|
|
||||||
- name: Create a directory for storing the API connection Information
|
|
||||||
file:
|
|
||||||
path: '{{ tmpdir_path }}'
|
|
||||||
state: directory
|
|
||||||
|
|
||||||
- name: Copy the files needed for the connection to entrust API to the host
|
|
||||||
copy:
|
|
||||||
src: '{{ entrust_api_client_cert_path }}'
|
|
||||||
dest: '{{ entrust_api_cert }}'
|
|
||||||
|
|
||||||
- name: Copy the files needed for the connection to entrust API to the host
|
|
||||||
copy:
|
|
||||||
src: '{{ entrust_api_client_cert_key_path }}'
|
|
||||||
dest: '{{ entrust_api_cert_key }}'
|
|
||||||
|
|
||||||
## SETUP CSR TO REQUEST
|
|
||||||
- name: Generate a 2048 bit RSA private key
|
|
||||||
openssl_privatekey:
|
|
||||||
path: '{{ privatekey_path }}'
|
|
||||||
passphrase: '{{ privatekey_passphrase }}'
|
|
||||||
type: RSA
|
|
||||||
size: 2048
|
|
||||||
|
|
||||||
- name: Generate a certificate signing request using the generated key
|
|
||||||
openssl_csr:
|
|
||||||
path: '{{ csr_path }}'
|
|
||||||
privatekey_path: '{{ privatekey_path }}'
|
|
||||||
privatekey_passphrase: '{{ privatekey_passphrase }}'
|
|
||||||
common_name: '{{ common_name }}'
|
|
||||||
organization_name: '{{ organization_name | default(omit) }}'
|
|
||||||
organizational_unit_name: '{{ organizational_unit_name | default(omit) }}'
|
|
||||||
country_name: '{{ country_name | default(omit) }}'
|
|
||||||
state_or_province_name: '{{ state_or_province_name | default(omit) }}'
|
|
||||||
digest: sha256
|
|
||||||
|
|
||||||
- block:
|
|
||||||
- name: Have ECS generate a signed certificate
|
|
||||||
ecs_certificate:
|
|
||||||
backup: true
|
|
||||||
path: '{{ example1_cert_path }}'
|
|
||||||
full_chain_path: '{{ example1_chain_path }}'
|
|
||||||
csr: '{{ csr_path }}'
|
|
||||||
cert_type: '{{ example1_cert_type }}'
|
|
||||||
requester_name: '{{ entrust_requester_name }}'
|
|
||||||
requester_email: '{{ entrust_requester_email }}'
|
|
||||||
requester_phone: '{{ entrust_requester_phone }}'
|
|
||||||
entrust_api_user: '{{ entrust_api_user }}'
|
|
||||||
entrust_api_key: '{{ entrust_api_key }}'
|
|
||||||
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
|
|
||||||
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
|
|
||||||
register: example1_result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- example1_result is not failed
|
|
||||||
- example1_result.changed
|
|
||||||
- example1_result.tracking_id > 0
|
|
||||||
- example1_result.serial_number is string
|
|
||||||
|
|
||||||
# Internal CA refuses to issue certificates with the same DN in a short time frame
|
|
||||||
- name: Sleep for 5 seconds so we don't run into duplicate-request errors
|
|
||||||
pause:
|
|
||||||
seconds: 5
|
|
||||||
|
|
||||||
- name: Attempt to have ECS generate a signed certificate, but existing one is valid
|
|
||||||
ecs_certificate:
|
|
||||||
backup: true
|
|
||||||
path: '{{ example1_cert_path }}'
|
|
||||||
full_chain_path: '{{ example1_chain_path }}'
|
|
||||||
csr: '{{ csr_path }}'
|
|
||||||
cert_type: '{{ example1_cert_type }}'
|
|
||||||
requester_name: '{{ entrust_requester_name }}'
|
|
||||||
requester_email: '{{ entrust_requester_email }}'
|
|
||||||
requester_phone: '{{ entrust_requester_phone }}'
|
|
||||||
entrust_api_user: '{{ entrust_api_user }}'
|
|
||||||
entrust_api_key: '{{ entrust_api_key }}'
|
|
||||||
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
|
|
||||||
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
|
|
||||||
register: example2_result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- example2_result is not failed
|
|
||||||
- not example2_result.changed
|
|
||||||
- example2_result.backup_file is undefined
|
|
||||||
- example2_result.backup_full_chain_file is undefined
|
|
||||||
- example2_result.serial_number == example1_result.serial_number
|
|
||||||
- example2_result.tracking_id == example1_result.tracking_id
|
|
||||||
|
|
||||||
# Internal CA refuses to issue certificates with the same DN in a short time frame
|
|
||||||
- name: Sleep for 5 seconds so we don't run into duplicate-request errors
|
|
||||||
pause:
|
|
||||||
seconds: 5
|
|
||||||
|
|
||||||
- name: Force a reissue with no CSR, verify that contents changed
|
|
||||||
ecs_certificate:
|
|
||||||
backup: true
|
|
||||||
force: true
|
|
||||||
path: '{{ example1_cert_path }}'
|
|
||||||
full_chain_path: '{{ example1_chain_path }}'
|
|
||||||
cert_type: '{{ example1_cert_type }}'
|
|
||||||
request_type: reissue
|
|
||||||
requester_name: '{{ entrust_requester_name }}'
|
|
||||||
requester_email: '{{ entrust_requester_email }}'
|
|
||||||
requester_phone: '{{ entrust_requester_phone }}'
|
|
||||||
entrust_api_user: '{{ entrust_api_user }}'
|
|
||||||
entrust_api_key: '{{ entrust_api_key }}'
|
|
||||||
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
|
|
||||||
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
|
|
||||||
register: example3_result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- example3_result is not failed
|
|
||||||
- example3_result.changed
|
|
||||||
- example3_result.backup_file is string
|
|
||||||
- example3_result.backup_full_chain_file is string
|
|
||||||
- example3_result.tracking_id > 0
|
|
||||||
- example3_result.tracking_id != example1_result.tracking_id
|
|
||||||
- example3_result.serial_number != example1_result.serial_number
|
|
||||||
|
|
||||||
# Internal CA refuses to issue certificates with the same DN in a short time frame
|
|
||||||
- name: Sleep for 5 seconds so we don't run into duplicate-request errors
|
|
||||||
pause:
|
|
||||||
seconds: 5
|
|
||||||
|
|
||||||
- name: Test a request with all of the various optional possible fields populated
|
|
||||||
ecs_certificate:
|
|
||||||
path: '{{ example4_cert_path }}'
|
|
||||||
full_chain_path: '{{ example4_full_chain_path }}'
|
|
||||||
csr: '{{ csr_path }}'
|
|
||||||
subject_alt_name: '{{ example4_subject_alt_name }}'
|
|
||||||
eku: '{{ example4_eku }}'
|
|
||||||
ct_log: true
|
|
||||||
cert_type: '{{ example4_cert_type }}'
|
|
||||||
org: '{{ example4_org }}'
|
|
||||||
ou: '{{ example4_ou }}'
|
|
||||||
tracking_info: '{{ example4_tracking_info }}'
|
|
||||||
additional_emails: '{{ example4_additional_emails }}'
|
|
||||||
custom_fields: '{{ example4_custom_fields }}'
|
|
||||||
cert_expiry: '{{ example4_cert_expiry }}'
|
|
||||||
requester_name: '{{ entrust_requester_name }}'
|
|
||||||
requester_email: '{{ entrust_requester_email }}'
|
|
||||||
requester_phone: '{{ entrust_requester_phone }}'
|
|
||||||
entrust_api_user: '{{ entrust_api_user }}'
|
|
||||||
entrust_api_key: '{{ entrust_api_key }}'
|
|
||||||
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
|
|
||||||
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
|
|
||||||
register: example4_result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- example4_result is not failed
|
|
||||||
- example4_result.changed
|
|
||||||
- example4_result.backup_file is undefined
|
|
||||||
- example4_result.backup_full_chain_file is undefined
|
|
||||||
- example4_result.tracking_id > 0
|
|
||||||
- example4_result.serial_number is string
|
|
||||||
|
|
||||||
# For bug 61738, verify that the full chain is valid
|
|
||||||
- name: Verify that the full chain path can be successfully imported
|
|
||||||
command: '{{ openssl_binary }} verify "{{ example4_full_chain_path }}"'
|
|
||||||
register: openssl_result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "' OK' in openssl_result.stdout_lines[0]"
|
|
||||||
|
|
||||||
always:
|
|
||||||
- name: clean-up temporary folder
|
|
||||||
file:
|
|
||||||
path: '{{ tmpdir_path }}'
|
|
||||||
state: absent
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
---
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# vars file for test_ecs_certificate
|
|
||||||
|
|
||||||
# Path on various hosts that cacerts need to be put as a prerequisite to API server cert validation.
|
|
||||||
# May need to be customized for some environments based on SSL implementations
|
|
||||||
# that ansible "urls" module utility is using as a backing.
|
|
||||||
cacerts_bundle_path: /etc/pki/tls/certs
|
|
||||||
|
|
||||||
common_name: '{{ ansible_date_time.epoch }}.ansint.testcertificates.com'
|
|
||||||
organization_name: CMS API, Inc.
|
|
||||||
organizational_unit_name: RSA
|
|
||||||
country_name: US
|
|
||||||
state_or_province_name: MA
|
|
||||||
privatekey_passphrase: Passphrase452!
|
|
||||||
tmpdir_path: /tmp/ecs_cert_test/{{ ansible_date_time.epoch }}
|
|
||||||
privatekey_path: '{{ tmpdir_path }}/testcertificates.key'
|
|
||||||
entrust_api_cert: '{{ tmpdir_path }}/authcert.cer'
|
|
||||||
entrust_api_cert_key: '{{ tmpdir_path }}/authkey.cer'
|
|
||||||
csr_path: '{{ tmpdir_path }}/request.csr'
|
|
||||||
|
|
||||||
entrust_requester_name: C Trufan
|
|
||||||
entrust_requester_email: CTIntegrationTests@entrustdatacard.com
|
|
||||||
entrust_requester_phone: 1-555-555-5555 # e.g. 15555555555
|
|
||||||
|
|
||||||
# TEST 1
|
|
||||||
example1_cert_path: '{{ tmpdir_path }}/issuedcert_1.pem'
|
|
||||||
example1_chain_path: '{{ tmpdir_path }}/issuedcert_1_chain.pem'
|
|
||||||
example1_cert_type: EV_SSL
|
|
||||||
|
|
||||||
example4_cert_path: '{{ tmpdir_path }}/issuedcert_2.pem'
|
|
||||||
example4_subject_alt_name:
|
|
||||||
- ansible.testcertificates.com
|
|
||||||
- www.testcertificates.com
|
|
||||||
example4_eku: SERVER_AND_CLIENT_AUTH
|
|
||||||
example4_cert_type: UC_SSL
|
|
||||||
# Test a secondary org and special characters
|
|
||||||
example4_org: Cañon City, Inc.
|
|
||||||
example4_ou:
|
|
||||||
- StringrsaString
|
|
||||||
example4_tracking_info: Submitted via Ansible Integration
|
|
||||||
example4_additional_emails:
|
|
||||||
- itsupport@testcertificates.com
|
|
||||||
- jsmith@ansible.com
|
|
||||||
example4_custom_fields:
|
|
||||||
text1: Admin
|
|
||||||
text2: Invoice 25
|
|
||||||
number1: 342
|
|
||||||
date3: '2018-01-01'
|
|
||||||
email2: sales@ansible.testcertificates.com
|
|
||||||
dropdown2: Dropdown 2 Value 1
|
|
||||||
example4_cert_expiry: 2020-08-15
|
|
||||||
example4_full_chain_path: '{{ tmpdir_path }}/issuedcert_2_chain.pem'
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# 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
|
|
||||||
|
|
||||||
# Not enabled due to lack of access to test environments. May be enabled using custom integration_config.yml
|
|
||||||
# Example integation_config.yml
|
|
||||||
# ---
|
|
||||||
# entrust_api_user:
|
|
||||||
# entrust_api_key:
|
|
||||||
# entrust_api_client_cert_path: /var/integration-testing/publicCert.pem
|
|
||||||
# entrust_api_client_cert_key_path: /var/integration-testing/privateKey.pem
|
|
||||||
# entrust_api_ip_address: 127.0.0.1
|
|
||||||
# entrust_cloud_ip_address: 127.0.0.1
|
|
||||||
# # Used for certificate path validation of QA environments - we chose not to support disabling path validation ever.
|
|
||||||
# cacerts_bundle_path_local: /var/integration-testing/cacerts
|
|
||||||
|
|
||||||
### WARNING: This test will update HOSTS file and CERTIFICATE STORE of target host, in order to be able to validate
|
|
||||||
# to a QA environment. ###
|
|
||||||
unsupported
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
---
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# defaults file for test_ecs_domain
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
---
|
|
||||||
# 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:
|
|
||||||
- prepare_tests
|
|
||||||
@@ -1,277 +0,0 @@
|
|||||||
---
|
|
||||||
# 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 #
|
|
||||||
####################################################################
|
|
||||||
|
|
||||||
## Verify that integration_config was specified
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- entrust_api_user is defined
|
|
||||||
- entrust_api_key is defined
|
|
||||||
- entrust_api_ip_address is defined
|
|
||||||
- entrust_cloud_ip_address is defined
|
|
||||||
- entrust_api_client_cert_path is defined or entrust_api_client_cert_contents is defined
|
|
||||||
- entrust_api_client_cert_key_path is defined or entrust_api_client_cert_key_contents
|
|
||||||
- cacerts_bundle_path_local is defined
|
|
||||||
|
|
||||||
## SET UP TEST ENVIRONMENT ########################################################################
|
|
||||||
- name: copy the files needed for verifying test server certificate to the host
|
|
||||||
copy:
|
|
||||||
src: '{{ cacerts_bundle_path_local }}/'
|
|
||||||
dest: '{{ cacerts_bundle_path }}'
|
|
||||||
|
|
||||||
- name: Update the CA certificates for our QA certs (collection may need updating if new QA environments used)
|
|
||||||
command: c_rehash {{ cacerts_bundle_path }}
|
|
||||||
|
|
||||||
- name: Update hosts file
|
|
||||||
lineinfile:
|
|
||||||
path: /etc/hosts
|
|
||||||
state: present
|
|
||||||
regexp: 'api.entrust.net$'
|
|
||||||
line: '{{ entrust_api_ip_address }} api.entrust.net'
|
|
||||||
|
|
||||||
- name: Update hosts file
|
|
||||||
lineinfile:
|
|
||||||
path: /etc/hosts
|
|
||||||
state: present
|
|
||||||
regexp: 'cloud.entrust.net$'
|
|
||||||
line: '{{ entrust_cloud_ip_address }} cloud.entrust.net'
|
|
||||||
|
|
||||||
- name: Clear out the temporary directory for storing the API connection information
|
|
||||||
file:
|
|
||||||
path: '{{ tmpdir_path }}'
|
|
||||||
state: absent
|
|
||||||
|
|
||||||
- name: Create a directory for storing the API connection Information
|
|
||||||
file:
|
|
||||||
path: '{{ tmpdir_path }}'
|
|
||||||
state: directory
|
|
||||||
|
|
||||||
- name: Copy the files needed for the connection to entrust API to the host
|
|
||||||
copy:
|
|
||||||
src: '{{ entrust_api_client_cert_path }}'
|
|
||||||
dest: '{{ entrust_api_cert }}'
|
|
||||||
|
|
||||||
- name: Copy the files needed for the connection to entrust API to the host
|
|
||||||
copy:
|
|
||||||
src: '{{ entrust_api_client_cert_key_path }}'
|
|
||||||
dest: '{{ entrust_api_cert_key }}'
|
|
||||||
|
|
||||||
- block:
|
|
||||||
- name: Have ECS request a domain validation via dns
|
|
||||||
ecs_domain:
|
|
||||||
domain_name: dns.{{ common_name }}
|
|
||||||
verification_method: dns
|
|
||||||
entrust_api_user: '{{ entrust_api_user }}'
|
|
||||||
entrust_api_key: '{{ entrust_api_key }}'
|
|
||||||
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
|
|
||||||
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
|
|
||||||
register: dns_result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- dns_result is not failed
|
|
||||||
- dns_result.changed
|
|
||||||
- dns_result.domain_status == 'INITIAL_VERIFICATION'
|
|
||||||
- dns_result.verification_method == 'dns'
|
|
||||||
- dns_result.dns_location is string
|
|
||||||
- dns_result.dns_contents is string
|
|
||||||
- dns_result.dns_resource_type is string
|
|
||||||
- dns_result.file_location is undefined
|
|
||||||
- dns_result.file_contents is undefined
|
|
||||||
- dns_result.emails is undefined
|
|
||||||
|
|
||||||
- name: Have ECS request a domain validation via web_server
|
|
||||||
ecs_domain:
|
|
||||||
domain_name: FILE.{{ common_name }}
|
|
||||||
verification_method: web_server
|
|
||||||
entrust_api_user: '{{ entrust_api_user }}'
|
|
||||||
entrust_api_key: '{{ entrust_api_key }}'
|
|
||||||
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
|
|
||||||
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
|
|
||||||
register: file_result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- file_result is not failed
|
|
||||||
- file_result.changed
|
|
||||||
- file_result.domain_status == 'INITIAL_VERIFICATION'
|
|
||||||
- file_result.verification_method == 'web_server'
|
|
||||||
- file_result.dns_location is undefined
|
|
||||||
- file_result.dns_contents is undefined
|
|
||||||
- file_result.dns_resource_type is undefined
|
|
||||||
- file_result.file_location is string
|
|
||||||
- file_result.file_contents is string
|
|
||||||
- file_result.emails is undefined
|
|
||||||
|
|
||||||
- name: Have ECS request a domain validation via email
|
|
||||||
ecs_domain:
|
|
||||||
domain_name: email.{{ common_name }}
|
|
||||||
verification_method: email
|
|
||||||
verification_email: admin@testcertificates.com
|
|
||||||
entrust_api_user: '{{ entrust_api_user }}'
|
|
||||||
entrust_api_key: '{{ entrust_api_key }}'
|
|
||||||
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
|
|
||||||
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
|
|
||||||
register: email_result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- email_result is not failed
|
|
||||||
- email_result.changed
|
|
||||||
- email_result.domain_status == 'INITIAL_VERIFICATION'
|
|
||||||
- email_result.verification_method == 'email'
|
|
||||||
- email_result.dns_location is undefined
|
|
||||||
- email_result.dns_contents is undefined
|
|
||||||
- email_result.dns_resource_type is undefined
|
|
||||||
- email_result.file_location is undefined
|
|
||||||
- email_result.file_contents is undefined
|
|
||||||
- email_result.emails[0] == 'admin@testcertificates.com'
|
|
||||||
|
|
||||||
- name: Have ECS request a domain validation via email with no address provided
|
|
||||||
ecs_domain:
|
|
||||||
domain_name: email2.{{ common_name }}
|
|
||||||
verification_method: email
|
|
||||||
entrust_api_user: '{{ entrust_api_user }}'
|
|
||||||
entrust_api_key: '{{ entrust_api_key }}'
|
|
||||||
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
|
|
||||||
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
|
|
||||||
register: email_result2
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- email_result2 is not failed
|
|
||||||
- email_result2.changed
|
|
||||||
- email_result2.domain_status == 'INITIAL_VERIFICATION'
|
|
||||||
- email_result2.verification_method == 'email'
|
|
||||||
- email_result2.dns_location is undefined
|
|
||||||
- email_result2.dns_contents is undefined
|
|
||||||
- email_result2.dns_resource_type is undefined
|
|
||||||
- email_result2.file_location is undefined
|
|
||||||
- email_result2.file_contents is undefined
|
|
||||||
- email_result2.emails is defined
|
|
||||||
|
|
||||||
- name: Have ECS request a domain validation via manual
|
|
||||||
ecs_domain:
|
|
||||||
domain_name: manual.{{ common_name }}
|
|
||||||
verification_method: manual
|
|
||||||
entrust_api_user: '{{ entrust_api_user }}'
|
|
||||||
entrust_api_key: '{{ entrust_api_key }}'
|
|
||||||
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
|
|
||||||
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
|
|
||||||
register: manual_result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- manual_result is not failed
|
|
||||||
- manual_result.changed
|
|
||||||
- manual_result.domain_status == 'INITIAL_VERIFICATION'
|
|
||||||
- manual_result.verification_method == 'manual'
|
|
||||||
- manual_result.dns_location is undefined
|
|
||||||
- manual_result.dns_contents is undefined
|
|
||||||
- manual_result.dns_resource_type is undefined
|
|
||||||
- manual_result.file_location is undefined
|
|
||||||
- manual_result.file_contents is undefined
|
|
||||||
- manual_result.emails is undefined
|
|
||||||
|
|
||||||
- name: Have ECS request a domain validation via dns that remains unchanged
|
|
||||||
ecs_domain:
|
|
||||||
domain_name: dns.{{ common_name }}
|
|
||||||
verification_method: dns
|
|
||||||
entrust_api_user: '{{ entrust_api_user }}'
|
|
||||||
entrust_api_key: '{{ entrust_api_key }}'
|
|
||||||
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
|
|
||||||
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
|
|
||||||
register: dns_result2
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- dns_result2 is not failed
|
|
||||||
- not dns_result2.changed
|
|
||||||
- dns_result2.domain_status == 'INITIAL_VERIFICATION'
|
|
||||||
- dns_result2.verification_method == 'dns'
|
|
||||||
- dns_result2.dns_location is string
|
|
||||||
- dns_result2.dns_contents is string
|
|
||||||
- dns_result2.dns_resource_type is string
|
|
||||||
- dns_result2.file_location is undefined
|
|
||||||
- dns_result2.file_contents is undefined
|
|
||||||
- dns_result2.emails is undefined
|
|
||||||
|
|
||||||
- name: Have ECS request a domain validation via FILE for dns, to change verification method
|
|
||||||
ecs_domain:
|
|
||||||
domain_name: dns.{{ common_name }}
|
|
||||||
verification_method: web_server
|
|
||||||
entrust_api_user: '{{ entrust_api_user }}'
|
|
||||||
entrust_api_key: '{{ entrust_api_key }}'
|
|
||||||
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
|
|
||||||
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
|
|
||||||
register: dns_result_now_file
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- dns_result_now_file is not failed
|
|
||||||
- dns_result_now_file.changed
|
|
||||||
- dns_result_now_file.domain_status == 'INITIAL_VERIFICATION'
|
|
||||||
- dns_result_now_file.verification_method == 'web_server'
|
|
||||||
- dns_result_now_file.dns_location is undefined
|
|
||||||
- dns_result_now_file.dns_contents is undefined
|
|
||||||
- dns_result_now_file.dns_resource_type is undefined
|
|
||||||
- dns_result_now_file.file_location is string
|
|
||||||
- dns_result_now_file.file_contents is string
|
|
||||||
- dns_result_now_file.emails is undefined
|
|
||||||
|
|
||||||
- name: Request revalidation of an approved domain
|
|
||||||
ecs_domain:
|
|
||||||
domain_name: '{{ existing_domain_common_name }}'
|
|
||||||
verification_method: manual
|
|
||||||
entrust_api_user: '{{ entrust_api_user }}'
|
|
||||||
entrust_api_key: '{{ entrust_api_key }}'
|
|
||||||
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
|
|
||||||
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
|
|
||||||
register: manual_existing_domain
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- manual_existing_domain is not failed
|
|
||||||
- not manual_existing_domain.changed
|
|
||||||
- manual_existing_domain.domain_status == 'RE_VERIFICATION'
|
|
||||||
- manual_existing_domain.dns_location is undefined
|
|
||||||
- manual_existing_domain.dns_contents is undefined
|
|
||||||
- manual_existing_domain.dns_resource_type is undefined
|
|
||||||
- manual_existing_domain.file_location is undefined
|
|
||||||
- manual_existing_domain.file_contents is undefined
|
|
||||||
- manual_existing_domain.emails is undefined
|
|
||||||
|
|
||||||
- name: Request revalidation of an approved domain
|
|
||||||
ecs_domain:
|
|
||||||
domain_name: '{{ existing_domain_common_name }}'
|
|
||||||
verification_method: web_server
|
|
||||||
entrust_api_user: '{{ entrust_api_user }}'
|
|
||||||
entrust_api_key: '{{ entrust_api_key }}'
|
|
||||||
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
|
|
||||||
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
|
|
||||||
register: file_existing_domain_revalidate
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- file_existing_domain_revalidate is not failed
|
|
||||||
- file_existing_domain_revalidate.changed
|
|
||||||
- file_existing_domain_revalidate.domain_status == 'RE_VERIFICATION'
|
|
||||||
- file_existing_domain_revalidate.verification_method == 'web_server'
|
|
||||||
- file_existing_domain_revalidate.dns_location is undefined
|
|
||||||
- file_existing_domain_revalidate.dns_contents is undefined
|
|
||||||
- file_existing_domain_revalidate.dns_resource_type is undefined
|
|
||||||
- file_existing_domain_revalidate.file_location is string
|
|
||||||
- file_existing_domain_revalidate.file_contents is string
|
|
||||||
- file_existing_domain_revalidate.emails is undefined
|
|
||||||
|
|
||||||
always:
|
|
||||||
- name: clean-up temporary folder
|
|
||||||
file:
|
|
||||||
path: '{{ tmpdir_path }}'
|
|
||||||
state: absent
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
---
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# vars file for test_ecs_certificate
|
|
||||||
|
|
||||||
# Path on various hosts that cacerts need to be put as a prerequisite to API server cert validation.
|
|
||||||
# May need to be customized for some environments based on SSL implementations
|
|
||||||
# that ansible "urls" module utility is using as a backing.
|
|
||||||
cacerts_bundle_path: /etc/pki/tls/certs
|
|
||||||
|
|
||||||
common_name: '{{ ansible_date_time.epoch }}.testcertificates.com'
|
|
||||||
existing_domain_common_name: 'testcertificates.com'
|
|
||||||
|
|
||||||
tmpdir_path: /tmp/ecs_cert_test/{{ ansible_date_time.epoch }}
|
|
||||||
|
|
||||||
entrust_api_cert: '{{ tmpdir_path }}/authcert.cer'
|
|
||||||
entrust_api_cert_key: '{{ tmpdir_path }}/authkey.cer'
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
meta/runtime.yml runtime-metadata # Bug in ansible-test: https://github.com/ansible/ansible/pull/85198
|
||||||
plugins/module_utils/_acme/account.py pep8:E704
|
plugins/module_utils/_acme/account.py pep8:E704
|
||||||
plugins/module_utils/_acme/acme.py pep8:E704
|
plugins/module_utils/_acme/acme.py pep8:E704
|
||||||
plugins/module_utils/_acme/acme.py pylint:unpacking-non-sequence
|
plugins/module_utils/_acme/acme.py pylint:unpacking-non-sequence
|
||||||
@@ -5,7 +6,6 @@ plugins/module_utils/_acme/backend_openssl_cli.py pep8:E704
|
|||||||
plugins/module_utils/_acme/certificate.py pep8:E704
|
plugins/module_utils/_acme/certificate.py pep8:E704
|
||||||
plugins/module_utils/_crypto/cryptography_support.py pep8:E704
|
plugins/module_utils/_crypto/cryptography_support.py pep8:E704
|
||||||
plugins/module_utils/_crypto/module_backends/certificate.py no-assert
|
plugins/module_utils/_crypto/module_backends/certificate.py no-assert
|
||||||
plugins/module_utils/_crypto/module_backends/certificate_entrust.py no-assert
|
|
||||||
plugins/module_utils/_crypto/module_backends/certificate_ownca.py no-assert
|
plugins/module_utils/_crypto/module_backends/certificate_ownca.py no-assert
|
||||||
plugins/module_utils/_crypto/module_backends/certificate_selfsigned.py no-assert
|
plugins/module_utils/_crypto/module_backends/certificate_selfsigned.py no-assert
|
||||||
plugins/module_utils/_crypto/module_backends/csr.py no-assert
|
plugins/module_utils/_crypto/module_backends/csr.py no-assert
|
||||||
@@ -21,8 +21,6 @@ plugins/modules/acme_certificate_deactivate_authz.py pylint:unpacking-non-sequen
|
|||||||
plugins/modules/acme_certificate_order_finalize.py pylint:unpacking-non-sequence
|
plugins/modules/acme_certificate_order_finalize.py pylint:unpacking-non-sequence
|
||||||
plugins/modules/acme_certificate_revoke.py pylint:unpacking-non-sequence
|
plugins/modules/acme_certificate_revoke.py pylint:unpacking-non-sequence
|
||||||
plugins/modules/acme_inspect.py pylint:unpacking-non-sequence
|
plugins/modules/acme_inspect.py pylint:unpacking-non-sequence
|
||||||
plugins/modules/ecs_certificate.py no-assert
|
|
||||||
plugins/modules/ecs_domain.py pep8:E704
|
|
||||||
plugins/modules/get_certificate.py pylint:unknown-option-value
|
plugins/modules/get_certificate.py pylint:unknown-option-value
|
||||||
plugins/modules/luks_device.py no-assert
|
plugins/modules/luks_device.py no-assert
|
||||||
plugins/modules/openssl_pkcs12.py no-assert
|
plugins/modules/openssl_pkcs12.py no-assert
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
|
meta/runtime.yml runtime-metadata # Bug in ansible-test: https://github.com/ansible/ansible/pull/85198
|
||||||
plugins/module_utils/_acme/account.py pep8:E704
|
plugins/module_utils/_acme/account.py pep8:E704
|
||||||
plugins/module_utils/_acme/acme.py pep8:E704
|
plugins/module_utils/_acme/acme.py pep8:E704
|
||||||
plugins/module_utils/_acme/backend_openssl_cli.py pep8:E704
|
plugins/module_utils/_acme/backend_openssl_cli.py pep8:E704
|
||||||
plugins/module_utils/_acme/certificate.py pep8:E704
|
plugins/module_utils/_acme/certificate.py pep8:E704
|
||||||
plugins/module_utils/_crypto/cryptography_support.py pep8:E704
|
plugins/module_utils/_crypto/cryptography_support.py pep8:E704
|
||||||
plugins/module_utils/_crypto/module_backends/certificate.py no-assert
|
plugins/module_utils/_crypto/module_backends/certificate.py no-assert
|
||||||
plugins/module_utils/_crypto/module_backends/certificate_entrust.py no-assert
|
|
||||||
plugins/module_utils/_crypto/module_backends/certificate_ownca.py no-assert
|
plugins/module_utils/_crypto/module_backends/certificate_ownca.py no-assert
|
||||||
plugins/module_utils/_crypto/module_backends/certificate_selfsigned.py no-assert
|
plugins/module_utils/_crypto/module_backends/certificate_selfsigned.py no-assert
|
||||||
plugins/module_utils/_crypto/module_backends/csr.py no-assert
|
plugins/module_utils/_crypto/module_backends/csr.py no-assert
|
||||||
@@ -13,8 +13,6 @@ plugins/module_utils/_crypto/support.py pep8:E704
|
|||||||
plugins/module_utils/_openssh/backends/keypair_backend.py no-assert
|
plugins/module_utils/_openssh/backends/keypair_backend.py no-assert
|
||||||
plugins/module_utils/_openssh/certificate.py pep8:E704
|
plugins/module_utils/_openssh/certificate.py pep8:E704
|
||||||
plugins/modules/acme_certificate.py no-assert
|
plugins/modules/acme_certificate.py no-assert
|
||||||
plugins/modules/ecs_certificate.py no-assert
|
|
||||||
plugins/modules/ecs_domain.py pep8:E704
|
|
||||||
plugins/modules/luks_device.py no-assert
|
plugins/modules/luks_device.py no-assert
|
||||||
plugins/modules/openssl_pkcs12.py no-assert
|
plugins/modules/openssl_pkcs12.py no-assert
|
||||||
tests/ee/roles/smoke/library/smoke_ipaddress.py shebang
|
tests/ee/roles/smoke/library/smoke_ipaddress.py shebang
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
|
meta/runtime.yml runtime-metadata # Bug in ansible-test: https://github.com/ansible/ansible/pull/85198
|
||||||
plugins/module_utils/_crypto/module_backends/certificate.py no-assert
|
plugins/module_utils/_crypto/module_backends/certificate.py no-assert
|
||||||
plugins/module_utils/_crypto/module_backends/certificate_entrust.py no-assert
|
|
||||||
plugins/module_utils/_crypto/module_backends/certificate_ownca.py no-assert
|
plugins/module_utils/_crypto/module_backends/certificate_ownca.py no-assert
|
||||||
plugins/module_utils/_crypto/module_backends/certificate_selfsigned.py no-assert
|
plugins/module_utils/_crypto/module_backends/certificate_selfsigned.py no-assert
|
||||||
plugins/module_utils/_crypto/module_backends/csr.py no-assert
|
plugins/module_utils/_crypto/module_backends/csr.py no-assert
|
||||||
plugins/module_utils/_crypto/module_backends/privatekey_convert.py no-assert
|
plugins/module_utils/_crypto/module_backends/privatekey_convert.py no-assert
|
||||||
plugins/module_utils/_openssh/backends/keypair_backend.py no-assert
|
plugins/module_utils/_openssh/backends/keypair_backend.py no-assert
|
||||||
plugins/modules/acme_certificate.py no-assert
|
plugins/modules/acme_certificate.py no-assert
|
||||||
plugins/modules/ecs_certificate.py no-assert
|
|
||||||
plugins/modules/luks_device.py no-assert
|
plugins/modules/luks_device.py no-assert
|
||||||
plugins/modules/openssl_pkcs12.py no-assert
|
plugins/modules/openssl_pkcs12.py no-assert
|
||||||
tests/ee/roles/smoke/library/smoke_ipaddress.py shebang
|
tests/ee/roles/smoke/library/smoke_ipaddress.py shebang
|
||||||
|
|||||||
Reference in New Issue
Block a user