Compare commits

...

42 Commits
1.8.0 ... 1.9.5

Author SHA1 Message Date
Felix Fontein
fbadcbeb29 Release 1.9.5. 2021-10-06 13:08:43 +02:00
Felix Fontein
e991375f55 Prepare 1.9.5 release. 2021-10-05 22:28:03 +02:00
Felix Fontein
33c99014ae [stable-1] Fix PyOpenSSL backends with cryptography 35.0.0 (#300)
* Try to make compatible with cryptography 35.0.0.

* Forgot import.

ci_complete

* Add changelog fragment.
2021-10-05 22:19:11 +02:00
patchback[bot]
fbd6ff6ead x509_certificate: document that *notBefore/*notAfter are not used for idempotency (#298) (#301)
* Document that *notBefore/*notAfter are not used for idempotency.

* Change formulation.

(cherry picked from commit ed03841fd1)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-10-03 22:20:34 +02:00
patchback[bot]
c4ab2eb3b5 Fix PKCS#12 friendly name extraction for cryptography 35.0.0. (#296) (#299)
(cherry picked from commit d6c0d53442)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-10-03 21:37:37 +02:00
patchback[bot]
44b6df0ce5 Support cryptography 35.0.0 for all modules except openssl_pkcs12 (#294) (#297)
* Add some workarounds for cryptography 35.0.0.

* Make fix work with very old cryptography versions as well (which supported multiple backends).

* [TEMP] Disable openssl_pkcs12 tests to see whether everything else works.

* Revert "[TEMP] Disable openssl_pkcs12 tests to see whether everything else works."

This reverts commit 3f905bc795.

* Add changelog fragment.

* Remove unnecessary assignment.

* Simplify code change.

* [TEMP] Disable openssl_pkcs12 tests to see whether everything else works.

* Revert "[TEMP] Disable openssl_pkcs12 tests to see whether everything else works."

This reverts commit fdb210528e.

(cherry picked from commit a2a7d94055)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-10-03 17:23:35 +02:00
Felix Fontein
14a42505a9 Ansible-core devel dropped support for Python 2.6.
(cherry picked from commit 2a7e452cf8)
2021-10-01 13:46:08 +02:00
Felix Fontein
44cbd33cb7 Run CI on stable branches only once per week.
(cherry picked from commit 24e7d07973)
2021-10-01 13:44:44 +02:00
Felix Fontein
4411a71d06 Temporarily fix CI for cryptography 35.0.0 release. (#292)
(cherry picked from commit 57c364fe87)
2021-09-30 13:45:38 +02:00
Felix Fontein
bfe37bc668 Next expected 1.x.y release is 1.9.5. 2021-09-28 17:31:41 +02:00
Felix Fontein
d784e0a52b Release 1.9.4. 2021-09-28 17:17:41 +02:00
Felix Fontein
d73a2942a2 Prepare 1.9.4 release. 2021-09-28 16:53:56 +02:00
Felix Fontein
8af4847373 Update CI matrix to include ansible-core's stable-2.12 branch (#286)
* Update CI matrix to include ansible-core's stable-2.12 branch.

* Adjust README.

* Fix stage names.
2021-09-28 15:35:26 +02:00
Felix Fontein
44f7367e21 Extend CI (#283)
* Run all tests on all targets. Remove hack in setup_acme.

* Fix some failing tests.

* OpenSSH tests do not work yet with default image on Ansible 2.9. Let's skip them on the cloud target.

* Make tests pass again.

* Make sure to install *latest* versions of cryptography and pyOpenSSL when not installing system packages, whenever possible.

ci_complete

* Update/fix aliases files.
2021-09-25 17:21:06 +02:00
Felix Fontein
0733b0d521 Prepare ansible-core devel branch version bump that is planned for later today. 2021-09-24 18:45:50 +02:00
Ajpantuso
771a9eebcf Initial commit (#285) 2021-09-24 06:59:52 +02:00
Felix Fontein
0fdede5d7a Fix CI (1/2) (#284)
* New default docker image no longer contains bcrypt.

* Install cryptography for ACME tests.

* Add constraints.
2021-09-23 21:56:03 +02:00
Felix Fontein
56b2130c6e openssl_privatekey_pipe is an action plugin. (#267) 2021-09-21 07:29:26 +02:00
Felix Fontein
6c018b94da Improve CI (#281)
* Install PyOpenSSL and cryptography from PyPi if target Python != system Python.

* Work around some CentOS6, 7, Ubuntu 16.04 problems. Improve jinja2 compatibility handling.

* Skip tasks that require properties that aren't always there.

* Only install OpenSSL when not present.

* Improve output.

* Improve get_certificate integration test graceful failing.

* Fix tests.

* Fix assert.

* OpenSSL peculiarities.

* Fix condition.
2021-09-18 15:21:40 +02:00
Felix Fontein
63f4598737 acme_challenge_cert_helper: fail better to avoid crashes in Ansible (#282)
* Prevent acme_challenge_cert_helper triggering a bug in Ansible.

* Add changelog fragment.
2021-09-17 19:35:43 +02:00
Felix Fontein
598cdf0a21 Older openssl versions (1.0.1/1.0.2) do not seem to support '-' for /dev/stdin. (#279) 2021-09-15 20:42:52 +02:00
Ajpantuso
eea7bfc6bf openssh_cert - adding signature_algorithm option (#277)
* Initial Commit

* Update supported OpenSSH versions for RSA SHA-2 signed certs

* Updating 'regenerate' documentation
2021-09-15 08:53:53 +02:00
Felix Fontein
8521c96e8a Next expected release is 1.10.0. 2021-09-14 12:33:06 +02:00
Felix Fontein
d90cc5142b Release 1.9.3. 2021-09-14 08:15:32 +02:00
Felix Fontein
37aab65396 Prepare 1.9.3 release. 2021-09-14 07:14:03 +02:00
Felix Fontein
baff003ea8 Fix changelog from last time. 2021-09-14 07:13:25 +02:00
Felix Fontein
03427e35a7 Fix idempotency for non-ASCII string comparisons. (#271) 2021-09-14 07:06:35 +02:00
Felix Fontein
170fa40014 ipaddress is part of stdlib for Python 3. (#275) 2021-09-12 17:21:10 +02:00
Felix Fontein
330b30d5d2 certificate_complete_chain tests need cryptography installed on the target, so use setup_openssl. (#272) 2021-09-11 11:29:03 +02:00
Felix Fontein
67b8274faf openssl_csr: fix error in docs (#269)
* Fix error in docs.

* Add missing word.
2021-09-10 20:53:50 +02:00
Felix Fontein
02ee3fb974 Improve CI (#268)
* Remove superfluous remote_src.

* Use temp dir twice instead of output_dir.

* Use remote temp directory instead of output_dir.

* Fix syntax error.

* Add some fixes.

* Copy more files to remote.

* More fixes.

* Fixing ACME/'cloud' tests.

* Forgot when.

* Try to fix filters.

* Skip unnecessary steps.

* Avoid collision.
2021-09-07 22:37:40 +02:00
Felix Fontein
93ced1956c The next expected release is again 1.10.0. 2021-08-30 22:01:49 +02:00
Felix Fontein
a9e358ea57 Bugfix release 1.9.2. 2021-08-30 22:01:16 +02:00
Felix Fontein
ffcdbc5d0c Add non-existing 1.9.1 release. 2021-08-30 22:00:39 +02:00
Felix Fontein
6740cae10f Next release is expected to be 1.10.0. 2021-08-30 20:46:46 +02:00
Felix Fontein
915379459d Release 1.9.0. 2021-08-30 20:12:47 +02:00
Felix Fontein
a4a12bae27 Prepare 1.9.0 release. 2021-08-27 05:54:45 +02:00
Felix Fontein
94fc356338 https://github.com/diafygi/acme-tiny/pull/254 has been merged. (#265) 2021-08-22 12:41:41 +02:00
Ajpantuso
08ada24a53 openssh_keypair - Add diff support and general cleanup (#260)
* Initial commit

* Matching tests to overwritten permissions behavior with cryptography

* Ensuring key validation only occurs when state=present and accomodating CentOS6 restrictions

* Making ssh-keygen behavior explicit by version in tests

* Ensuring cyrptography not excluded in new conditions

* Adding changelog fragment

* Fixing sanity checks

* Improving readability

* Applying review suggestions

* addressing restore_on_failure conflict
2021-08-18 09:22:31 +02:00
Ajpantuso
b59846b9fa get_certificate - add starttls option with support for mysql (#264)
* Initial commit

* Adding changelog fragment

* Applying initial review suggestion
2021-08-15 15:40:54 +02:00
Felix Fontein
c9ec463893 Fix sanity failures (#263)
* Fix sanity failures.

* Add changelog fragment.
2021-08-12 09:23:11 +00:00
Felix Fontein
38ce150f80 Next expected release is 1.9.0. 2021-08-10 18:26:55 +02:00
166 changed files with 3529 additions and 2166 deletions

View File

@@ -19,6 +19,11 @@ schedules:
branches:
include:
- main
- cron: 0 12 * * 0
displayName: Weekly (old stable branches)
always: true
branches:
include:
- stable-*
variables:
@@ -55,6 +60,17 @@ stages:
test: 'devel/sanity/extra'
- name: Units
test: 'devel/units/1'
- stage: Ansible_2_12
displayName: Sanity & Units 2.12
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
targets:
- name: Sanity
test: '2.12/sanity/1'
- name: Units
test: '2.12/units/1'
- stage: Ansible_2_11
displayName: Sanity & Units 2.11
dependsOn: []
@@ -97,8 +113,6 @@ stages:
parameters:
testFormat: devel/linux/{0}/1
targets:
- name: CentOS 6
test: centos6
- name: CentOS 7
test: centos7
- name: CentOS 8
@@ -115,6 +129,24 @@ stages:
test: ubuntu1804
- name: Ubuntu 20.04
test: ubuntu2004
- stage: Docker_2_12
displayName: Docker 2.12
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
testFormat: 2.12/linux/{0}/1
targets:
- name: CentOS 6
test: centos6
- name: CentOS 8
test: centos8
- name: Fedora 33
test: fedora33
- name: openSUSE 15 py3
test: opensuse15
- name: Ubuntu 20.04
test: ubuntu2004
- stage: Docker_2_11
displayName: Docker 2.11
dependsOn: []
@@ -131,12 +163,8 @@ stages:
test: fedora32
- name: openSUSE 15 py2
test: opensuse15py2
- name: openSUSE 15 py3
test: opensuse15
- name: Ubuntu 18.04
test: ubuntu1804
- name: Ubuntu 20.04
test: ubuntu2004
- stage: Docker_2_10
displayName: Docker 2.10
dependsOn: []
@@ -147,22 +175,10 @@ stages:
targets:
- name: CentOS 6
test: centos6
- name: CentOS 7
test: centos7
- name: CentOS 8
test: centos8
- name: Fedora 31
test: fedora31
- name: Fedora 32
test: fedora32
- name: openSUSE 15 py2
test: opensuse15py2
- name: openSUSE 15 py3
test: opensuse15
- name: Ubuntu 16.04
test: ubuntu1604
- name: Ubuntu 18.04
test: ubuntu1804
- stage: Docker_2_9
displayName: Docker 2.9
dependsOn: []
@@ -175,16 +191,8 @@ stages:
test: centos6
- name: CentOS 7
test: centos7
- name: CentOS 8
test: centos8
- name: Fedora 30
test: fedora30
- name: Fedora 31
test: fedora31
- name: openSUSE 15 py2
test: opensuse15py2
- name: openSUSE 15 py3
test: opensuse15
- name: Ubuntu 16.04
test: ubuntu1604
- name: Ubuntu 18.04
@@ -209,6 +217,20 @@ stages:
test: freebsd/12.2
- name: FreeBSD 13.0
test: freebsd/13.0
- stage: Remote_2_12
displayName: Remote 2.12
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
testFormat: 2.12/{0}/1
targets:
- name: macOS 11.1
test: macos/11.1
- name: RHEL 8.4
test: rhel/8.4
- name: FreeBSD 13.0
test: freebsd/13.0
- stage: Remote_2_11
displayName: Remote 2.11
dependsOn: []
@@ -221,8 +243,6 @@ stages:
test: rhel/7.9
- name: RHEL 8.3
test: rhel/8.3
- name: macOS 11.1
test: macos/11.1
- name: FreeBSD 12.2
test: freebsd/12.2
- stage: Remote_2_10
@@ -233,8 +253,6 @@ stages:
parameters:
testFormat: 2.10/{0}/1
targets:
- name: RHEL 7.8
test: rhel/7.8
- name: OS X 10.11
test: osx/10.11
- name: macOS 10.15
@@ -261,7 +279,6 @@ stages:
nameFormat: Python {0}
testFormat: devel/cloud/{0}/1
targets:
- test: 2.6
- test: 2.7
- test: 3.5
- test: 3.6
@@ -269,6 +286,17 @@ stages:
- test: 3.8
- test: 3.9
- test: "3.10"
- stage: Cloud_2_12
displayName: Cloud 2.12
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Python {0}
testFormat: 2.12/cloud/{0}/1
targets:
- test: 2.6
- test: 3.9
- stage: Cloud_2_11
displayName: Cloud 2.11
dependsOn: []
@@ -306,20 +334,24 @@ stages:
condition: succeededOrFailed()
dependsOn:
- Ansible_devel
- Ansible_2_12
- Ansible_2_11
- Ansible_2_10
- Ansible_2_9
- Remote_devel
- Docker_devel
- Cloud_devel
- Remote_2_12
- Remote_2_11
- Docker_2_11
- Cloud_2_11
- Remote_2_10
- Docker_2_10
- Cloud_2_10
- Remote_2_9
- Docker_devel
- Docker_2_12
- Docker_2_11
- Docker_2_10
- Docker_2_9
- Cloud_devel
- Cloud_2_12
- Cloud_2_11
- Cloud_2_10
- Cloud_2_9
jobs:
- template: templates/coverage.yml

View File

@@ -5,6 +5,89 @@ Community Crypto Release Notes
.. contents:: Topics
v1.9.5
======
Release Summary
---------------
Bugfix release to fully support cryptography 35.0.0.
Bugfixes
--------
- get_certificate - fix compatibility with the cryptography 35.0.0 release (https://github.com/ansible-collections/community.crypto/pull/294).
- openssl_csr_info - fix compatibility with the cryptography 35.0.0 release (https://github.com/ansible-collections/community.crypto/pull/294).
- openssl_csr_info - fix compatibility with the cryptography 35.0.0 release in PyOpenSSL backend (https://github.com/ansible-collections/community.crypto/pull/300).
- openssl_pkcs12 - fix compatibility with the cryptography 35.0.0 release (https://github.com/ansible-collections/community.crypto/pull/296).
- x509_certificate_info - fix compatibility with the cryptography 35.0.0 release (https://github.com/ansible-collections/community.crypto/pull/294).
- x509_certificate_info - fix compatibility with the cryptography 35.0.0 release in PyOpenSSL backend (https://github.com/ansible-collections/community.crypto/pull/300).
v1.9.4
======
Release Summary
---------------
Regular bugfix release.
Bugfixes
--------
- acme_* modules - fix commands composed for OpenSSL backend to retrieve information on CSRs and certificates from stdin to use ``/dev/stdin`` instead of ``-``. This is needed for OpenSSL 1.0.1 and 1.0.2, apparently (https://github.com/ansible-collections/community.crypto/pull/279).
- acme_challenge_cert_helper - only return exception when cryptography is not installed, not when a too old version of it is installed. This prevents Ansible's callback to crash (https://github.com/ansible-collections/community.crypto/pull/281).
v1.9.3
======
Release Summary
---------------
Regular bugfix release.
Bugfixes
--------
- openssl_csr and openssl_csr_pipe - make sure that Unicode strings are used to compare strings with the cryptography backend. This fixes idempotency problems with non-ASCII letters on Python 2 (https://github.com/ansible-collections/community.crypto/issues/270, https://github.com/ansible-collections/community.crypto/pull/271).
v1.9.2
======
Release Summary
---------------
Bugfix release to fix the changelog. No other change compared to 1.9.0.
v1.9.1
======
Release Summary
---------------
Accidental 1.9.1 release. Identical to 1.9.0.
v1.9.0
======
Release Summary
---------------
Regular feature release.
Minor Changes
-------------
- get_certificate - added ``starttls`` option to retrieve certificates from servers which require clients to request an encrypted connection (https://github.com/ansible-collections/community.crypto/pull/264).
- openssh_keypair - added ``diff`` support (https://github.com/ansible-collections/community.crypto/pull/260).
Bugfixes
--------
- keypair_backend module utils - simplify code to pass sanity tests (https://github.com/ansible-collections/community.crypto/pull/263).
- openssh_keypair - fixed ``cryptography`` backend to preserve original file permissions when regenerating a keypair requires existing files to be overwritten (https://github.com/ansible-collections/community.crypto/pull/260).
- openssh_keypair - fixed error handling to restore original keypair if regeneration fails (https://github.com/ansible-collections/community.crypto/pull/260).
- x509_crl - restore inherited function signature to pass sanity tests (https://github.com/ansible-collections/community.crypto/pull/263).
v1.8.0
======

View File

@@ -11,7 +11,7 @@ Please note that this collection does **not** support Windows targets.
## Tested with Ansible
Tested with the current Ansible 2.9, ansible-base 2.10 and ansible-core 2.11 releases and the current development version of ansible-core. Ansible versions before 2.9.10 are not supported.
Tested with the current Ansible 2.9, ansible-base 2.10, ansible-core 2.11 and ansible-core 2.12 releases and the current development version of ansible-core. Ansible versions before 2.9.10 are not supported.
## External requirements

View File

@@ -503,3 +503,82 @@ releases:
- 257-openssh-keypair-fix-pubkey-permissions.yml
- ansible-core-_text.yml
release_date: '2021-08-10'
1.9.0:
changes:
bugfixes:
- keypair_backend module utils - simplify code to pass sanity tests (https://github.com/ansible-collections/community.crypto/pull/263).
- openssh_keypair - fixed ``cryptography`` backend to preserve original file
permissions when regenerating a keypair requires existing files to be overwritten
(https://github.com/ansible-collections/community.crypto/pull/260).
- openssh_keypair - fixed error handling to restore original keypair if regeneration
fails (https://github.com/ansible-collections/community.crypto/pull/260).
- x509_crl - restore inherited function signature to pass sanity tests (https://github.com/ansible-collections/community.crypto/pull/263).
minor_changes:
- get_certificate - added ``starttls`` option to retrieve certificates from
servers which require clients to request an encrypted connection (https://github.com/ansible-collections/community.crypto/pull/264).
- openssh_keypair - added ``diff`` support (https://github.com/ansible-collections/community.crypto/pull/260).
release_summary: Regular feature release.
fragments:
- 1.9.0.yml
- 260-openssh_keypair-diff-support.yml
- 263-sanity.yml
- 264-get_certificate-add-starttls-option.yml
release_date: '2021-08-30'
1.9.1:
changes:
release_summary: Accidental 1.9.1 release. Identical to 1.9.0.
release_date: '2021-08-30'
1.9.2:
changes:
release_summary: Bugfix release to fix the changelog. No other change compared
to 1.9.0.
fragments:
- 1.9.2.yml
release_date: '2021-08-30'
1.9.3:
changes:
bugfixes:
- openssl_csr and openssl_csr_pipe - make sure that Unicode strings are used
to compare strings with the cryptography backend. This fixes idempotency problems
with non-ASCII letters on Python 2 (https://github.com/ansible-collections/community.crypto/issues/270,
https://github.com/ansible-collections/community.crypto/pull/271).
release_summary: Regular bugfix release.
fragments:
- 1.9.3.yml
- 271-openssl_csr-utf8.yml
release_date: '2021-09-14'
1.9.4:
changes:
bugfixes:
- acme_* modules - fix commands composed for OpenSSL backend to retrieve information
on CSRs and certificates from stdin to use ``/dev/stdin`` instead of ``-``.
This is needed for OpenSSL 1.0.1 and 1.0.2, apparently (https://github.com/ansible-collections/community.crypto/pull/279).
- acme_challenge_cert_helper - only return exception when cryptography is not
installed, not when a too old version of it is installed. This prevents Ansible's
callback to crash (https://github.com/ansible-collections/community.crypto/pull/281).
release_summary: Regular bugfix release.
fragments:
- 1.9.4.yml
- 279-acme-openssl.yml
- 282-acme_challenge_cert_helper-error.yml
release_date: '2021-09-28'
1.9.5:
changes:
bugfixes:
- get_certificate - fix compatibility with the cryptography 35.0.0 release (https://github.com/ansible-collections/community.crypto/pull/294).
- openssl_csr_info - fix compatibility with the cryptography 35.0.0 release
(https://github.com/ansible-collections/community.crypto/pull/294).
- openssl_csr_info - fix compatibility with the cryptography 35.0.0 release
in PyOpenSSL backend (https://github.com/ansible-collections/community.crypto/pull/300).
- openssl_pkcs12 - fix compatibility with the cryptography 35.0.0 release (https://github.com/ansible-collections/community.crypto/pull/296).
- x509_certificate_info - fix compatibility with the cryptography 35.0.0 release
(https://github.com/ansible-collections/community.crypto/pull/294).
- x509_certificate_info - fix compatibility with the cryptography 35.0.0 release
in PyOpenSSL backend (https://github.com/ansible-collections/community.crypto/pull/300).
release_summary: Bugfix release to fully support cryptography 35.0.0.
fragments:
- 1.9.5.yml
- 294-cryptography-35.0.0.yml
- 296-openssl_pkcs12-cryptography-35.yml
- 300-pyopenssl-cryptography-35.yml
release_date: '2021-10-06'

View File

@@ -1,6 +1,6 @@
namespace: community
name: crypto
version: 1.8.0
version: 1.9.5
readme: README.md
authors:
- Ansible (github.com/ansible)

View File

@@ -457,8 +457,8 @@ options:
- Time will always be interpreted as UTC.
- Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer
+ C([w | d | h | m | s]) (e.g. C(+32w1d2h).
- Note that if using relative time this module is NOT idempotent.
- If this value is not specified, the certificate will start being valid from now.
- Note that this value is B(not used to determine whether an existing certificate should be regenerated).
- This is only used by the C(ownca) provider.
type: str
default: +0s
@@ -470,8 +470,8 @@ options:
- Time will always be interpreted as UTC.
- Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer
+ C([w | d | h | m | s]) (e.g. C(+32w1d2h).
- Note that if using relative time this module is NOT idempotent.
- If this value is not specified, the certificate will stop being valid 10 years from now.
- Note that this value is B(not used to determine whether an existing certificate should be regenerated).
- This is only used by the C(ownca) provider.
- On macOS 10.15 and onwards, TLS server certificates must have a validity period of 825 days or fewer.
Please see U(https://support.apple.com/en-us/HT210176) for more details.
@@ -548,8 +548,8 @@ options:
- Time will always be interpreted as UTC.
- Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer
+ C([w | d | h | m | s]) (e.g. C(+32w1d2h).
- Note that if using relative time this module is NOT idempotent.
- If this value is not specified, the certificate will start being valid from now.
- Note that this value is B(not used to determine whether an existing certificate should be regenerated).
- This is only used by the C(selfsigned) provider.
type: str
default: +0s
@@ -562,8 +562,8 @@ options:
- Time will always be interpreted as UTC.
- Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer
+ C([w | d | h | m | s]) (e.g. C(+32w1d2h).
- Note that if using relative time this module is NOT idempotent.
- If this value is not specified, the certificate will stop being valid 10 years from now.
- Note that this value is B(not used to determine whether an existing certificate should be regenerated).
- This is only used by the C(selfsigned) provider.
- On macOS 10.15 and onwards, TLS server certificates must have a validity period of 825 days or fewer.
Please see U(https://support.apple.com/en-us/HT210176) for more details.

View File

@@ -227,12 +227,11 @@ options:
description:
- The authority key identifier as a hex string, where two bytes are separated by colons.
- "Example: C(00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33)"
- If specified, I(authority_cert_issuer) must also be specified.
- "Please note that commercial CAs ignore this value, respectively use a value of their
own choice. Specifying this option is mostly useful for self-signed certificates
or for own CAs."
- Note that this is only supported if the C(cryptography) backend is used!
- The C(AuthorityKeyIdentifier) will only be added if at least one of I(authority_key_identifier),
- The C(AuthorityKeyIdentifier) extension will only be added if at least one of I(authority_key_identifier),
I(authority_cert_issuer) and I(authority_cert_serial_number) is specified.
type: str
authority_cert_issuer:
@@ -241,23 +240,24 @@ options:
- Values must be prefixed by their options. (i.e., C(email), C(URI), C(DNS), C(RID), C(IP), C(dirName),
C(otherName) and the ones specific to your CA)
- "Example: C(DNS:ca.example.org)"
- If specified, I(authority_key_identifier) must also be specified.
- If specified, I(authority_cert_serial_number) must also be specified.
- "Please note that commercial CAs ignore this value, respectively use a value of their
own choice. Specifying this option is mostly useful for self-signed certificates
or for own CAs."
- Note that this is only supported if the C(cryptography) backend is used!
- The C(AuthorityKeyIdentifier) will only be added if at least one of I(authority_key_identifier),
- The C(AuthorityKeyIdentifier) extension will only be added if at least one of I(authority_key_identifier),
I(authority_cert_issuer) and I(authority_cert_serial_number) is specified.
type: list
elements: str
authority_cert_serial_number:
description:
- The authority cert serial number.
- If specified, I(authority_cert_issuer) must also be specified.
- Note that this is only supported if the C(cryptography) backend is used!
- "Please note that commercial CAs ignore this value, respectively use a value of their
own choice. Specifying this option is mostly useful for self-signed certificates
or for own CAs."
- The C(AuthorityKeyIdentifier) will only be added if at least one of I(authority_key_identifier),
- The C(AuthorityKeyIdentifier) extension will only be added if at least one of I(authority_key_identifier),
I(authority_cert_issuer) and I(authority_cert_serial_number) is specified.
type: int
crl_distribution_points:

View File

@@ -230,7 +230,7 @@ class OpenSSLCLIBackend(CryptoBackend):
filename = csr_filename
data = None
if csr_content is not None:
filename = '-'
filename = '/dev/stdin'
data = csr_content.encode('utf-8')
openssl_csr_cmd = [self.openssl_binary, "req", "-in", filename, "-noout", "-text"]
@@ -267,7 +267,7 @@ class OpenSSLCLIBackend(CryptoBackend):
filename = cert_filename
data = None
if cert_content is not None:
filename = '-'
filename = '/dev/stdin'
data = cert_content.encode('utf-8')
cert_filename_suffix = ''
elif cert_filename is not None:

View File

@@ -20,6 +20,10 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
# WARNING: this function no longer works with cryptography 35.0.0 and newer!
# It must **ONLY** be used in compatibility code for older
# cryptography versions!
def obj2txt(openssl_lib, openssl_ffi, obj):
# Set to 80 on the recommendation of
# https://www.openssl.org/docs/crypto/OBJ_nid2ln.html#return_values

View File

@@ -23,12 +23,15 @@ import base64
import binascii
import re
from distutils.version import LooseVersion
from ansible.module_utils.common.text.converters import to_text, to_bytes
from ._asn1 import serialize_asn1_string_as_der
try:
import cryptography
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
import ipaddress
except ImportError:
@@ -67,9 +70,19 @@ def cryptography_get_extensions_from_cert(cert):
# Since cryptography won't give us the DER value for an extension
# (that is only stored for unrecognized extensions), we have to re-do
# the extension parsing outselves.
backend = default_backend()
try:
# For certain old versions of cryptography, backend is a MultiBackend object,
# which has no _lib attribute. In that case, revert to the old approach.
backend._lib
except AttributeError:
backend = cert._backend
result = dict()
backend = cert._backend
x509_obj = cert._x509
# With cryptography 35.0.0, we can no longer use obj2txt. Unfortunately it still does
# not allow to get the raw value of an extension, so we have to use this ugly hack:
exts = list(cert.extensions)
for i in range(backend._lib.X509_get_ext_count(x509_obj)):
ext = backend._lib.X509_get_ext(x509_obj, i)
@@ -83,8 +96,12 @@ def cryptography_get_extensions_from_cert(cert):
critical=(crit == 1),
value=base64.b64encode(der),
)
oid = obj2txt(backend._lib, backend._ffi, backend._lib.X509_EXTENSION_get_object(ext))
try:
oid = obj2txt(backend._lib, backend._ffi, backend._lib.X509_EXTENSION_get_object(ext))
except AttributeError:
oid = exts[i].oid.dotted_string
result[oid] = entry
return result
@@ -93,7 +110,13 @@ def cryptography_get_extensions_from_csr(csr):
# (that is only stored for unrecognized extensions), we have to re-do
# the extension parsing outselves.
result = dict()
backend = csr._backend
backend = default_backend()
try:
# For certain old versions of cryptography, backend is a MultiBackend object,
# which has no _lib attribute. In that case, revert to the old approach.
backend._lib
except AttributeError:
backend = csr._backend
extensions = backend._lib.X509_REQ_get_extensions(csr._x509_req)
extensions = backend._ffi.gc(
@@ -104,6 +127,10 @@ def cryptography_get_extensions_from_csr(csr):
)
)
# With cryptography 35.0.0, we can no longer use obj2txt. Unfortunately it still does
# not allow to get the raw value of an extension, so we have to use this ugly hack:
exts = list(csr.extensions)
for i in range(backend._lib.sk_X509_EXTENSION_num(extensions)):
ext = backend._lib.sk_X509_EXTENSION_value(extensions, i)
if ext == backend._ffi.NULL:
@@ -116,8 +143,12 @@ def cryptography_get_extensions_from_csr(csr):
critical=(crit == 1),
value=base64.b64encode(der),
)
oid = obj2txt(backend._lib, backend._ffi, backend._lib.X509_EXTENSION_get_object(ext))
try:
oid = obj2txt(backend._lib, backend._ffi, backend._lib.X509_EXTENSION_get_object(ext))
except AttributeError:
oid = exts[i].oid.dotted_string
result[oid] = entry
return result
@@ -450,9 +481,35 @@ def parse_pkcs12(pkcs12_bytes, passphrase=None):
friendly_name = None
if certificate:
# See https://github.com/pyca/cryptography/issues/5760#issuecomment-842687238
maybe_name = certificate._backend._lib.X509_alias_get0(
certificate._x509, certificate._backend._ffi.NULL)
if maybe_name != certificate._backend._ffi.NULL:
friendly_name = certificate._backend._ffi.string(maybe_name)
backend = default_backend()
try:
# For certain old versions of cryptography, backend is a MultiBackend object,
# which has no _lib attribute. In that case, revert to the old approach.
backend._lib
except AttributeError:
backend = certificate._backend
if LooseVersion(cryptography.__version__) >= LooseVersion('35.0'):
# This code basically does what load_key_and_certificates() does, but without error-checking.
# Since load_key_and_certificates succeeded, it should not fail.
pkcs12 = backend._ffi.gc(
backend._lib.d2i_PKCS12_bio(backend._bytes_to_bio(pkcs12_bytes).bio, backend._ffi.NULL),
backend._lib.PKCS12_free)
certificate_x509_ptr = backend._ffi.new("X509 **")
with backend._zeroed_null_terminated_buf(to_bytes(passphrase) if passphrase is not None else None) as passphrase_buffer:
backend._lib.PKCS12_parse(
pkcs12,
passphrase_buffer,
backend._ffi.new("EVP_PKEY **"),
certificate_x509_ptr,
backend._ffi.new("Cryptography_STACK_OF_X509 **"))
if certificate_x509_ptr[0] != backend._ffi.NULL:
maybe_name = backend._lib.X509_alias_get0(certificate_x509_ptr[0], backend._ffi.NULL)
if maybe_name != backend._ffi.NULL:
friendly_name = backend._ffi.string(maybe_name)
else:
# cryptography < 35.0.0
maybe_name = backend._lib.X509_alias_get0(certificate._x509, backend._ffi.NULL)
if maybe_name != backend._ffi.NULL:
friendly_name = backend._ffi.string(maybe_name)
return private_key, certificate, additional_certificates, friendly_name

View File

@@ -592,7 +592,7 @@ class CertificateSigningRequestCryptographyBackend(CertificateSigningRequestBack
def _check_csr(self):
"""Check whether provided parameters, assuming self.existing_csr and self.privatekey have been populated."""
def _check_subject(csr):
subject = [(cryptography_name_to_oid(entry[0]), entry[1]) for entry in self.subject]
subject = [(cryptography_name_to_oid(entry[0]), to_text(entry[1])) for entry in self.subject]
current_subject = [(sub.oid, sub.value) for sub in csr.subject]
return set(subject) == set(current_subject)
@@ -604,8 +604,8 @@ class CertificateSigningRequestCryptographyBackend(CertificateSigningRequestBack
def _check_subjectAltName(extensions):
current_altnames_ext = _find_extension(extensions, cryptography.x509.SubjectAlternativeName)
current_altnames = [str(altname) for altname in current_altnames_ext.value] if current_altnames_ext else []
altnames = [str(cryptography_get_name(altname)) for altname in self.subjectAltName] if self.subjectAltName else []
current_altnames = [to_text(altname) for altname in current_altnames_ext.value] if current_altnames_ext else []
altnames = [to_text(cryptography_get_name(altname)) for altname in self.subjectAltName] if self.subjectAltName else []
if set(altnames) != set(current_altnames):
return False
if altnames:
@@ -678,10 +678,10 @@ class CertificateSigningRequestCryptographyBackend(CertificateSigningRequestBack
def _check_nameConstraints(extensions):
current_nc_ext = _find_extension(extensions, cryptography.x509.NameConstraints)
current_nc_perm = [str(altname) for altname in current_nc_ext.value.permitted_subtrees] if current_nc_ext else []
current_nc_excl = [str(altname) for altname in current_nc_ext.value.excluded_subtrees] if current_nc_ext else []
nc_perm = [str(cryptography_get_name(altname, 'name constraints permitted')) for altname in self.name_constraints_permitted]
nc_excl = [str(cryptography_get_name(altname, 'name constraints excluded')) for altname in self.name_constraints_excluded]
current_nc_perm = [to_text(altname) for altname in current_nc_ext.value.permitted_subtrees] if current_nc_ext else []
current_nc_excl = [to_text(altname) for altname in current_nc_ext.value.excluded_subtrees] if current_nc_ext else []
nc_perm = [to_text(cryptography_get_name(altname, 'name constraints permitted')) for altname in self.name_constraints_permitted]
nc_excl = [to_text(cryptography_get_name(altname, 'name constraints excluded')) for altname in self.name_constraints_excluded]
if set(nc_perm) != set(current_nc_perm) or set(nc_excl) != set(current_nc_excl):
return False
if nc_perm or nc_excl:
@@ -710,9 +710,9 @@ class CertificateSigningRequestCryptographyBackend(CertificateSigningRequestBack
aci = None
csr_aci = None
if self.authority_cert_issuer is not None:
aci = [str(cryptography_get_name(n, 'authority cert issuer')) for n in self.authority_cert_issuer]
aci = [to_text(cryptography_get_name(n, 'authority cert issuer')) for n in self.authority_cert_issuer]
if ext.value.authority_cert_issuer is not None:
csr_aci = [str(n) for n in ext.value.authority_cert_issuer]
csr_aci = [to_text(n) for n in ext.value.authority_cert_issuer]
return (ext.value.key_identifier == self.authority_key_identifier
and csr_aci == aci
and ext.value.authority_cert_serial_number == self.authority_cert_serial_number)

View File

@@ -21,10 +21,12 @@ __metaclass__ = type
import base64
from ansible.module_utils.common.text.converters import to_bytes, to_text
from ansible.module_utils.common.text.converters import to_bytes, to_text, to_native
from ansible_collections.community.crypto.plugins.module_utils.compat import ipaddress as compat_ipaddress
from ._objects import OID_LOOKUP
try:
import OpenSSL
except ImportError:
@@ -87,18 +89,25 @@ def pyopenssl_get_extensions_from_cert(cert):
critical=bool(ext.get_critical()),
value=base64.b64encode(ext.get_data()),
)
oid = obj2txt(
OpenSSL._util.lib,
OpenSSL._util.ffi,
OpenSSL._util.lib.X509_EXTENSION_get_object(ext._extension)
)
# This could also be done a bit simpler:
#
# oid = obj2txt(OpenSSL._util.lib, OpenSSL._util.ffi, OpenSSL._util.lib.OBJ_nid2obj(ext._nid))
#
# Unfortunately this gives the wrong result in case the linked OpenSSL
# doesn't know the OID. That's why we have to get the OID dotted string
# similarly to how cryptography does it.
try:
oid = obj2txt(
OpenSSL._util.lib,
OpenSSL._util.ffi,
OpenSSL._util.lib.X509_EXTENSION_get_object(ext._extension)
)
# This could also be done a bit simpler:
#
# oid = obj2txt(OpenSSL._util.lib, OpenSSL._util.ffi, OpenSSL._util.lib.OBJ_nid2obj(ext._nid))
#
# Unfortunately this gives the wrong result in case the linked OpenSSL
# doesn't know the OID. That's why we have to get the OID dotted string
# similarly to how cryptography does it.
except AttributeError:
# When PyOpenSSL is used with cryptography >= 35.0.0, obj2txt cannot be used.
# We try to figure out the OID with our internal lookup table, and if we fail,
# we use the short name OpenSSL returns.
oid = to_native(ext.get_short_name())
oid = OID_LOOKUP.get(oid, oid)
result[oid] = entry
return result
@@ -113,18 +122,25 @@ def pyopenssl_get_extensions_from_csr(csr):
critical=bool(ext.get_critical()),
value=base64.b64encode(ext.get_data()),
)
oid = obj2txt(
OpenSSL._util.lib,
OpenSSL._util.ffi,
OpenSSL._util.lib.X509_EXTENSION_get_object(ext._extension)
)
# This could also be done a bit simpler:
#
# oid = obj2txt(OpenSSL._util.lib, OpenSSL._util.ffi, OpenSSL._util.lib.OBJ_nid2obj(ext._nid))
#
# Unfortunately this gives the wrong result in case the linked OpenSSL
# doesn't know the OID. That's why we have to get the OID dotted string
# similarly to how cryptography does it.
try:
oid = obj2txt(
OpenSSL._util.lib,
OpenSSL._util.ffi,
OpenSSL._util.lib.X509_EXTENSION_get_object(ext._extension)
)
# This could also be done a bit simpler:
#
# oid = obj2txt(OpenSSL._util.lib, OpenSSL._util.ffi, OpenSSL._util.lib.OBJ_nid2obj(ext._nid))
#
# Unfortunately this gives the wrong result in case the linked OpenSSL
# doesn't know the OID. That's why we have to get the OID dotted string
# similarly to how cryptography does it.
except AttributeError:
# When PyOpenSSL is used with cryptography >= 35.0.0, obj2txt cannot be used.
# We try to figure out the OID with our internal lookup table, and if we fail,
# we use the short name OpenSSL returns.
oid = to_native(ext.get_short_name())
oid = OID_LOOKUP.get(oid, oid)
result[oid] = entry
return result

View File

@@ -18,7 +18,15 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import abc
import os
import stat
from ansible.module_utils import six
from ansible_collections.community.crypto.plugins.module_utils.openssh.utils import (
parse_openssh_version,
)
def restore_on_failure(f):
@@ -40,3 +48,281 @@ def restore_on_failure(f):
@restore_on_failure
def safe_atomic_move(module, path, destination):
module.atomic_move(path, destination)
def _restore_all_on_failure(f):
def backup_and_restore(self, sources_and_destinations, *args, **kwargs):
backups = [(d, self.module.backup_local(d)) for s, d in sources_and_destinations if os.path.exists(d)]
try:
f(self, sources_and_destinations, *args, **kwargs)
except Exception:
for destination, backup in backups:
self.module.atomic_move(backup, destination)
raise
else:
for destination, backup in backups:
self.module.add_cleanup_file(backup)
return backup_and_restore
@six.add_metaclass(abc.ABCMeta)
class OpensshModule(object):
def __init__(self, module):
self.module = module
self.changed = False
self.check_mode = self.module.check_mode
def execute(self):
self._execute()
self.module.exit_json(**self.result)
@abc.abstractmethod
def _execute(self):
pass
@property
def result(self):
result = self._result
result['changed'] = self.changed
if self.module._diff:
result['diff'] = self.diff
return result
@property
@abc.abstractmethod
def _result(self):
pass
@property
@abc.abstractmethod
def diff(self):
pass
@staticmethod
def skip_if_check_mode(f):
def wrapper(self, *args, **kwargs):
if not self.check_mode:
f(self, *args, **kwargs)
return wrapper
@staticmethod
def trigger_change(f):
def wrapper(self, *args, **kwargs):
f(self, *args, **kwargs)
self.changed = True
return wrapper
def _check_if_base_dir(self, path):
base_dir = os.path.dirname(path) or '.'
if not os.path.isdir(base_dir):
self.module.fail_json(
name=base_dir,
msg='The directory %s does not exist or the file is not a directory' % base_dir
)
def _get_ssh_version(self):
ssh_bin = self.module.get_bin_path('ssh')
if not ssh_bin:
return ""
return parse_openssh_version(self.module.run_command([ssh_bin, '-V', '-q'])[2].strip())
@_restore_all_on_failure
def _safe_secure_move(self, sources_and_destinations):
"""Moves a list of files from 'source' to 'destination' and restores 'destination' from backup upon failure.
If 'destination' does not already exist, then 'source' permissions are preserved to prevent
exposing protected data ('atomic_move' uses the 'destination' base directory mask for
permissions if 'destination' does not already exists).
"""
for source, destination in sources_and_destinations:
if os.path.exists(destination):
self.module.atomic_move(source, destination)
else:
self.module.preserved_copy(source, destination)
def _update_permissions(self, path):
file_args = self.module.load_file_common_arguments(self.module.params)
file_args['path'] = path
if not self.module.check_file_absent_if_check_mode(path):
self.changed = self.module.set_fs_attributes_if_different(file_args, self.changed)
else:
self.changed = True
class KeygenCommand(object):
def __init__(self, module):
self._bin_path = module.get_bin_path('ssh-keygen', True)
self._run_command = module.run_command
def generate_certificate(self, certificate_path, identifier, options, pkcs11_provider, principals,
serial_number, signature_algorithm, signing_key_path, type,
time_parameters, use_agent, **kwargs):
args = [self._bin_path, '-s', signing_key_path, '-P', '', '-I', identifier]
if options:
for option in options:
args.extend(['-O', option])
if pkcs11_provider:
args.extend(['-D', pkcs11_provider])
if principals:
args.extend(['-n', ','.join(principals)])
if serial_number is not None:
args.extend(['-z', str(serial_number)])
if type == 'host':
args.extend(['-h'])
if use_agent:
args.extend(['-U'])
if time_parameters.validity_string:
args.extend(['-V', time_parameters.validity_string])
if signature_algorithm:
args.extend(['-t', signature_algorithm])
args.append(certificate_path)
return self._run_command(args, **kwargs)
def generate_keypair(self, private_key_path, size, type, comment, **kwargs):
args = [
self._bin_path,
'-q',
'-N', '',
'-b', str(size),
'-t', type,
'-f', private_key_path,
'-C', comment or ''
]
# "y" must be entered in response to the "overwrite" prompt
data = 'y' if os.path.exists(private_key_path) else None
return self._run_command(args, data=data, **kwargs)
def get_certificate_info(self, certificate_path, **kwargs):
return self._run_command([self._bin_path, '-L', '-f', certificate_path], **kwargs)
def get_matching_public_key(self, private_key_path, **kwargs):
return self._run_command([self._bin_path, '-P', '', '-y', '-f', private_key_path], **kwargs)
def get_private_key(self, private_key_path, **kwargs):
return self._run_command([self._bin_path, '-l', '-f', private_key_path], **kwargs)
def update_comment(self, private_key_path, comment, **kwargs):
if os.path.exists(private_key_path) and not os.access(private_key_path, os.W_OK):
try:
os.chmod(private_key_path, stat.S_IWUSR + stat.S_IRUSR)
except (IOError, OSError) as e:
raise e("The private key at %s is not writeable preventing a comment update" % private_key_path)
return self._run_command([self._bin_path, '-q', '-o', '-c', '-C', comment, '-f', private_key_path], **kwargs)
class PrivateKey(object):
def __init__(self, size, key_type, fingerprint):
self._size = size
self._type = key_type
self._fingerprint = fingerprint
@property
def size(self):
return self._size
@property
def type(self):
return self._type
@property
def fingerprint(self):
return self._fingerprint
@classmethod
def from_string(cls, string):
properties = string.split()
return cls(
size=int(properties[0]),
key_type=properties[-1][1:-1].lower(),
fingerprint=properties[1],
)
def to_dict(self):
return {
'size': self._size,
'type': self._type,
'fingerprint': self._fingerprint,
}
class PublicKey(object):
def __init__(self, type_string, data, comment):
self._type_string = type_string
self._data = data
self._comment = comment
def __eq__(self, other):
if not isinstance(other, type(self)):
return NotImplemented
return all([
self._type_string == other._type_string,
self._data == other._data,
(self._comment == other._comment) if self._comment is not None and other._comment is not None else True
])
def __ne__(self, other):
return not self == other
def __str__(self):
return "%s %s" % (self._type_string, self._data)
@property
def comment(self):
return self._comment
@comment.setter
def comment(self, value):
self._comment = value
@property
def data(self):
return self._data
@property
def type_string(self):
return self._type_string
@classmethod
def from_string(cls, string):
properties = string.strip('\n').split(' ', 2)
return cls(
type_string=properties[0],
data=properties[1],
comment=properties[2] if len(properties) > 2 else ""
)
@classmethod
def load(cls, path):
try:
with open(path, 'r') as f:
properties = f.read().strip(' \n').split(' ', 2)
except (IOError, OSError):
raise
if len(properties) < 2:
return None
return cls(
type_string=properties[0],
data=properties[1],
comment='' if len(properties) <= 2 else properties[2],
)
def to_dict(self):
return {
'comment': self._comment,
'public_key': self._data,
}

View File

@@ -20,16 +20,13 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
import abc
import errno
import os
import stat
from distutils.version import LooseVersion
from ansible.module_utils import six
from ansible.module_utils.basic import missing_required_lib
from ansible.module_utils.common.text.converters import to_native, to_text, to_bytes
from ansible_collections.community.crypto.plugins.module_utils.openssh.utils import parse_openssh_version
from ansible_collections.community.crypto.plugins.module_utils.openssh.cryptography import (
HAS_OPENSSH_SUPPORT,
HAS_OPENSSH_PRIVATE_FORMAT,
@@ -39,322 +36,334 @@ from ansible_collections.community.crypto.plugins.module_utils.openssh.cryptogra
OpenSSHError,
OpensshKeypair,
)
from ansible_collections.community.crypto.plugins.module_utils.openssh.backends.common import (
KeygenCommand,
OpensshModule,
PrivateKey,
PublicKey,
)
from ansible_collections.community.crypto.plugins.module_utils.openssh.utils import (
any_in,
file_mode,
secure_write,
)
@six.add_metaclass(abc.ABCMeta)
class KeypairBackend(object):
class KeypairBackend(OpensshModule):
def __init__(self, module):
self.module = module
super(KeypairBackend, self).__init__(module)
self.path = module.params['path']
self.force = module.params['force']
self.size = module.params['size']
self.type = module.params['type']
self.comment = module.params['comment']
self.passphrase = module.params['passphrase']
self.regenerate = module.params['regenerate']
self.comment = self.module.params['comment']
self.private_key_path = self.module.params['path']
self.public_key_path = self.private_key_path + '.pub'
self.regenerate = self.module.params['regenerate'] if not self.module.params['force'] else 'always'
self.state = self.module.params['state']
self.type = self.module.params['type']
self.changed = False
self.fingerprint = ''
self.public_key = {}
self.size = self._get_size(self.module.params['size'])
self._validate_path()
if self.regenerate == 'always':
self.force = True
self.original_private_key = None
self.original_public_key = None
self.private_key = None
self.public_key = None
def _get_size(self, size):
if self.type in ('rsa', 'rsa1'):
self.size = 4096 if self.size is None else self.size
if self.size < 1024:
module.fail_json(msg=('For RSA keys, the minimum size is 1024 bits and the default is 4096 bits. '
'Attempting to use bit lengths under 1024 will cause the module to fail.'))
result = 4096 if size is None else size
if result < 1024:
return self.module.fail_json(
msg="For RSA keys, the minimum size is 1024 bits and the default is 4096 bits. " +
"Attempting to use bit lengths under 1024 will cause the module to fail."
)
elif self.type == 'dsa':
self.size = 1024 if self.size is None else self.size
if self.size != 1024:
module.fail_json(msg=('DSA keys must be exactly 1024 bits as specified by FIPS 186-2.'))
result = 1024 if size is None else size
if result != 1024:
return self.module.fail_json(msg="DSA keys must be exactly 1024 bits as specified by FIPS 186-2.")
elif self.type == 'ecdsa':
self.size = 256 if self.size is None else self.size
if self.size not in (256, 384, 521):
module.fail_json(msg=('For ECDSA keys, size determines the key length by selecting from '
'one of three elliptic curve sizes: 256, 384 or 521 bits. '
'Attempting to use bit lengths other than these three values for '
'ECDSA keys will cause this module to fail. '))
result = 256 if size is None else size
if result not in (256, 384, 521):
return self.module.fail_json(
msg="For ECDSA keys, size determines the key length by selecting from one of " +
"three elliptic curve sizes: 256, 384 or 521 bits. " +
"Attempting to use bit lengths other than these three values for ECDSA keys will " +
"cause this module to fail."
)
elif self.type == 'ed25519':
# User input is ignored for `key size` when `key type` is ed25519
self.size = 256
result = 256
else:
module.fail_json(msg="%s is not a valid value for key type" % self.type)
return self.module.fail_json(msg="%s is not a valid value for key type" % self.type)
def generate(self):
if self.force or not self.is_private_key_valid(perms_required=False):
try:
if self.exists() and not os.access(self.path, os.W_OK):
os.chmod(self.path, stat.S_IWUSR + stat.S_IRUSR)
self._generate_keypair()
self.changed = True
except (IOError, OSError) as e:
self.remove()
self.module.fail_json(msg="%s" % to_native(e))
return result
self.fingerprint = self._get_current_key_properties()[2]
self.public_key = self._get_public_key()
elif not self.is_public_key_valid(perms_required=False):
pubkey = self._get_public_key()
try:
with open(self.path + ".pub", "w") as pubkey_f:
pubkey_f.write(pubkey + '\n')
os.chmod(self.path + ".pub", stat.S_IWUSR + stat.S_IRUSR + stat.S_IRGRP + stat.S_IROTH)
except (IOError, OSError):
self.module.fail_json(
msg='The public key is missing or does not match the private key. '
'Unable to regenerate the public key.')
self.changed = True
self.public_key = pubkey
def _validate_path(self):
self._check_if_base_dir(self.private_key_path)
if self.comment:
try:
if self.exists() and not os.access(self.path, os.W_OK):
os.chmod(self.path, stat.S_IWUSR + stat.S_IRUSR)
except (IOError, OSError):
self.module.fail_json(msg='Unable to update the comment for the public key.')
self._update_comment()
if os.path.isdir(self.private_key_path):
self.module.fail_json(msg='%s is a directory. Please specify a path to a file.' % self.private_key_path)
private_key_perms_changed = self._permissions_changed()
public_key_perms_changed = self._permissions_changed(public_key=True)
if private_key_perms_changed or public_key_perms_changed:
self.changed = True
def _execute(self):
self.original_private_key = self._load_private_key()
self.original_public_key = self._load_public_key()
def is_private_key_valid(self, perms_required=True):
if not self.exists():
return False
if self.state == 'present':
self._validate_key_load()
if self._check_pass_protected_or_broken_key():
if self.regenerate in ('full_idempotence', 'always'):
return False
self.module.fail_json(msg='Unable to read the key. The key is protected with a passphrase or broken.'
' Will not proceed. To force regeneration, call the module with `generate`'
' set to `full_idempotence` or `always`, or with `force=yes`.')
if self._should_generate():
self._generate()
elif not self._public_key_valid():
self._restore_public_key()
if not self._private_key_loadable():
if os.path.isdir(self.path):
self.module.fail_json(msg='%s is a directory. Please specify a path to a file.' % self.path)
self.private_key = self._load_private_key()
self.public_key = self._load_public_key()
if self.regenerate in ('full_idempotence', 'always'):
return False
self.module.fail_json(msg='Unable to read the key. The key is protected with a passphrase or broken.'
' Will not proceed. To force regeneration, call the module with `generate`'
' set to `full_idempotence` or `always`, or with `force=yes`.')
keysize, keytype, self.fingerprint = self._get_current_key_properties()
if self.regenerate == 'never':
return True
if not (self.type == keytype and self.size == keysize):
if self.regenerate in ('partial_idempotence', 'full_idempotence', 'always'):
return False
self.module.fail_json(
msg='Key has wrong type and/or size.'
' Will not proceed. To force regeneration, call the module with `generate`'
' set to `partial_idempotence`, `full_idempotence` or `always`, or with `force=yes`.'
)
# Perms required short-circuits evaluation to prevent the side-effects of running _permissions_changed
# when check_mode is not enabled
return not (perms_required and self._permissions_changed())
def is_public_key_valid(self, perms_required=True):
def _get_pubkey_content():
if self.exists(public_key=True):
with open(self.path + ".pub", "r") as pubkey_f:
present_pubkey = pubkey_f.read().strip(' \n')
return present_pubkey
else:
return ''
def _parse_pubkey(pubkey_content):
if pubkey_content:
parts = pubkey_content.split(' ', 2)
if len(parts) < 2:
return ()
return parts[0], parts[1], '' if len(parts) <= 2 else parts[2]
return ()
def _pubkey_valid(pubkey):
if pubkey_parts and _parse_pubkey(pubkey):
return pubkey_parts[:2] == _parse_pubkey(pubkey)[:2]
return False
def _comment_valid():
if pubkey_parts:
return pubkey_parts[2] == self.comment
return False
pubkey_parts = _parse_pubkey(_get_pubkey_content())
pubkey = self._get_public_key()
if _pubkey_valid(pubkey):
self.public_key = pubkey
for path in (self.private_key_path, self.public_key_path):
self._update_permissions(path)
else:
return False
if self._should_remove():
self._remove()
if self.comment and not _comment_valid():
return False
# Perms required short-circuits evaluation to prevent the side-effects of running _permissions_changes
# when check_mode is not enabled
return not (perms_required and self._permissions_changed(public_key=True))
def _permissions_changed(self, public_key=False):
file_args = self.module.load_file_common_arguments(self.module.params)
if public_key:
file_args['path'] = file_args['path'] + '.pub'
if self.module.check_file_absent_if_check_mode(file_args['path']):
return True
return self.module.set_fs_attributes_if_different(file_args, False)
@property
def result(self):
return {
'changed': self.changed,
'size': self.size,
'type': self.type,
'filename': self.path,
'fingerprint': self.fingerprint if self.fingerprint else '',
'public_key': self.public_key,
'comment': self.comment if self.comment else '',
}
def remove(self):
"""Remove the resource from the filesystem."""
try:
os.remove(self.path)
self.changed = True
except (IOError, OSError) as exc:
if exc.errno != errno.ENOENT:
self.module.fail_json(msg=to_native(exc))
else:
def _load_private_key(self):
result = None
if self._private_key_exists():
try:
result = self._get_private_key()
except Exception:
pass
if self.exists(public_key=True):
return result
def _private_key_exists(self):
return os.path.exists(self.private_key_path)
@abc.abstractmethod
def _get_private_key(self):
pass
def _load_public_key(self):
result = None
if self._public_key_exists():
try:
os.remove(self.path + ".pub")
self.changed = True
except (IOError, OSError) as exc:
if exc.errno != errno.ENOENT:
self.module.fail_json(msg=to_native(exc))
else:
pass
result = PublicKey.load(self.public_key_path)
except (IOError, OSError):
pass
return result
def exists(self, public_key=False):
return os.path.exists(self.path if not public_key else self.path + ".pub")
def _public_key_exists(self):
return os.path.exists(self.public_key_path)
def _validate_key_load(self):
if (self._private_key_exists()
and self.regenerate in ('never', 'fail', 'partial_idempotence')
and (self.original_private_key is None or not self._private_key_readable())):
self.module.fail_json(
msg="Unable to read the key. The key is protected with a passphrase or broken. " +
"Will not proceed. To force regeneration, call the module with `generate` " +
"set to `full_idempotence` or `always`, or with `force=yes`."
)
@abc.abstractmethod
def _generate_keypair(self):
def _private_key_readable(self):
pass
def _should_generate(self):
if self.regenerate == 'never':
return self.original_private_key is None
elif self.regenerate == 'fail':
if not self._private_key_valid():
self.module.fail_json(
msg="Key has wrong type and/or size. Will not proceed. " +
"To force regeneration, call the module with `generate` set to " +
"`partial_idempotence`, `full_idempotence` or `always`, or with `force=yes`."
)
return self.original_private_key is None
elif self.regenerate in ('partial_idempotence', 'full_idempotence'):
return not self._private_key_valid()
else:
return True
def _private_key_valid(self):
if self.original_private_key is None:
return False
return all([
self.size == self.original_private_key.size,
self.type == self.original_private_key.type,
])
@OpensshModule.trigger_change
@OpensshModule.skip_if_check_mode
def _generate(self):
temp_private_key, temp_public_key = self._generate_temp_keypair()
try:
self._safe_secure_move([(temp_private_key, self.private_key_path), (temp_public_key, self.public_key_path)])
except OSError as e:
self.module.fail_json(msg=to_native(e))
def _generate_temp_keypair(self):
temp_private_key = os.path.join(self.module.tmpdir, os.path.basename(self.private_key_path))
temp_public_key = temp_private_key + '.pub'
try:
self._generate_keypair(temp_private_key)
except (IOError, OSError) as e:
self.module.fail_json(msg=to_native(e))
for f in (temp_private_key, temp_public_key):
self.module.add_cleanup_file(f)
return temp_private_key, temp_public_key
@abc.abstractmethod
def _get_current_key_properties(self):
def _generate_keypair(self, private_key_path):
pass
def _public_key_valid(self):
if self.original_public_key is None:
return False
valid_public_key = self._get_public_key()
valid_public_key.comment = self.comment
return self.original_public_key == valid_public_key
@abc.abstractmethod
def _get_public_key(self):
pass
@OpensshModule.trigger_change
@OpensshModule.skip_if_check_mode
def _restore_public_key(self):
try:
temp_public_key = self._create_temp_public_key(str(self._get_public_key()) + '\n')
self._safe_secure_move([
(temp_public_key, self.public_key_path)
])
except (IOError, OSError):
self.module.fail_json(
msg="The public key is missing or does not match the private key. " +
"Unable to regenerate the public key."
)
if self.comment:
self._update_comment()
def _create_temp_public_key(self, content):
temp_public_key = os.path.join(self.module.tmpdir, os.path.basename(self.public_key_path))
default_permissions = 0o644
existing_permissions = file_mode(self.public_key_path)
try:
secure_write(temp_public_key, existing_permissions or default_permissions, to_bytes(content))
except (IOError, OSError) as e:
self.module.fail_json(msg=to_native(e))
self.module.add_cleanup_file(temp_public_key)
return temp_public_key
@abc.abstractmethod
def _update_comment(self):
pass
@abc.abstractmethod
def _private_key_loadable(self):
pass
def _should_remove(self):
return self._private_key_exists() or self._public_key_exists()
@abc.abstractmethod
def _check_pass_protected_or_broken_key(self):
pass
@OpensshModule.trigger_change
@OpensshModule.skip_if_check_mode
def _remove(self):
try:
if self._private_key_exists():
os.remove(self.private_key_path)
if self._public_key_exists():
os.remove(self.public_key_path)
except (IOError, OSError) as e:
self.module.fail_json(msg=to_native(e))
@property
def _result(self):
private_key = self.private_key or self.original_private_key
public_key = self.public_key or self.original_public_key
return {
'size': self.size,
'type': self.type,
'filename': self.private_key_path,
'fingerprint': private_key.fingerprint if private_key else '',
'public_key': str(public_key) if public_key else '',
'comment': public_key.comment if public_key else '',
}
@property
def diff(self):
before = self.original_private_key.to_dict() if self.original_private_key else {}
before.update(self.original_public_key.to_dict() if self.original_public_key else {})
after = self.private_key.to_dict() if self.private_key else {}
after.update(self.public_key.to_dict() if self.public_key else {})
return {
'before': before,
'after': after,
}
class KeypairBackendOpensshBin(KeypairBackend):
def __init__(self, module):
super(KeypairBackendOpensshBin, self).__init__(module)
self.openssh_bin = module.get_bin_path('ssh-keygen')
self.ssh_keygen = KeygenCommand(self.module)
def _load_privatekey(self):
return self.module.run_command([self.openssh_bin, '-lf', self.path])
def _generate_keypair(self, private_key_path):
self.ssh_keygen.generate_keypair(private_key_path, self.size, self.type, self.comment)
def _get_publickey_from_privatekey(self):
# -P '' is always included as an option to induce the expected standard output for
# _check_pass_protected_or_broken_key, but introduces no side-effects when used to
# output a matching public key
return self.module.run_command([self.openssh_bin, '-P', '', '-yf', self.path])
def _generate_keypair(self):
args = [
self.openssh_bin,
'-q',
'-N', '',
'-b', str(self.size),
'-t', self.type,
'-f', self.path,
'-C', self.comment if self.comment else ''
]
# "y" must be entered in response to the "overwrite" prompt
stdin_data = 'y' if self.exists() else None
self.module.run_command(args, data=stdin_data)
def _get_current_key_properties(self):
rc, stdout, stderr = self._load_privatekey()
properties = stdout.split()
keysize = int(properties[0])
fingerprint = properties[1]
keytype = properties[-1][1:-1].lower()
return keysize, keytype, fingerprint
def _get_private_key(self):
private_key_content = self.ssh_keygen.get_private_key(self.private_key_path)[1]
return PrivateKey.from_string(private_key_content)
def _get_public_key(self):
rc, stdout, stderr = self._get_publickey_from_privatekey()
return stdout.strip('\n')
public_key_content = self.ssh_keygen.get_matching_public_key(self.private_key_path)[1]
return PublicKey.from_string(public_key_content)
def _private_key_readable(self):
rc, stdout, stderr = self.ssh_keygen.get_matching_public_key(self.private_key_path)
return not (rc == 255 or any_in(stderr, 'is not a public key file', 'incorrect passphrase', 'load failed'))
def _update_comment(self):
return self.module.run_command([self.openssh_bin, '-q', '-o', '-c', '-C', self.comment, '-f', self.path])
def _private_key_loadable(self):
rc, stdout, stderr = self._load_privatekey()
return rc == 0
def _check_pass_protected_or_broken_key(self):
rc, stdout, stderr = self._get_publickey_from_privatekey()
return rc == 255 or any_in(stderr, 'is not a public key file', 'incorrect passphrase', 'load failed')
try:
self.ssh_keygen.update_comment(self.private_key_path, self.comment)
except (IOError, OSError) as e:
self.module.fail_json(msg=to_native(e))
class KeypairBackendCryptography(KeypairBackend):
def __init__(self, module):
super(KeypairBackendCryptography, self).__init__(module)
if module.params['private_key_format'] == 'auto':
ssh = module.get_bin_path('ssh')
if ssh:
proc = module.run_command([ssh, '-Vq'])
ssh_version = parse_openssh_version(proc[2].strip())
else:
# Default to OpenSSH 7.8 compatibility when OpenSSH is not installed
ssh_version = "7.8"
if self.type == 'rsa1':
self.module.fail_json(msg="RSA1 keys are not supported by the cryptography backend")
self.private_key_format = 'SSH'
self.passphrase = to_bytes(module.params['passphrase']) if module.params['passphrase'] else None
self.private_key_format = self._get_key_format(module.params['private_key_format'])
def _get_key_format(self, key_format):
result = 'SSH'
if key_format == 'auto':
# Default to OpenSSH 7.8 compatibility when OpenSSH is not installed
ssh_version = self._get_ssh_version() or "7.8"
if LooseVersion(ssh_version) < LooseVersion("7.8") and self.type != 'ed25519':
# OpenSSH made SSH formatted private keys available in version 6.5,
# but still defaulted to PKCS1 format with the exception of ed25519 keys
self.private_key_format = 'PKCS1'
result = 'PKCS1'
if self.private_key_format == 'SSH' and not HAS_OPENSSH_PRIVATE_FORMAT:
module.fail_json(
if result == 'SSH' and not HAS_OPENSSH_PRIVATE_FORMAT:
self.module.fail_json(
msg=missing_required_lib(
'cryptography >= 3.0',
reason="to load/dump private keys in the default OpenSSH format for OpenSSH >= 7.8 " +
@@ -362,96 +371,72 @@ class KeypairBackendCryptography(KeypairBackend):
)
)
if self.type == 'rsa1':
module.fail_json(msg="RSA1 keys are not supported by the cryptography backend")
return result
self.passphrase = to_bytes(self.passphrase) if self.passphrase else None
def _load_privatekey(self):
return OpensshKeypair.load(path=self.path, passphrase=self.passphrase, no_public_key=True)
def _generate_keypair(self):
def _generate_keypair(self, private_key_path):
keypair = OpensshKeypair.generate(
keytype=self.type,
size=self.size,
passphrase=self.passphrase,
comment=self.comment if self.comment else "",
comment=self.comment or '',
)
with open(self.path, 'w+b') as f:
f.write(
OpensshKeypair.encode_openssh_privatekey(
keypair.asymmetric_keypair,
self.private_key_format
)
)
# ssh-keygen defaults private key permissions to 0600 octal
os.chmod(self.path, stat.S_IWUSR + stat.S_IRUSR)
with open(self.path + '.pub', 'w+b') as f:
f.write(keypair.public_key)
# ssh-keygen defaults public key permissions to 0644 octal
os.chmod(self.path + ".pub", stat.S_IWUSR + stat.S_IRUSR + stat.S_IRGRP + stat.S_IROTH)
def _get_current_key_properties(self):
keypair = self._load_privatekey()
encoded_private_key = OpensshKeypair.encode_openssh_privatekey(
keypair.asymmetric_keypair, self.private_key_format
)
secure_write(private_key_path, 0o600, encoded_private_key)
return keypair.size, keypair.key_type, keypair.fingerprint
public_key_path = private_key_path + '.pub'
secure_write(public_key_path, 0o644, keypair.public_key)
def _get_private_key(self):
keypair = OpensshKeypair.load(path=self.private_key_path, passphrase=self.passphrase, no_public_key=True)
return PrivateKey(
size=keypair.size,
key_type=keypair.key_type,
fingerprint=keypair.fingerprint,
)
def _get_public_key(self):
try:
keypair = self._load_privatekey()
keypair = OpensshKeypair.load(path=self.private_key_path, passphrase=self.passphrase, no_public_key=True)
except OpenSSHError:
# Simulates the null output of ssh-keygen
return ""
return to_text(keypair.public_key)
return PublicKey.from_string(to_text(keypair.public_key))
def _update_comment(self):
keypair = self._load_privatekey()
def _private_key_readable(self):
try:
keypair.comment = self.comment
with open(self.path + ".pub", "w+b") as pubkey_file:
pubkey_file.write(keypair.public_key + b'\n')
except (InvalidCommentError, IOError, OSError) as e:
# Return values while unused currently are made to simulate the output of run_command()
return 1, "Comment could not be updated", to_native(e)
return 0, "Comment updated successfully", ""
def _private_key_loadable(self):
try:
self._load_privatekey()
except OpenSSHError:
return False
return True
def _check_pass_protected_or_broken_key(self):
try:
OpensshKeypair.load(
path=self.path,
passphrase=self.passphrase,
no_public_key=True,
)
OpensshKeypair.load(path=self.private_key_path, passphrase=self.passphrase, no_public_key=True)
except (InvalidPrivateKeyFileError, InvalidPassphraseError):
return True
return False
# Cryptography >= 3.0 uses a SSH key loader which does not raise an exception when a passphrase is provided
# when loading an unencrypted key
if self.passphrase:
try:
OpensshKeypair.load(
path=self.path,
passphrase=None,
no_public_key=True,
)
OpensshKeypair.load(path=self.private_key_path, passphrase=None, no_public_key=True)
except (InvalidPrivateKeyFileError, InvalidPassphraseError):
return False
else:
return True
else:
return False
return False
return True
def _update_comment(self):
keypair = OpensshKeypair.load(path=self.private_key_path, passphrase=self.passphrase, no_public_key=True)
try:
keypair.comment = self.comment
except InvalidCommentError as e:
self.module.fail_json(msg=to_native(e))
def any_in(sequence, *elements):
return any([e in sequence for e in elements])
try:
temp_public_key = self._create_temp_public_key(keypair.public_key + b'\n')
self._safe_secure_move([(temp_public_key, self.public_key_path)])
except (IOError, OSError) as e:
self.module.fail_json(msg=to_native(e))
def select_backend(module, backend):

View File

@@ -555,6 +555,11 @@ class OpensshCertificate(object):
def signing_key(self):
return to_text(self._cert_info.signing_key_fingerprint())
@property
def signature_type(self):
signature_data = OpensshParser.signature_data(self.signature)
return to_text(signature_data['signature_type'])
@staticmethod
def _parse_cert_info(pub_key_type, parser):
cert_info = get_cert_info_object(pub_key_type)

View File

@@ -19,7 +19,9 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import os
import re
from contextlib import contextmanager
from struct import Struct
from ansible.module_utils.six import PY3
@@ -54,6 +56,16 @@ _UINT64 = Struct(b'!Q')
_UINT64_MAX = 0xFFFFFFFFFFFFFFFF
def any_in(sequence, *elements):
return any(e in sequence for e in elements)
def file_mode(path):
if not os.path.exists(path):
return 0o000
return os.stat(path).st_mode & 0o777
def parse_openssh_version(version_string):
"""Parse the version output of ssh -V and return version numbers that can be compared"""
@@ -68,6 +80,20 @@ def parse_openssh_version(version_string):
return version
@contextmanager
def secure_open(path, mode):
fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, mode)
try:
yield fd
finally:
os.close(fd)
def secure_write(path, mode, content):
with secure_open(path, mode) as fd:
os.write(fd, content)
# See https://datatracker.ietf.org/doc/html/rfc4251#section-5 for SSH data types
class OpensshParser(object):
"""Parser for OpenSSH encoded objects"""
@@ -175,8 +201,9 @@ class OpensshParser(object):
signature_blob = parser.string()
blob_parser = cls(signature_blob)
if signature_type == b'ssh-rsa':
if signature_type in (b'ssh-rsa', b'rsa-sha2-256', b'rsa-sha2-512'):
# https://datatracker.ietf.org/doc/html/rfc4253#section-6.6
# https://datatracker.ietf.org/doc/html/rfc8332#section-3
signature_data['s'] = cls._big_int(signature_blob, "big")
elif signature_type == b'ssh-dss':
# https://datatracker.ietf.org/doc/html/rfc4253#section-6.6

View File

@@ -202,7 +202,10 @@ def main():
),
)
if not HAS_CRYPTOGRAPHY:
module.fail_json(msg=missing_required_lib('cryptography >= 1.3'), exception=CRYPTOGRAPHY_IMP_ERR)
# Some callbacks die when exception is provided with value None
if CRYPTOGRAPHY_IMP_ERR:
module.fail_json(msg=missing_required_lib('cryptography >= 1.3'), exception=CRYPTOGRAPHY_IMP_ERR)
module.fail_json(msg=missing_required_lib('cryptography >= 1.3'))
try:
# Get parameters

View File

@@ -50,6 +50,14 @@ options:
- Proxy port used when get a certificate.
type: int
default: 8080
starttls:
description:
- Requests a secure connection for protocols which require clients to initiate encryption.
- Only available for C(mysql) currently.
type: str
choices:
- mysql
version_added: 1.9.0
timeout:
description:
- The timeout in seconds
@@ -209,6 +217,20 @@ else:
CRYPTOGRAPHY_FOUND = True
def send_starttls_packet(sock, server_type):
if server_type == 'mysql':
ssl_request_packet = (
b'\x20\x00\x00\x01\x85\xae\x7f\x00' +
b'\x00\x00\x00\x01\x21\x00\x00\x00' +
b'\x00\x00\x00\x00\x00\x00\x00\x00' +
b'\x00\x00\x00\x00\x00\x00\x00\x00' +
b'\x00\x00\x00\x00'
)
sock.recv(8192) # discard initial handshake from server for this naive implementation
sock.send(ssl_request_packet)
def main():
module = AnsibleModule(
argument_spec=dict(
@@ -220,6 +242,7 @@ def main():
server_name=dict(type='str'),
timeout=dict(type='int', default=10),
select_crypto_backend=dict(type='str', choices=['auto', 'pyopenssl', 'cryptography'], default='auto'),
starttls=dict(type='str', choices=['mysql']),
),
)
@@ -230,6 +253,7 @@ def main():
proxy_port = module.params.get('proxy_port')
timeout = module.params.get('timeout')
server_name = module.params.get('server_name')
start_tls_server_type = module.params.get('starttls')
backend = module.params.get('select_crypto_backend')
if backend == 'auto':
@@ -305,6 +329,9 @@ def main():
ctx.check_hostname = False
ctx.verify_mode = CERT_NONE
if start_tls_server_type is not None:
send_starttls_packet(sock, start_tls_server_type)
cert = ctx.wrap_socket(sock, server_hostname=server_name or host).getpeercert(True)
cert = DER_cert_to_PEM_cert(cert)
except Exception as e:

View File

@@ -44,12 +44,12 @@ options:
required: true
regenerate:
description:
- When C(never) the task will fail if a certificate already exists at I(path) and is unreadable.
Otherwise, a new certificate will only be generated if there is no existing certificate.
- When C(never) the task will fail if a certificate already exists at I(path) and is unreadable
otherwise a new certificate will only be generated if there is no existing certificate.
- When C(fail) the task will fail if a certificate already exists at I(path) and does not
match the module's options.
- When C(partial_idempotence) an existing certificate will be regenerated based on
I(serial), I(type), I(valid_from), I(valid_to), I(valid_at), and I(principals).
I(serial), I(signature_algorithm), I(type), I(valid_from), I(valid_to), I(valid_at), and I(principals).
- When C(full_idempotence) I(identifier), I(options), I(public_key), and I(signing_key)
are also considered when compared against an existing certificate.
- C(always) is equivalent to I(force=true).
@@ -62,6 +62,26 @@ options:
- always
default: partial_idempotence
version_added: 1.8.0
signature_algorithm:
description:
- As of OpenSSH 8.2 the SHA-1 signature algorithm for RSA keys has been disabled and C(ssh) will refuse
host certificates signed with the SHA-1 algorithm. OpenSSH 8.1 made C(rsa-sha2-512) the default algorithm
when acting as a CA and signing certificates with a RSA key. However, for OpenSSH versions less than 8.1
the SHA-2 signature algorithms, C(rsa-sha2-256) or C(rsa-sha2-512), must be specified using this option
if compatibility with newer C(ssh) clients is required. Conversely if hosts using OpenSSH version 8.2
or greater must remain compatible with C(ssh) clients using OpenSSH less than 7.2, then C(ssh-rsa)
can be used when generating host certificates (a corresponding change to the sshd_config to add C(ssh-rsa)
to the C(CASignatureAlgorithms) keyword is also required).
- Using any value for this option with a non-RSA I(signing_key) will cause this module to fail.
- "Note: OpenSSH versions prior to 7.2 do not support SHA-2 signature algorithms for RSA keys and OpenSSH
versions prior to 7.3 do not support SHA-2 signature algorithms for certificates."
- See U(https://www.openssh.com/txt/release-8.2) for more information.
type: str
choices:
- ssh-rsa
- rsa-sha2-256
- rsa-sha2-512
version_added: 1.10.0
signing_key:
description:
- The path to the private openssh key that is used for signing the public key in order to generate the certificate.
@@ -239,12 +259,15 @@ info:
import os
from distutils.version import LooseVersion
from sys import version_info
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.common.text.converters import to_native, to_text
from ansible_collections.community.crypto.plugins.module_utils.openssh.backends.common import safe_atomic_move
from ansible_collections.community.crypto.plugins.module_utils.openssh.backends.common import (
KeygenCommand,
OpensshModule,
PrivateKey,
)
from ansible_collections.community.crypto.plugins.module_utils.openssh.certificate import (
OpensshCertificate,
@@ -252,153 +275,122 @@ from ansible_collections.community.crypto.plugins.module_utils.openssh.certifica
parse_option_list,
)
from ansible_collections.community.crypto.plugins.module_utils.openssh.utils import (
parse_openssh_version,
)
PY27 = version_info[0:2] >= (2, 7)
class Certificate(object):
class Certificate(OpensshModule):
def __init__(self, module):
self.check_mode = module.check_mode
self.module = module
self.ssh_keygen = module.get_bin_path('ssh-keygen', True)
super(Certificate, self).__init__(module)
self.ssh_keygen = KeygenCommand(self.module)
self.force = module.params['force']
self.identifier = module.params['identifier'] or ""
self.options = module.params['options'] or []
self.path = module.params['path']
self.pkcs11_provider = module.params['pkcs11_provider']
self.principals = module.params['principals'] or []
self.public_key = module.params['public_key']
self.regenerate = module.params['regenerate'] if not self.force else 'always'
self.serial_number = module.params['serial_number']
self.signing_key = module.params['signing_key']
self.state = module.params['state']
self.type = module.params['type']
self.use_agent = module.params['use_agent']
self.valid_at = module.params['valid_at']
self.identifier = self.module.params['identifier'] or ""
self.options = self.module.params['options'] or []
self.path = self.module.params['path']
self.pkcs11_provider = self.module.params['pkcs11_provider']
self.principals = self.module.params['principals'] or []
self.public_key = self.module.params['public_key']
self.regenerate = self.module.params['regenerate'] if not self.module.params['force'] else 'always'
self.serial_number = self.module.params['serial_number']
self.signature_algorithm = self.module.params['signature_algorithm']
self.signing_key = self.module.params['signing_key']
self.state = self.module.params['state']
self.type = self.module.params['type']
self.use_agent = self.module.params['use_agent']
self.valid_at = self.module.params['valid_at']
self._check_if_base_dir(self.path)
if self.state == 'present':
self._validate_parameters()
self.changed = False
self.data = None
self.original_data = None
if self._exists():
self._load_certificate()
self.time_parameters = None
if self.state == 'present':
try:
self.time_parameters = OpensshCertificateTimeParameters(
valid_from=module.params['valid_from'],
valid_to=module.params['valid_to'],
)
except ValueError as e:
self.module.fail_json(msg=to_native(e))
self._set_time_parameters()
if self.exists():
try:
self.original_data = OpensshCertificate.load(self.path)
except (TypeError, ValueError) as e:
if self.regenerate in ('never', 'fail'):
self.module.fail_json(msg="Unable to read existing certificate: %s" % to_native(e))
self.module.warn("Unable to read existing certificate: %s" % to_native(e))
def _validate_parameters(self):
for path in (self.public_key, self.signing_key):
self._check_if_base_dir(path)
self._validate_parameters()
if self.options and self.type == "host":
self.module.fail_json(msg="Options can only be used with user certificates.")
def exists(self):
return os.path.exists(self.path)
if self.use_agent:
self._use_agent_available()
def generate(self):
if self._should_generate():
if not self.check_mode:
temp_cert = self._generate_temp_certificate()
try:
safe_atomic_move(self.module, temp_cert, self.path)
except OSError as e:
self.module.fail_json(msg="Unable to write certificate to %s: %s" % (self.path, to_native(e)))
try:
self.data = OpensshCertificate.load(self.path)
except (TypeError, ValueError) as e:
self.module.fail_json(msg="Unable to read new certificate: %s" % to_native(e))
self.changed = True
if self.exists():
self._update_permissions()
def remove(self):
if self.exists():
if not self.check_mode:
try:
os.remove(self.path)
except OSError as e:
self.module.fail_json(msg="Unable to remove existing certificate: %s" % to_native(e))
self.changed = True
@property
def result(self):
result = {'changed': self.changed}
if self.module._diff:
result['diff'] = {
'before': get_cert_dict(self.original_data),
'after': get_cert_dict(self.data)
}
if self.state == 'present':
result.update({
'type': self.type,
'filename': self.path,
'info': format_cert_info(self._get_cert_info()),
})
return result
def _check_if_base_dir(self, path):
base_dir = os.path.dirname(path) or '.'
if not os.path.isdir(base_dir):
def _use_agent_available(self):
ssh_version = self._get_ssh_version()
if not ssh_version:
self.module.fail_json(msg="Failed to determine ssh version")
elif LooseVersion(ssh_version) < LooseVersion("7.6"):
self.module.fail_json(
name=base_dir,
msg='The directory %s does not exist or the file is not a directory' % base_dir
msg="Signing with CA key in ssh agent requires ssh 7.6 or newer." +
" Your version is: %s" % ssh_version
)
def _command_arguments(self, key_copy_path):
result = [
self.ssh_keygen,
'-s', self.signing_key,
'-P', '',
'-I', self.identifier,
]
def _exists(self):
return os.path.exists(self.path)
if self.options:
for option in self.options:
result.extend(['-O', option])
if self.pkcs11_provider:
result.extend(['-D', self.pkcs11_provider])
if self.principals:
result.extend(['-n', ','.join(self.principals)])
if self.serial_number is not None:
result.extend(['-z', str(self.serial_number)])
if self.type == 'host':
result.extend(['-h'])
if self.use_agent:
result.extend(['-U'])
if self.time_parameters.validity_string:
result.extend(['-V', self.time_parameters.validity_string])
result.append(key_copy_path)
return result
def _compare_options(self):
def _load_certificate(self):
try:
critical_options, extensions = parse_option_list(self.options)
except ValueError as e:
return self.module.fail_json(msg=to_native(e))
self.original_data = OpensshCertificate.load(self.path)
except (TypeError, ValueError) as e:
if self.regenerate in ('never', 'fail'):
self.module.fail_json(msg="Unable to read existing certificate: %s" % to_native(e))
self.module.warn("Unable to read existing certificate: %s" % to_native(e))
def _set_time_parameters(self):
try:
self.time_parameters = OpensshCertificateTimeParameters(
valid_from=self.module.params['valid_from'],
valid_to=self.module.params['valid_to'],
)
except ValueError as e:
self.module.fail_json(msg=to_native(e))
def _execute(self):
if self.state == 'present':
if self._should_generate():
self._generate()
self._update_permissions(self.path)
else:
if self._exists():
self._remove()
def _should_generate(self):
if self.regenerate == 'never':
return self.original_data is None
elif self.regenerate == 'fail':
if self.original_data and not self._is_fully_valid():
self.module.fail_json(
msg="Certificate does not match the provided options.",
cert=get_cert_dict(self.original_data)
)
return self.original_data is None
elif self.regenerate == 'partial_idempotence':
return self.original_data is None or not self._is_partially_valid()
elif self.regenerate == 'full_idempotence':
return self.original_data is None or not self._is_fully_valid()
else:
return True
def _is_fully_valid(self):
return self._is_partially_valid() and all([
self._compare_options(),
self.original_data.key_id == self.identifier,
self.original_data.public_key == self._get_key_fingerprint(self.public_key),
self.original_data.signing_key == self._get_key_fingerprint(self.signing_key),
])
def _is_partially_valid(self):
return all([
set(self.original_data.critical_options) == set(critical_options),
set(self.original_data.extensions) == set(extensions)
set(self.original_data.principals) == set(self.principals),
self.original_data.signature_type == self.signature_algorithm if self.signature_algorithm else True,
self.original_data.serial == self.serial_number if self.serial_number is not None else True,
self.original_data.type == self.type,
self._compare_time_parameters(),
])
def _compare_time_parameters(self):
@@ -415,6 +407,35 @@ class Certificate(object):
original_time_parameters.within_range(self.valid_at)
])
def _compare_options(self):
try:
critical_options, extensions = parse_option_list(self.options)
except ValueError as e:
return self.module.fail_json(msg=to_native(e))
return all([
set(self.original_data.critical_options) == set(critical_options),
set(self.original_data.extensions) == set(extensions)
])
def _get_key_fingerprint(self, path):
private_key_content = self.ssh_keygen.get_private_key(path, check_rc=True)[1]
return PrivateKey.from_string(private_key_content).fingerprint
@OpensshModule.trigger_change
@OpensshModule.skip_if_check_mode
def _generate(self):
try:
temp_certificate = self._generate_temp_certificate()
self._safe_secure_move([(temp_certificate, self.path)])
except OSError as e:
self.module.fail_json(msg="Unable to write certificate to %s: %s" % (self.path, to_native(e)))
try:
self.data = OpensshCertificate.load(self.path)
except (TypeError, ValueError) as e:
self.module.fail_json(msg="Unable to read new certificate: %s" % to_native(e))
def _generate_temp_certificate(self):
key_copy = os.path.join(self.module.tmpdir, os.path.basename(self.public_key))
@@ -424,77 +445,44 @@ class Certificate(object):
self.module.fail_json(msg="Unable to stage temporary key: %s" % to_native(e))
self.module.add_cleanup_file(key_copy)
self.module.run_command(self._command_arguments(key_copy), environ_update=dict(TZ="UTC"), check_rc=True)
self.ssh_keygen.generate_certificate(
key_copy, self.identifier, self.options, self.pkcs11_provider, self.principals, self.serial_number,
self.signature_algorithm, self.signing_key, self.type, self.time_parameters, self.use_agent,
environ_update=dict(TZ="UTC"), check_rc=True
)
temp_cert = os.path.splitext(key_copy)[0] + '-cert.pub'
self.module.add_cleanup_file(temp_cert)
return temp_cert
def _get_cert_info(self):
return self.module.run_command([self.ssh_keygen, '-Lf', self.path])[1]
@OpensshModule.trigger_change
@OpensshModule.skip_if_check_mode
def _remove(self):
try:
os.remove(self.path)
except OSError as e:
self.module.fail_json(msg="Unable to remove existing certificate: %s" % to_native(e))
def _get_key_fingerprint(self, path):
stdout = self.module.run_command([self.ssh_keygen, '-lf', path], check_rc=True)[1]
return stdout.split()[1]
@property
def _result(self):
if self.state != 'present':
return {}
def _is_valid(self):
partial_result = all([
set(self.original_data.principals) == set(self.principals),
self.original_data.serial == self.serial_number if self.serial_number is not None else True,
self.original_data.type == self.type,
self._compare_time_parameters(),
])
certificate_info = self.ssh_keygen.get_certificate_info(self.path)[1]
if self.regenerate == 'partial_idempotence':
return partial_result
return {
'type': self.type,
'filename': self.path,
'info': format_cert_info(certificate_info),
}
return partial_result and all([
self._compare_options(),
self.original_data.key_id == self.identifier,
self.original_data.public_key == self._get_key_fingerprint(self.public_key),
self.original_data.signing_key == self._get_key_fingerprint(self.signing_key),
])
def _should_generate(self):
if self.regenerate == 'never':
return self.original_data is None
elif self.regenerate == 'fail':
if self.original_data and not self._is_valid():
self.module.fail_json(
msg="Certificate does not match the provided options.",
cert=get_cert_dict(self.original_data)
)
return self.original_data is None
elif self.regenerate in ('partial_idempotence', 'full_idempotence'):
return self.original_data is None or not self._is_valid()
else:
return True
def _update_permissions(self):
file_args = self.module.load_file_common_arguments(self.module.params)
self.changed = self.module.set_fs_attributes_if_different(file_args, self.changed)
def _validate_parameters(self):
self._check_if_base_dir(self.path)
if self.state == 'present':
for path in (self.public_key, self.signing_key):
self._check_if_base_dir(path)
if self.options and self.type == "host":
self.module.fail_json(msg="Options can only be used with user certificates.")
if self.use_agent:
ssh_version_string = self.module.run_command([self.module.get_bin_path('ssh', True), '-Vq'])[2].strip()
ssh_version = parse_openssh_version(ssh_version_string)
if ssh_version is None:
self.module.fail_json(msg="Failed to parse ssh version from: %s" % ssh_version_string)
elif LooseVersion(ssh_version) < LooseVersion("7.6"):
self.module.fail_json(
msg="Signing with CA key in ssh agent requires ssh 7.6 or newer." +
" Your version is: %s" % ssh_version_string
)
@property
def diff(self):
return {
'before': get_cert_dict(self.original_data),
'after': get_cert_dict(self.data)
}
def format_cert_info(cert_info):
@@ -519,6 +507,8 @@ def get_cert_dict(data):
result = data.to_dict()
result.pop('nonce')
result['signature_algorithm'] = data.signature_type
return result
@@ -537,6 +527,7 @@ def main():
default='partial_idempotence',
choices=['never', 'fail', 'partial_idempotence', 'full_idempotence', 'always']
),
signature_algorithm=dict(type='str', choices=['ssh-rsa', 'rsa-sha2-256', 'rsa-sha2-512']),
signing_key=dict(type='path'),
serial_number=dict(type='int'),
state=dict(type='str', default='present', choices=['absent', 'present']),
@@ -551,14 +542,7 @@ def main():
required_if=[('state', 'present', ['type', 'signing_key', 'public_key', 'valid_from', 'valid_to'])],
)
certificate = Certificate(module)
if certificate.state == 'present':
certificate.generate()
else:
certificate.remove()
module.exit_json(**certificate.result)
Certificate(module).execute()
if __name__ == '__main__':

View File

@@ -186,8 +186,6 @@ comment:
sample: test@comment
'''
import os
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.crypto.plugins.module_utils.openssh.backends.keypair_backend import (
@@ -218,32 +216,9 @@ def main():
add_file_common_args=True,
)
base_dir = os.path.dirname(module.params['path']) or '.'
if not os.path.isdir(base_dir):
module.fail_json(
name=base_dir,
msg='The directory %s does not exist or the file is not a directory' % base_dir
)
keypair = select_backend(module, module.params['backend'])[1]
if module.params['state'] == 'present':
if module.check_mode:
keypair.changed = any([
keypair.force,
not keypair.is_private_key_valid(),
not keypair.is_public_key_valid()
])
else:
keypair.generate()
else:
# When `state=absent` no details from an existing key at the given `path` are returned in the module result
if module.check_mode:
keypair.changed = keypair.exists()
else:
keypair.remove()
module.exit_json(**keypair.result)
keypair.execute()
if __name__ == '__main__':

View File

@@ -597,7 +597,7 @@ class CRL(OpenSSLObject):
entry['invalidity_date_critical'],
)
def check(self, perms_required=True, ignore_conversion=True):
def check(self, module, perms_required=True, ignore_conversion=True):
"""Ensure the resource is in its desired state."""
state_and_perms = super(CRL, self).check(self.module, perms_required)
@@ -689,9 +689,9 @@ class CRL(OpenSSLObject):
def generate(self):
result = None
if not self.check(perms_required=False, ignore_conversion=True) or self.force:
if not self.check(self.module, perms_required=False, ignore_conversion=True) or self.force:
result = self._generate_crl()
elif not self.check(perms_required=False, ignore_conversion=False) and self.crl:
elif not self.check(self.module, perms_required=False, ignore_conversion=False) and self.crl:
if self.format == 'pem':
result = self.crl.public_bytes(Encoding.PEM)
else:
@@ -834,7 +834,7 @@ def main():
if module.params['state'] == 'present':
if module.check_mode:
result = crl.dump(check_mode=True)
result['changed'] = module.params['force'] or not crl.check() or not crl.check(ignore_conversion=False)
result['changed'] = module.params['force'] or not crl.check(module) or not crl.check(module, ignore_conversion=False)
module.exit_json(**result)
crl.generate()

View File

@@ -1,2 +1,14 @@
shippable/cloud/group1
cloud/acme
# Since skipping below fails miserably with ansible-core 2.11 and earlier, we have to skip all POSIX tests...
# (https://github.com/ansible/ansible/issues/75711)
# shippable/posix/group1
# Skip all VMs, since we cannot talk to the ACME simulator from these:
# (TODO: remove when ansible-core 2.12 is the earliest version we support)
# skip/aix
# skip/freebsd
# skip/macos
# skip/osx
# skip/rhel

View File

@@ -1,2 +1,3 @@
dependencies:
- setup_acme
- setup_remote_tmp_dir

View File

@@ -1,9 +1,9 @@
- block:
- name: Generate account keys
openssl_privatekey:
path: "{{ output_dir }}/{{ item.name }}.pem"
passphrase: "{{ item.pass | default(omit, true) }}"
cipher: "{{ 'auto' if item.pass | default() else omit }}"
path: "{{ remote_tmp_dir }}/{{ item.name }}.pem"
passphrase: "{{ item.pass | default(omit) | default(omit, true) }}"
cipher: "{{ 'auto' if (item.pass | default(false)) else omit }}"
type: ECC
curve: secp256r1
force: true
@@ -11,8 +11,8 @@
- name: Parse account keys (to ease debugging some test failures)
openssl_privatekey_info:
path: "{{ output_dir }}/{{ item.name }}.pem"
passphrase: "{{ item.pass | default(omit, true) }}"
path: "{{ remote_tmp_dir }}/{{ item.name }}.pem"
passphrase: "{{ item.pass | default(omit) | default(omit, true) }}"
return_private_key_data: true
loop: "{{ account_keys }}"
@@ -28,7 +28,7 @@
- name: Do not try to create account
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
@@ -40,7 +40,7 @@
- name: Create it now (check mode, diff)
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
@@ -56,7 +56,7 @@
- name: Create it now
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
@@ -70,7 +70,7 @@
- name: Create it now (idempotent)
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
@@ -81,10 +81,15 @@
- mailto:example@example.org
register: account_created_idempotent
- name: Read account key
slurp:
src: '{{ remote_tmp_dir }}/accountkey.pem'
register: slurp
- name: Change email address (check mode, diff)
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_content: "{{ lookup('file', output_dir ~ '/accountkey.pem') }}"
account_key_content: "{{ slurp.content | b64decode }}"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
@@ -99,7 +104,7 @@
- name: Change email address
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_content: "{{ lookup('file', output_dir ~ '/accountkey.pem') }}"
account_key_content: "{{ slurp.content | b64decode }}"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
@@ -112,7 +117,7 @@
- name: Change email address (idempotent)
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
account_uri: "{{ account_created.account_uri }}"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
@@ -126,7 +131,7 @@
- name: Cannot access account with wrong URI
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
account_uri: "{{ account_created.account_uri ~ '12345thisdoesnotexist' }}"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
@@ -139,7 +144,7 @@
- name: Clear contact email addresses (check mode, diff)
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
@@ -153,7 +158,7 @@
- name: Clear contact email addresses
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
@@ -165,7 +170,7 @@
- name: Clear contact email addresses (idempotent)
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
@@ -177,11 +182,11 @@
- name: Change account key (check mode, diff)
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
new_account_key_src: "{{ output_dir }}/accountkey2.pem"
new_account_key_src: "{{ remote_tmp_dir }}/accountkey2.pem"
new_account_key_passphrase: "{{ 'hunter2' if select_crypto_backend != 'openssl' else omit }}"
state: changed_key
contact:
@@ -193,11 +198,11 @@
- name: Change account key
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
new_account_key_src: "{{ output_dir }}/accountkey2.pem"
new_account_key_src: "{{ remote_tmp_dir }}/accountkey2.pem"
new_account_key_passphrase: "{{ 'hunter2' if select_crypto_backend != 'openssl' else omit }}"
state: changed_key
contact:
@@ -207,7 +212,7 @@
- name: Deactivate account (check mode, diff)
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey2.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey2.pem"
account_key_passphrase: "{{ 'hunter2' if select_crypto_backend != 'openssl' else omit }}"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
@@ -220,7 +225,7 @@
- name: Deactivate account
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey2.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey2.pem"
account_key_passphrase: "{{ 'hunter2' if select_crypto_backend != 'openssl' else omit }}"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
@@ -231,7 +236,7 @@
- name: Deactivate account (idempotent)
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey2.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey2.pem"
account_key_passphrase: "{{ 'hunter2' if select_crypto_backend != 'openssl' else omit }}"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
@@ -242,7 +247,7 @@
- name: Do not try to create account II
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey2.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey2.pem"
account_key_passphrase: "{{ 'hunter2' if select_crypto_backend != 'openssl' else omit }}"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
@@ -255,7 +260,7 @@
- name: Do not try to create account III
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
@@ -267,7 +272,7 @@
- name: Create account with External Account Binding
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/{{ item.account }}.pem"
account_key_src: "{{ remote_tmp_dir }}/{{ item.account }}.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no

View File

@@ -17,12 +17,12 @@
- name: Remove output directory
file:
path: "{{ output_dir }}"
path: "{{ remote_tmp_dir }}"
state: absent
- name: Re-create output directory
file:
path: "{{ output_dir }}"
path: "{{ remote_tmp_dir }}"
state: directory
- block:

View File

@@ -1,2 +1,14 @@
shippable/cloud/group1
cloud/acme
# Since skipping below fails miserably with ansible-core 2.11 and earlier, we have to skip all POSIX tests...
# (https://github.com/ansible/ansible/issues/75711)
# shippable/posix/group1
# Skip all VMs, since we cannot talk to the ACME simulator from these:
# (TODO: remove when ansible-core 2.12 is the earliest version we support)
# skip/aix
# skip/freebsd
# skip/macos
# skip/osx
# skip/rhel

View File

@@ -1,2 +1,3 @@
dependencies:
- setup_acme
- setup_remote_tmp_dir

View File

@@ -2,7 +2,7 @@
- block:
- name: Generate account keys
openssl_privatekey:
path: "{{ output_dir }}/{{ item }}.pem"
path: "{{ remote_tmp_dir }}/{{ item }}.pem"
type: ECC
curve: secp256r1
force: true
@@ -10,7 +10,7 @@
- name: Parse account keys (to ease debugging some test failures)
openssl_privatekey_info:
path: "{{ output_dir }}/{{ item }}.pem"
path: "{{ remote_tmp_dir }}/{{ item }}.pem"
return_private_key_data: true
loop: "{{ account_keys }}"
@@ -22,7 +22,7 @@
- name: Check that account does not exist
acme_account_info:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
@@ -31,7 +31,7 @@
- name: Create it now
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
@@ -44,16 +44,21 @@
- name: Check that account exists
acme_account_info:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
register: account_created
- name: Read account key
slurp:
src: '{{ remote_tmp_dir }}/accountkey.pem'
register: slurp
- name: Clear email address
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_content: "{{ lookup('file', output_dir ~ '/accountkey.pem') }}"
account_key_content: "{{ slurp.content | b64decode }}"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
@@ -64,7 +69,7 @@
- name: Check that account was modified
acme_account_info:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
@@ -74,7 +79,7 @@
- name: Check with wrong account URI
acme_account_info:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
@@ -84,7 +89,7 @@
- name: Check with wrong account key
acme_account_info:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey2.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey2.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no

View File

@@ -17,12 +17,12 @@
- name: Remove output directory
file:
path: "{{ output_dir }}"
path: "{{ remote_tmp_dir }}"
state: absent
- name: Re-create output directory
file:
path: "{{ output_dir }}"
path: "{{ remote_tmp_dir }}"
state: directory
- block:

View File

@@ -1,2 +1,14 @@
shippable/cloud/group1
cloud/acme
# Since skipping below fails miserably with ansible-core 2.11 and earlier, we have to skip all POSIX tests...
# (https://github.com/ansible/ansible/issues/75711)
# shippable/posix/group1
# Skip all VMs, since we cannot talk to the ACME simulator from these:
# (TODO: remove when ansible-core 2.12 is the earliest version we support)
# skip/aix
# skip/freebsd
# skip/macos
# skip/osx
# skip/rhel

View File

@@ -1,2 +1,5 @@
dependencies:
- setup_acme
- setup_pyopenssl # needed for Ubuntu 16.04
- setup_remote_tmp_dir
- prepare_jinja2_compat

View File

@@ -3,7 +3,7 @@
- block:
- name: Generate account keys
openssl_privatekey:
path: "{{ output_dir }}/{{ item.name }}.pem"
path: "{{ remote_tmp_dir }}/{{ item.name }}.pem"
type: "{{ item.type }}"
size: "{{ item.size | default(omit) }}"
curve: "{{ item.curve | default(omit) }}"
@@ -28,15 +28,19 @@
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
account_key_src: "{{ output_dir }}/account-ec256.pem"
account_key_src: "{{ remote_tmp_dir }}/account-ec256.pem"
state: absent
- name: Read account key (EC384)
slurp:
src: '{{ remote_tmp_dir }}/account-ec384.pem'
register: slurp
- name: Create ECC384 account
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
account_key_content: "{{ lookup('file', output_dir ~ '/account-ec384.pem') }}"
account_key_content: "{{ slurp.content | b64decode }}"
state: present
allow_creation: yes
terms_agreed: yes
@@ -49,7 +53,7 @@
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
account_key_src: "{{ output_dir }}/account-rsa.pem"
account_key_src: "{{ remote_tmp_dir }}/account-rsa.pem"
state: present
allow_creation: yes
terms_agreed: yes
@@ -115,6 +119,10 @@
set_fact:
cert_2_obtain_results: "{{ certificate_obtain_result }}"
cert_2_alternate: "{{ 0 if select_crypto_backend == 'cryptography' else 0 }}"
- name: Read account key (RSA)
slurp:
src: '{{ remote_tmp_dir }}/account-rsa.pem'
register: slurp_account_key
- name: Obtain cert 3
include_tasks: obtain-cert.yml
vars:
@@ -123,7 +131,7 @@
key_type: ec384
subject_alt_name: "DNS:*.example.com,DNS:example.org,DNS:t1.example.com"
subject_alt_name_critical: no
account_key_content: "{{ lookup('file', output_dir ~ '/account-rsa.pem') }}"
account_key_content: "{{ slurp_account_key.content | b64decode }}"
challenge: dns-01
modify_account: no
deactivate_authzs: no
@@ -231,6 +239,10 @@
set_fact:
cert_5_recreate_2: "{{ challenge_data is changed }}"
cert_5c_obtain_results: "{{ certificate_obtain_result }}"
- name: Read account key (EC384)
slurp:
src: '{{ remote_tmp_dir }}/account-ec384.pem'
register: slurp_account_key
- name: Obtain cert 5 (should again by force)
include_tasks: obtain-cert.yml
vars:
@@ -239,7 +251,7 @@
key_type: ec521
subject_alt_name: "DNS:t2.example.com"
subject_alt_name_critical: no
account_key_content: "{{ lookup('file', output_dir ~ '/account-ec384.pem') }}"
account_key_content: "{{ slurp_account_key.content | b64decode }}"
challenge: http-01
modify_account: no
deactivate_authzs: yes
@@ -252,189 +264,204 @@
set_fact:
cert_5_recreate_3: "{{ challenge_data is changed }}"
cert_5d_obtain_results: "{{ certificate_obtain_result }}"
- name: Obtain cert 6
include_tasks: obtain-cert.yml
vars:
certgen_title: Certificate 6
certificate_name: cert-6
key_type: rsa
rsa_bits: "{{ default_rsa_key_size }}"
subject_alt_name: "DNS:example.org"
subject_alt_name_critical: no
account_key: account-ec256
challenge: tls-alpn-01
modify_account: yes
deactivate_authzs: no
force: no
remaining_days: 10
terms_agreed: yes
account_email: "example@example.org"
acme_expected_root_number: 0
select_chain:
# All intermediates have the same subject key identifier, so always
# the first chain will be found, and we need a second condition to
# make sure that the first condition actually works. (The second
# condition has been tested above.)
- test_certificates: first
subject_key_identifier: "{{ acme_intermediates[0].subject_key_identifier }}"
- test_certificates: last
issuer: "{{ acme_roots[1].subject }}"
use_csr_content: true
- name: Store obtain results for cert 6
set_fact:
cert_6_obtain_results: "{{ certificate_obtain_result }}"
cert_6_alternate: "{{ 0 if select_crypto_backend == 'cryptography' else 0 }}"
- name: Obtain cert 7
include_tasks: obtain-cert.yml
vars:
certgen_title: Certificate 7
certificate_name: cert-7
key_type: rsa
rsa_bits: "{{ default_rsa_key_size }}"
subject_alt_name:
- "IP:127.0.0.1"
# - "IP:::1"
subject_alt_name_critical: no
account_key: account-ec256
challenge: http-01
modify_account: yes
deactivate_authzs: no
force: no
remaining_days: 10
terms_agreed: yes
account_email: "example@example.org"
acme_expected_root_number: 2
select_chain:
- test_certificates: last
authority_key_identifier: "{{ acme_roots[2].subject_key_identifier }}"
use_csr_content: false
- name: Store obtain results for cert 7
set_fact:
cert_7_obtain_results: "{{ certificate_obtain_result }}"
cert_7_alternate: "{{ 2 if select_crypto_backend == 'cryptography' else 0 }}"
- name: Obtain cert 8
include_tasks: obtain-cert.yml
vars:
certgen_title: Certificate 8
certificate_name: cert-8
key_type: rsa
rsa_bits: "{{ default_rsa_key_size }}"
subject_alt_name:
- "IP:127.0.0.1"
# IPv4 only since our test validation server doesn't work
# with IPv6 (thanks to Python's socketserver).
subject_alt_name_critical: no
account_key: account-ec256
challenge: tls-alpn-01
challenge_alpn_tls: acme_challenge_cert_helper
modify_account: yes
deactivate_authzs: no
force: no
remaining_days: 10
terms_agreed: yes
account_email: "example@example.org"
use_csr_content: true
- name: Store obtain results for cert 8
set_fact:
cert_8_obtain_results: "{{ certificate_obtain_result }}"
cert_8_alternate: "{{ 0 if select_crypto_backend == 'cryptography' else 0 }}"
- block:
- name: Obtain cert 6
include_tasks: obtain-cert.yml
vars:
certgen_title: Certificate 6
certificate_name: cert-6
key_type: rsa
rsa_bits: "{{ default_rsa_key_size }}"
subject_alt_name: "DNS:example.org"
subject_alt_name_critical: no
account_key: account-ec256
challenge: tls-alpn-01
modify_account: yes
deactivate_authzs: no
force: no
remaining_days: 10
terms_agreed: yes
account_email: "example@example.org"
acme_expected_root_number: 0
select_chain:
# All intermediates have the same subject key identifier, so always
# the first chain will be found, and we need a second condition to
# make sure that the first condition actually works. (The second
# condition has been tested above.)
- test_certificates: first
subject_key_identifier: "{{ acme_intermediates[0].subject_key_identifier }}"
- test_certificates: last
issuer: "{{ acme_roots[1].subject }}"
use_csr_content: true
- name: Store obtain results for cert 6
set_fact:
cert_6_obtain_results: "{{ certificate_obtain_result }}"
cert_6_alternate: "{{ 0 if select_crypto_backend == 'cryptography' else 0 }}"
when: acme_intermediates[0].subject_key_identifier is defined
- block:
- name: Obtain cert 7
include_tasks: obtain-cert.yml
vars:
certgen_title: Certificate 7
certificate_name: cert-7
key_type: rsa
rsa_bits: "{{ default_rsa_key_size }}"
subject_alt_name:
- "IP:127.0.0.1"
# - "IP:::1"
subject_alt_name_critical: no
account_key: account-ec256
challenge: http-01
modify_account: yes
deactivate_authzs: no
force: no
remaining_days: 10
terms_agreed: yes
account_email: "example@example.org"
acme_expected_root_number: 2
select_chain:
- test_certificates: last
authority_key_identifier: "{{ acme_roots[2].subject_key_identifier }}"
use_csr_content: false
- name: Store obtain results for cert 7
set_fact:
cert_7_obtain_results: "{{ certificate_obtain_result }}"
cert_7_alternate: "{{ 2 if select_crypto_backend == 'cryptography' else 0 }}"
when: acme_roots[2].subject_key_identifier is defined
- block:
- name: Obtain cert 8
include_tasks: obtain-cert.yml
vars:
certgen_title: Certificate 8
certificate_name: cert-8
key_type: rsa
rsa_bits: "{{ default_rsa_key_size }}"
subject_alt_name:
- "IP:127.0.0.1"
# IPv4 only since our test validation server doesn't work
# with IPv6 (thanks to Python's socketserver).
subject_alt_name_critical: no
account_key: account-ec256
challenge: tls-alpn-01
challenge_alpn_tls: acme_challenge_cert_helper
modify_account: yes
deactivate_authzs: no
force: no
remaining_days: 10
terms_agreed: yes
account_email: "example@example.org"
use_csr_content: true
- name: Store obtain results for cert 8
set_fact:
cert_8_obtain_results: "{{ certificate_obtain_result }}"
cert_8_alternate: "{{ 0 if select_crypto_backend == 'cryptography' else 0 }}"
when: cryptography_version.stdout is version('1.3', '>=')
## DISSECT CERTIFICATES #######################################################################
# Make sure certificates are valid. Root certificate for Pebble equals the chain certificate.
- name: Verifying cert 1
command: '{{ openssl_binary }} verify -CAfile "{{ output_dir }}/cert-1-root.pem" -untrusted "{{ output_dir }}/cert-1-chain.pem" "{{ output_dir }}/cert-1.pem"'
command: '{{ openssl_binary }} verify -CAfile "{{ remote_tmp_dir }}/cert-1-root.pem" -untrusted "{{ remote_tmp_dir }}/cert-1-chain.pem" "{{ remote_tmp_dir }}/cert-1.pem"'
ignore_errors: yes
register: cert_1_valid
- name: Verifying cert 2
command: '{{ openssl_binary }} verify -CAfile "{{ output_dir }}/cert-2-root.pem" -untrusted "{{ output_dir }}/cert-2-chain.pem" "{{ output_dir }}/cert-2.pem"'
command: '{{ openssl_binary }} verify -CAfile "{{ remote_tmp_dir }}/cert-2-root.pem" -untrusted "{{ remote_tmp_dir }}/cert-2-chain.pem" "{{ remote_tmp_dir }}/cert-2.pem"'
ignore_errors: yes
register: cert_2_valid
- name: Verifying cert 3
command: '{{ openssl_binary }} verify -CAfile "{{ output_dir }}/cert-3-root.pem" -untrusted "{{ output_dir }}/cert-3-chain.pem" "{{ output_dir }}/cert-3.pem"'
command: '{{ openssl_binary }} verify -CAfile "{{ remote_tmp_dir }}/cert-3-root.pem" -untrusted "{{ remote_tmp_dir }}/cert-3-chain.pem" "{{ remote_tmp_dir }}/cert-3.pem"'
ignore_errors: yes
register: cert_3_valid
- name: Verifying cert 4
command: '{{ openssl_binary }} verify -CAfile "{{ output_dir }}/cert-4-root.pem" -untrusted "{{ output_dir }}/cert-4-chain.pem" "{{ output_dir }}/cert-4.pem"'
command: '{{ openssl_binary }} verify -CAfile "{{ remote_tmp_dir }}/cert-4-root.pem" -untrusted "{{ remote_tmp_dir }}/cert-4-chain.pem" "{{ remote_tmp_dir }}/cert-4.pem"'
ignore_errors: yes
register: cert_4_valid
- name: Verifying cert 5
command: '{{ openssl_binary }} verify -CAfile "{{ output_dir }}/cert-5-root.pem" -untrusted "{{ output_dir }}/cert-5-chain.pem" "{{ output_dir }}/cert-5.pem"'
command: '{{ openssl_binary }} verify -CAfile "{{ remote_tmp_dir }}/cert-5-root.pem" -untrusted "{{ remote_tmp_dir }}/cert-5-chain.pem" "{{ remote_tmp_dir }}/cert-5.pem"'
ignore_errors: yes
register: cert_5_valid
- name: Verifying cert 6
command: '{{ openssl_binary }} verify -CAfile "{{ output_dir }}/cert-6-root.pem" -untrusted "{{ output_dir }}/cert-6-chain.pem" "{{ output_dir }}/cert-6.pem"'
command: '{{ openssl_binary }} verify -CAfile "{{ remote_tmp_dir }}/cert-6-root.pem" -untrusted "{{ remote_tmp_dir }}/cert-6-chain.pem" "{{ remote_tmp_dir }}/cert-6.pem"'
ignore_errors: yes
register: cert_6_valid
when: acme_intermediates[0].subject_key_identifier is defined
- name: Verifying cert 7
command: '{{ openssl_binary }} verify -CAfile "{{ output_dir }}/cert-7-root.pem" -untrusted "{{ output_dir }}/cert-7-chain.pem" "{{ output_dir }}/cert-7.pem"'
command: '{{ openssl_binary }} verify -CAfile "{{ remote_tmp_dir }}/cert-7-root.pem" -untrusted "{{ remote_tmp_dir }}/cert-7-chain.pem" "{{ remote_tmp_dir }}/cert-7.pem"'
ignore_errors: yes
register: cert_7_valid
when: acme_roots[2].subject_key_identifier is defined
- name: Verifying cert 8
command: '{{ openssl_binary }} verify -CAfile "{{ output_dir }}/cert-8-root.pem" -untrusted "{{ output_dir }}/cert-8-chain.pem" "{{ output_dir }}/cert-8.pem"'
command: '{{ openssl_binary }} verify -CAfile "{{ remote_tmp_dir }}/cert-8-root.pem" -untrusted "{{ remote_tmp_dir }}/cert-8-chain.pem" "{{ remote_tmp_dir }}/cert-8.pem"'
ignore_errors: yes
register: cert_8_valid
when: cryptography_version.stdout is version('1.3', '>=')
# Dump certificate info
- name: Dumping cert 1
command: '{{ openssl_binary }} x509 -in "{{ output_dir }}/cert-1.pem" -noout -text'
command: '{{ openssl_binary }} x509 -in "{{ remote_tmp_dir }}/cert-1.pem" -noout -text'
register: cert_1_text
- name: Dumping cert 2
command: '{{ openssl_binary }} x509 -in "{{ output_dir }}/cert-2.pem" -noout -text'
command: '{{ openssl_binary }} x509 -in "{{ remote_tmp_dir }}/cert-2.pem" -noout -text'
register: cert_2_text
- name: Dumping cert 3
command: '{{ openssl_binary }} x509 -in "{{ output_dir }}/cert-3.pem" -noout -text'
command: '{{ openssl_binary }} x509 -in "{{ remote_tmp_dir }}/cert-3.pem" -noout -text'
register: cert_3_text
- name: Dumping cert 4
command: '{{ openssl_binary }} x509 -in "{{ output_dir }}/cert-4.pem" -noout -text'
command: '{{ openssl_binary }} x509 -in "{{ remote_tmp_dir }}/cert-4.pem" -noout -text'
register: cert_4_text
- name: Dumping cert 5
command: '{{ openssl_binary }} x509 -in "{{ output_dir }}/cert-5.pem" -noout -text'
command: '{{ openssl_binary }} x509 -in "{{ remote_tmp_dir }}/cert-5.pem" -noout -text'
register: cert_5_text
- name: Dumping cert 6
command: '{{ openssl_binary }} x509 -in "{{ output_dir }}/cert-6.pem" -noout -text'
command: '{{ openssl_binary }} x509 -in "{{ remote_tmp_dir }}/cert-6.pem" -noout -text'
register: cert_6_text
when: acme_intermediates[0].subject_key_identifier is defined
- name: Dumping cert 7
command: '{{ openssl_binary }} x509 -in "{{ output_dir }}/cert-7.pem" -noout -text'
command: '{{ openssl_binary }} x509 -in "{{ remote_tmp_dir }}/cert-7.pem" -noout -text'
register: cert_7_text
when: acme_roots[2].subject_key_identifier is defined
- name: Dumping cert 8
command: '{{ openssl_binary }} x509 -in "{{ output_dir }}/cert-8.pem" -noout -text'
command: '{{ openssl_binary }} x509 -in "{{ remote_tmp_dir }}/cert-8.pem" -noout -text'
register: cert_8_text
when: cryptography_version.stdout is version('1.3', '>=')
# Dump certificate info
- name: Dumping cert 1
x509_certificate_info:
path: "{{ output_dir }}/cert-1.pem"
path: "{{ remote_tmp_dir }}/cert-1.pem"
register: cert_1_info
- name: Dumping cert 2
x509_certificate_info:
path: "{{ output_dir }}/cert-2.pem"
path: "{{ remote_tmp_dir }}/cert-2.pem"
register: cert_2_info
- name: Dumping cert 3
x509_certificate_info:
path: "{{ output_dir }}/cert-3.pem"
path: "{{ remote_tmp_dir }}/cert-3.pem"
register: cert_3_info
- name: Dumping cert 4
x509_certificate_info:
path: "{{ output_dir }}/cert-4.pem"
path: "{{ remote_tmp_dir }}/cert-4.pem"
register: cert_4_info
- name: Dumping cert 5
x509_certificate_info:
path: "{{ output_dir }}/cert-5.pem"
path: "{{ remote_tmp_dir }}/cert-5.pem"
register: cert_5_info
- name: Dumping cert 6
x509_certificate_info:
path: "{{ output_dir }}/cert-6.pem"
path: "{{ remote_tmp_dir }}/cert-6.pem"
register: cert_6_info
when: acme_intermediates[0].subject_key_identifier is defined
- name: Dumping cert 7
x509_certificate_info:
path: "{{ output_dir }}/cert-7.pem"
path: "{{ remote_tmp_dir }}/cert-7.pem"
register: cert_7_info
when: acme_roots[2].subject_key_identifier is defined
- name: Dumping cert 8
x509_certificate_info:
path: "{{ output_dir }}/cert-8.pem"
path: "{{ remote_tmp_dir }}/cert-8.pem"
register: cert_8_info
when: cryptography_version.stdout is version('1.3', '>=')
## GET ACCOUNT ORDERS #########################################################################
- name: Don't retrieve orders
acme_account_info:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/account-ec256.pem"
account_key_src: "{{ remote_tmp_dir }}/account-ec256.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
@@ -443,7 +470,7 @@
- name: Retrieve orders as URL list (1/2)
acme_account_info:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/account-ec256.pem"
account_key_src: "{{ remote_tmp_dir }}/account-ec256.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
@@ -452,7 +479,7 @@
- name: Retrieve orders as URL list (2/2)
acme_account_info:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/account-ec384.pem"
account_key_src: "{{ remote_tmp_dir }}/account-ec384.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
@@ -461,7 +488,7 @@
- name: Retrieve orders as object list (1/2)
acme_account_info:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/account-ec256.pem"
account_key_src: "{{ remote_tmp_dir }}/account-ec256.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
@@ -470,7 +497,7 @@
- name: Retrieve orders as object list (2/2)
acme_account_info:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/account-ec384.pem"
account_key_src: "{{ remote_tmp_dir }}/account-ec384.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no

View File

@@ -8,38 +8,48 @@
- name: Obtain root and intermediate certificates
get_url:
url: "http://{{ acme_host }}:5000/{{ item.0 }}-certificate-for-ca/{{ item.1 }}"
dest: "{{ output_dir }}/acme-{{ item.0 }}-{{ item.1 }}.pem"
dest: "{{ remote_tmp_dir }}/acme-{{ item.0 }}-{{ item.1 }}.pem"
loop: "{{ query('nested', types, root_numbers) }}"
- name: Analyze root certificates
x509_certificate_info:
path: "{{ output_dir }}/acme-root-{{ item }}.pem"
path: "{{ remote_tmp_dir }}/acme-root-{{ item }}.pem"
loop: "{{ root_numbers }}"
register: acme_roots
- name: Analyze intermediate certificates
x509_certificate_info:
path: "{{ output_dir }}/acme-intermediate-{{ item }}.pem"
path: "{{ remote_tmp_dir }}/acme-intermediate-{{ item }}.pem"
loop: "{{ root_numbers }}"
register: acme_intermediates
- set_fact:
x__: "{{ item | dict2items | selectattr('key', 'in', interesting_keys) | list | items2dict }}"
y__: "{{ lookup('file', output_dir ~ '/acme-root-' ~ item.item ~ '.pem', rstrip=False) }}"
loop: "{{ acme_roots.results }}"
register: acme_roots_tmp
- name: Read root certificates
slurp:
src: "{{ remote_tmp_dir ~ '/acme-root-' ~ item ~ '.pem' }}"
loop: "{{ root_numbers }}"
register: slurp_roots
- set_fact:
x__: "{{ item | dict2items | selectattr('key', 'in', interesting_keys) | list | items2dict }}"
loop: "{{ acme_roots.results }}"
register: acme_roots_tmp
- name: Read intermediate certificates
slurp:
src: "{{ remote_tmp_dir ~ '/acme-intermediate-' ~ item ~ '.pem' }}"
loop: "{{ root_numbers }}"
register: slurp_intermediates
- set_fact:
x__: "{{ item | dict2items | selectattr('key', 'in', interesting_keys) | list | items2dict }}"
y__: "{{ lookup('file', output_dir ~ '/acme-intermediate-' ~ item.item ~ '.pem', rstrip=False) }}"
loop: "{{ acme_intermediates.results }}"
register: acme_intermediates_tmp
- set_fact:
acme_roots: "{{ acme_roots_tmp.results | map(attribute='ansible_facts.x__') | list }}"
acme_root_certs: "{{ acme_roots_tmp.results | map(attribute='ansible_facts.y__') | list }}"
acme_root_certs: "{{ slurp_roots.results | map(attribute='content') | map('b64decode') | list }}"
acme_intermediates: "{{ acme_intermediates_tmp.results | map(attribute='ansible_facts.x__') | list }}"
acme_intermediate_certs: "{{ acme_intermediates_tmp.results | map(attribute='ansible_facts.y__') | list }}"
acme_intermediate_certs: "{{ slurp_intermediates.results | map(attribute='content') | map('b64decode') | list }}"
vars:
types:
@@ -88,12 +98,12 @@
- name: Remove output directory
file:
path: "{{ output_dir }}"
path: "{{ remote_tmp_dir }}"
state: absent
- name: Re-create output directory
file:
path: "{{ output_dir }}"
path: "{{ remote_tmp_dir }}"
state: directory
- block:

View File

@@ -7,6 +7,14 @@
assert:
that:
- "'DNS:example.com' in cert_1_text.stdout"
- name: Read certificate 1 files
slurp:
src: '{{ remote_tmp_dir }}/{{ item }}'
loop:
- cert-1.pem
- cert-1-chain.pem
- cert-1-fullchain.pem
register: slurp
- name: Check that certificate 1 retrieval got all chains
assert:
that:
@@ -15,9 +23,9 @@
- "'cert' in cert_1_obtain_results.all_chains[cert_1_alternate | int]"
- "'chain' in cert_1_obtain_results.all_chains[cert_1_alternate | int]"
- "'full_chain' in cert_1_obtain_results.all_chains[cert_1_alternate | int]"
- "lookup('file', output_dir ~ '/cert-1.pem', rstrip=False) == cert_1_obtain_results.all_chains[cert_1_alternate | int].cert"
- "lookup('file', output_dir ~ '/cert-1-chain.pem', rstrip=False) == cert_1_obtain_results.all_chains[cert_1_alternate | int].chain"
- "lookup('file', output_dir ~ '/cert-1-fullchain.pem', rstrip=False) == cert_1_obtain_results.all_chains[cert_1_alternate | int].full_chain"
- "(slurp.results[0].content | b64decode) == cert_1_obtain_results.all_chains[cert_1_alternate | int].cert"
- "(slurp.results[1].content | b64decode) == cert_1_obtain_results.all_chains[cert_1_alternate | int].chain"
- "(slurp.results[2].content | b64decode) == cert_1_obtain_results.all_chains[cert_1_alternate | int].full_chain"
- name: Check that certificate 2 is valid
assert:
@@ -28,6 +36,14 @@
that:
- "'DNS:*.example.com' in cert_2_text.stdout"
- "'DNS:example.com' in cert_2_text.stdout"
- name: Read certificate 2 files
slurp:
src: '{{ remote_tmp_dir }}/{{ item }}'
loop:
- cert-2.pem
- cert-2-chain.pem
- cert-2-fullchain.pem
register: slurp
- name: Check that certificate 1 retrieval got all chains
assert:
that:
@@ -36,9 +52,9 @@
- "'cert' in cert_2_obtain_results.all_chains[cert_2_alternate | int]"
- "'chain' in cert_2_obtain_results.all_chains[cert_2_alternate | int]"
- "'full_chain' in cert_2_obtain_results.all_chains[cert_2_alternate | int]"
- "lookup('file', output_dir ~ '/cert-2.pem', rstrip=False) == cert_2_obtain_results.all_chains[cert_2_alternate | int].cert"
- "lookup('file', output_dir ~ '/cert-2-chain.pem', rstrip=False) == cert_2_obtain_results.all_chains[cert_2_alternate | int].chain"
- "lookup('file', output_dir ~ '/cert-2-fullchain.pem', rstrip=False) == cert_2_obtain_results.all_chains[cert_2_alternate | int].full_chain"
- "(slurp.results[0].content | b64decode) == cert_2_obtain_results.all_chains[cert_2_alternate | int].cert"
- "(slurp.results[1].content | b64decode) == cert_2_obtain_results.all_chains[cert_2_alternate | int].chain"
- "(slurp.results[2].content | b64decode) == cert_2_obtain_results.all_chains[cert_2_alternate | int].full_chain"
- name: Check that certificate 3 is valid
assert:
@@ -50,6 +66,14 @@
- "'DNS:*.example.com' in cert_3_text.stdout"
- "'DNS:example.org' in cert_3_text.stdout"
- "'DNS:t1.example.com' in cert_3_text.stdout"
- name: Read certificate 3 files
slurp:
src: '{{ remote_tmp_dir }}/{{ item }}'
loop:
- cert-3.pem
- cert-3-chain.pem
- cert-3-fullchain.pem
register: slurp
- name: Check that certificate 1 retrieval got all chains
assert:
that:
@@ -58,9 +82,9 @@
- "'cert' in cert_3_obtain_results.all_chains[cert_3_alternate | int]"
- "'chain' in cert_3_obtain_results.all_chains[cert_3_alternate | int]"
- "'full_chain' in cert_3_obtain_results.all_chains[cert_3_alternate | int]"
- "lookup('file', output_dir ~ '/cert-3.pem', rstrip=False) == cert_3_obtain_results.all_chains[cert_3_alternate | int].cert"
- "lookup('file', output_dir ~ '/cert-3-chain.pem', rstrip=False) == cert_3_obtain_results.all_chains[cert_3_alternate | int].chain"
- "lookup('file', output_dir ~ '/cert-3-fullchain.pem', rstrip=False) == cert_3_obtain_results.all_chains[cert_3_alternate | int].full_chain"
- "(slurp.results[0].content | b64decode) == cert_3_obtain_results.all_chains[cert_3_alternate | int].cert"
- "(slurp.results[1].content | b64decode) == cert_3_obtain_results.all_chains[cert_3_alternate | int].chain"
- "(slurp.results[2].content | b64decode) == cert_3_obtain_results.all_chains[cert_3_alternate | int].full_chain"
- name: Check that certificate 4 is valid
assert:
@@ -100,14 +124,38 @@
that:
- cert_5_recreate_3 == True
- name: Check that certificate 6 is valid
assert:
that:
- cert_6_valid is not failed
- name: Check that certificate 6 contains correct SANs
assert:
that:
- "'DNS:example.org' in cert_6_text.stdout"
- block:
- name: Check that certificate 6 is valid
assert:
that:
- cert_6_valid is not failed
- name: Check that certificate 6 contains correct SANs
assert:
that:
- "'DNS:example.org' in cert_6_text.stdout"
when: acme_intermediates[0].subject_key_identifier is defined
- block:
- name: Check that certificate 7 is valid
assert:
that:
- cert_7_valid is not failed
- name: Check that certificate 7 contains correct SANs
assert:
that:
- "'IP Address:127.0.0.1' in cert_8_text.stdout or 'IP:127.0.0.1' in cert_8_text.stdout"
when: acme_roots[2].subject_key_identifier is defined
- block:
- name: Check that certificate 8 is valid
assert:
that:
- cert_8_valid is not failed
- name: Check that certificate 8 contains correct SANs
assert:
that:
- "'IP Address:127.0.0.1' in cert_8_text.stdout or 'IP:127.0.0.1' in cert_8_text.stdout"
when: cryptography_version.stdout is version('1.3', '>=')
- name: Validate that orders were not retrieved
assert:

View File

@@ -1,2 +1,14 @@
shippable/cloud/group1
cloud/acme
# Since skipping below fails miserably with ansible-core 2.11 and earlier, we have to skip all POSIX tests...
# (https://github.com/ansible/ansible/issues/75711)
# shippable/posix/group1
# Skip all VMs, since we cannot talk to the ACME simulator from these:
# (TODO: remove when ansible-core 2.12 is the earliest version we support)
# skip/aix
# skip/freebsd
# skip/macos
# skip/osx
# skip/rhel

View File

@@ -1,2 +1,3 @@
dependencies:
- setup_acme
- setup_remote_tmp_dir

View File

@@ -3,7 +3,7 @@
- block:
- name: Generate account keys
openssl_privatekey:
path: "{{ output_dir }}/{{ item.name }}.pem"
path: "{{ remote_tmp_dir }}/{{ item.name }}.pem"
type: "{{ item.type }}"
size: "{{ item.size | default(omit) }}"
curve: "{{ item.curve | default(omit) }}"
@@ -22,6 +22,10 @@
type: RSA
size: "{{ default_rsa_key_size }}"
## CREATE ACCOUNTS AND OBTAIN CERTIFICATES ####################################################
- name: Read account key (EC256)
slurp:
src: '{{ remote_tmp_dir }}/account-ec256.pem'
register: slurp_account_key
- name: Obtain cert 1
include_tasks: obtain-cert.yml
vars:
@@ -31,7 +35,7 @@
rsa_bits: "{{ default_rsa_key_size }}"
subject_alt_name: "DNS:example.com"
subject_alt_name_critical: no
account_key_content: "{{ lookup('file', output_dir ~ '/account-ec256.pem') }}"
account_key_content: "{{ slurp_account_key.content | b64decode }}"
challenge: http-01
modify_account: yes
deactivate_authzs: no
@@ -76,8 +80,8 @@
- name: Revoke certificate 1 via account key
acme_certificate_revoke:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/account-ec256.pem"
certificate: "{{ output_dir }}/cert-1.pem"
account_key_src: "{{ remote_tmp_dir }}/account-ec256.pem"
certificate: "{{ remote_tmp_dir }}/cert-1.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
@@ -86,19 +90,23 @@
- name: Revoke certificate 2 via certificate private key
acme_certificate_revoke:
select_crypto_backend: "{{ select_crypto_backend }}"
private_key_src: "{{ output_dir }}/cert-2.key"
private_key_src: "{{ remote_tmp_dir }}/cert-2.key"
private_key_passphrase: "{{ 'hunter2' if select_crypto_backend != 'openssl' else omit }}"
certificate: "{{ output_dir }}/cert-2.pem"
certificate: "{{ remote_tmp_dir }}/cert-2.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
ignore_errors: yes
register: cert_2_revoke
- name: Read account key (RSA)
slurp:
src: '{{ remote_tmp_dir }}/account-rsa.pem'
register: slurp_account_key
- name: Revoke certificate 3 via account key (fullchain)
acme_certificate_revoke:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_content: "{{ lookup('file', output_dir ~ '/account-rsa.pem') }}"
certificate: "{{ output_dir }}/cert-3-fullchain.pem"
account_key_content: "{{ slurp_account_key.content | b64decode }}"
certificate: "{{ remote_tmp_dir }}/cert-3-fullchain.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no

View File

@@ -17,12 +17,12 @@
- name: Remove output directory
file:
path: "{{ output_dir }}"
path: "{{ remote_tmp_dir }}"
state: absent
- name: Re-create output directory
file:
path: "{{ output_dir }}"
path: "{{ remote_tmp_dir }}"
state: directory
- block:

View File

@@ -1,2 +1,14 @@
shippable/cloud/group1
cloud/acme
# Since skipping below fails miserably with ansible-core 2.11 and earlier, we have to skip all POSIX tests...
# (https://github.com/ansible/ansible/issues/75711)
# shippable/posix/group1
# Skip all VMs, since we cannot talk to the ACME simulator from these:
# (TODO: remove when ansible-core 2.12 is the earliest version we support)
# skip/aix
# skip/freebsd
# skip/macos
# skip/osx
# skip/rhel

View File

@@ -1,2 +1,3 @@
dependencies:
- setup_acme
- setup_remote_tmp_dir

View File

@@ -7,7 +7,7 @@
- block:
- name: Generate ECC256 accoun keys
openssl_privatekey:
path: "{{ output_dir }}/account-ec256.pem"
path: "{{ remote_tmp_dir }}/account-ec256.pem"
type: ECC
curve: secp256r1
force: true
@@ -31,4 +31,4 @@
terms_agreed: yes
account_email: "example@example.org"
when: openssl_version.stdout is version('1.0.0', '>=') or cryptography_version.stdout is version('1.5', '>=')
when: cryptography_version.stdout is version('1.5', '>=')

View File

@@ -1,2 +1,14 @@
shippable/cloud/group1
cloud/acme
# Since skipping below fails miserably with ansible-core 2.11 and earlier, we have to skip all POSIX tests...
# (https://github.com/ansible/ansible/issues/75711)
# shippable/posix/group1
# Skip all VMs, since we cannot talk to the ACME simulator from these:
# (TODO: remove when ansible-core 2.12 is the earliest version we support)
# skip/aix
# skip/freebsd
# skip/macos
# skip/osx
# skip/rhel

View File

@@ -1,2 +1,4 @@
dependencies:
- setup_acme
- setup_remote_tmp_dir
- prepare_jinja2_compat

View File

@@ -2,7 +2,7 @@
- block:
- name: Generate account keys
openssl_privatekey:
path: "{{ output_dir }}/{{ item }}.pem"
path: "{{ remote_tmp_dir }}/{{ item }}.pem"
type: ECC
curve: secp256r1
force: true
@@ -10,7 +10,7 @@
- name: Parse account keys (to ease debugging some test failures)
openssl_privatekey_info:
path: "{{ output_dir }}/{{ item }}.pem"
path: "{{ remote_tmp_dir }}/{{ item }}.pem"
return_private_key_data: true
loop: "{{ account_keys }}"
@@ -32,7 +32,7 @@
acme_directory: https://{{ acme_host }}:14000/dir
acme_version: 2
validate_certs: no
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
url: "{{ directory.directory.newAccount}}"
method: post
content: '{"termsOfServiceAgreed":true}'
@@ -46,7 +46,7 @@
acme_directory: https://{{ acme_host }}:14000/dir
acme_version: 2
validate_certs: no
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
account_uri: "{{ account_creation.headers.location }}"
url: "{{ account_creation.headers.location }}"
method: get
@@ -58,7 +58,7 @@
acme_directory: https://{{ acme_host }}:14000/dir
acme_version: 2
validate_certs: no
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
account_uri: "{{ account_creation.headers.location }}"
url: "{{ account_creation.headers.location }}"
method: post
@@ -77,7 +77,7 @@
acme_directory: https://{{ acme_host }}:14000/dir
acme_version: 2
validate_certs: no
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
account_uri: "{{ account_creation.headers.location }}"
url: "{{ directory.directory.newOrder }}"
method: post
@@ -100,7 +100,7 @@
acme_directory: https://{{ acme_host }}:14000/dir
acme_version: 2
validate_certs: no
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
account_uri: "{{ account_creation.headers.location }}"
url: "{{ new_order.headers.location }}"
method: get
@@ -112,7 +112,7 @@
acme_directory: https://{{ acme_host }}:14000/dir
acme_version: 2
validate_certs: no
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
account_uri: "{{ account_creation.headers.location }}"
url: "{{ item }}"
method: get
@@ -125,7 +125,7 @@
acme_directory: https://{{ acme_host }}:14000/dir
acme_version: 2
validate_certs: no
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
account_uri: "{{ account_creation.headers.location }}"
url: "{{ (item.challenges | selectattr('type', 'equalto', 'http-01') | list)[0].url }}"
method: get
@@ -138,7 +138,7 @@
acme_directory: https://{{ acme_host }}:14000/dir
acme_version: 2
validate_certs: no
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
account_uri: "{{ account_creation.headers.location }}"
url: "{{ item.url }}"
method: post
@@ -152,7 +152,7 @@
acme_directory: https://{{ acme_host }}:14000/dir
acme_version: 2
validate_certs: no
account_key_src: "{{ output_dir }}/accountkey.pem"
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
account_uri: "{{ account_creation.headers.location }}"
url: "{{ item.url }}"
method: get

View File

@@ -17,12 +17,12 @@
- name: Remove output directory
file:
path: "{{ output_dir }}"
path: "{{ remote_tmp_dir }}"
state: absent
- name: Re-create output directory
file:
path: "{{ output_dir }}"
path: "{{ remote_tmp_dir }}"
state: directory
- block:

View File

@@ -1 +1,2 @@
shippable/cloud/group1
shippable/posix/group1

View File

@@ -1,2 +1,3 @@
dependencies:
- setup_openssl
- setup_remote_tmp_dir

View File

@@ -3,9 +3,6 @@
# and should not be used as examples of how to write Ansible roles #
####################################################################
- name: register cryptography version
command: '{{ ansible_python.executable }} -c ''import cryptography; print(cryptography.__version__)'''
register: cryptography_version
- block:
- name: Make sure testhost directory exists
file:
@@ -16,10 +13,9 @@
copy:
src: '{{ role_path }}/files/'
dest: '{{ remote_tmp_dir }}/files/'
remote_src: yes
- name: Find root for cert 1
certificate_complete_chain:
input_chain: '{{ lookup(''file'', ''cert1-fullchain.pem'', rstrip=False) }}'
input_chain: '{{ lookup("file", "cert1-fullchain.pem", rstrip=False) }}'
root_certificates:
- '{{ remote_tmp_dir }}/files/roots/'
register: cert1_root
@@ -30,7 +26,7 @@
- cert1_root.root == lookup('file', 'cert1-root.pem', rstrip=False)
- name: Find rootchain for cert 1
certificate_complete_chain:
input_chain: '{{ lookup(''file'', ''cert1.pem'', rstrip=False) }}'
input_chain: '{{ lookup("file", "cert1.pem", rstrip=False) }}'
intermediate_certificates:
- '{{ remote_tmp_dir }}/files/cert1-chain.pem'
root_certificates:
@@ -44,7 +40,7 @@
- cert1_rootchain.root == lookup('file', 'cert1-root.pem', rstrip=False)
- name: Find root for cert 2
certificate_complete_chain:
input_chain: '{{ lookup(''file'', ''cert2-fullchain.pem'', rstrip=False) }}'
input_chain: '{{ lookup("file", "cert2-fullchain.pem", rstrip=False) }}'
root_certificates:
- '{{ remote_tmp_dir }}/files/roots/'
register: cert2_root
@@ -55,7 +51,7 @@
- cert2_root.root == lookup('file', 'cert2-root.pem', rstrip=False)
- name: Find rootchain for cert 2
certificate_complete_chain:
input_chain: '{{ lookup(''file'', ''cert2.pem'', rstrip=False) }}'
input_chain: '{{ lookup("file", "cert2.pem", rstrip=False) }}'
intermediate_certificates:
- '{{ remote_tmp_dir }}/files/cert2-chain.pem'
root_certificates:
@@ -69,7 +65,7 @@
- cert2_rootchain.root == lookup('file', 'cert2-root.pem', rstrip=False)
- name: Find alternate rootchain for cert 2
certificate_complete_chain:
input_chain: '{{ lookup(''file'', ''cert2.pem'', rstrip=True) }}'
input_chain: '{{ lookup("file", "cert2.pem", rstrip=True) }}'
intermediate_certificates:
- '{{ remote_tmp_dir }}/files/cert2-altchain.pem'
root_certificates:

View File

@@ -1,3 +1,4 @@
shippable/cloud/group1
shippable/posix/group1
destructive
needs/httptester

View File

@@ -4,16 +4,35 @@
# and should not be used as examples of how to write Ansible roles #
####################################################################
- set_fact:
skip_tests: false
- block:
- name: Get servers certificate with backend auto-detection
get_certificate:
host: "{{ httpbin_host }}"
port: 443
ignore_errors: true
register: result
- set_fact:
skip_tests: |
{{
result is failed and (
'error: [Errno 1] _ssl.c:492: error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure' in result.msg
or
'error: _ssl.c:314: Invalid SSL protocol variant specified.' in result.msg
)
}}
- assert:
that:
- result is success or skip_tests
when: |
pyopenssl_version.stdout is version('0.15', '>=') or
(cryptography_version.stdout is version('1.6', '>=') and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6))
cryptography_version.stdout is version('1.6', '>=')
- block:
@@ -21,17 +40,7 @@
vars:
select_crypto_backend: pyopenssl
when: pyopenssl_version.stdout is version('0.15', '>=')
- name: Remove output directory
file:
path: "{{ output_dir }}"
state: absent
- name: Re-create output directory
file:
path: "{{ output_dir }}"
state: directory
when: pyopenssl_version.stdout is version('0.15', '>=') and not skip_tests
- block:
@@ -42,6 +51,4 @@
# The module doesn't work with CentOS 6. Since the pyOpenSSL installed there is too old,
# we never noticed before. This becomes a problem with the new cryptography backend,
# since there is a new enough cryptography version...
when: |
cryptography_version.stdout is version('1.6', '>=') and
(ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)
when: cryptography_version.stdout is version('1.6', '>=') and not skip_tests

View File

@@ -97,14 +97,19 @@
# We got the correct response from the module
- "'ca_cert file does not exist' == result.msg"
- name: Get a temp directory
tempfile:
state: directory
register: my_temp_dir
- name: Download CA Cert as pem from server
get_url:
url: "http://ansible.http.tests/cacert.pem"
dest: "{{ output_dir }}/temp.pem"
dest: "{{ my_temp_dir.path }}/temp.pem"
- name: Get servers certificate comparing it to its own ca_cert file
get_certificate:
ca_cert: '{{ output_dir }}/temp.pem'
ca_cert: '{{ my_temp_dir.path }}/temp.pem'
host: "{{ httpbin_host }}"
port: 443
select_crypto_backend: "{{ select_crypto_backend }}"
@@ -115,11 +120,6 @@
- result is not changed
- result is not failed
- name: Get a temp directory
tempfile:
state: directory
register: my_temp_dir
- name: Deploy the bogus_ca.pem file
copy:
src: "bogus_ca.pem"

View File

@@ -0,0 +1,2 @@
dependencies:
- setup_remote_tmp_dir

View File

@@ -4,18 +4,25 @@
# and should not be used as examples of how to write Ansible roles #
####################################################################
- name: Copy keyfiles
copy:
src: '{{ item }}'
dest: '{{ remote_tmp_dir }}/{{ item }}'
loop:
- keyfile1
- keyfile2
- name: Make sure cryptsetup is installed
package:
name: cryptsetup
state: present
become: yes
- name: Create cryptfile
command: dd if=/dev/zero of={{ output_dir.replace('~', ansible_env.HOME) }}/cryptfile bs=1M count=32
command: dd if=/dev/zero of={{ remote_tmp_dir.replace('~', ansible_env.HOME) }}/cryptfile bs=1M count=32
- name: Create lookback device
command: losetup -f {{ output_dir.replace('~', ansible_env.HOME) }}/cryptfile
command: losetup -f {{ remote_tmp_dir.replace('~', ansible_env.HOME) }}/cryptfile
become: yes
- name: Determine loop device name
command: losetup -j {{ output_dir.replace('~', ansible_env.HOME) }}/cryptfile --output name
command: losetup -j {{ remote_tmp_dir.replace('~', ansible_env.HOME) }}/cryptfile --output name
become: yes
register: cryptfile_device_output
- set_fact:
@@ -37,5 +44,5 @@
- command: losetup -d "{{ cryptfile_device }}"
become: yes
- file:
dest: "{{ output_dir }}/cryptfile"
dest: "{{ remote_tmp_dir }}/cryptfile"
state: absent

View File

@@ -3,7 +3,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: present
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
pbkdf:
iteration_time: 0.1
check_mode: yes
@@ -13,7 +13,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: present
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
pbkdf:
iteration_time: 0.1
become: yes
@@ -22,7 +22,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: present
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
pbkdf:
iteration_time: 0.1
become: yes
@@ -31,7 +31,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: present
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
pbkdf:
iteration_time: 0.1
check_mode: yes
@@ -48,7 +48,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
check_mode: yes
become: yes
register: open_check
@@ -56,21 +56,21 @@
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
become: yes
register: open
- name: Open (idempotent)
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
become: yes
register: open_idem
- name: Open (idempotent, check)
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
check_mode: yes
become: yes
register: open_idem_check
@@ -118,7 +118,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
become: yes
- name: Closed (via device, check)
@@ -158,7 +158,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
become: yes
- name: Absent (check)

View File

@@ -3,7 +3,7 @@
luks_device:
device: /dev/asdfasdfasdf
state: present
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
pbkdf:
iteration_time: 0.1
check_mode: yes
@@ -14,7 +14,7 @@
luks_device:
device: /dev/asdfasdfasdf
state: present
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
pbkdf:
iteration_time: 0.1
ignore_errors: yes
@@ -31,7 +31,7 @@
luks_device:
device: /tmp/
state: present
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
pbkdf:
iteration_time: 0.1
check_mode: yes
@@ -42,7 +42,7 @@
luks_device:
device: /tmp/
state: present
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
pbkdf:
iteration_time: 0.1
ignore_errors: yes

View File

@@ -3,7 +3,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: closed
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
pbkdf:
iteration_time: 0.1
become: yes
@@ -14,7 +14,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
become: yes
ignore_errors: yes
register: open_try
@@ -31,7 +31,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile2"
keyfile: "{{ remote_tmp_dir }}/keyfile2"
become: yes
ignore_errors: yes
register: open_try
@@ -43,8 +43,8 @@
luks_device:
device: "{{ cryptfile_device }}"
state: closed
keyfile: "{{ role_path }}/files/keyfile1"
new_keyfile: "{{ role_path }}/files/keyfile2"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
new_keyfile: "{{ remote_tmp_dir }}/keyfile2"
pbkdf:
iteration_time: 0.1
become: yes
@@ -54,8 +54,8 @@
luks_device:
device: "{{ cryptfile_device }}"
state: closed
keyfile: "{{ role_path }}/files/keyfile1"
new_keyfile: "{{ role_path }}/files/keyfile2"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
new_keyfile: "{{ remote_tmp_dir }}/keyfile2"
become: yes
register: result_2
@@ -70,7 +70,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile2"
keyfile: "{{ remote_tmp_dir }}/keyfile2"
become: yes
ignore_errors: yes
register: open_try
@@ -91,8 +91,8 @@
luks_device:
device: "{{ cryptfile_device }}"
state: closed
keyfile: "{{ role_path }}/files/keyfile1"
remove_keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
remove_keyfile: "{{ remote_tmp_dir }}/keyfile1"
become: yes
register: result_1
@@ -100,8 +100,8 @@
luks_device:
device: "{{ cryptfile_device }}"
state: closed
keyfile: "{{ role_path }}/files/keyfile1"
remove_keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
remove_keyfile: "{{ remote_tmp_dir }}/keyfile1"
become: yes
register: result_2
@@ -116,7 +116,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
become: yes
ignore_errors: yes
register: open_try
@@ -128,7 +128,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile2"
keyfile: "{{ remote_tmp_dir }}/keyfile2"
become: yes
ignore_errors: yes
register: open_try
@@ -149,8 +149,8 @@
luks_device:
device: "{{ cryptfile_device }}"
state: closed
keyfile: "{{ role_path }}/files/keyfile2"
remove_keyfile: "{{ role_path }}/files/keyfile2"
keyfile: "{{ remote_tmp_dir }}/keyfile2"
remove_keyfile: "{{ remote_tmp_dir }}/keyfile2"
become: yes
ignore_errors: yes
register: remove_last_key
@@ -165,7 +165,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile2"
keyfile: "{{ remote_tmp_dir }}/keyfile2"
become: yes
ignore_errors: yes
register: open_try
@@ -182,8 +182,8 @@
luks_device:
device: "{{ cryptfile_device }}"
state: closed
keyfile: "{{ role_path }}/files/keyfile2"
remove_keyfile: "{{ role_path }}/files/keyfile2"
keyfile: "{{ remote_tmp_dir }}/keyfile2"
remove_keyfile: "{{ remote_tmp_dir }}/keyfile2"
force_remove_last_key: yes
become: yes
@@ -193,7 +193,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile2"
keyfile: "{{ remote_tmp_dir }}/keyfile2"
become: yes
ignore_errors: yes
register: open_try

View File

@@ -3,7 +3,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: present
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
keysize: 256
pbkdf:
iteration_count: 1000
@@ -13,7 +13,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: present
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
keysize: 256
pbkdf:
iteration_count: 1000
@@ -23,7 +23,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: present
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
keysize: 512
pbkdf:
iteration_count: 1000
@@ -33,7 +33,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: present
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
passphrase: "{{ cryptfile_passphrase1 }}"
pbkdf:
iteration_count: 1000

View File

@@ -54,7 +54,7 @@
state: closed
passphrase: "{{ cryptfile_passphrase1 }}"
new_passphrase: "{{ cryptfile_passphrase2 }}"
new_keyfile: "{{ role_path }}/files/keyfile1"
new_keyfile: "{{ remote_tmp_dir }}/keyfile1"
pbkdf:
iteration_time: 0.1
become: yes
@@ -122,7 +122,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
become: yes
ignore_errors: yes
register: open_try
@@ -135,7 +135,7 @@
device: "{{ cryptfile_device }}"
state: closed
passphrase: "{{ cryptfile_passphrase1 }}"
new_keyfile: "{{ role_path }}/files/keyfile1"
new_keyfile: "{{ remote_tmp_dir }}/keyfile1"
pbkdf:
iteration_time: 0.1
become: yes
@@ -144,7 +144,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: closed
remove_keyfile: "{{ role_path }}/files/keyfile1"
remove_keyfile: "{{ remote_tmp_dir }}/keyfile1"
remove_passphrase: "{{ cryptfile_passphrase1 }}"
become: yes
ignore_errors: yes
@@ -157,7 +157,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
become: yes
ignore_errors: yes
register: open_try
@@ -219,7 +219,7 @@
luks_device:
device: "{{ cryptfile_device }}"
state: closed
keyfile: "{{ role_path }}/files/keyfile1"
keyfile: "{{ remote_tmp_dir }}/keyfile1"
new_passphrase: "{{ cryptfile_passphrase3 }}"
pbkdf:
iteration_time: 0.1

View File

@@ -1,3 +1,4 @@
dependencies:
- setup_ssh_keygen
- setup_ssh_agent
- setup_remote_tmp_dir

View File

@@ -5,9 +5,9 @@
- name: Declare global variables
set_fact:
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
certificate_path: '{{ output_dir }}/id_cert'
signing_key: '{{ remote_tmp_dir }}/id_key'
public_key: '{{ remote_tmp_dir }}/id_key.pub'
certificate_path: '{{ remote_tmp_dir }}/id_cert'
- name: Generate keypair
openssh_keypair:

View File

@@ -4,8 +4,8 @@
####################################################################
- set_fact:
new_signing_key: "{{ output_dir }}/new_key"
new_public_key: "{{ output_dir }}/new_key.pub"
new_signing_key: "{{ remote_tmp_dir }}/new_key"
new_public_key: "{{ remote_tmp_dir }}/new_key.pub"
- name: Generate new test key
openssh_keypair:
@@ -20,6 +20,81 @@
valid_from: always
valid_to: forever
- block:
- name: Generate cert with updated signature algorithm
openssh_cert:
type: user
path: "{{ certificate_path }}"
public_key: "{{ public_key }}"
signing_key: "{{ signing_key }}"
signature_algorithm: rsa-sha2-256
valid_from: always
valid_to: forever
register: updated_signature_algorithm
- name: Assert signature algorithm update causes change
assert:
that:
- updated_signature_algorithm is changed
- name: Generate cert with updated signature algorithm (idempotent)
openssh_cert:
type: user
path: "{{ certificate_path }}"
public_key: "{{ public_key }}"
signing_key: "{{ signing_key }}"
signature_algorithm: rsa-sha2-256
valid_from: always
valid_to: forever
register: updated_signature_algorithm_idempotent
- name: Assert signature algorithm update is idempotent
assert:
that:
- updated_signature_algorithm_idempotent is not changed
- name: Generate cert with original signature algorithm
openssh_cert:
type: user
path: "{{ certificate_path }}"
public_key: "{{ public_key }}"
signing_key: "{{ signing_key }}"
signature_algorithm: ssh-rsa
valid_from: always
valid_to: forever
register: second_signature_algorithm
- name: Assert second signature algorithm update causes change
assert:
that:
- second_signature_algorithm is changed
- name: Omit signature algorithm
openssh_cert:
type: user
path: "{{ certificate_path }}"
public_key: "{{ public_key }}"
signing_key: "{{ signing_key }}"
valid_from: always
valid_to: forever
register: omitted_signature_algorithm
- name: Assert omitted_signature_algorithm does not cause change
assert:
that:
- omitted_signature_algorithm is not changed
- name: Revert to original certificate
openssh_cert:
type: user
path: "{{ certificate_path }}"
public_key: "{{ public_key }}"
signing_key: "{{ signing_key }}"
valid_from: always
valid_to: forever
regenerate: always
when: openssh_version is version("7.3", ">=")
- name: Generate cert with new signing key
openssh_cert:
type: user

View File

@@ -12,7 +12,7 @@
type: user
signing_key: "{{ signing_key }}"
public_key: "{{ public_key }}"
path: '{{ output_dir }}/id_cert_with_agent'
path: '{{ remote_tmp_dir }}/id_cert_with_agent'
use_agent: true
valid_from: always
valid_to: forever
@@ -33,7 +33,7 @@
type: user
signing_key: "{{ signing_key }}"
public_key: "{{ public_key }}"
path: '{{ output_dir }}/id_cert_with_agent'
path: '{{ remote_tmp_dir }}/id_cert_with_agent'
use_agent: true
valid_from: always
valid_to: forever
@@ -44,7 +44,7 @@
type: user
signing_key: "{{ signing_key }}"
public_key: "{{ public_key }}"
path: '{{ output_dir }}/id_cert_with_agent'
path: '{{ remote_tmp_dir }}/id_cert_with_agent'
use_agent: true
valid_from: always
valid_to: forever
@@ -54,7 +54,7 @@
type: user
signing_key: "{{ signing_key }}"
public_key: "{{ public_key }}"
path: '{{ output_dir }}/id_cert_with_agent'
path: '{{ remote_tmp_dir }}/id_cert_with_agent'
use_agent: true
valid_from: always
valid_to: forever
@@ -71,7 +71,7 @@
type: user
signing_key: "{{ signing_key }}"
public_key: "{{ public_key }}"
path: '{{ output_dir }}/id_cert_with_agent'
path: '{{ remote_tmp_dir }}/id_cert_with_agent'
use_agent: true
valid_from: always
valid_to: forever
@@ -80,4 +80,4 @@
- name: Remove certificate
openssh_cert:
state: absent
path: '{{ output_dir }}/id_cert_with_agent'
path: '{{ remote_tmp_dir }}/id_cert_with_agent'

View File

@@ -1,4 +1,5 @@
dependencies:
- setup_ssh_keygen
- setup_openssl
- setup_bcrypt
- setup_bcrypt
- setup_remote_tmp_dir

View File

@@ -6,7 +6,7 @@
- name: Backend auto-detection test
openssh_keypair:
path: '{{ output_dir }}/auto_backend_key'
path: '{{ remote_tmp_dir }}/auto_backend_key'
state: "{{ item }}"
loop: ['present', 'absent']

View File

@@ -6,7 +6,7 @@
- name: "({{ backend }}) Generate key (check mode)"
openssh_keypair:
path: "{{ output_dir }}/core"
path: "{{ remote_tmp_dir }}/core"
size: 2048
backend: "{{ backend }}"
register: check_core_output
@@ -14,14 +14,14 @@
- name: "({{ backend }}) Generate key"
openssh_keypair:
path: "{{ output_dir }}/core"
path: "{{ remote_tmp_dir }}/core"
size: 2048
backend: "{{ backend }}"
register: core_output
- name: "({{ backend }}) Generate key (check mode idempotent)"
openssh_keypair:
path: "{{ output_dir }}/core"
path: "{{ remote_tmp_dir }}/core"
size: 2048
backend: "{{ backend }}"
register: idempotency_check_core_output
@@ -29,7 +29,7 @@
- name: "({{ backend }}) Generate key (idempotent)"
openssh_keypair:
path: '{{ output_dir }}/core'
path: '{{ remote_tmp_dir }}/core'
size: 2048
backend: "{{ backend }}"
register: idempotency_core_output
@@ -52,8 +52,8 @@
that:
- core_output['fingerprint'] is string
- core_output['fingerprint'].startswith('SHA256:')
# only distro old enough that it still gives md5 with no prefix
when: not (ansible_distribution == 'CentOS' and ansible_distribution_major_version == '6')
# SHA256 was made the default hashing algorithm for fingerprints in OpenSSH 6.8
when: not (backend == 'opensshbin' and openssh_version is version('6.8', '<'))
- name: "({{ backend }}) Assert key returns public_key"
assert:
@@ -74,7 +74,7 @@
- core_output['type'] == 'rsa'
- name: "({{ backend }}) Retrieve key size from 'ssh-keygen'"
shell: "ssh-keygen -lf {{ output_dir }}/core | grep -o -E '^[0-9]+'"
shell: "ssh-keygen -lf {{ remote_tmp_dir }}/core | grep -o -E '^[0-9]+'"
register: core_size_ssh_keygen
- name: "({{ backend }}) Assert key size matches 'ssh-keygen' output"
@@ -82,13 +82,18 @@
that:
- core_size_ssh_keygen.stdout == '2048'
- name: "({{ backend }}) Read core.pub"
slurp:
src: '{{ remote_tmp_dir }}/core.pub'
register: slurp
- name: "({{ backend }}) Assert public key module return equal to the public key content"
assert:
that:
- "core_output.public_key == lookup('file', output_dir ~ '/core.pub').strip('\n')"
- "core_output.public_key == (slurp.content | b64decode).strip('\n ')"
- name: "({{ backend }}) Remove key"
openssh_keypair:
path: '{{ output_dir }}/core'
path: '{{ remote_tmp_dir }}/core'
backend: "{{ backend }}"
state: absent

View File

@@ -1,10 +1,10 @@
---
- name: Generate a password protected key
command: 'ssh-keygen -f {{ output_dir }}/password_protected -N {{ passphrase }}'
command: 'ssh-keygen -f {{ remote_tmp_dir }}/password_protected -N {{ passphrase }}'
- name: Modify the password protected key with passphrase
openssh_keypair:
path: '{{ output_dir }}/password_protected'
path: '{{ remote_tmp_dir }}/password_protected'
size: 1024
passphrase: "{{ passphrase }}"
backend: cryptography
@@ -12,14 +12,14 @@
- name: Check password protected key idempotency
openssh_keypair:
path: '{{ output_dir }}/password_protected'
path: '{{ remote_tmp_dir }}/password_protected'
size: 1024
passphrase: "{{ passphrase }}"
backend: cryptography
register: password_protected_idempotency_output
- name: Ensure that ssh-keygen can read keys generated with passphrase
command: 'ssh-keygen -yf {{ output_dir }}/password_protected -P {{ passphrase }}'
command: 'ssh-keygen -yf {{ remote_tmp_dir }}/password_protected -P {{ passphrase }}'
register: password_protected_ssh_keygen_output
- name: Check that password protected key with passphrase was regenerated
@@ -31,18 +31,18 @@
- name: Remove password protected key
openssh_keypair:
path: '{{ output_dir }}/password_protected'
path: '{{ remote_tmp_dir }}/password_protected'
backend: cryptography
state: absent
- name: Generate an unprotected key
openssh_keypair:
path: '{{ output_dir }}/unprotected'
path: '{{ remote_tmp_dir }}/unprotected'
backend: cryptography
- name: Modify unprotected key with passphrase
openssh_keypair:
path: '{{ output_dir }}/unprotected'
path: '{{ remote_tmp_dir }}/unprotected'
size: 2048
passphrase: "{{ passphrase }}"
backend: cryptography
@@ -51,7 +51,7 @@
- name: Modify unprotected key with passphrase (force)
openssh_keypair:
path: '{{ output_dir }}/unprotected'
path: '{{ remote_tmp_dir }}/unprotected'
size: 2048
passphrase: "{{ passphrase }}"
force: true
@@ -66,16 +66,16 @@
- name: Remove unprotected key
openssh_keypair:
path: '{{ output_dir }}/unprotected'
path: '{{ remote_tmp_dir }}/unprotected'
backend: cryptography
state: absent
- name: Generate PEM encoded key with passphrase
command: 'ssh-keygen -b 4096 -f {{ output_dir }}/pem_encoded -N {{ passphrase }} -m PEM'
command: 'ssh-keygen -b 4096 -f {{ remote_tmp_dir }}/pem_encoded -N {{ passphrase }} -m PEM'
- name: Try to verify a PEM encoded key
openssh_keypair:
path: '{{ output_dir }}/pem_encoded'
path: '{{ remote_tmp_dir }}/pem_encoded'
passphrase: "{{ passphrase }}"
backend: cryptography
register: pem_encoded_output
@@ -87,6 +87,6 @@
- name: Remove PEM encoded key
openssh_keypair:
path: '{{ output_dir }}/pem_encoded'
path: '{{ remote_tmp_dir }}/pem_encoded'
backend: cryptography
state: absent

View File

@@ -10,12 +10,12 @@
content: ''
mode: '0700'
loop:
- "{{ output_dir }}/broken"
- "{{ output_dir }}/broken.pub"
- "{{ remote_tmp_dir }}/broken"
- "{{ remote_tmp_dir }}/broken.pub"
- name: "({{ backend }}) Regenerate key - broken"
openssh_keypair:
path: "{{ output_dir }}/broken"
path: "{{ remote_tmp_dir }}/broken"
backend: "{{ backend }}"
register: broken_output
ignore_errors: true
@@ -28,7 +28,7 @@
- name: "({{ backend }}) Regenerate key with force - broken"
openssh_keypair:
path: "{{ output_dir }}/broken"
path: "{{ remote_tmp_dir }}/broken"
backend: "{{ backend }}"
force: true
register: force_broken_output
@@ -40,24 +40,24 @@
- name: "({{ backend }}) Remove key - broken"
openssh_keypair:
path: "{{ output_dir }}/broken"
path: "{{ remote_tmp_dir }}/broken"
backend: "{{ backend }}"
state: absent
- name: "({{ backend }}) Generate key - write-only"
openssh_keypair:
path: "{{ output_dir }}/write-only"
path: "{{ remote_tmp_dir }}/write-only"
mode: "0200"
backend: "{{ backend }}"
- name: "({{ backend }}) Check private key status - write-only"
stat:
path: '{{ output_dir }}/write-only'
path: '{{ remote_tmp_dir }}/write-only'
register: write_only_private_key
- name: "({{ backend }}) Check public key status - write-only"
stat:
path: '{{ output_dir }}/write-only.pub'
path: '{{ remote_tmp_dir }}/write-only.pub'
register: write_only_public_key
- name: "({{ backend }}) Assert that private and public keys match permissions - write-only"
@@ -68,14 +68,14 @@
- name: "({{ backend }}) Regenerate key with force - write-only"
openssh_keypair:
path: "{{ output_dir }}/write-only"
path: "{{ remote_tmp_dir }}/write-only"
backend: "{{ backend }}"
force: true
register: write_only_output
- name: "({{ backend }}) Check private key status after regeneration - write-only"
stat:
path: '{{ output_dir }}/write-only'
path: '{{ remote_tmp_dir }}/write-only'
register: write_only_private_key_after
- name: "({{ backend }}) Assert key is regenerated - write-only"
@@ -87,26 +87,19 @@
assert:
that:
- write_only_private_key_after.stat.mode == '0200'
when: backend == 'opensshbin'
- name: "({{ backend }}) Assert key permissions are not preserved with 'cryptography'"
assert:
that:
- write_only_private_key_after.stat.mode == '0600'
when: backend == 'cryptography'
- name: "({{ backend }}) Remove key - write-only"
openssh_keypair:
path: "{{ output_dir }}/write-only"
path: "{{ remote_tmp_dir }}/write-only"
backend: "{{ backend }}"
state: absent
- name: "({{ backend }}) Generate key with ssh-keygen - password_protected"
command: "ssh-keygen -f {{ output_dir }}/password_protected -N {{ passphrase }}"
command: "ssh-keygen -f {{ remote_tmp_dir }}/password_protected -N {{ passphrase }}"
- name: "({{ backend }}) Modify key - password_protected"
openssh_keypair:
path: "{{ output_dir }}/password_protected"
path: "{{ remote_tmp_dir }}/password_protected"
size: 2048
backend: "{{ backend }}"
register: password_protected_output
@@ -120,7 +113,7 @@
- name: "({{ backend }}) Modify key with 'force=true' - password_protected"
openssh_keypair:
path: "{{ output_dir }}/password_protected"
path: "{{ remote_tmp_dir }}/password_protected"
size: 2048
backend: "{{ backend }}"
force: true
@@ -133,6 +126,6 @@
- name: "({{ backend }}) Remove key - password_protected"
openssh_keypair:
path: "{{ output_dir }}/password_protected"
path: "{{ remote_tmp_dir }}/password_protected"
backend: "{{ backend }}"
state: absent

View File

@@ -12,13 +12,13 @@
- name: "({{ backend }}) Generate keys with default size - size"
openssh_keypair:
path: "{{ output_dir }}/default_size_{{ item }}"
path: "{{ remote_tmp_dir }}/default_size_{{ item }}"
type: "{{ item }}"
backend: "{{ backend }}"
loop: "{{ key_types }}"
- name: "({{ backend }}) Retrieve key size from 'ssh-keygen' - size"
shell: "ssh-keygen -lf {{ output_dir }}/default_size_{{ item }} | grep -o -E '^[0-9]+'"
shell: "ssh-keygen -lf {{ remote_tmp_dir }}/default_size_{{ item }} | grep -o -E '^[0-9]+'"
loop: "{{ key_types }}"
register: key_size_output
@@ -31,19 +31,19 @@
- name: "({{ backend }}) Remove keys - size"
openssh_keypair:
path: "{{ output_dir }}/default_size_{{ item }}"
path: "{{ remote_tmp_dir }}/default_size_{{ item }}"
state: absent
loop: "{{ key_types }}"
- block:
- name: "({{ backend }}) Generate ed25519 key with default size - size"
openssh_keypair:
path: "{{ output_dir }}/default_size_ed25519"
path: "{{ remote_tmp_dir }}/default_size_ed25519"
type: ed25519
backend: "{{ backend }}"
- name: "({{ backend }}) Retrieve ed25519 key size from 'ssh-keygen' - size"
shell: "ssh-keygen -lf {{ output_dir }}/default_size_ed25519 | grep -o -E '^[0-9]+'"
shell: "ssh-keygen -lf {{ remote_tmp_dir }}/default_size_ed25519 | grep -o -E '^[0-9]+'"
register: ed25519_key_size_output
- name: "({{ backend }}) Assert ed25519 key size matches default size - size"
@@ -53,19 +53,20 @@
- name: "({{ backend }}) Remove ed25519 key - size"
openssh_keypair:
path: "{{ output_dir }}/default_size_ed25519"
path: "{{ remote_tmp_dir }}/default_size_ed25519"
state: absent
when: not (ansible_distribution == 'CentOS' and ansible_distribution_major_version == '6')
# Support for ed25519 keys was added in OpenSSH 6.5
when: not (backend == 'opensshbin' and openssh_version is version('6.5', '<'))
- name: "({{ backend }}) Generate key - force"
openssh_keypair:
path: "{{ output_dir }}/force"
path: "{{ remote_tmp_dir }}/force"
type: rsa
backend: "{{ backend }}"
- name: "({{ backend }}) Regenerate key - force"
openssh_keypair:
path: "{{ output_dir }}/force"
path: "{{ remote_tmp_dir }}/force"
type: rsa
force: true
backend: "{{ backend }}"
@@ -78,33 +79,39 @@
- name: "({{ backend }}) Remove key - force"
openssh_keypair:
path: "{{ output_dir }}/force"
path: "{{ remote_tmp_dir }}/force"
state: absent
backend: "{{ backend }}"
- name: "({{ backend }}) Generate key - comment"
openssh_keypair:
path: "{{ output_dir }}/comment"
path: "{{ remote_tmp_dir }}/comment"
comment: "test@comment"
backend: "{{ backend }}"
register: comment_output
- name: "({{ backend }}) Modify comment - comment"
openssh_keypair:
path: "{{ output_dir }}/comment"
path: "{{ remote_tmp_dir }}/comment"
comment: "test_modified@comment"
backend: "{{ backend }}"
register: modified_comment_output
- name: "({{ backend }}) Assert only comment changed - comment"
- name: "({{ backend }}) Assert comment preserved public key - comment"
assert:
that:
- comment_output.public_key == modified_comment_output.public_key
- comment_output.comment == 'test@comment'
- name: "({{ backend }}) Assert comment changed - comment"
assert:
that:
- modified_comment_output.comment == 'test_modified@comment'
# Support for updating comments for key types other than rsa1 was added in OpenSSH 7.2
when: not (backend == 'opensshbin' and openssh_version is version('7.2', '<'))
- name: "({{ backend }}) Remove key - comment"
openssh_keypair:
path: "{{ output_dir }}/comment"
path: "{{ remote_tmp_dir }}/comment"
state: absent
backend: "{{ backend }}"

View File

@@ -5,27 +5,33 @@
####################################################################
# Ensures no conflicts from previous test runs
- name: "({{ backend }}) Find old test artifacts"
ansible.builtin.find:
paths: "{{ remote_tmp_dir }}"
patterns:
- "regenerate*"
register: old_test_artifacts
- name: "({{ backend }}) Cleanup Output Directory"
ansible.builtin.file:
path: "{{ item }}"
path: "{{ item.path }}"
state: absent
with_fileglob:
- "{{ output_dir }}/regenerate*"
loop: "{{ old_test_artifacts.files }}"
- name: "({{ backend }}) Regenerate - setup simple keys"
openssh_keypair:
path: '{{ output_dir }}/regenerate-a-{{ item }}'
path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}'
type: rsa
size: 1024
backend: "{{ backend }}"
loop: "{{ regenerate_values }}"
- name: "({{ backend }}) Regenerate - setup password protected keys"
command: 'ssh-keygen -f {{ output_dir }}/regenerate-b-{{ item }} -N {{ passphrase }}'
command: 'ssh-keygen -f {{ remote_tmp_dir }}/regenerate-b-{{ item }} -N {{ passphrase }}'
loop: "{{ regenerate_values }}"
- name: "({{ backend }}) Regenerate - setup broken keys"
copy:
dest: '{{ output_dir }}/regenerate-c-{{ item.0 }}{{ item.1 }}'
dest: '{{ remote_tmp_dir }}/regenerate-c-{{ item.0 }}{{ item.1 }}'
content: 'broken key'
mode: '0700'
with_nested:
@@ -33,12 +39,12 @@
- [ '', '.pub' ]
- name: "({{ backend }}) Regenerate - setup password protected keys for passphrse test"
command: 'ssh-keygen -f {{ output_dir }}/regenerate-d-{{ item }} -N {{ passphrase }}'
command: 'ssh-keygen -f {{ remote_tmp_dir }}/regenerate-d-{{ item }} -N {{ passphrase }}'
loop: "{{ regenerate_values }}"
- name: "({{ backend }}) Regenerate - modify broken keys (check mode)"
openssh_keypair:
path: '{{ output_dir }}/regenerate-c-{{ item }}'
path: '{{ remote_tmp_dir }}/regenerate-c-{{ item }}'
type: rsa
size: 1024
regenerate: '{{ item }}'
@@ -60,7 +66,7 @@
- name: "({{ backend }}) Regenerate - modify broken keys"
openssh_keypair:
path: '{{ output_dir }}/regenerate-c-{{ item }}'
path: '{{ remote_tmp_dir }}/regenerate-c-{{ item }}'
type: rsa
size: 1024
regenerate: '{{ item }}'
@@ -81,7 +87,7 @@
- name: "({{ backend }}) Regenerate - modify password protected keys (check mode)"
openssh_keypair:
path: '{{ output_dir }}/regenerate-b-{{ item }}'
path: '{{ remote_tmp_dir }}/regenerate-b-{{ item }}'
type: rsa
size: 1024
regenerate: '{{ item }}'
@@ -103,7 +109,7 @@
- name: "({{ backend }}) Regenerate - modify password protected keys with passphrase (check mode)"
openssh_keypair:
path: '{{ output_dir }}/regenerate-b-{{ item }}'
path: '{{ remote_tmp_dir }}/regenerate-b-{{ item }}'
type: rsa
size: 1024
passphrase: "{{ passphrase }}"
@@ -127,7 +133,7 @@
- name: "({{ backend }}) Regenerate - modify password protected keys"
openssh_keypair:
path: '{{ output_dir }}/regenerate-b-{{ item }}'
path: '{{ remote_tmp_dir }}/regenerate-b-{{ item }}'
type: rsa
size: 1024
regenerate: '{{ item }}'
@@ -148,7 +154,7 @@
- name: "({{ backend }}) Regenerate - modify password protected keys with passphrase"
openssh_keypair:
path: '{{ output_dir }}/regenerate-d-{{ item }}'
path: '{{ remote_tmp_dir }}/regenerate-d-{{ item }}'
type: rsa
size: 1024
passphrase: "{{ passphrase }}"
@@ -171,7 +177,7 @@
- name: "({{ backend }}) Regenerate - not modify regular keys (check mode)"
openssh_keypair:
path: '{{ output_dir }}/regenerate-a-{{ item }}'
path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}'
type: rsa
size: 1024
regenerate: '{{ item }}'
@@ -189,7 +195,7 @@
- name: "({{ backend }}) Regenerate - not modify regular keys"
openssh_keypair:
path: '{{ output_dir }}/regenerate-a-{{ item }}'
path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}'
type: rsa
size: 1024
regenerate: '{{ item }}'
@@ -206,7 +212,7 @@
- name: "({{ backend }}) Regenerate - adjust key size (check mode)"
openssh_keypair:
path: '{{ output_dir }}/regenerate-a-{{ item }}'
path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}'
type: rsa
size: 1048
regenerate: '{{ item }}'
@@ -226,7 +232,7 @@
- name: "({{ backend }}) Regenerate - adjust key size"
openssh_keypair:
path: '{{ output_dir }}/regenerate-a-{{ item }}'
path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}'
type: rsa
size: 1048
regenerate: '{{ item }}'
@@ -245,8 +251,8 @@
- name: "({{ backend }}) Regenerate - redistribute keys"
copy:
src: '{{ output_dir }}/regenerate-a-always{{ item.1 }}'
dest: '{{ output_dir }}/regenerate-a-{{ item.0 }}{{ item.1 }}'
src: '{{ remote_tmp_dir }}/regenerate-a-always{{ item.1 }}'
dest: '{{ remote_tmp_dir }}/regenerate-a-{{ item.0 }}{{ item.1 }}'
remote_src: true
with_nested:
- "{{ regenerate_values }}"
@@ -255,7 +261,7 @@
- name: "({{ backend }}) Regenerate - adjust key type (check mode)"
openssh_keypair:
path: '{{ output_dir }}/regenerate-a-{{ item }}'
path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}'
type: dsa
size: 1024
regenerate: '{{ item }}'
@@ -275,7 +281,7 @@
- name: "({{ backend }}) Regenerate - adjust key type"
openssh_keypair:
path: '{{ output_dir }}/regenerate-a-{{ item }}'
path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}'
type: dsa
size: 1024
regenerate: '{{ item }}'
@@ -294,8 +300,8 @@
- name: "({{ backend }}) Regenerate - redistribute keys"
copy:
src: '{{ output_dir }}/regenerate-a-always{{ item.1 }}'
dest: '{{ output_dir }}/regenerate-a-{{ item.0 }}{{ item.1 }}'
src: '{{ remote_tmp_dir }}/regenerate-a-always{{ item.1 }}'
dest: '{{ remote_tmp_dir }}/regenerate-a-{{ item.0 }}{{ item.1 }}'
remote_src: true
with_nested:
- "{{ regenerate_values }}"
@@ -304,7 +310,7 @@
- name: "({{ backend }}) Regenerate - adjust comment (check mode)"
openssh_keypair:
path: '{{ output_dir }}/regenerate-a-{{ item }}'
path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}'
type: dsa
size: 1024
comment: test comment
@@ -320,7 +326,7 @@
- name: "({{ backend }}) Regenerate - adjust comment"
openssh_keypair:
path: '{{ output_dir }}/regenerate-a-{{ item }}'
path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}'
type: dsa
size: 1024
comment: test comment

View File

@@ -6,36 +6,36 @@
- name: "({{ backend }}) Generate key"
openssh_keypair:
path: '{{ output_dir }}/removed'
path: '{{ remote_tmp_dir }}/removed'
backend: "{{ backend }}"
state: present
- name: "({{ backend }}) Generate key (idempotency)"
openssh_keypair:
path: '{{ output_dir }}/removed'
path: '{{ remote_tmp_dir }}/removed'
backend: "{{ backend }}"
state: present
- name: "({{ backend }}) Remove key"
openssh_keypair:
state: absent
path: '{{ output_dir }}/removed'
path: '{{ remote_tmp_dir }}/removed'
backend: "{{ backend }}"
- name: "({{ backend }}) Remove key (idempotency)"
openssh_keypair:
state: absent
path: '{{ output_dir }}/removed'
path: '{{ remote_tmp_dir }}/removed'
backend: "{{ backend }}"
- name: "({{ backend }}) Check private key status"
stat:
path: '{{ output_dir }}/removed'
path: '{{ remote_tmp_dir }}/removed'
register: removed_private_key
- name: "({{ backend }}) Check public key status"
stat:
path: '{{ output_dir }}/removed.pub'
path: '{{ remote_tmp_dir }}/removed.pub'
register: removed_public_key
- name: "({{ backend }}) Assert key pair files are removed"

View File

@@ -1,2 +1,3 @@
shippable/cloud/group1
shippable/posix/group1
destructive

View File

@@ -1,3 +1,4 @@
dependencies:
- setup_openssl
- setup_pyopenssl
- setup_remote_tmp_dir

View File

@@ -1,13 +1,13 @@
---
- name: "({{ select_crypto_backend }}) Generate privatekey"
openssl_privatekey:
path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/privatekey.pem'
size: '{{ default_rsa_key_size }}'
- name: "({{ select_crypto_backend }}) Generate CSR (check mode)"
openssl_csr:
path: '{{ output_dir }}/csr.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -17,8 +17,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR"
openssl_csr:
path: '{{ output_dir }}/csr.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -27,8 +27,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR (idempotent)"
openssl_csr:
path: '{{ output_dir }}/csr.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -37,8 +37,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR (idempotent, check mode)"
openssl_csr:
path: '{{ output_dir }}/csr.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -48,8 +48,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR without SAN (check mode)"
openssl_csr:
path: '{{ output_dir }}/csr-nosan.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr-nosan.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
useCommonNameForSAN: no
@@ -59,8 +59,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR without SAN"
openssl_csr:
path: '{{ output_dir }}/csr-nosan.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr-nosan.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
useCommonNameForSAN: no
@@ -69,8 +69,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR without SAN (idempotent)"
openssl_csr:
path: '{{ output_dir }}/csr-nosan.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr-nosan.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
useCommonNameForSAN: no
@@ -79,8 +79,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR without SAN (idempotent, check mode)"
openssl_csr:
path: '{{ output_dir }}/csr-nosan.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr-nosan.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
useCommonNameForSAN: no
@@ -94,8 +94,8 @@
# and vice-versa for biometricInfo
- name: "({{ select_crypto_backend }}) Generate CSR with KU and XKU"
openssl_csr:
path: '{{ output_dir }}/csr_ku_xku.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_ku_xku.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
CN: www.ansible.com
keyUsage:
@@ -110,8 +110,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR with KU and XKU (test idempotency)"
openssl_csr:
path: '{{ output_dir }}/csr_ku_xku.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_ku_xku.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: 'www.ansible.com'
keyUsage:
@@ -127,8 +127,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR with KU and XKU (test XKU change)"
openssl_csr:
path: '{{ output_dir }}/csr_ku_xku.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_ku_xku.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: 'www.ansible.com'
keyUsage:
@@ -143,8 +143,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR with KU and XKU (test KU change)"
openssl_csr:
path: '{{ output_dir }}/csr_ku_xku.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_ku_xku.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: 'www.ansible.com'
keyUsage:
@@ -158,15 +158,15 @@
- name: "({{ select_crypto_backend }}) Generate CSR with old API"
openssl_csr:
path: '{{ output_dir }}/csr_oldapi.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_oldapi.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
commonName: www.ansible.com
select_crypto_backend: '{{ select_crypto_backend }}'
- name: "({{ select_crypto_backend }}) Generate CSR with invalid SAN (1/2)"
openssl_csr:
path: '{{ output_dir }}/csrinvsan.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csrinvsan.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject_alt_name: invalid-san.example.com
select_crypto_backend: '{{ select_crypto_backend }}'
register: generate_csr_invalid_san
@@ -174,8 +174,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR with invalid SAN (2/2)"
openssl_csr:
path: '{{ output_dir }}/csrinvsan2.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csrinvsan2.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject_alt_name: "DNS:system:kube-controller-manager"
select_crypto_backend: '{{ select_crypto_backend }}'
register: generate_csr_invalid_san_2
@@ -183,16 +183,16 @@
- name: "({{ select_crypto_backend }}) Generate CSR with OCSP Must Staple"
openssl_csr:
path: '{{ output_dir }}/csr_ocsp.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_ocsp.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject_alt_name: "DNS:www.ansible.com"
ocsp_must_staple: true
select_crypto_backend: '{{ select_crypto_backend }}'
- name: "({{ select_crypto_backend }}) Generate CSR with OCSP Must Staple (test idempotency)"
openssl_csr:
path: '{{ output_dir }}/csr_ocsp.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_ocsp.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject_alt_name: "DNS:www.ansible.com"
ocsp_must_staple: true
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -200,22 +200,22 @@
- name: "({{ select_crypto_backend }}) Generate ECC privatekey"
openssl_privatekey:
path: '{{ output_dir }}/privatekey2.pem'
path: '{{ remote_tmp_dir }}/privatekey2.pem'
type: ECC
curve: secp384r1
- name: "({{ select_crypto_backend }}) Generate CSR with ECC privatekey"
openssl_csr:
path: '{{ output_dir }}/csr2.csr'
privatekey_path: '{{ output_dir }}/privatekey2.pem'
path: '{{ remote_tmp_dir }}/csr2.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey2.pem'
subject:
commonName: www.ansible.com
select_crypto_backend: '{{ select_crypto_backend }}'
- name: "({{ select_crypto_backend }}) Generate CSR with text common name"
openssl_csr:
path: '{{ output_dir }}/csr3.csr'
privatekey_path: '{{ output_dir }}/privatekey2.pem'
path: '{{ remote_tmp_dir }}/csr3.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey2.pem'
subject:
commonName: This is for Ansible
useCommonNameForSAN: no
@@ -223,24 +223,24 @@
- name: "({{ select_crypto_backend }}) Generate CSR with country name"
openssl_csr:
path: '{{ output_dir }}/csr4.csr'
privatekey_path: '{{ output_dir }}/privatekey2.pem'
path: '{{ remote_tmp_dir }}/csr4.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey2.pem'
country_name: de
select_crypto_backend: '{{ select_crypto_backend }}'
register: country_idempotent_1
- name: "({{ select_crypto_backend }}) Generate CSR with country name (idempotent)"
openssl_csr:
path: '{{ output_dir }}/csr4.csr'
privatekey_path: '{{ output_dir }}/privatekey2.pem'
path: '{{ remote_tmp_dir }}/csr4.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey2.pem'
country_name: de
select_crypto_backend: '{{ select_crypto_backend }}'
register: country_idempotent_2
- name: "({{ select_crypto_backend }}) Generate CSR with country name (idempotent 2)"
openssl_csr:
path: '{{ output_dir }}/csr4.csr'
privatekey_path: '{{ output_dir }}/privatekey2.pem'
path: '{{ remote_tmp_dir }}/csr4.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey2.pem'
subject:
C: de
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -248,8 +248,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR with country name (bad country name)"
openssl_csr:
path: '{{ output_dir }}/csr4.csr'
privatekey_path: '{{ output_dir }}/privatekey2.pem'
path: '{{ remote_tmp_dir }}/csr4.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey2.pem'
subject:
C: dex
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -258,7 +258,7 @@
- name: "({{ select_crypto_backend }}) Generate privatekey with password"
openssl_privatekey:
path: '{{ output_dir }}/privatekeypw.pem'
path: '{{ remote_tmp_dir }}/privatekeypw.pem'
passphrase: hunter2
cipher: auto
select_crypto_backend: cryptography
@@ -266,16 +266,16 @@
- name: "({{ select_crypto_backend }}) Generate CSR with privatekey passphrase"
openssl_csr:
path: '{{ output_dir }}/csr_pw.csr'
privatekey_path: '{{ output_dir }}/privatekeypw.pem'
path: '{{ remote_tmp_dir }}/csr_pw.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekeypw.pem'
privatekey_passphrase: hunter2
select_crypto_backend: '{{ select_crypto_backend }}'
register: passphrase_1
- name: "({{ select_crypto_backend }}) Generate CSR (failed passphrase 1)"
openssl_csr:
path: '{{ output_dir }}/csr_pw1.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_pw1.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
privatekey_passphrase: hunter2
select_crypto_backend: '{{ select_crypto_backend }}'
ignore_errors: yes
@@ -283,8 +283,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR (failed passphrase 2)"
openssl_csr:
path: '{{ output_dir }}/csr_pw2.csr'
privatekey_path: '{{ output_dir }}/privatekeypw.pem'
path: '{{ remote_tmp_dir }}/csr_pw2.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekeypw.pem'
privatekey_passphrase: wrong_password
select_crypto_backend: '{{ select_crypto_backend }}'
ignore_errors: yes
@@ -292,20 +292,20 @@
- name: "({{ select_crypto_backend }}) Generate CSR (failed passphrase 3)"
openssl_csr:
path: '{{ output_dir }}/csr_pw3.csr'
privatekey_path: '{{ output_dir }}/privatekeypw.pem'
path: '{{ remote_tmp_dir }}/csr_pw3.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekeypw.pem'
select_crypto_backend: '{{ select_crypto_backend }}'
ignore_errors: yes
register: passphrase_error_3
- name: "({{ select_crypto_backend }}) Create broken CSR"
copy:
dest: "{{ output_dir }}/csrbroken.csr"
dest: "{{ remote_tmp_dir }}/csrbroken.csr"
content: "broken"
- name: "({{ select_crypto_backend }}) Regenerate broken CSR"
openssl_csr:
path: '{{ output_dir }}/csrbroken.csr'
privatekey_path: '{{ output_dir }}/privatekey2.pem'
path: '{{ remote_tmp_dir }}/csrbroken.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey2.pem'
subject:
commonName: This is for Ansible
useCommonNameForSAN: no
@@ -314,8 +314,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR"
openssl_csr:
path: '{{ output_dir }}/csr_backup.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_backup.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
backup: yes
@@ -323,8 +323,8 @@
register: csr_backup_1
- name: "({{ select_crypto_backend }}) Generate CSR (idempotent)"
openssl_csr:
path: '{{ output_dir }}/csr_backup.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_backup.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
backup: yes
@@ -332,8 +332,8 @@
register: csr_backup_2
- name: "({{ select_crypto_backend }}) Generate CSR (change)"
openssl_csr:
path: '{{ output_dir }}/csr_backup.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_backup.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: ansible.com
backup: yes
@@ -341,7 +341,7 @@
register: csr_backup_3
- name: "({{ select_crypto_backend }}) Generate CSR (remove)"
openssl_csr:
path: '{{ output_dir }}/csr_backup.csr'
path: '{{ remote_tmp_dir }}/csr_backup.csr'
state: absent
backup: yes
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -349,7 +349,7 @@
register: csr_backup_4
- name: "({{ select_crypto_backend }}) Generate CSR (remove, idempotent)"
openssl_csr:
path: '{{ output_dir }}/csr_backup.csr'
path: '{{ remote_tmp_dir }}/csr_backup.csr'
state: absent
backup: yes
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -357,8 +357,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR with subject key identifier"
openssl_csr:
path: '{{ output_dir }}/csr_ski.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_ski.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
subject_key_identifier: "00:11:22:33"
@@ -368,8 +368,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR with subject key identifier (idempotency)"
openssl_csr:
path: '{{ output_dir }}/csr_ski.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_ski.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
subject_key_identifier: "00:11:22:33"
@@ -379,8 +379,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR with subject key identifier (change)"
openssl_csr:
path: '{{ output_dir }}/csr_ski.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_ski.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
subject_key_identifier: "44:55:66:77:88"
@@ -390,8 +390,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR with subject key identifier (auto-create)"
openssl_csr:
path: '{{ output_dir }}/csr_ski.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_ski.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
create_subject_key_identifier: yes
@@ -401,8 +401,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR with subject key identifier (auto-create idempotency)"
openssl_csr:
path: '{{ output_dir }}/csr_ski.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_ski.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
create_subject_key_identifier: yes
@@ -412,8 +412,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR with subject key identifier (remove)"
openssl_csr:
path: '{{ output_dir }}/csr_ski.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_ski.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -422,8 +422,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR with authority key identifier"
openssl_csr:
path: '{{ output_dir }}/csr_aki.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_aki.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
authority_key_identifier: "00:11:22:33"
@@ -433,8 +433,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR with authority key identifier (idempotency)"
openssl_csr:
path: '{{ output_dir }}/csr_aki.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_aki.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
authority_key_identifier: "00:11:22:33"
@@ -444,8 +444,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR with authority key identifier (change)"
openssl_csr:
path: '{{ output_dir }}/csr_aki.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_aki.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
authority_key_identifier: "44:55:66:77:88"
@@ -455,8 +455,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR with authority key identifier (remove)"
openssl_csr:
path: '{{ output_dir }}/csr_aki.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_aki.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -465,8 +465,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR with authority cert issuer / serial number"
openssl_csr:
path: '{{ output_dir }}/csr_acisn.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_acisn.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
authority_cert_issuer:
@@ -479,8 +479,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR with authority cert issuer / serial number (idempotency)"
openssl_csr:
path: '{{ output_dir }}/csr_acisn.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_acisn.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
authority_cert_issuer:
@@ -493,8 +493,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR with authority cert issuer / serial number (change issuer)"
openssl_csr:
path: '{{ output_dir }}/csr_acisn.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_acisn.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
authority_cert_issuer:
@@ -507,8 +507,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR with authority cert issuer / serial number (change serial number)"
openssl_csr:
path: '{{ output_dir }}/csr_acisn.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_acisn.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
authority_cert_issuer:
@@ -521,8 +521,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR with authority cert issuer / serial number (remove)"
openssl_csr:
path: '{{ output_dir }}/csr_acisn.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_acisn.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
when: select_crypto_backend != 'pyopenssl'
@@ -530,20 +530,20 @@
- name: "({{ select_crypto_backend }}) Generate CSR with everything"
openssl_csr:
path: '{{ output_dir }}/csr_everything.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_everything.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.example.com
C: de
L: Somewhere
ST: Zurich
streetAddress: Welcome Street
O: Ansible
organizationalUnitName: Crypto Department
ST: Zürich
streetAddress: Welcome Street N° 5
O: Ansiblé
organizationalUnitName: Crÿpto Depârtment
serialNumber: "1234"
SN: Last Name
SN: Last Name Which Happens To Be A Very Løng String With A Lot Of Spaces, Jr.
GN: First Name
title: Chief
title: Chïeff
pseudonym: test
UID: asdf
emailAddress: test@example.com
@@ -638,20 +638,20 @@
- name: "({{ select_crypto_backend }}) Generate CSR with everything (idempotent, check mode)"
openssl_csr:
path: '{{ output_dir }}/csr_everything.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_everything.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.example.com
C: de
CN: www.example.com
countryName: de
L: Somewhere
ST: Zurich
streetAddress: Welcome Street
O: Ansible
organizationalUnitName: Crypto Department
ST: Zürich
streetAddress: Welcome Street N° 5
organizationName: Ansiblé
organizationalUnitName: Crÿpto Depârtment
serialNumber: "1234"
SN: Last Name
SN: Last Name Which Happens To Be A Very Løng String With A Lot Of Spaces, Jr.
GN: First Name
title: Chief
title: Chïeff
pseudonym: test
UID: asdf
emailAddress: test@example.com
@@ -747,20 +747,20 @@
- name: "({{ select_crypto_backend }}) Generate CSR with everything (idempotent)"
openssl_csr:
path: '{{ output_dir }}/csr_everything.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_everything.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.example.com
C: de
CN: www.example.com
countryName: de
L: Somewhere
ST: Zurich
streetAddress: Welcome Street
O: Ansible
organizationalUnitName: Crypto Department
ST: Zürich
streetAddress: Welcome Street N° 5
organizationName: Ansiblé
organizationalUnitName: Crÿpto Depârtment
serialNumber: "1234"
SN: Last Name
SN: Last Name Which Happens To Be A Very Løng String With A Lot Of Spaces, Jr.
GN: First Name
title: Chief
title: Chïeff
pseudonym: test
UID: asdf
emailAddress: test@example.com
@@ -855,7 +855,7 @@
- name: "({{ select_crypto_backend }}) Get info from CSR with everything"
community.crypto.openssl_csr_info:
path: '{{ output_dir }}/csr_everything.csr'
path: '{{ remote_tmp_dir }}/csr_everything.csr'
select_crypto_backend: '{{ select_crypto_backend }}'
register: everything_info
@@ -863,7 +863,7 @@
block:
- name: "({{ select_crypto_backend }}) Generate privatekeys"
openssl_privatekey:
path: '{{ output_dir }}/privatekey_{{ item }}.pem'
path: '{{ remote_tmp_dir }}/privatekey_{{ item }}.pem'
type: '{{ item }}'
loop:
- Ed25519
@@ -877,8 +877,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR"
openssl_csr:
path: '{{ output_dir }}/csr_{{ item }}.csr'
privatekey_path: '{{ output_dir }}/privatekey_{{ item }}.pem'
path: '{{ remote_tmp_dir }}/csr_{{ item }}.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey_{{ item }}.pem'
subject:
commonName: www.ansible.com
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -890,8 +890,8 @@
- name: "({{ select_crypto_backend }}) Generate CSR (idempotent)"
openssl_csr:
path: '{{ output_dir }}/csr_{{ item }}.csr'
privatekey_path: '{{ output_dir }}/privatekey_{{ item }}.pem'
path: '{{ remote_tmp_dir }}/csr_{{ item }}.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey_{{ item }}.pem'
subject:
commonName: www.ansible.com
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -907,8 +907,8 @@
block:
- name: "({{ select_crypto_backend }}) Create CSR with CRL distribution endpoints"
openssl_csr:
path: '{{ output_dir }}/csr_crl_d_e.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_crl_d_e.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
crl_distribution_points:
@@ -930,8 +930,8 @@
- name: "({{ select_crypto_backend }}) Create CSR with CRL distribution endpoints (idempotence)"
openssl_csr:
path: '{{ output_dir }}/csr_crl_d_e.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_crl_d_e.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
crl_distribution_points:
@@ -953,8 +953,8 @@
- name: "({{ select_crypto_backend }}) Create CSR with CRL distribution endpoints (change)"
openssl_csr:
path: '{{ output_dir }}/csr_crl_d_e.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_crl_d_e.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
crl_distribution_points:
@@ -975,8 +975,8 @@
- name: "({{ select_crypto_backend }}) Create CSR with CRL distribution endpoints (no endpoints)"
openssl_csr:
path: '{{ output_dir }}/csr_crl_d_e.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_crl_d_e.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -984,8 +984,8 @@
- name: "({{ select_crypto_backend }}) Create CSR with CRL distribution endpoints"
openssl_csr:
path: '{{ output_dir }}/csr_crl_d_e.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_crl_d_e.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
crl_distribution_points:

View File

@@ -6,12 +6,12 @@
- name: Prepare private key for backend autodetection test
openssl_privatekey:
path: '{{ output_dir }}/privatekey_backend_selection.pem'
path: '{{ remote_tmp_dir }}/privatekey_backend_selection.pem'
size: '{{ default_rsa_key_size }}'
- name: Run module with backend autodetection
openssl_csr:
path: '{{ output_dir }}/csr_backend_selection.csr'
privatekey_path: '{{ output_dir }}/privatekey_backend_selection.pem'
path: '{{ remote_tmp_dir }}/csr_backend_selection.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey_backend_selection.pem'
subject:
commonName: www.ansible.com
@@ -29,12 +29,12 @@
- name: Remove output directory
file:
path: "{{ output_dir }}"
path: "{{ remote_tmp_dir }}"
state: absent
- name: Re-create output directory
file:
path: "{{ output_dir }}"
path: "{{ remote_tmp_dir }}"
state: directory
- block:

View File

@@ -1,14 +1,14 @@
---
- name: "({{ select_crypto_backend }}) Validate CSR (test - privatekey modulus)"
shell: '{{ openssl_binary }} rsa -noout -modulus -in {{ output_dir }}/privatekey.pem'
shell: '{{ openssl_binary }} rsa -noout -modulus -in {{ remote_tmp_dir }}/privatekey.pem'
register: privatekey_modulus
- name: "({{ select_crypto_backend }}) Validate CSR (test - Common Name)"
shell: "{{ openssl_binary }} req -noout -subject -in {{ output_dir }}/csr.csr -nameopt oneline,-space_eq"
shell: "{{ openssl_binary }} req -noout -subject -in {{ remote_tmp_dir }}/csr.csr -nameopt oneline,-space_eq"
register: csr_cn
- name: "({{ select_crypto_backend }}) Validate CSR (test - csr modulus)"
shell: '{{ openssl_binary }} req -noout -modulus -in {{ output_dir }}/csr.csr'
shell: '{{ openssl_binary }} req -noout -modulus -in {{ remote_tmp_dir }}/csr.csr'
register: csr_modulus
- name: "({{ select_crypto_backend }}) Validate CSR (assert)"
@@ -25,11 +25,16 @@
- generate_csr_idempotent is not changed
- generate_csr_idempotent_check is not changed
- name: "({{ select_crypto_backend }}) Read CSR"
slurp:
src: '{{ remote_tmp_dir }}/csr.csr'
register: slurp
- name: "({{ select_crypto_backend }}) Validate CSR (data retrieval)"
assert:
that:
- generate_csr_check.csr is none
- generate_csr.csr == lookup('file', output_dir ~ '/csr.csr', rstrip=False)
- generate_csr.csr == (slurp.content | b64decode)
- generate_csr.csr == generate_csr_idempotent.csr
- generate_csr.csr == generate_csr_idempotent_check.csr
@@ -49,11 +54,11 @@
- csr_ku_xku_change_2 is changed
- name: "({{ select_crypto_backend }}) Validate old_API CSR (test - Common Name)"
shell: "{{ openssl_binary }} req -noout -subject -in {{ output_dir }}/csr_oldapi.csr -nameopt oneline,-space_eq"
shell: "{{ openssl_binary }} req -noout -subject -in {{ remote_tmp_dir }}/csr_oldapi.csr -nameopt oneline,-space_eq"
register: csr_oldapi_cn
- name: "({{ select_crypto_backend }}) Validate old_API CSR (test - csr modulus)"
shell: '{{ openssl_binary }} req -noout -modulus -in {{ output_dir }}/csr_oldapi.csr'
shell: '{{ openssl_binary }} req -noout -modulus -in {{ remote_tmp_dir }}/csr_oldapi.csr'
register: csr_oldapi_modulus
- name: "({{ select_crypto_backend }}) Validate old_API CSR (assert)"
@@ -78,7 +83,7 @@
when: select_crypto_backend == 'cryptography' and cryptography_version.stdout is version('2.0', '<')
- name: "({{ select_crypto_backend }}) Validate OCSP Must Staple CSR (test - everything)"
shell: "{{ openssl_binary }} req -noout -in {{ output_dir }}/csr_ocsp.csr -text"
shell: "{{ openssl_binary }} req -noout -in {{ remote_tmp_dir }}/csr_ocsp.csr -text"
register: csr_ocsp
- name: "({{ select_crypto_backend }}) Validate OCSP Must Staple CSR (assert)"
@@ -93,15 +98,15 @@
- csr_ocsp_idempotency is not changed
- name: "({{ select_crypto_backend }}) Validate ECC CSR (test - privatekey's public key)"
shell: '{{ openssl_binary }} ec -pubout -in {{ output_dir }}/privatekey2.pem'
shell: '{{ openssl_binary }} ec -pubout -in {{ remote_tmp_dir }}/privatekey2.pem'
register: privatekey_ecc_key
- name: "({{ select_crypto_backend }}) Validate ECC CSR (test - Common Name)"
shell: "{{ openssl_binary }} req -noout -subject -in {{ output_dir }}/csr2.csr -nameopt oneline,-space_eq"
shell: "{{ openssl_binary }} req -noout -subject -in {{ remote_tmp_dir }}/csr2.csr -nameopt oneline,-space_eq"
register: csr_ecc_cn
- name: "({{ select_crypto_backend }}) Validate ECC CSR (test - CSR pubkey)"
shell: '{{ openssl_binary }} req -noout -pubkey -in {{ output_dir }}/csr2.csr'
shell: '{{ openssl_binary }} req -noout -pubkey -in {{ remote_tmp_dir }}/csr2.csr'
register: csr_ecc_pubkey
- name: "({{ select_crypto_backend }}) Validate ECC CSR (assert)"
@@ -111,7 +116,7 @@
- csr_ecc_pubkey.stdout == privatekey_ecc_key.stdout
- name: "({{ select_crypto_backend }}) Validate CSR (text common name - Common Name)"
shell: "{{ openssl_binary }} req -noout -subject -in {{ output_dir }}/csr3.csr -nameopt oneline,-space_eq"
shell: "{{ openssl_binary }} req -noout -subject -in {{ remote_tmp_dir }}/csr3.csr -nameopt oneline,-space_eq"
register: csr3_cn
- name: "({{ select_crypto_backend }}) Validate CSR (assert)"
@@ -219,16 +224,16 @@
- everything_info.subject.emailAddress == "test@example.com"
- everything_info.subject.givenName == "First Name"
- everything_info.subject.localityName == "Somewhere"
- everything_info.subject.organizationName == "Ansible"
- everything_info.subject.organizationalUnitName == "Crypto Department"
- everything_info.subject.organizationName == "Ansiblé"
- everything_info.subject.organizationalUnitName == "Crÿpto Depârtment"
- everything_info.subject.postalAddress == "1234 Somewhere"
- everything_info.subject.postalCode == "1234"
- everything_info.subject.pseudonym == "test"
- everything_info.subject.serialNumber == "1234"
- everything_info.subject.stateOrProvinceName == "Zurich"
- everything_info.subject.streetAddress == "Welcome Street"
- everything_info.subject.surname == "Last Name"
- everything_info.subject.title == "Chief"
- everything_info.subject.stateOrProvinceName == "Zürich"
- everything_info.subject.streetAddress == "Welcome Street N° 5"
- everything_info.subject.surname == "Last Name Which Happens To Be A Very Løng String With A Lot Of Spaces, Jr."
- everything_info.subject.title == "Chïeff"
- everything_info.subject.userId == "asdf"
- everything_info.subject | length == 16
- everything_info.subject_alt_name_critical == false

View File

@@ -1,2 +1,3 @@
shippable/cloud/group1
shippable/posix/group1
destructive

View File

@@ -1,3 +1,5 @@
dependencies:
- setup_openssl
- setup_pyopenssl
- setup_remote_tmp_dir
- prepare_jinja2_compat

View File

@@ -4,7 +4,7 @@
- name: "({{ select_crypto_backend }}) Get CSR info"
openssl_csr_info:
path: '{{ output_dir }}/csr_1.csr'
path: '{{ remote_tmp_dir }}/csr_1.csr'
select_crypto_backend: '{{ select_crypto_backend }}'
register: result
@@ -34,9 +34,14 @@
set_fact:
info_results: "{{ info_results + [result] }}"
- name: "({{ select_crypto_backend }}) Read CSR"
slurp:
src: '{{ remote_tmp_dir }}/csr_1.csr'
register: slurp
- name: "({{ select_crypto_backend }}) Get CSR info directly"
openssl_csr_info:
content: '{{ lookup("file", output_dir ~ "/csr_1.csr") }}'
content: '{{ slurp.content | b64decode }}'
select_crypto_backend: '{{ select_crypto_backend }}'
register: result_direct
@@ -47,7 +52,7 @@
- name: "({{ select_crypto_backend }}) Get CSR info"
openssl_csr_info:
path: '{{ output_dir }}/csr_2.csr'
path: '{{ remote_tmp_dir }}/csr_2.csr'
select_crypto_backend: '{{ select_crypto_backend }}'
register: result
@@ -57,7 +62,7 @@
- name: "({{ select_crypto_backend }}) Get CSR info"
openssl_csr_info:
path: '{{ output_dir }}/csr_3.csr'
path: '{{ remote_tmp_dir }}/csr_3.csr'
select_crypto_backend: '{{ select_crypto_backend }}'
register: result
@@ -79,7 +84,7 @@
- name: "({{ select_crypto_backend }}) Get CSR info"
openssl_csr_info:
path: '{{ output_dir }}/csr_4.csr'
path: '{{ remote_tmp_dir }}/csr_4.csr'
select_crypto_backend: '{{ select_crypto_backend }}'
register: result

View File

@@ -6,12 +6,12 @@
- name: Generate privatekey
openssl_privatekey:
path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/privatekey.pem'
size: '{{ default_rsa_key_size }}'
- name: Generate privatekey with password
openssl_privatekey:
path: '{{ output_dir }}/privatekeypw.pem'
path: '{{ remote_tmp_dir }}/privatekeypw.pem'
passphrase: hunter2
cipher: auto
select_crypto_backend: cryptography
@@ -19,8 +19,8 @@
- name: Generate CSR 1
openssl_csr:
path: '{{ output_dir }}/csr_1.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_1.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.example.com
C: de
@@ -87,8 +87,8 @@
- name: Generate CSR 2
openssl_csr:
path: '{{ output_dir }}/csr_2.csr'
privatekey_path: '{{ output_dir }}/privatekeypw.pem'
path: '{{ remote_tmp_dir }}/csr_2.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekeypw.pem'
privatekey_passphrase: hunter2
useCommonNameForSAN: no
basic_constraints:
@@ -96,8 +96,8 @@
- name: Generate CSR 3
openssl_csr:
path: '{{ output_dir }}/csr_3.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_3.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
useCommonNameForSAN: no
subject_alt_name:
- "DNS:*.ansible.com"
@@ -114,8 +114,8 @@
- name: Generate CSR 4
openssl_csr:
path: '{{ output_dir }}/csr_4.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/csr_4.csr'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
useCommonNameForSAN: no
authority_key_identifier: '{{ "44:55:66:77" if cryptography_version.stdout is version("1.3", ">=") else omit }}'

View File

@@ -1,2 +1,3 @@
shippable/cloud/group1
shippable/posix/group1
destructive

View File

@@ -1,3 +1,4 @@
dependencies:
- setup_openssl
- setup_pyopenssl
- setup_remote_tmp_dir

View File

@@ -1,12 +1,12 @@
---
- name: "({{ select_crypto_backend }}) Generate privatekey"
openssl_privatekey:
path: '{{ output_dir }}/privatekey.pem'
path: '{{ remote_tmp_dir }}/privatekey.pem'
size: '{{ default_rsa_key_size }}'
- name: "({{ select_crypto_backend }}) Generate CSR (check mode)"
openssl_csr_pipe:
privatekey_path: '{{ output_dir }}/privatekey.pem'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -15,7 +15,7 @@
- name: "({{ select_crypto_backend }}) Generate CSR"
openssl_csr_pipe:
privatekey_path: '{{ output_dir }}/privatekey.pem'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -24,7 +24,7 @@
- name: "({{ select_crypto_backend }}) Generate CSR (idempotent)"
openssl_csr_pipe:
content: "{{ generate_csr.csr }}"
privatekey_path: '{{ output_dir }}/privatekey.pem'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -33,7 +33,7 @@
- name: "({{ select_crypto_backend }}) Generate CSR (idempotent, check mode)"
openssl_csr_pipe:
content: "{{ generate_csr.csr }}"
privatekey_path: '{{ output_dir }}/privatekey.pem'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: www.ansible.com
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -43,7 +43,7 @@
- name: "({{ select_crypto_backend }}) Generate CSR (changed)"
openssl_csr_pipe:
content: "{{ generate_csr.csr }}"
privatekey_path: '{{ output_dir }}/privatekey.pem'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: ansible.com
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -52,7 +52,7 @@
- name: "({{ select_crypto_backend }}) Generate CSR (changed, check mode)"
openssl_csr_pipe:
content: "{{ generate_csr.csr }}"
privatekey_path: '{{ output_dir }}/privatekey.pem'
privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem'
subject:
commonName: ansible.com
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -60,7 +60,7 @@
register: generate_csr_changed_check
- name: "({{ select_crypto_backend }}) Validate CSR (test - privatekey modulus)"
shell: '{{ openssl_binary }} rsa -noout -modulus -in {{ output_dir }}/privatekey.pem'
shell: '{{ openssl_binary }} rsa -noout -modulus -in {{ remote_tmp_dir }}/privatekey.pem'
register: privatekey_modulus
- name: "({{ select_crypto_backend }}) Validate CSR (test - Common Name)"

View File

@@ -6,11 +6,11 @@
- name: Prepare private key for backend autodetection test
openssl_privatekey:
path: '{{ output_dir }}/privatekey_backend_selection.pem'
path: '{{ remote_tmp_dir }}/privatekey_backend_selection.pem'
size: '{{ default_rsa_key_size }}'
- name: Run module with backend autodetection
openssl_csr_pipe:
privatekey_path: '{{ output_dir }}/privatekey_backend_selection.pem'
privatekey_path: '{{ remote_tmp_dir }}/privatekey_backend_selection.pem'
subject:
commonName: www.ansible.com
@@ -24,12 +24,12 @@
- name: Remove output directory
file:
path: "{{ output_dir }}"
path: "{{ remote_tmp_dir }}"
state: absent
- name: Re-create output directory
file:
path: "{{ output_dir }}"
path: "{{ remote_tmp_dir }}"
state: directory
- block:

View File

@@ -1,2 +1,3 @@
shippable/cloud/group1
shippable/posix/group1
destructive

View File

@@ -1,2 +1,3 @@
dependencies:
- setup_openssl
- setup_remote_tmp_dir

View File

@@ -4,7 +4,7 @@
- name: "[{{ select_crypto_backend }}] Generate parameter (check mode)"
openssl_dhparam:
size: 768
path: '{{ output_dir }}/dh768.pem'
path: '{{ remote_tmp_dir }}/dh768.pem'
select_crypto_backend: "{{ select_crypto_backend }}"
return_content: yes
check_mode: true
@@ -13,7 +13,7 @@
- name: "[{{ select_crypto_backend }}] Generate parameter"
openssl_dhparam:
size: 768
path: '{{ output_dir }}/dh768.pem'
path: '{{ remote_tmp_dir }}/dh768.pem'
select_crypto_backend: "{{ select_crypto_backend }}"
return_content: yes
register: dhparam
@@ -21,7 +21,7 @@
- name: "[{{ select_crypto_backend }}] Don't regenerate parameters with no change (check mode)"
openssl_dhparam:
size: 768
path: '{{ output_dir }}/dh768.pem'
path: '{{ remote_tmp_dir }}/dh768.pem'
select_crypto_backend: "{{ select_crypto_backend }}"
return_content: yes
check_mode: true
@@ -30,39 +30,39 @@
- name: "[{{ select_crypto_backend }}] Don't regenerate parameters with no change"
openssl_dhparam:
size: 768
path: '{{ output_dir }}/dh768.pem'
path: '{{ remote_tmp_dir }}/dh768.pem'
select_crypto_backend: "{{ select_crypto_backend }}"
return_content: yes
register: dhparam_changed
- name: "[{{ select_crypto_backend }}] Generate parameters with size option"
openssl_dhparam:
path: '{{ output_dir }}/dh512.pem'
path: '{{ remote_tmp_dir }}/dh512.pem'
size: 512
select_crypto_backend: "{{ select_crypto_backend }}"
- name: "[{{ select_crypto_backend }}] Don't regenerate parameters with size option and no change"
openssl_dhparam:
path: '{{ output_dir }}/dh512.pem'
path: '{{ remote_tmp_dir }}/dh512.pem'
size: 512
select_crypto_backend: "{{ select_crypto_backend }}"
register: dhparam_changed_512
- copy:
src: '{{ output_dir }}/dh768.pem'
src: '{{ remote_tmp_dir }}/dh768.pem'
remote_src: yes
dest: '{{ output_dir }}/dh512.pem'
dest: '{{ remote_tmp_dir }}/dh512.pem'
- name: "[{{ select_crypto_backend }}] Re-generate if size is different"
openssl_dhparam:
path: '{{ output_dir }}/dh512.pem'
path: '{{ remote_tmp_dir }}/dh512.pem'
size: 512
select_crypto_backend: "{{ select_crypto_backend }}"
register: dhparam_changed_to_512
- name: "[{{ select_crypto_backend }}] Force re-generate parameters with size option"
openssl_dhparam:
path: '{{ output_dir }}/dh512.pem'
path: '{{ remote_tmp_dir }}/dh512.pem'
size: 512
force: yes
select_crypto_backend: "{{ select_crypto_backend }}"
@@ -70,11 +70,11 @@
- name: "[{{ select_crypto_backend }}] Create broken params"
copy:
dest: "{{ output_dir }}/dhbroken.pem"
dest: "{{ remote_tmp_dir }}/dhbroken.pem"
content: "broken"
- name: "[{{ select_crypto_backend }}] Regenerate broken params"
openssl_dhparam:
path: '{{ output_dir }}/dhbroken.pem'
path: '{{ remote_tmp_dir }}/dhbroken.pem'
size: 512
force: yes
select_crypto_backend: "{{ select_crypto_backend }}"
@@ -82,21 +82,21 @@
- name: "[{{ select_crypto_backend }}] Generate params"
openssl_dhparam:
path: '{{ output_dir }}/dh_backup.pem'
path: '{{ remote_tmp_dir }}/dh_backup.pem'
size: 512
backup: yes
select_crypto_backend: "{{ select_crypto_backend }}"
register: dhparam_backup_1
- name: "[{{ select_crypto_backend }}] Generate params (idempotent)"
openssl_dhparam:
path: '{{ output_dir }}/dh_backup.pem'
path: '{{ remote_tmp_dir }}/dh_backup.pem'
size: 512
backup: yes
select_crypto_backend: "{{ select_crypto_backend }}"
register: dhparam_backup_2
- name: "[{{ select_crypto_backend }}] Generate params (change)"
openssl_dhparam:
path: '{{ output_dir }}/dh_backup.pem'
path: '{{ remote_tmp_dir }}/dh_backup.pem'
size: 512
force: yes
backup: yes
@@ -104,7 +104,7 @@
register: dhparam_backup_3
- name: "[{{ select_crypto_backend }}] Generate params (remove)"
openssl_dhparam:
path: '{{ output_dir }}/dh_backup.pem'
path: '{{ remote_tmp_dir }}/dh_backup.pem'
state: absent
backup: yes
select_crypto_backend: "{{ select_crypto_backend }}"
@@ -112,7 +112,7 @@
register: dhparam_backup_4
- name: "[{{ select_crypto_backend }}] Generate params (remove, idempotent)"
openssl_dhparam:
path: '{{ output_dir }}/dh_backup.pem'
path: '{{ remote_tmp_dir }}/dh_backup.pem'
state: absent
backup: yes
select_crypto_backend: "{{ select_crypto_backend }}"

View File

@@ -9,7 +9,7 @@
- name: Run module with backend autodetection
openssl_dhparam:
path: '{{ output_dir }}/dh_backend_selection.pem'
path: '{{ remote_tmp_dir }}/dh_backend_selection.pem'
size: 512
- block:
@@ -24,12 +24,12 @@
- name: Remove output directory
file:
path: "{{ output_dir }}"
path: "{{ remote_tmp_dir }}"
state: absent
- name: Re-create output directory
file:
path: "{{ output_dir }}"
path: "{{ remote_tmp_dir }}"
state: directory
- block:

View File

@@ -1,12 +1,12 @@
---
- name: "[{{ select_crypto_backend }}] Validate generated params"
shell: '{{ openssl_binary }} dhparam -in {{ output_dir }}/{{ item }}.pem -noout -check'
shell: '{{ openssl_binary }} dhparam -in {{ remote_tmp_dir }}/{{ item }}.pem -noout -check'
with_items:
- dh768
- dh512
- name: "[{{ select_crypto_backend }}] Get bit size of 768"
shell: '{{ openssl_binary }} dhparam -noout -in {{ output_dir }}/dh768.pem -text | head -n1 | sed -ne "s@.*(\\([[:digit:]]\{1,\}\\) bit).*@\\1@p"'
shell: '{{ openssl_binary }} dhparam -noout -in {{ remote_tmp_dir }}/dh768.pem -text | head -n1 | sed -ne "s@.*(\\([[:digit:]]\{1,\}\\) bit).*@\\1@p"'
register: bit_size_dhparam
- name: "[{{ select_crypto_backend }}] Check bit size of default"
@@ -15,7 +15,7 @@
- bit_size_dhparam.stdout == "768"
- name: "[{{ select_crypto_backend }}] Get bit size of 512"
shell: '{{ openssl_binary }} dhparam -noout -in {{ output_dir }}/dh512.pem -text | head -n1 | sed -ne "s@.*(\\([[:digit:]]\{1,\}\\) bit).*@\\1@p"'
shell: '{{ openssl_binary }} dhparam -noout -in {{ remote_tmp_dir }}/dh512.pem -text | head -n1 | sed -ne "s@.*(\\([[:digit:]]\{1,\}\\) bit).*@\\1@p"'
register: bit_size_dhparam_512
- name: "[{{ select_crypto_backend }}] Check bit size of default"
@@ -34,10 +34,15 @@
- dhparam_changed_to_512 is changed
- dhparam_changed_force is changed
- name: "[{{ select_crypto_backend }}] Read result"
slurp:
src: '{{ remote_tmp_dir }}/dh768.pem'
register: slurp
- name: "[{{ select_crypto_backend }}] Make sure correct values are returned"
assert:
that:
- dhparam.dhparams == lookup('file', output_dir ~ '/dh768.pem', rstrip=False)
- dhparam.dhparams == (slurp.content | b64decode)
- dhparam.dhparams == dhparam_changed.dhparams
- name: "[{{ select_crypto_backend }}] Verify that broken params will be regenerated"

View File

@@ -1,2 +1,3 @@
shippable/cloud/group1
shippable/posix/group1
destructive

View File

@@ -1,3 +1,4 @@
dependencies:
- setup_openssl
- setup_pyopenssl
- setup_remote_tmp_dir

View File

@@ -2,10 +2,10 @@
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file (check mode)"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ output_dir }}/ansible.p12'
path: '{{ remote_tmp_dir }}/ansible.p12'
friendly_name: abracadabra
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
certificate_path: '{{ output_dir }}/ansible1.crt'
privatekey_path: '{{ remote_tmp_dir }}/ansible_pkey1.pem'
certificate_path: '{{ remote_tmp_dir }}/ansible1.crt'
state: present
return_content: true
check_mode: true
@@ -14,10 +14,10 @@
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ output_dir }}/ansible.p12'
path: '{{ remote_tmp_dir }}/ansible.p12'
friendly_name: abracadabra
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
certificate_path: '{{ output_dir }}/ansible1.crt'
privatekey_path: '{{ remote_tmp_dir }}/ansible_pkey1.pem'
certificate_path: '{{ remote_tmp_dir }}/ansible1.crt'
state: present
return_content: true
register: p12_standard
@@ -25,10 +25,10 @@
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file again, idempotency (check mode)"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ output_dir }}/ansible.p12'
path: '{{ remote_tmp_dir }}/ansible.p12'
friendly_name: abracadabra
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
certificate_path: '{{ output_dir }}/ansible1.crt'
privatekey_path: '{{ remote_tmp_dir }}/ansible_pkey1.pem'
certificate_path: '{{ remote_tmp_dir }}/ansible1.crt'
state: present
return_content: true
check_mode: true
@@ -37,17 +37,17 @@
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file again, idempotency"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ output_dir }}/ansible.p12'
path: '{{ remote_tmp_dir }}/ansible.p12'
friendly_name: abracadabra
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
certificate_path: '{{ output_dir }}/ansible1.crt'
privatekey_path: '{{ remote_tmp_dir }}/ansible_pkey1.pem'
certificate_path: '{{ remote_tmp_dir }}/ansible1.crt'
state: present
return_content: true
register: p12_standard_idempotency
- name: "({{ select_crypto_backend }}) Read ansible.p12"
slurp:
src: '{{ output_dir }}/ansible.p12'
src: '{{ remote_tmp_dir }}/ansible.p12'
register: ansible_p12_content
- name: "({{ select_crypto_backend }}) Validate PKCS#12"
@@ -59,10 +59,10 @@
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file (force)"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ output_dir }}/ansible.p12'
path: '{{ remote_tmp_dir }}/ansible.p12'
friendly_name: abracadabra
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
certificate_path: '{{ output_dir }}/ansible1.crt'
privatekey_path: '{{ remote_tmp_dir }}/ansible_pkey1.pem'
certificate_path: '{{ remote_tmp_dir }}/ansible1.crt'
state: present
force: true
register: p12_force
@@ -70,10 +70,10 @@
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file (force + change mode)"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ output_dir }}/ansible.p12'
path: '{{ remote_tmp_dir }}/ansible.p12'
friendly_name: abracadabra
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
certificate_path: '{{ output_dir }}/ansible1.crt'
privatekey_path: '{{ remote_tmp_dir }}/ansible_pkey1.pem'
certificate_path: '{{ remote_tmp_dir }}/ansible1.crt'
state: present
force: true
mode: '0644'
@@ -82,8 +82,8 @@
- name: "({{ select_crypto_backend }}) Dump PKCS#12"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
src: '{{ output_dir }}/ansible.p12'
path: '{{ output_dir }}/ansible_parse.pem'
src: '{{ remote_tmp_dir }}/ansible.p12'
path: '{{ remote_tmp_dir }}/ansible_parse.pem'
action: parse
state: present
register: p12_dumped
@@ -91,8 +91,8 @@
- name: "({{ select_crypto_backend }}) Dump PKCS#12 file again, idempotency"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
src: '{{ output_dir }}/ansible.p12'
path: '{{ output_dir }}/ansible_parse.pem'
src: '{{ remote_tmp_dir }}/ansible.p12'
path: '{{ remote_tmp_dir }}/ansible_parse.pem'
action: parse
state: present
register: p12_dumped_idempotency
@@ -100,8 +100,8 @@
- name: "({{ select_crypto_backend }}) Dump PKCS#12, check mode"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
src: '{{ output_dir }}/ansible.p12'
path: '{{ output_dir }}/ansible_parse.pem'
src: '{{ remote_tmp_dir }}/ansible.p12'
path: '{{ remote_tmp_dir }}/ansible_parse.pem'
action: parse
state: present
check_mode: true
@@ -110,36 +110,36 @@
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file with multiple certs and passphrase"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ output_dir }}/ansible_multi_certs.p12'
path: '{{ remote_tmp_dir }}/ansible_multi_certs.p12'
friendly_name: abracadabra
passphrase: hunter3
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
certificate_path: '{{ output_dir }}/ansible1.crt'
privatekey_path: '{{ remote_tmp_dir }}/ansible_pkey1.pem'
certificate_path: '{{ remote_tmp_dir }}/ansible1.crt'
other_certificates:
- '{{ output_dir }}/ansible2.crt'
- '{{ output_dir }}/ansible3.crt'
- '{{ remote_tmp_dir }}/ansible2.crt'
- '{{ remote_tmp_dir }}/ansible3.crt'
state: present
register: p12_multiple_certs
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file with multiple certs and passphrase, again (idempotency)"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ output_dir }}/ansible_multi_certs.p12'
path: '{{ remote_tmp_dir }}/ansible_multi_certs.p12'
friendly_name: abracadabra
passphrase: hunter3
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
certificate_path: '{{ output_dir }}/ansible1.crt'
privatekey_path: '{{ remote_tmp_dir }}/ansible_pkey1.pem'
certificate_path: '{{ remote_tmp_dir }}/ansible1.crt'
other_certificates:
- '{{ output_dir }}/ansible2.crt'
- '{{ output_dir }}/ansible3.crt'
- '{{ remote_tmp_dir }}/ansible2.crt'
- '{{ remote_tmp_dir }}/ansible3.crt'
state: present
register: p12_multiple_certs_idempotency
- name: "({{ select_crypto_backend }}) Dump PKCS#12 with multiple certs and passphrase"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
src: '{{ output_dir }}/ansible_multi_certs.p12'
path: '{{ output_dir }}/ansible_parse_multi_certs.pem'
src: '{{ remote_tmp_dir }}/ansible_multi_certs.p12'
path: '{{ remote_tmp_dir }}/ansible_parse_multi_certs.pem'
passphrase: hunter3
action: parse
state: present
@@ -147,11 +147,11 @@
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file (password fail 1)"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ output_dir }}/ansible_pw1.p12'
path: '{{ remote_tmp_dir }}/ansible_pw1.p12'
friendly_name: abracadabra
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
privatekey_path: '{{ remote_tmp_dir }}/ansible_pkey1.pem'
privatekey_passphrase: hunter2
certificate_path: '{{ output_dir }}/ansible1.crt'
certificate_path: '{{ remote_tmp_dir }}/ansible1.crt'
state: present
ignore_errors: true
register: passphrase_error_1
@@ -159,11 +159,11 @@
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file (password fail 2)"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ output_dir }}/ansible_pw2.p12'
path: '{{ remote_tmp_dir }}/ansible_pw2.p12'
friendly_name: abracadabra
privatekey_path: '{{ output_dir }}/privatekeypw.pem'
privatekey_path: '{{ remote_tmp_dir }}/privatekeypw.pem'
privatekey_passphrase: wrong_password
certificate_path: '{{ output_dir }}/ansible1.crt'
certificate_path: '{{ remote_tmp_dir }}/ansible1.crt'
state: present
ignore_errors: true
register: passphrase_error_2
@@ -171,10 +171,10 @@
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file (password fail 3)"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ output_dir }}/ansible_pw3.p12'
path: '{{ remote_tmp_dir }}/ansible_pw3.p12'
friendly_name: abracadabra
privatekey_path: '{{ output_dir }}/privatekeypw.pem'
certificate_path: '{{ output_dir }}/ansible1.crt'
privatekey_path: '{{ remote_tmp_dir }}/privatekeypw.pem'
certificate_path: '{{ remote_tmp_dir }}/ansible1.crt'
state: present
ignore_errors: true
register: passphrase_error_3
@@ -182,24 +182,24 @@
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file, no privatekey"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ output_dir }}/ansible_no_pkey.p12'
path: '{{ remote_tmp_dir }}/ansible_no_pkey.p12'
friendly_name: abracadabra
certificate_path: '{{ output_dir }}/ansible1.crt'
certificate_path: '{{ remote_tmp_dir }}/ansible1.crt'
state: present
register: p12_no_pkey
- name: "({{ select_crypto_backend }}) Create broken PKCS#12"
copy:
dest: '{{ output_dir }}/broken.p12'
dest: '{{ remote_tmp_dir }}/broken.p12'
content: broken
- name: "({{ select_crypto_backend }}) Regenerate broken PKCS#12"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ output_dir }}/broken.p12'
path: '{{ remote_tmp_dir }}/broken.p12'
friendly_name: abracadabra
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
certificate_path: '{{ output_dir }}/ansible1.crt'
privatekey_path: '{{ remote_tmp_dir }}/ansible_pkey1.pem'
certificate_path: '{{ remote_tmp_dir }}/ansible1.crt'
state: present
force: true
mode: '0644'
@@ -208,10 +208,10 @@
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ output_dir }}/ansible_backup.p12'
path: '{{ remote_tmp_dir }}/ansible_backup.p12'
friendly_name: abracadabra
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
certificate_path: '{{ output_dir }}/ansible1.crt'
privatekey_path: '{{ remote_tmp_dir }}/ansible_pkey1.pem'
certificate_path: '{{ remote_tmp_dir }}/ansible1.crt'
state: present
backup: true
register: p12_backup_1
@@ -219,10 +219,10 @@
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file (idempotent)"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ output_dir }}/ansible_backup.p12'
path: '{{ remote_tmp_dir }}/ansible_backup.p12'
friendly_name: abracadabra
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
certificate_path: '{{ output_dir }}/ansible1.crt'
privatekey_path: '{{ remote_tmp_dir }}/ansible_pkey1.pem'
certificate_path: '{{ remote_tmp_dir }}/ansible1.crt'
state: present
backup: true
register: p12_backup_2
@@ -230,10 +230,10 @@
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file (change)"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ output_dir }}/ansible_backup.p12'
path: '{{ remote_tmp_dir }}/ansible_backup.p12'
friendly_name: abra
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
certificate_path: '{{ output_dir }}/ansible1.crt'
privatekey_path: '{{ remote_tmp_dir }}/ansible_pkey1.pem'
certificate_path: '{{ remote_tmp_dir }}/ansible1.crt'
state: present
force: true
backup: true
@@ -242,7 +242,7 @@
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file (remove)"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ output_dir }}/ansible_backup.p12'
path: '{{ remote_tmp_dir }}/ansible_backup.p12'
state: absent
backup: true
return_content: true
@@ -251,7 +251,7 @@
- name: "({{ select_crypto_backend }}) Generate PKCS#12 file (remove, idempotent)"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ output_dir }}/ansible_backup.p12'
path: '{{ remote_tmp_dir }}/ansible_backup.p12'
state: absent
backup: true
register: p12_backup_5
@@ -259,11 +259,11 @@
- name: "({{ select_crypto_backend }}) Generate 'empty' PKCS#12 file"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ output_dir }}/ansible_empty.p12'
path: '{{ remote_tmp_dir }}/ansible_empty.p12'
friendly_name: abracadabra
other_certificates:
- '{{ output_dir }}/ansible2.crt'
- '{{ output_dir }}/ansible3.crt'
- '{{ remote_tmp_dir }}/ansible2.crt'
- '{{ remote_tmp_dir }}/ansible3.crt'
state: present
register: p12_empty
@@ -271,21 +271,21 @@
- name: "({{ select_crypto_backend }}) Generate 'empty' PKCS#12 file (idempotent)"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ output_dir }}/ansible_empty.p12'
path: '{{ remote_tmp_dir }}/ansible_empty.p12'
friendly_name: abracadabra
other_certificates:
- '{{ output_dir }}/ansible3.crt'
- '{{ output_dir }}/ansible2.crt'
- '{{ remote_tmp_dir }}/ansible3.crt'
- '{{ remote_tmp_dir }}/ansible2.crt'
state: present
register: p12_empty_idem
- name: "({{ select_crypto_backend }}) Generate 'empty' PKCS#12 file (idempotent, concatenated other certificates)"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
path: '{{ output_dir }}/ansible_empty.p12'
path: '{{ remote_tmp_dir }}/ansible_empty.p12'
friendly_name: abracadabra
other_certificates:
- '{{ output_dir }}/ansible23.crt'
- '{{ remote_tmp_dir }}/ansible23.crt'
other_certificates_parse_all: true
state: present
register: p12_empty_concat_idem
@@ -293,8 +293,8 @@
- name: "({{ select_crypto_backend }}) Generate 'empty' PKCS#12 file (parse)"
openssl_pkcs12:
select_crypto_backend: '{{ select_crypto_backend }}'
src: '{{ output_dir }}/ansible_empty.p12'
path: '{{ output_dir }}/ansible_empty.pem'
src: '{{ remote_tmp_dir }}/ansible_empty.p12'
path: '{{ remote_tmp_dir }}/ansible_empty.pem'
action: parse
- import_tasks: ../tests/validate.yml
@@ -303,7 +303,7 @@
- name: "({{ select_crypto_backend }}) Delete PKCS#12 file"
openssl_pkcs12:
state: absent
path: '{{ output_dir }}/{{ item }}.p12'
path: '{{ remote_tmp_dir }}/{{ item }}.p12'
loop:
- ansible
- ansible_no_pkey

View File

@@ -7,50 +7,56 @@
- block:
- name: Generate private keys
openssl_privatekey:
path: '{{ output_dir }}/ansible_pkey{{ item }}.pem'
path: '{{ remote_tmp_dir }}/ansible_pkey{{ item }}.pem'
size: '{{ default_rsa_key_size_certifiates }}'
loop: "{{ range(1, 4) | list }}"
- name: Generate privatekey with password
openssl_privatekey:
path: '{{ output_dir }}/privatekeypw.pem'
path: '{{ remote_tmp_dir }}/privatekeypw.pem'
passphrase: hunter2
cipher: auto
size: '{{ default_rsa_key_size }}'
- name: Generate CSRs
openssl_csr:
path: '{{ output_dir }}/ansible{{ item }}.csr'
privatekey_path: '{{ output_dir }}/ansible_pkey{{ item }}.pem'
path: '{{ remote_tmp_dir }}/ansible{{ item }}.csr'
privatekey_path: '{{ remote_tmp_dir }}/ansible_pkey{{ item }}.pem'
commonName: www{{ item }}.ansible.com
loop: "{{ range(1, 4) | list }}"
- name: Generate certificate
x509_certificate:
path: '{{ output_dir }}/ansible{{ item }}.crt'
privatekey_path: '{{ output_dir }}/ansible_pkey{{ item }}.pem'
csr_path: '{{ output_dir }}/ansible{{ item }}.csr'
path: '{{ remote_tmp_dir }}/ansible{{ item }}.crt'
privatekey_path: '{{ remote_tmp_dir }}/ansible_pkey{{ item }}.pem'
csr_path: '{{ remote_tmp_dir }}/ansible{{ item }}.csr'
provider: selfsigned
loop: "{{ range(1, 4) | list }}"
- name: Read files
slurp:
src: '{{ item }}'
loop:
- "{{ remote_tmp_dir ~ '/ansible2.crt' }}"
- "{{ remote_tmp_dir ~ '/ansible3.crt' }}"
register: slurp
- name: Generate concatenated PEM file
copy:
dest: '{{ output_dir }}/ansible23.crt'
content: |
{{ lookup("file", output_dir ~ "/ansible2.crt") }}
{{ lookup("file", output_dir ~ "/ansible3.crt") }}
dest: '{{ remote_tmp_dir }}/ansible23.crt'
content: '{{ slurp.results[0].content | b64decode }}{{ slurp.results[1].content | b64decode }}'
- name: Generate PKCS#12 file with backend autodetection
openssl_pkcs12:
path: '{{ output_dir }}/ansible.p12'
path: '{{ remote_tmp_dir }}/ansible.p12'
friendly_name: abracadabra
privatekey_path: '{{ output_dir }}/ansible_pkey1.pem'
certificate_path: '{{ output_dir }}/ansible1.crt'
privatekey_path: '{{ remote_tmp_dir }}/ansible_pkey1.pem'
certificate_path: '{{ remote_tmp_dir }}/ansible1.crt'
state: present
- name: Delete result
file:
path: '{{ output_dir }}/ansible.p12'
path: '{{ remote_tmp_dir }}/ansible.p12'
state: absent
- block:

View File

@@ -1,14 +1,14 @@
---
- name: '({{ select_crypto_backend }}) Validate PKCS#12'
command: "{{ openssl_binary }} pkcs12 -info -in {{ output_dir }}/ansible.p12 -nodes -passin pass:''"
command: "{{ openssl_binary }} pkcs12 -info -in {{ remote_tmp_dir }}/ansible.p12 -nodes -passin pass:''"
register: p12
- name: '({{ select_crypto_backend }}) Validate PKCS#12 with no private key'
command: "{{ openssl_binary }} pkcs12 -info -in {{ output_dir }}/ansible_no_pkey.p12 -nodes -passin pass:''"
command: "{{ openssl_binary }} pkcs12 -info -in {{ remote_tmp_dir }}/ansible_no_pkey.p12 -nodes -passin pass:''"
register: p12_validate_no_pkey
- name: '({{ select_crypto_backend }}) Validate PKCS#12 with multiple certs'
shell: "{{ openssl_binary }} pkcs12 -info -in {{ output_dir }}/ansible_multi_certs.p12 -nodes -passin pass:'hunter3' | grep subject"
shell: "{{ openssl_binary }} pkcs12 -info -in {{ remote_tmp_dir }}/ansible_multi_certs.p12 -nodes -passin pass:'hunter3' | grep subject"
register: p12_validate_multi_certs
- name: '({{ select_crypto_backend }}) Validate PKCS#12 (assert)'
@@ -62,11 +62,20 @@
- p12_backup_5.backup_file is undefined
- p12_backup_4.pkcs12 is none
- name: '({{ select_crypto_backend }}) Read files'
slurp:
src: '{{ item }}'
loop:
- "{{ remote_tmp_dir ~ '/ansible_empty.pem' }}"
- "{{ remote_tmp_dir ~ '/ansible2.crt' }}"
- "{{ remote_tmp_dir ~ '/ansible3.crt' }}"
register: slurp
- name: '({{ select_crypto_backend }}) Load "empty" file'
set_fact:
empty_contents: "{{ lookup('file', output_dir ~ '/ansible_empty.pem') }}"
empty_expected_pyopenssl: "{{ lookup('file', output_dir ~ '/ansible3.crt') ~ '\n' ~ lookup('file', output_dir ~ '/ansible2.crt') }}"
empty_expected_cryptography: "{{ lookup('file', output_dir ~ '/ansible2.crt') ~ '\n' ~ lookup('file', output_dir ~ '/ansible3.crt') }}"
empty_contents: "{{ slurp.results[0].content | b64decode }}"
empty_expected_pyopenssl: "{{ (slurp.results[2].content | b64decode) ~ (slurp.results[1].content | b64decode) }}"
empty_expected_cryptography: "{{ (slurp.results[1].content | b64decode) ~ (slurp.results[2].content | b64decode) }}"
- name: '({{ select_crypto_backend }}) Check "empty" file'
assert:

View File

@@ -1,2 +1,3 @@
shippable/cloud/group1
shippable/posix/group1
destructive

View File

@@ -1,3 +1,4 @@
dependencies:
- setup_openssl
- setup_pyopenssl
- setup_remote_tmp_dir

View File

@@ -1,7 +1,7 @@
---
- name: "({{ select_crypto_backend }}) Generate privatekey1 - standard (check mode)"
openssl_privatekey:
path: '{{ output_dir }}/privatekey1.pem'
path: '{{ remote_tmp_dir }}/privatekey1.pem'
select_crypto_backend: '{{ select_crypto_backend }}'
return_content: yes
check_mode: true
@@ -9,14 +9,14 @@
- name: "({{ select_crypto_backend }}) Generate privatekey1 - standard"
openssl_privatekey:
path: '{{ output_dir }}/privatekey1.pem'
path: '{{ remote_tmp_dir }}/privatekey1.pem'
select_crypto_backend: '{{ select_crypto_backend }}'
return_content: yes
register: privatekey1
- name: "({{ select_crypto_backend }}) Generate privatekey1 - standard (idempotence, check mode)"
openssl_privatekey:
path: '{{ output_dir }}/privatekey1.pem'
path: '{{ remote_tmp_dir }}/privatekey1.pem'
select_crypto_backend: '{{ select_crypto_backend }}'
return_content: yes
check_mode: true
@@ -24,34 +24,34 @@
- name: "({{ select_crypto_backend }}) Generate privatekey1 - standard (idempotence)"
openssl_privatekey:
path: '{{ output_dir }}/privatekey1.pem'
path: '{{ remote_tmp_dir }}/privatekey1.pem'
select_crypto_backend: '{{ select_crypto_backend }}'
return_content: yes
register: privatekey1_idempotence
- name: "({{ select_crypto_backend }}) Generate privatekey2 - size 2048"
openssl_privatekey:
path: '{{ output_dir }}/privatekey2.pem'
path: '{{ remote_tmp_dir }}/privatekey2.pem'
size: 2048
select_crypto_backend: '{{ select_crypto_backend }}'
- name: "({{ select_crypto_backend }}) Generate privatekey3 - type DSA"
openssl_privatekey:
path: '{{ output_dir }}/privatekey3.pem'
path: '{{ remote_tmp_dir }}/privatekey3.pem'
type: DSA
size: 3072
select_crypto_backend: '{{ select_crypto_backend }}'
- name: "({{ select_crypto_backend }}) Generate privatekey4 - standard"
openssl_privatekey:
path: '{{ output_dir }}/privatekey4.pem'
path: '{{ remote_tmp_dir }}/privatekey4.pem'
size: '{{ default_rsa_key_size }}'
select_crypto_backend: '{{ select_crypto_backend }}'
- name: "({{ select_crypto_backend }}) Delete privatekey4 - standard"
openssl_privatekey:
state: absent
path: '{{ output_dir }}/privatekey4.pem'
path: '{{ remote_tmp_dir }}/privatekey4.pem'
select_crypto_backend: '{{ select_crypto_backend }}'
return_content: yes
register: privatekey4_delete
@@ -59,13 +59,13 @@
- name: "({{ select_crypto_backend }}) Delete privatekey4 - standard (idempotence)"
openssl_privatekey:
state: absent
path: '{{ output_dir }}/privatekey4.pem'
path: '{{ remote_tmp_dir }}/privatekey4.pem'
select_crypto_backend: '{{ select_crypto_backend }}'
register: privatekey4_delete_idempotence
- name: "({{ select_crypto_backend }}) Generate privatekey5 - standard - with passphrase"
openssl_privatekey:
path: '{{ output_dir }}/privatekey5.pem'
path: '{{ remote_tmp_dir }}/privatekey5.pem'
passphrase: ansible
cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}"
size: '{{ default_rsa_key_size }}'
@@ -73,7 +73,7 @@
- name: "({{ select_crypto_backend }}) Generate privatekey5 - standard - idempotence"
openssl_privatekey:
path: '{{ output_dir }}/privatekey5.pem'
path: '{{ remote_tmp_dir }}/privatekey5.pem'
passphrase: ansible
cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}"
size: '{{ default_rsa_key_size }}'
@@ -82,7 +82,7 @@
- name: "({{ select_crypto_backend }}) Generate privatekey6 - standard - with non-ASCII passphrase"
openssl_privatekey:
path: '{{ output_dir }}/privatekey6.pem'
path: '{{ remote_tmp_dir }}/privatekey6.pem'
passphrase: ànsïblé
cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}"
size: '{{ default_rsa_key_size }}'
@@ -154,7 +154,7 @@
- name: "({{ select_crypto_backend }}) Test ECC key generation"
openssl_privatekey:
path: '{{ output_dir }}/privatekey-{{ item.curve }}.pem'
path: '{{ remote_tmp_dir }}/privatekey-{{ item.curve }}.pem'
type: ECC
curve: "{{ item.curve }}"
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -168,7 +168,7 @@
- name: "({{ select_crypto_backend }}) Test ECC key generation (idempotency)"
openssl_privatekey:
path: '{{ output_dir }}/privatekey-{{ item.curve }}.pem'
path: '{{ remote_tmp_dir }}/privatekey-{{ item.curve }}.pem'
type: ECC
curve: "{{ item.curve }}"
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -183,7 +183,7 @@
- block:
- name: "({{ select_crypto_backend }}) Test other type generation"
openssl_privatekey:
path: '{{ output_dir }}/privatekey-{{ item.type }}.pem'
path: '{{ remote_tmp_dir }}/privatekey-{{ item.type }}.pem'
type: "{{ item.type }}"
select_crypto_backend: '{{ select_crypto_backend }}'
when: cryptography_version.stdout is version(item.min_version, '>=')
@@ -195,7 +195,7 @@
- name: "({{ select_crypto_backend }}) Test other type generation (idempotency)"
openssl_privatekey:
path: '{{ output_dir }}/privatekey-{{ item.type }}.pem'
path: '{{ remote_tmp_dir }}/privatekey-{{ item.type }}.pem'
type: "{{ item.type }}"
select_crypto_backend: '{{ select_crypto_backend }}'
when: cryptography_version.stdout is version(item.min_version, '>=')
@@ -219,7 +219,7 @@
- name: "({{ select_crypto_backend }}) Generate privatekey with passphrase"
openssl_privatekey:
path: '{{ output_dir }}/privatekeypw.pem'
path: '{{ remote_tmp_dir }}/privatekeypw.pem'
passphrase: hunter2
cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}"
size: '{{ default_rsa_key_size }}'
@@ -229,7 +229,7 @@
- name: "({{ select_crypto_backend }}) Generate privatekey with passphrase (idempotent)"
openssl_privatekey:
path: '{{ output_dir }}/privatekeypw.pem'
path: '{{ remote_tmp_dir }}/privatekeypw.pem'
passphrase: hunter2
cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}"
size: '{{ default_rsa_key_size }}'
@@ -239,7 +239,7 @@
- name: "({{ select_crypto_backend }}) Regenerate privatekey without passphrase"
openssl_privatekey:
path: '{{ output_dir }}/privatekeypw.pem'
path: '{{ remote_tmp_dir }}/privatekeypw.pem'
size: '{{ default_rsa_key_size }}'
select_crypto_backend: '{{ select_crypto_backend }}'
backup: yes
@@ -247,7 +247,7 @@
- name: "({{ select_crypto_backend }}) Regenerate privatekey without passphrase (idempotent)"
openssl_privatekey:
path: '{{ output_dir }}/privatekeypw.pem'
path: '{{ remote_tmp_dir }}/privatekeypw.pem'
size: '{{ default_rsa_key_size }}'
select_crypto_backend: '{{ select_crypto_backend }}'
backup: yes
@@ -255,7 +255,7 @@
- name: "({{ select_crypto_backend }}) Regenerate privatekey with passphrase"
openssl_privatekey:
path: '{{ output_dir }}/privatekeypw.pem'
path: '{{ remote_tmp_dir }}/privatekeypw.pem'
passphrase: hunter2
cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}"
size: '{{ default_rsa_key_size }}'
@@ -265,18 +265,18 @@
- name: "({{ select_crypto_backend }}) Create broken key"
copy:
dest: "{{ output_dir }}/broken"
dest: "{{ remote_tmp_dir }}/broken"
content: "broken"
- name: "({{ select_crypto_backend }}) Regenerate broken key"
openssl_privatekey:
path: '{{ output_dir }}/broken.pem'
path: '{{ remote_tmp_dir }}/broken.pem'
size: '{{ default_rsa_key_size }}'
select_crypto_backend: '{{ select_crypto_backend }}'
register: output_broken
- name: "({{ select_crypto_backend }}) Remove module"
openssl_privatekey:
path: '{{ output_dir }}/privatekeypw.pem'
path: '{{ remote_tmp_dir }}/privatekeypw.pem'
passphrase: hunter2
cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}"
size: '{{ default_rsa_key_size }}'
@@ -287,7 +287,7 @@
- name: "({{ select_crypto_backend }}) Remove module (idempotent)"
openssl_privatekey:
path: '{{ output_dir }}/privatekeypw.pem'
path: '{{ remote_tmp_dir }}/privatekeypw.pem'
passphrase: hunter2
cipher: "{{ 'aes256' if select_crypto_backend == 'pyopenssl' else 'auto' }}"
size: '{{ default_rsa_key_size }}'
@@ -298,19 +298,19 @@
- name: "({{ select_crypto_backend }}) Generate privatekey_mode (mode 0400)"
openssl_privatekey:
path: '{{ output_dir }}/privatekey_mode.pem'
path: '{{ remote_tmp_dir }}/privatekey_mode.pem'
mode: '0400'
size: '{{ default_rsa_key_size }}'
select_crypto_backend: '{{ select_crypto_backend }}'
register: privatekey_mode_1
- name: "({{ select_crypto_backend }}) Stat for privatekey_mode"
stat:
path: '{{ output_dir }}/privatekey_mode.pem'
path: '{{ remote_tmp_dir }}/privatekey_mode.pem'
register: privatekey_mode_1_stat
- name: "({{ select_crypto_backend }}) Generate privatekey_mode (mode 0400, idempotency)"
openssl_privatekey:
path: '{{ output_dir }}/privatekey_mode.pem'
path: '{{ remote_tmp_dir }}/privatekey_mode.pem'
mode: '0400'
size: '{{ default_rsa_key_size }}'
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -325,7 +325,7 @@
- name: "({{ select_crypto_backend }}) Generate privatekey_mode (mode 0400, force)"
openssl_privatekey:
path: '{{ output_dir }}/privatekey_mode.pem'
path: '{{ remote_tmp_dir }}/privatekey_mode.pem'
mode: '0400'
force: yes
size: '{{ default_rsa_key_size }}'
@@ -333,13 +333,13 @@
register: privatekey_mode_3
- name: "({{ select_crypto_backend }}) Stat for privatekey_mode"
stat:
path: '{{ output_dir }}/privatekey_mode.pem'
path: '{{ remote_tmp_dir }}/privatekey_mode.pem'
register: privatekey_mode_3_stat
- block:
- name: "({{ select_crypto_backend }}) Generate privatekey_fmt_1 - auto format"
openssl_privatekey:
path: '{{ output_dir }}/privatekey_fmt_1.pem'
path: '{{ remote_tmp_dir }}/privatekey_fmt_1.pem'
format: auto
size: '{{ default_rsa_key_size }}'
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -347,7 +347,7 @@
- name: "({{ select_crypto_backend }}) Generate privatekey_fmt_1 - auto format (idempotent)"
openssl_privatekey:
path: '{{ output_dir }}/privatekey_fmt_1.pem'
path: '{{ remote_tmp_dir }}/privatekey_fmt_1.pem'
format: auto
size: '{{ default_rsa_key_size }}'
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -355,7 +355,7 @@
- name: "({{ select_crypto_backend }}) Generate privatekey_fmt_1 - PKCS1 format"
openssl_privatekey:
path: '{{ output_dir }}/privatekey_fmt_1.pem'
path: '{{ remote_tmp_dir }}/privatekey_fmt_1.pem'
format: pkcs1
size: '{{ default_rsa_key_size }}'
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -363,7 +363,7 @@
- name: "({{ select_crypto_backend }}) Generate privatekey_fmt_1 - PKCS8 format"
openssl_privatekey:
path: '{{ output_dir }}/privatekey_fmt_1.pem'
path: '{{ remote_tmp_dir }}/privatekey_fmt_1.pem'
format: pkcs8
size: '{{ default_rsa_key_size }}'
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -371,7 +371,7 @@
- name: "({{ select_crypto_backend }}) Generate privatekey_fmt_1 - PKCS8 format (idempotent)"
openssl_privatekey:
path: '{{ output_dir }}/privatekey_fmt_1.pem'
path: '{{ remote_tmp_dir }}/privatekey_fmt_1.pem'
format: pkcs8
size: '{{ default_rsa_key_size }}'
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -379,7 +379,7 @@
- name: "({{ select_crypto_backend }}) Generate privatekey_fmt_1 - auto format (ignore)"
openssl_privatekey:
path: '{{ output_dir }}/privatekey_fmt_1.pem'
path: '{{ remote_tmp_dir }}/privatekey_fmt_1.pem'
format: auto_ignore
size: '{{ default_rsa_key_size }}'
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -387,7 +387,7 @@
- name: "({{ select_crypto_backend }}) Generate privatekey_fmt_1 - auto format (no ignore)"
openssl_privatekey:
path: '{{ output_dir }}/privatekey_fmt_1.pem'
path: '{{ remote_tmp_dir }}/privatekey_fmt_1.pem'
format: auto
size: '{{ default_rsa_key_size }}'
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -395,7 +395,7 @@
- name: "({{ select_crypto_backend }}) Generate privatekey_fmt_1 - raw format (fail)"
openssl_privatekey:
path: '{{ output_dir }}/privatekey_fmt_1.pem'
path: '{{ remote_tmp_dir }}/privatekey_fmt_1.pem'
format: raw
size: '{{ default_rsa_key_size }}'
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -404,13 +404,13 @@
- name: "({{ select_crypto_backend }}) Generate privatekey_fmt_1 - PKCS8 format (convert)"
openssl_privatekey_info:
path: '{{ output_dir }}/privatekey_fmt_1.pem'
path: '{{ remote_tmp_dir }}/privatekey_fmt_1.pem'
select_crypto_backend: '{{ select_crypto_backend }}'
register: privatekey_fmt_1_step_9_before
- name: "({{ select_crypto_backend }}) Generate privatekey_fmt_1 - PKCS8 format (convert)"
openssl_privatekey:
path: '{{ output_dir }}/privatekey_fmt_1.pem'
path: '{{ remote_tmp_dir }}/privatekey_fmt_1.pem'
format: pkcs8
format_mismatch: convert
size: '{{ default_rsa_key_size }}'
@@ -419,7 +419,7 @@
- name: "({{ select_crypto_backend }}) Generate privatekey_fmt_1 - PKCS8 format (convert)"
openssl_privatekey_info:
path: '{{ output_dir }}/privatekey_fmt_1.pem'
path: '{{ remote_tmp_dir }}/privatekey_fmt_1.pem'
select_crypto_backend: '{{ select_crypto_backend }}'
register: privatekey_fmt_1_step_9_after
@@ -428,7 +428,7 @@
- block:
- name: "({{ select_crypto_backend }}) Generate privatekey_fmt_2 - PKCS8 format"
openssl_privatekey:
path: '{{ output_dir }}/privatekey_fmt_2.pem'
path: '{{ remote_tmp_dir }}/privatekey_fmt_2.pem'
type: X448
format: pkcs8
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -437,7 +437,7 @@
- name: "({{ select_crypto_backend }}) Generate privatekey_fmt_2 - PKCS8 format (idempotent)"
openssl_privatekey:
path: '{{ output_dir }}/privatekey_fmt_2.pem'
path: '{{ remote_tmp_dir }}/privatekey_fmt_2.pem'
type: X448
format: pkcs8
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -446,7 +446,7 @@
- name: "({{ select_crypto_backend }}) Generate privatekey_fmt_2 - raw format"
openssl_privatekey:
path: '{{ output_dir }}/privatekey_fmt_2.pem'
path: '{{ remote_tmp_dir }}/privatekey_fmt_2.pem'
type: X448
format: raw
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -456,7 +456,7 @@
- name: "({{ select_crypto_backend }}) Read privatekey_fmt_2.pem"
slurp:
src: "{{ output_dir }}/privatekey_fmt_2.pem"
src: "{{ remote_tmp_dir }}/privatekey_fmt_2.pem"
ignore_errors: yes
register: content
@@ -468,7 +468,7 @@
- name: "({{ select_crypto_backend }}) Generate privatekey_fmt_2 - raw format (idempotent)"
openssl_privatekey:
path: '{{ output_dir }}/privatekey_fmt_2.pem'
path: '{{ remote_tmp_dir }}/privatekey_fmt_2.pem'
type: X448
format: raw
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -478,7 +478,7 @@
- name: "({{ select_crypto_backend }}) Read privatekey_fmt_2.pem"
slurp:
src: "{{ output_dir }}/privatekey_fmt_2.pem"
src: "{{ remote_tmp_dir }}/privatekey_fmt_2.pem"
ignore_errors: yes
register: content
@@ -490,7 +490,7 @@
- name: "({{ select_crypto_backend }}) Generate privatekey_fmt_2 - auto format (ignore)"
openssl_privatekey:
path: '{{ output_dir }}/privatekey_fmt_2.pem'
path: '{{ remote_tmp_dir }}/privatekey_fmt_2.pem'
type: X448
format: auto_ignore
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -500,7 +500,7 @@
- name: "({{ select_crypto_backend }}) Read privatekey_fmt_2.pem"
slurp:
src: "{{ output_dir }}/privatekey_fmt_2.pem"
src: "{{ remote_tmp_dir }}/privatekey_fmt_2.pem"
ignore_errors: yes
register: content
@@ -512,7 +512,7 @@
- name: "({{ select_crypto_backend }}) Generate privatekey_fmt_2 - auto format (no ignore)"
openssl_privatekey:
path: '{{ output_dir }}/privatekey_fmt_2.pem'
path: '{{ remote_tmp_dir }}/privatekey_fmt_2.pem'
type: X448
format: auto
select_crypto_backend: '{{ select_crypto_backend }}'
@@ -520,10 +520,16 @@
ignore_errors: yes
register: privatekey_fmt_2_step_6
- name: "({{ select_crypto_backend }}) Read private key"
slurp:
src: '{{ remote_tmp_dir }}/privatekey_fmt_2.pem'
register: slurp
when: privatekey_fmt_2_step_1 is not failed
- name: "({{ select_crypto_backend }}) Generate privatekey_fmt_2 - verify that returned content is not base64 encoded"
assert:
that:
- privatekey_fmt_2_step_6.privatekey == lookup('file', output_dir ~ '/privatekey_fmt_2.pem', rstrip=False)
- privatekey_fmt_2_step_6.privatekey == (slurp.content | b64decode)
when: privatekey_fmt_2_step_1 is not failed
when: 'select_crypto_backend == "cryptography" and cryptography_version.stdout is version("2.6", ">=")'
@@ -534,14 +540,14 @@
- name: "({{ select_crypto_backend }}) Regenerate - setup simple keys"
openssl_privatekey:
path: '{{ output_dir }}/regenerate-a-{{ item }}.pem'
path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}.pem'
type: RSA
size: '{{ default_rsa_key_size }}'
select_crypto_backend: '{{ select_crypto_backend }}'
loop: "{{ regenerate_values }}"
- name: "({{ select_crypto_backend }}) Regenerate - setup password protected keys"
openssl_privatekey:
path: '{{ output_dir }}/regenerate-b-{{ item }}.pem'
path: '{{ remote_tmp_dir }}/regenerate-b-{{ item }}.pem'
type: RSA
size: '{{ default_rsa_key_size }}'
passphrase: hunter2
@@ -550,14 +556,14 @@
loop: "{{ regenerate_values }}"
- name: "({{ select_crypto_backend }}) Regenerate - setup broken keys"
copy:
dest: '{{ output_dir }}/regenerate-c-{{ item }}.pem'
dest: '{{ remote_tmp_dir }}/regenerate-c-{{ item }}.pem'
content: 'broken key'
mode: '0700'
loop: "{{ regenerate_values }}"
- name: "({{ select_crypto_backend }}) Regenerate - modify broken keys (check mode)"
openssl_privatekey:
path: '{{ output_dir }}/regenerate-c-{{ item }}.pem'
path: '{{ remote_tmp_dir }}/regenerate-c-{{ item }}.pem'
type: RSA
size: '{{ default_rsa_key_size }}'
regenerate: '{{ item }}'
@@ -579,7 +585,7 @@
- name: "({{ select_crypto_backend }}) Regenerate - modify broken keys"
openssl_privatekey:
path: '{{ output_dir }}/regenerate-c-{{ item }}.pem'
path: '{{ remote_tmp_dir }}/regenerate-c-{{ item }}.pem'
type: RSA
size: '{{ default_rsa_key_size }}'
regenerate: '{{ item }}'
@@ -600,7 +606,7 @@
- name: "({{ select_crypto_backend }}) Regenerate - modify password protected keys (check mode)"
openssl_privatekey:
path: '{{ output_dir }}/regenerate-b-{{ item }}.pem'
path: '{{ remote_tmp_dir }}/regenerate-b-{{ item }}.pem'
type: RSA
size: '{{ default_rsa_key_size }}'
regenerate: '{{ item }}'
@@ -622,7 +628,7 @@
- name: "({{ select_crypto_backend }}) Regenerate - modify password protected keys"
openssl_privatekey:
path: '{{ output_dir }}/regenerate-b-{{ item }}.pem'
path: '{{ remote_tmp_dir }}/regenerate-b-{{ item }}.pem'
type: RSA
size: '{{ default_rsa_key_size }}'
regenerate: '{{ item }}'
@@ -643,7 +649,7 @@
- name: "({{ select_crypto_backend }}) Regenerate - not modify regular keys (check mode)"
openssl_privatekey:
path: '{{ output_dir }}/regenerate-a-{{ item }}.pem'
path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}.pem'
type: RSA
size: '{{ default_rsa_key_size }}'
regenerate: '{{ item }}'
@@ -661,7 +667,7 @@
- name: "({{ select_crypto_backend }}) Regenerate - not modify regular keys"
openssl_privatekey:
path: '{{ output_dir }}/regenerate-a-{{ item }}.pem'
path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}.pem'
type: RSA
size: '{{ default_rsa_key_size }}'
regenerate: '{{ item }}'
@@ -678,7 +684,7 @@
- name: "({{ select_crypto_backend }}) Regenerate - adjust key size (check mode)"
openssl_privatekey:
path: '{{ output_dir }}/regenerate-a-{{ item }}.pem'
path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}.pem'
type: RSA
size: '{{ default_rsa_key_size + 20 }}'
regenerate: '{{ item }}'
@@ -698,7 +704,7 @@
- name: "({{ select_crypto_backend }}) Regenerate - adjust key size"
openssl_privatekey:
path: '{{ output_dir }}/regenerate-a-{{ item }}.pem'
path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}.pem'
type: RSA
size: '{{ default_rsa_key_size + 20 }}'
regenerate: '{{ item }}'
@@ -717,15 +723,15 @@
- name: "({{ select_crypto_backend }}) Regenerate - redistribute keys"
copy:
src: '{{ output_dir }}/regenerate-a-always.pem'
dest: '{{ output_dir }}/regenerate-a-{{ item }}.pem'
src: '{{ remote_tmp_dir }}/regenerate-a-always.pem'
dest: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}.pem'
remote_src: true
loop: "{{ regenerate_values }}"
when: "item != 'always'"
- name: "({{ select_crypto_backend }}) Regenerate - adjust key type (check mode)"
openssl_privatekey:
path: '{{ output_dir }}/regenerate-a-{{ item }}.pem'
path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}.pem'
type: DSA
size: '{{ default_rsa_key_size }}'
regenerate: '{{ item }}'
@@ -745,7 +751,7 @@
- name: "({{ select_crypto_backend }}) Regenerate - adjust key type"
openssl_privatekey:
path: '{{ output_dir }}/regenerate-a-{{ item }}.pem'
path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}.pem'
type: DSA
size: '{{ default_rsa_key_size }}'
regenerate: '{{ item }}'
@@ -765,15 +771,15 @@
- block:
- name: "({{ select_crypto_backend }}) Regenerate - redistribute keys"
copy:
src: '{{ output_dir }}/regenerate-a-always.pem'
dest: '{{ output_dir }}/regenerate-a-{{ item }}.pem'
src: '{{ remote_tmp_dir }}/regenerate-a-always.pem'
dest: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}.pem'
remote_src: true
loop: "{{ regenerate_values }}"
when: "item != 'always'"
- name: "({{ select_crypto_backend }}) Regenerate - format mismatch (check mode)"
openssl_privatekey:
path: '{{ output_dir }}/regenerate-a-{{ item }}.pem'
path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}.pem'
type: DSA
size: '{{ default_rsa_key_size }}'
format: pkcs8
@@ -794,7 +800,7 @@
- name: "({{ select_crypto_backend }}) Regenerate - format mismatch"
openssl_privatekey:
path: '{{ output_dir }}/regenerate-a-{{ item }}.pem'
path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}.pem'
type: DSA
size: '{{ default_rsa_key_size }}'
format: pkcs8
@@ -814,15 +820,15 @@
- name: "({{ select_crypto_backend }}) Regenerate - redistribute keys"
copy:
src: '{{ output_dir }}/regenerate-a-always.pem'
dest: '{{ output_dir }}/regenerate-a-{{ item }}.pem'
src: '{{ remote_tmp_dir }}/regenerate-a-always.pem'
dest: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}.pem'
remote_src: true
loop: "{{ regenerate_values }}"
when: "item != 'always'"
- name: "({{ select_crypto_backend }}) Regenerate - convert format (check mode)"
openssl_privatekey:
path: '{{ output_dir }}/regenerate-a-{{ item }}.pem'
path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}.pem'
type: DSA
size: '{{ default_rsa_key_size }}'
format: pkcs1
@@ -842,7 +848,7 @@
- name: "({{ select_crypto_backend }}) Regenerate - convert format"
openssl_privatekey:
path: '{{ output_dir }}/regenerate-a-{{ item }}.pem'
path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}.pem'
type: DSA
size: '{{ default_rsa_key_size }}'
format: pkcs1

View File

@@ -33,7 +33,7 @@
- name: Run module with backend autodetection
openssl_privatekey:
path: '{{ output_dir }}/privatekey_backend_selection.pem'
path: '{{ remote_tmp_dir }}/privatekey_backend_selection.pem'
size: '{{ default_rsa_key_size }}'
- block:
@@ -51,12 +51,12 @@
- name: Remove output directory
file:
path: "{{ output_dir }}"
path: "{{ remote_tmp_dir }}"
state: absent
- name: Re-create output directory
file:
path: "{{ output_dir }}"
path: "{{ remote_tmp_dir }}"
state: directory
- block:
@@ -75,7 +75,7 @@
block:
- name: "Fingerprint comparison: pyOpenSSL"
openssl_privatekey:
path: '{{ output_dir }}/fingerprint-{{ item }}.pem'
path: '{{ remote_tmp_dir }}/fingerprint-{{ item }}.pem'
type: "{{ item }}"
size: '{{ default_rsa_key_size }}'
select_crypto_backend: pyopenssl
@@ -86,7 +86,7 @@
- name: "Fingerprint comparison: cryptography"
openssl_privatekey:
path: '{{ output_dir }}/fingerprint-{{ item }}.pem'
path: '{{ remote_tmp_dir }}/fingerprint-{{ item }}.pem'
type: "{{ item }}"
size: '{{ default_rsa_key_size }}'
select_crypto_backend: cryptography

View File

@@ -2,6 +2,11 @@
- set_fact:
system_potentially_has_no_algorithm_support: "{{ ansible_os_family == 'FreeBSD' }}"
- name: "({{ select_crypto_backend }}) Read private key"
slurp:
src: '{{ remote_tmp_dir }}/privatekey1.pem'
register: slurp
- name: "({{ select_crypto_backend }}) Validate privatekey1 idempotency and content returned"
assert:
that:
@@ -9,12 +14,12 @@
- privatekey1 is changed
- privatekey1_idempotence_check is not changed
- privatekey1_idempotence is not changed
- privatekey1.privatekey == lookup('file', output_dir ~ '/privatekey1.pem', rstrip=False)
- privatekey1.privatekey == (slurp.content | b64decode)
- privatekey1.privatekey == privatekey1_idempotence.privatekey
- name: "({{ select_crypto_backend }}) Validate privatekey1 (test - RSA key with size 4096 bits)"
shell: "{{ openssl_binary }} rsa -noout -text -in {{ output_dir }}/privatekey1.pem | grep Private | sed 's/\\(RSA *\\)*Private-Key: (\\(.*\\) bit.*)/\\2/'"
shell: "{{ openssl_binary }} rsa -noout -text -in {{ remote_tmp_dir }}/privatekey1.pem | grep Private | sed 's/\\(RSA *\\)*Private-Key: (\\(.*\\) bit.*)/\\2/'"
register: privatekey1
- name: "({{ select_crypto_backend }}) Validate privatekey1 (assert - RSA key with size 4096 bits)"
@@ -24,7 +29,7 @@
- name: "({{ select_crypto_backend }}) Validate privatekey2 (test - RSA key with size 2048 bits)"
shell: "{{ openssl_binary }} rsa -noout -text -in {{ output_dir }}/privatekey2.pem | grep Private | sed 's/\\(RSA *\\)*Private-Key: (\\(.*\\) bit.*)/\\2/'"
shell: "{{ openssl_binary }} rsa -noout -text -in {{ remote_tmp_dir }}/privatekey2.pem | grep Private | sed 's/\\(RSA *\\)*Private-Key: (\\(.*\\) bit.*)/\\2/'"
register: privatekey2
- name: "({{ select_crypto_backend }}) Validate privatekey2 (assert - RSA key with size 2048 bits)"
@@ -34,7 +39,7 @@
- name: "({{ select_crypto_backend }}) Validate privatekey3 (test - DSA key with size 3072 bits)"
shell: "{{ openssl_binary }} dsa -noout -text -in {{ output_dir }}/privatekey3.pem | grep Private | sed 's/\\(RSA *\\)*Private-Key: (\\(.*\\) bit.*)/\\2/'"
shell: "{{ openssl_binary }} dsa -noout -text -in {{ remote_tmp_dir }}/privatekey3.pem | grep Private | sed 's/\\(RSA *\\)*Private-Key: (\\(.*\\) bit.*)/\\2/'"
register: privatekey3
- name: Validate privatekey3 (assert - DSA key with size 3072 bits)
@@ -45,7 +50,7 @@
- name: "({{ select_crypto_backend }}) Validate privatekey4 (test - Ensure key has been removed)"
stat:
path: '{{ output_dir }}/privatekey4.pem'
path: '{{ remote_tmp_dir }}/privatekey4.pem'
register: privatekey4
- name: "({{ select_crypto_backend }}) Validate privatekey4 (assert - Ensure key has been removed)"
@@ -62,7 +67,7 @@
- name: "({{ select_crypto_backend }}) Validate privatekey5 (test - Passphrase protected key + idempotence)"
shell: "{{ openssl_binary }} rsa -noout -text -in {{ output_dir }}/privatekey5.pem -passin pass:ansible | grep Private | sed 's/\\(RSA *\\)*Private-Key: (\\(.*\\) bit.*)/\\2/'"
shell: "{{ openssl_binary }} rsa -noout -text -in {{ remote_tmp_dir }}/privatekey5.pem -passin pass:ansible | grep Private | sed 's/\\(RSA *\\)*Private-Key: (\\(.*\\) bit.*)/\\2/'"
register: privatekey5
# Current version of OS/X that runs in the CI (10.11) does not have an up to date version of the OpenSSL library
# leading to this test to fail when run in the CI. However, this test has been run for 10.12 and has returned succesfully.
@@ -81,7 +86,7 @@
- name: "({{ select_crypto_backend }}) Validate privatekey6 (test - Passphrase protected key with non ascii character)"
shell: "{{ openssl_binary }} rsa -noout -text -in {{ output_dir }}/privatekey6.pem -passin pass:ànsïblé | grep Private | sed 's/\\(RSA *\\)*Private-Key: (\\(.*\\) bit.*)/\\2/'"
shell: "{{ openssl_binary }} rsa -noout -text -in {{ remote_tmp_dir }}/privatekey6.pem -passin pass:ànsïblé | grep Private | sed 's/\\(RSA *\\)*Private-Key: (\\(.*\\) bit.*)/\\2/'"
register: privatekey6
when: openssl_version.stdout is version('0.9.8zh', '>=')
@@ -92,7 +97,7 @@
when: openssl_version.stdout is version('0.9.8zh', '>=')
- name: "({{ select_crypto_backend }}) Validate ECC generation (dump with OpenSSL)"
shell: "{{ openssl_binary }} ec -in {{ output_dir }}/privatekey-{{ item.item.curve }}.pem -noout -text | grep 'ASN1 OID: ' | sed 's/ASN1 OID: \\([^ ]*\\)/\\1/'"
shell: "{{ openssl_binary }} ec -in {{ remote_tmp_dir }}/privatekey-{{ item.item.curve }}.pem -noout -text | grep 'ASN1 OID: ' | sed 's/ASN1 OID: \\([^ ]*\\)/\\1/'"
loop: "{{ privatekey_ecc_generate.results }}"
register: privatekey_ecc_dump
when: openssl_version.stdout is version('0.9.8zh', '>=') and 'skip_reason' not in item

View File

@@ -1,2 +1,3 @@
shippable/cloud/group1
shippable/posix/group1
destructive

View File

@@ -1,3 +1,5 @@
dependencies:
- setup_openssl
- setup_pyopenssl
- setup_remote_tmp_dir
- prepare_jinja2_compat

Some files were not shown because too many files have changed in this diff Show More