Initial commit

This commit is contained in:
Ansible Core Team
2020-03-09 13:11:34 +00:00
commit a9f45b4d5b
249 changed files with 37903 additions and 0 deletions

1
tests/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
output/

View File

@@ -0,0 +1,2 @@
shippable/cloud/group1
cloud/acme

View File

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

View File

@@ -0,0 +1,244 @@
- name: Generate account key
command: openssl ecparam -name prime256v1 -genkey -out {{ output_dir }}/accountkey.pem
- name: Parse account key (to ease debugging some test failures)
command: openssl ec -in {{ output_dir }}/accountkey.pem -noout -text
- name: Do not try to create account
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
state: present
allow_creation: no
ignore_errors: yes
register: account_not_created
- name: Create it now (check mode, diff)
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
state: present
allow_creation: yes
terms_agreed: yes
contact:
- mailto:example@example.org
check_mode: yes
diff: yes
register: account_created_check
- name: Create it now
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
state: present
allow_creation: yes
terms_agreed: yes
contact:
- mailto:example@example.org
register: account_created
- name: Create it now (idempotent)
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
state: present
allow_creation: yes
terms_agreed: yes
contact:
- mailto:example@example.org
register: account_created_idempotent
- name: Change email address (check mode, diff)
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_content: "{{ lookup('file', output_dir ~ '/accountkey.pem') }}"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
state: present
# allow_creation: no
contact:
- mailto:example@example.com
check_mode: yes
diff: yes
register: account_modified_check
- name: Change email address
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_content: "{{ lookup('file', output_dir ~ '/accountkey.pem') }}"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
state: present
# allow_creation: no
contact:
- mailto:example@example.com
register: account_modified
- name: Change email address (idempotent)
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
account_uri: "{{ account_created.account_uri }}"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
state: present
# allow_creation: no
contact:
- mailto:example@example.com
register: account_modified_idempotent
- name: Cannot access account with wrong URI
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
account_uri: "{{ account_created.account_uri ~ '12345thisdoesnotexist' }}"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
state: present
contact: []
ignore_errors: yes
register: account_modified_wrong_uri
- name: Clear contact email addresses (check mode, diff)
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
state: present
# allow_creation: no
contact: []
check_mode: yes
diff: yes
register: account_modified_2_check
- name: Clear contact email addresses
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
state: present
# allow_creation: no
contact: []
register: account_modified_2
- name: Clear contact email addresses (idempotent)
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
state: present
# allow_creation: no
contact: []
register: account_modified_2_idempotent
- name: Generate new account key
command: openssl ecparam -name secp384r1 -genkey -out {{ output_dir }}/accountkey2.pem
- name: Parse account key (to ease debugging some test failures)
command: openssl ec -in {{ output_dir }}/accountkey2.pem -noout -text
- name: Change account key (check mode, diff)
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
new_account_key_src: "{{ output_dir }}/accountkey2.pem"
state: changed_key
contact:
- mailto:example@example.com
check_mode: yes
diff: yes
register: account_change_key_check
- name: Change account key
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
new_account_key_src: "{{ output_dir }}/accountkey2.pem"
state: changed_key
contact:
- mailto:example@example.com
register: account_change_key
- name: Deactivate account (check mode, diff)
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey2.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
state: absent
check_mode: yes
diff: yes
register: account_deactivate_check
- name: Deactivate account
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey2.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
state: absent
register: account_deactivate
- name: Deactivate account (idempotent)
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey2.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
state: absent
register: account_deactivate_idempotent
- name: Do not try to create account II
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey2.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
state: present
allow_creation: no
ignore_errors: yes
register: account_not_created_2
- name: Do not try to create account III
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
state: present
allow_creation: no
ignore_errors: yes
register: account_not_created_3

View File

@@ -0,0 +1,31 @@
---
- block:
- name: Running tests with OpenSSL backend
include_tasks: impl.yml
vars:
select_crypto_backend: openssl
- import_tasks: ../tests/validate.yml
# Old 0.9.8 versions have insufficient CLI support for signing with EC keys
when: openssl_version.stdout is version('1.0.0', '>=')
- name: Remove output directory
file:
path: "{{ output_dir }}"
state: absent
- name: Re-create output directory
file:
path: "{{ output_dir }}"
state: directory
- block:
- name: Running tests with cryptography backend
include_tasks: impl.yml
vars:
select_crypto_backend: cryptography
- import_tasks: ../tests/validate.yml
when: cryptography_version.stdout is version('1.5', '>=')

View File

@@ -0,0 +1,129 @@
---
- name: Validate that account wasn't created in the first step
assert:
that:
- account_not_created is failed
- account_not_created.msg == 'Account does not exist or is deactivated.'
- name: Validate that account was created in the second step (check mode)
assert:
that:
- account_created_check is changed
- account_created_check.account_uri is none
- "'diff' in account_created_check"
- "account_created_check.diff.before == {}"
- "'after' in account_created_check.diff"
- account_created_check.diff.after.contact | length == 1
- account_created_check.diff.after.contact[0] == 'mailto:example@example.org'
- name: Validate that account was created in the second step
assert:
that:
- account_created is changed
- account_created.account_uri is not none
- name: Validate that account was created in the second step (idempotency)
assert:
that:
- account_created_idempotent is not changed
- account_created_idempotent.account_uri is not none
- name: Validate that email address was changed (check mode)
assert:
that:
- account_modified_check is changed
- account_modified_check.account_uri is not none
- "'diff' in account_modified_check"
- account_modified_check.diff.before.contact | length == 1
- account_modified_check.diff.before.contact[0] == 'mailto:example@example.org'
- account_modified_check.diff.after.contact | length == 1
- account_modified_check.diff.after.contact[0] == 'mailto:example@example.com'
- name: Validate that email address was changed
assert:
that:
- account_modified is changed
- account_modified.account_uri is not none
- name: Validate that email address was not changed a second time (idempotency)
assert:
that:
- account_modified_idempotent is not changed
- account_modified_idempotent.account_uri is not none
- name: Make sure that with the wrong account URI, the account cannot be changed
assert:
that:
- account_modified_wrong_uri is failed
- name: Validate that email address was cleared (check mode)
assert:
that:
- account_modified_2_check is changed
- account_modified_2_check.account_uri is not none
- "'diff' in account_modified_2_check"
- account_modified_2_check.diff.before.contact | length == 1
- account_modified_2_check.diff.before.contact[0] == 'mailto:example@example.com'
- account_modified_2_check.diff.after.contact | length == 0
- name: Validate that email address was cleared
assert:
that:
- account_modified_2 is changed
- account_modified_2.account_uri is not none
- name: Validate that email address was not cleared a second time (idempotency)
assert:
that:
- account_modified_2_idempotent is not changed
- account_modified_2_idempotent.account_uri is not none
- name: Validate that the account key was changed (check mode)
assert:
that:
- account_change_key_check is changed
- account_change_key_check.account_uri is not none
- "'diff' in account_change_key_check"
- account_change_key_check.diff.before.public_account_key != account_change_key_check.diff.after.public_account_key
- name: Validate that the account key was changed
assert:
that:
- account_change_key is changed
- account_change_key.account_uri is not none
- name: Validate that the account was deactivated (check mode)
assert:
that:
- account_deactivate_check is changed
- account_deactivate_check.account_uri is not none
- "'diff' in account_deactivate_check"
- "account_deactivate_check.diff.before != {}"
- "account_deactivate_check.diff.after == {}"
- name: Validate that the account was deactivated
assert:
that:
- account_deactivate is changed
- account_deactivate.account_uri is not none
- name: Validate that the account was really deactivated (idempotency)
assert:
that:
- account_deactivate_idempotent is not changed
# The next condition should be true for all conforming ACME servers.
# In case it is not true, it could be both an error in acme_account
# and in the ACME server.
- account_deactivate_idempotent.account_uri is none
- name: Validate that the account is gone (new account key)
assert:
that:
- account_not_created_2 is failed
- account_not_created_2.msg == 'Account does not exist or is deactivated.'
- name: Validate that the account is gone (old account key)
assert:
that:
- account_not_created_3 is failed
- account_not_created_3.msg == 'Account does not exist or is deactivated.'

View File

@@ -0,0 +1,2 @@
shippable/cloud/group1
cloud/acme

View File

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

View File

@@ -0,0 +1,82 @@
---
- name: Generate account key
command: openssl ecparam -name prime256v1 -genkey -out {{ output_dir }}/accountkey.pem
- name: Generate second account key
command: openssl ecparam -name prime256v1 -genkey -out {{ output_dir }}/accountkey2.pem
- name: Parse account key (to ease debugging some test failures)
command: openssl ec -in {{ output_dir }}/accountkey.pem -noout -text
- name: Check that account does not exist
acme_account_info:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
register: account_not_created
- name: Create it now
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
state: present
allow_creation: yes
terms_agreed: yes
contact:
- mailto:example@example.org
- name: Check that account exists
acme_account_info:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
register: account_created
- name: Clear email address
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_content: "{{ lookup('file', output_dir ~ '/accountkey.pem') }}"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
state: present
allow_creation: no
contact: []
- name: Check that account was modified
acme_account_info:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
account_uri: "{{ account_created.account_uri }}"
register: account_modified
- name: Check with wrong account URI
acme_account_info:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
account_uri: "{{ account_created.account_uri }}test1234doesnotexists"
register: account_not_exist
- name: Check with wrong account key
acme_account_info:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_src: "{{ output_dir }}/accountkey2.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
account_uri: "{{ account_created.account_uri }}"
ignore_errors: yes
register: account_wrong_key

View File

@@ -0,0 +1,31 @@
---
- block:
- name: Running tests with OpenSSL backend
include_tasks: impl.yml
vars:
select_crypto_backend: openssl
- import_tasks: ../tests/validate.yml
# Old 0.9.8 versions have insufficient CLI support for signing with EC keys
when: openssl_version.stdout is version('1.0.0', '>=')
- name: Remove output directory
file:
path: "{{ output_dir }}"
state: absent
- name: Re-create output directory
file:
path: "{{ output_dir }}"
state: directory
- block:
- name: Running tests with cryptography backend
include_tasks: impl.yml
vars:
select_crypto_backend: cryptography
- import_tasks: ../tests/validate.yml
when: cryptography_version.stdout is version('1.5', '>=')

View File

@@ -0,0 +1,40 @@
---
- name: Validate that account wasn't there
assert:
that:
- not account_not_created.exists
- account_not_created.account_uri is none
- "'account' not in account_not_created"
- name: Validate that account was created
assert:
that:
- account_created.exists
- account_created.account_uri is not none
- "'account' in account_created"
- "'contact' in account_created.account"
- "'public_account_key' in account_created.account"
- account_created.account.contact | length == 1
- "account_created.account.contact[0] == 'mailto:example@example.org'"
- name: Validate that account email was removed
assert:
that:
- account_modified.exists
- account_modified.account_uri is not none
- "'account' in account_modified"
- "'contact' in account_modified.account"
- "'public_account_key' in account_modified.account"
- account_modified.account.contact | length == 0
- name: Validate that account does not exist with wrong account URI
assert:
that:
- not account_not_exist.exists
- account_not_exist.account_uri is none
- "'account' not in account_not_exist"
- name: Validate that account cannot be accessed with wrong key
assert:
that:
- account_wrong_key is failed

View File

@@ -0,0 +1,2 @@
shippable/cloud/group1
cloud/acme

View File

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

View File

@@ -0,0 +1,451 @@
---
## SET UP ACCOUNT KEYS ########################################################################
- name: Create ECC256 account key
command: openssl ecparam -name prime256v1 -genkey -out {{ output_dir }}/account-ec256.pem
- name: Create ECC384 account key
command: openssl ecparam -name secp384r1 -genkey -out {{ output_dir }}/account-ec384.pem
- name: Create RSA-2048 account key
command: openssl genrsa -out {{ output_dir }}/account-rsa2048.pem 2048
## SET UP ACCOUNTS ############################################################################
- name: Make sure ECC256 account hasn't been created yet
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
account_key_src: "{{ output_dir }}/account-ec256.pem"
state: absent
- 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') }}"
state: present
allow_creation: yes
terms_agreed: yes
contact:
- mailto:example@example.org
- mailto:example@example.com
- name: Create RSA-2048 account
acme_account:
select_crypto_backend: "{{ select_crypto_backend }}"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
account_key_src: "{{ output_dir }}/account-rsa2048.pem"
state: present
allow_creation: yes
terms_agreed: yes
contact: []
## OBTAIN CERTIFICATES ########################################################################
- name: Obtain cert 1
include_tasks: obtain-cert.yml
vars:
certgen_title: Certificate 1
certificate_name: cert-1
key_type: rsa
rsa_bits: 2048
subject_alt_name: "DNS:example.com"
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"
retrieve_all_alternates: yes
acme_expected_root_number: 1
select_chain:
- test_certificates: last
issuer: "{{ acme_roots[1].subject }}"
- name: Store obtain results for cert 1
set_fact:
cert_1_obtain_results: "{{ certificate_obtain_result }}"
cert_1_alternate: "{{ 1 if select_crypto_backend == 'cryptography' else 0 }}"
- name: Obtain cert 2
include_tasks: obtain-cert.yml
vars:
certgen_title: Certificate 2
certificate_name: cert-2
key_type: ec256
subject_alt_name: "DNS:*.example.com,DNS:example.com"
subject_alt_name_critical: yes
account_key: account-ec384
challenge: dns-01
modify_account: no
deactivate_authzs: yes
force: no
remaining_days: 10
terms_agreed: no
account_email: ""
acme_expected_root_number: 0
retrieve_all_alternates: yes
select_chain:
# All intermediates have the same subject, 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: all
subject: "{{ acme_intermediates[0].subject }}"
- test_certificates: all
issuer: "{{ acme_roots[2].subject }}"
- name: Store obtain results for cert 2
set_fact:
cert_2_obtain_results: "{{ certificate_obtain_result }}"
cert_2_alternate: "{{ 0 if select_crypto_backend == 'cryptography' else 0 }}"
- name: Obtain cert 3
include_tasks: obtain-cert.yml
vars:
certgen_title: Certificate 3
certificate_name: cert-3
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-rsa2048.pem') }}"
challenge: dns-01
modify_account: no
deactivate_authzs: no
force: no
remaining_days: 10
terms_agreed: no
account_email: ""
acme_expected_root_number: 0
retrieve_all_alternates: yes
select_chain:
- test_certificates: last
subject: "{{ acme_roots[1].subject }}"
- name: Store obtain results for cert 3
set_fact:
cert_3_obtain_results: "{{ certificate_obtain_result }}"
cert_3_alternate: "{{ 0 if select_crypto_backend == 'cryptography' else 0 }}"
- name: Obtain cert 4
include_tasks: obtain-cert.yml
vars:
certgen_title: Certificate 4
certificate_name: cert-4
key_type: rsa
rsa_bits: 2048
subject_alt_name: "DNS:example.com,DNS:t1.example.com,DNS:test.t2.example.com,DNS:example.org,DNS:test.example.org"
subject_alt_name_critical: no
account_key: account-rsa2048
challenge: http-01
modify_account: no
deactivate_authzs: yes
force: yes
remaining_days: 10
terms_agreed: no
account_email: ""
acme_expected_root_number: 2
select_chain:
- test_certificates: last
issuer: "{{ acme_roots[2].subject }}"
- test_certificates: last
issuer: "{{ acme_roots[1].subject }}"
- name: Store obtain results for cert 4
set_fact:
cert_4_obtain_results: "{{ certificate_obtain_result }}"
cert_4_alternate: "{{ 2 if select_crypto_backend == 'cryptography' else 0 }}"
- name: Obtain cert 5
include_tasks: obtain-cert.yml
vars:
certgen_title: Certificate 5, Iteration 1/4
certificate_name: cert-5
key_type: ec521
subject_alt_name: "DNS:t2.example.com"
subject_alt_name_critical: no
account_key: account-ec384
challenge: http-01
modify_account: no
deactivate_authzs: yes
force: yes
remaining_days: 10
terms_agreed: no
account_email: ""
- name: Store obtain results for cert 5a
set_fact:
cert_5a_obtain_results: "{{ certificate_obtain_result }}"
cert_5_alternate: "{{ 0 if select_crypto_backend == 'cryptography' else 0 }}"
- name: Obtain cert 5 (should not, since already there and valid for more than 10 days)
include_tasks: obtain-cert.yml
vars:
certgen_title: Certificate 5, Iteration 2/4
certificate_name: cert-5
key_type: ec521
subject_alt_name: "DNS:t2.example.com"
subject_alt_name_critical: no
account_key: account-ec384
challenge: http-01
modify_account: no
deactivate_authzs: yes
force: no
remaining_days: 10
terms_agreed: no
account_email: ""
- name: Store obtain results for cert 5b
set_fact:
cert_5_recreate_1: "{{ challenge_data is changed }}"
- name: Obtain cert 5 (should again by less days)
include_tasks: obtain-cert.yml
vars:
certgen_title: Certificate 5, Iteration 3/4
certificate_name: cert-5
key_type: ec521
subject_alt_name: "DNS:t2.example.com"
subject_alt_name_critical: no
account_key: account-ec384
challenge: http-01
modify_account: no
deactivate_authzs: yes
force: yes
remaining_days: 1000
terms_agreed: no
account_email: ""
- name: Store obtain results for cert 5c
set_fact:
cert_5_recreate_2: "{{ challenge_data is changed }}"
cert_5c_obtain_results: "{{ certificate_obtain_result }}"
- name: Obtain cert 5 (should again by force)
include_tasks: obtain-cert.yml
vars:
certgen_title: Certificate 5, Iteration 4/4
certificate_name: cert-5
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') }}"
challenge: http-01
modify_account: no
deactivate_authzs: yes
force: yes
remaining_days: 10
terms_agreed: no
account_email: ""
- name: Store obtain results for cert 5d
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: 2048
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: last
subject_key_identifier: "{{ acme_intermediates[0].subject_key_identifier }}"
- test_certificates: last
issuer: "{{ acme_roots[1].subject }}"
- 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: 2048
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 }}"
- 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: 2048
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"
- 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 }}"
## DISSECT CERTIFICATES #######################################################################
# Make sure certificates are valid. Root certificate for Pebble equals the chain certificate.
- name: Verifying cert 1
command: openssl verify -CAfile "{{ output_dir }}/cert-1-root.pem" -untrusted "{{ output_dir }}/cert-1-chain.pem" "{{ output_dir }}/cert-1.pem"
ignore_errors: yes
register: cert_1_valid
- name: Verifying cert 2
command: openssl verify -CAfile "{{ output_dir }}/cert-2-root.pem" -untrusted "{{ output_dir }}/cert-2-chain.pem" "{{ output_dir }}/cert-2.pem"
ignore_errors: yes
register: cert_2_valid
- name: Verifying cert 3
command: openssl verify -CAfile "{{ output_dir }}/cert-3-root.pem" -untrusted "{{ output_dir }}/cert-3-chain.pem" "{{ output_dir }}/cert-3.pem"
ignore_errors: yes
register: cert_3_valid
- name: Verifying cert 4
command: openssl verify -CAfile "{{ output_dir }}/cert-4-root.pem" -untrusted "{{ output_dir }}/cert-4-chain.pem" "{{ output_dir }}/cert-4.pem"
ignore_errors: yes
register: cert_4_valid
- name: Verifying cert 5
command: openssl verify -CAfile "{{ output_dir }}/cert-5-root.pem" -untrusted "{{ output_dir }}/cert-5-chain.pem" "{{ output_dir }}/cert-5.pem"
ignore_errors: yes
register: cert_5_valid
- name: Verifying cert 6
command: openssl verify -CAfile "{{ output_dir }}/cert-6-root.pem" -untrusted "{{ output_dir }}/cert-6-chain.pem" "{{ output_dir }}/cert-6.pem"
ignore_errors: yes
register: cert_6_valid
- name: Verifying cert 7
command: openssl verify -CAfile "{{ output_dir }}/cert-7-root.pem" -untrusted "{{ output_dir }}/cert-7-chain.pem" "{{ output_dir }}/cert-7.pem"
ignore_errors: yes
register: cert_7_valid
- name: Verifying cert 8
command: openssl verify -CAfile "{{ output_dir }}/cert-8-root.pem" -untrusted "{{ output_dir }}/cert-8-chain.pem" "{{ output_dir }}/cert-8.pem"
ignore_errors: yes
register: cert_8_valid
# Dump certificate info
- name: Dumping cert 1
command: openssl x509 -in "{{ output_dir }}/cert-1.pem" -noout -text
register: cert_1_text
- name: Dumping cert 2
command: openssl x509 -in "{{ output_dir }}/cert-2.pem" -noout -text
register: cert_2_text
- name: Dumping cert 3
command: openssl x509 -in "{{ output_dir }}/cert-3.pem" -noout -text
register: cert_3_text
- name: Dumping cert 4
command: openssl x509 -in "{{ output_dir }}/cert-4.pem" -noout -text
register: cert_4_text
- name: Dumping cert 5
command: openssl x509 -in "{{ output_dir }}/cert-5.pem" -noout -text
register: cert_5_text
- name: Dumping cert 6
command: openssl x509 -in "{{ output_dir }}/cert-6.pem" -noout -text
register: cert_6_text
- name: Dumping cert 7
command: openssl x509 -in "{{ output_dir }}/cert-7.pem" -noout -text
register: cert_7_text
- name: Dumping cert 8
command: openssl x509 -in "{{ output_dir }}/cert-8.pem" -noout -text
register: cert_8_text
# Dump certificate info
- name: Dumping cert 1
openssl_certificate_info:
path: "{{ output_dir }}/cert-1.pem"
register: cert_1_info
- name: Dumping cert 2
openssl_certificate_info:
path: "{{ output_dir }}/cert-2.pem"
register: cert_2_info
- name: Dumping cert 3
openssl_certificate_info:
path: "{{ output_dir }}/cert-3.pem"
register: cert_3_info
- name: Dumping cert 4
openssl_certificate_info:
path: "{{ output_dir }}/cert-4.pem"
register: cert_4_info
- name: Dumping cert 5
openssl_certificate_info:
path: "{{ output_dir }}/cert-5.pem"
register: cert_5_info
- name: Dumping cert 6
openssl_certificate_info:
path: "{{ output_dir }}/cert-6.pem"
register: cert_6_info
- name: Dumping cert 7
openssl_certificate_info:
path: "{{ output_dir }}/cert-7.pem"
register: cert_7_info
- name: Dumping cert 8
openssl_certificate_info:
path: "{{ output_dir }}/cert-8.pem"
register: cert_8_info
## 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"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
retrieve_orders: ignore
register: account_orders_not
- 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"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
retrieve_orders: url_list
register: account_orders_urls
- 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"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
retrieve_orders: url_list
register: account_orders_urls2
- 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"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
retrieve_orders: object_list
register: account_orders_full
- 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"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
retrieve_orders: object_list
register: account_orders_full2

View File

@@ -0,0 +1,102 @@
---
- block:
- 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"
loop: "{{ query('nested', types, root_numbers) }}"
- name: Analyze root certificates
openssl_certificate_info:
path: "{{ output_dir }}/acme-root-{{ item }}.pem"
loop: "{{ root_numbers }}"
register: acme_roots
- name: Analyze intermediate certificates
openssl_certificate_info:
path: "{{ output_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
- 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_intermediates: "{{ acme_intermediates_tmp.results | map(attribute='ansible_facts.x__') | list }}"
acme_intermediate_certs: "{{ acme_intermediates_tmp.results | map(attribute='ansible_facts.y__') | list }}"
vars:
types:
- root
- intermediate
root_numbers:
# The number 3 comes from here: https://github.com/ansible/acme-test-container/blob/master/run.sh#L12
- 0
- 1
- 2
- 3
interesting_keys:
- authority_key_identifier
- subject_key_identifier
- issuer
- subject
#- serial_number
#- public_key_fingerprints
- name: ACME root certificate info
debug:
var: acme_roots
#- name: ACME root certificates as PEM
# debug:
# var: acme_root_certs
- name: ACME intermediate certificate info
debug:
var: acme_intermediates
#- name: ACME intermediate certificates as PEM
# debug:
# var: acme_intermediate_certs
- block:
- name: Running tests with OpenSSL backend
include_tasks: impl.yml
vars:
select_crypto_backend: openssl
- import_tasks: ../tests/validate.yml
# Old 0.9.8 versions have insufficient CLI support for signing with EC keys
when: openssl_version.stdout is version('1.0.0', '>=')
- name: Remove output directory
file:
path: "{{ output_dir }}"
state: absent
- name: Re-create output directory
file:
path: "{{ output_dir }}"
state: directory
- block:
- name: Running tests with cryptography backend
include_tasks: impl.yml
vars:
select_crypto_backend: cryptography
- import_tasks: ../tests/validate.yml
when: cryptography_version.stdout is version('1.5', '>=')

View File

@@ -0,0 +1 @@
../../setup_acme/tasks/obtain-cert.yml

View File

@@ -0,0 +1,144 @@
---
- name: Check that certificate 1 is valid
assert:
that:
- cert_1_valid is not failed
- name: Check that certificate 1 contains correct SANs
assert:
that:
- "'DNS:example.com' in cert_1_text.stdout"
- name: Check that certificate 1 retrieval got all chains
assert:
that:
- "'all_chains' in cert_1_obtain_results"
- "cert_1_obtain_results.all_chains | length > 1"
- "'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"
- name: Check that certificate 2 is valid
assert:
that:
- cert_2_valid is not failed
- name: Check that certificate 2 contains correct SANs
assert:
that:
- "'DNS:*.example.com' in cert_2_text.stdout"
- "'DNS:example.com' in cert_2_text.stdout"
- name: Check that certificate 1 retrieval got all chains
assert:
that:
- "'all_chains' in cert_2_obtain_results"
- "cert_2_obtain_results.all_chains | length > 1"
- "'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"
- name: Check that certificate 3 is valid
assert:
that:
- cert_3_valid is not failed
- name: Check that certificate 3 contains correct SANs
assert:
that:
- "'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: Check that certificate 1 retrieval got all chains
assert:
that:
- "'all_chains' in cert_3_obtain_results"
- "cert_3_obtain_results.all_chains | length > 1"
- "'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"
- name: Check that certificate 4 is valid
assert:
that:
- cert_4_valid is not failed
- name: Check that certificate 4 contains correct SANs
assert:
that:
- "'DNS:example.com' in cert_4_text.stdout"
- "'DNS:t1.example.com' in cert_4_text.stdout"
- "'DNS:test.t2.example.com' in cert_4_text.stdout"
- "'DNS:example.org' in cert_4_text.stdout"
- "'DNS:test.example.org' in cert_4_text.stdout"
- name: Check that certificate 4 retrieval did not get all chains
assert:
that:
- "'all_chains' not in cert_4_obtain_results"
- name: Check that certificate 5 is valid
assert:
that:
- cert_5_valid is not failed
- name: Check that certificate 5 contains correct SANs
assert:
that:
- "'DNS:t2.example.com' in cert_5_text.stdout"
- name: Check that certificate 5 was not recreated on the first try
assert:
that:
- cert_5_recreate_1 == False
- name: Check that certificate 5 was recreated on the second try
assert:
that:
- cert_5_recreate_2 == True
- name: Check that certificate 5 was recreated on the third try
assert:
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"
- name: Validate that orders were not retrieved
assert:
that:
- "'account' in account_orders_not"
- "'orders' not in account_orders_not"
- name: Validate that orders were retrieved as list of URLs (1/2)
assert:
that:
- "'account' in account_orders_urls"
- "'orders' in account_orders_urls"
- "account_orders_urls.orders[0] is string"
- name: Validate that orders were retrieved as list of URLs (2/2)
assert:
that:
- "'account' in account_orders_urls2"
- "'orders' in account_orders_urls2"
- "account_orders_urls2.orders[0] is string"
- name: Validate that orders were retrieved as list of objects (1/2)
assert:
that:
- "'account' in account_orders_full"
- "'orders' in account_orders_full"
- "account_orders_full.orders[0].status is string"
- name: Validate that orders were retrieved as list of objects (2/2)
assert:
that:
- "'account' in account_orders_full2"
- "'orders' in account_orders_full2"
- "account_orders_full2.orders[0].status is string"

View File

@@ -0,0 +1,2 @@
shippable/cloud/group1
cloud/acme

View File

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

View File

@@ -0,0 +1,89 @@
---
## SET UP ACCOUNT KEYS ########################################################################
- name: Create ECC256 account key
command: openssl ecparam -name prime256v1 -genkey -out {{ output_dir }}/account-ec256.pem
- name: Create ECC384 account key
command: openssl ecparam -name secp384r1 -genkey -out {{ output_dir }}/account-ec384.pem
- name: Create RSA-2048 account key
command: openssl genrsa -out {{ output_dir }}/account-rsa2048.pem 2048
## CREATE ACCOUNTS AND OBTAIN CERTIFICATES ####################################################
- name: Obtain cert 1
include_tasks: obtain-cert.yml
vars:
certgen_title: Certificate 1 for revocation
certificate_name: cert-1
key_type: rsa
rsa_bits: 2048
subject_alt_name: "DNS:example.com"
subject_alt_name_critical: no
account_key_content: "{{ lookup('file', output_dir ~ '/account-ec256.pem') }}"
challenge: http-01
modify_account: yes
deactivate_authzs: no
force: no
remaining_days: 10
terms_agreed: yes
account_email: "example@example.org"
- name: Obtain cert 2
include_tasks: obtain-cert.yml
vars:
certgen_title: Certificate 2 for revocation
certificate_name: cert-2
key_type: ec256
subject_alt_name: "DNS:*.example.com"
subject_alt_name_critical: yes
account_key: account-ec384
challenge: dns-01
modify_account: yes
deactivate_authzs: yes
force: no
remaining_days: 10
terms_agreed: yes
account_email: "example@example.org"
- name: Obtain cert 3
include_tasks: obtain-cert.yml
vars:
certgen_title: Certificate 3 for revocation
certificate_name: cert-3
key_type: ec384
subject_alt_name: "DNS:t1.example.com"
subject_alt_name_critical: no
account_key: account-rsa2048
challenge: dns-01
modify_account: yes
deactivate_authzs: no
force: no
remaining_days: 10
terms_agreed: yes
account_email: "example@example.org"
## REVOKE CERTIFICATES ########################################################################
- 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"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
ignore_errors: yes
register: cert_1_revoke
- 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"
certificate: "{{ output_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: Revoke certificate 3 via account key (fullchain)
acme_certificate_revoke:
select_crypto_backend: "{{ select_crypto_backend }}"
account_key_content: "{{ lookup('file', output_dir ~ '/account-rsa2048.pem') }}"
certificate: "{{ output_dir }}/cert-3-fullchain.pem"
acme_version: 2
acme_directory: https://{{ acme_host }}:14000/dir
validate_certs: no
ignore_errors: yes
register: cert_3_revoke

View File

@@ -0,0 +1,31 @@
---
- block:
- name: Running tests with OpenSSL backend
include_tasks: impl.yml
vars:
select_crypto_backend: openssl
- import_tasks: ../tests/validate.yml
# Old 0.9.8 versions have insufficient CLI support for signing with EC keys
when: openssl_version.stdout is version('1.0.0', '>=')
- name: Remove output directory
file:
path: "{{ output_dir }}"
state: absent
- name: Re-create output directory
file:
path: "{{ output_dir }}"
state: directory
- block:
- name: Running tests with cryptography backend
include_tasks: impl.yml
vars:
select_crypto_backend: cryptography
- import_tasks: ../tests/validate.yml
when: cryptography_version.stdout is version('1.5', '>=')

View File

@@ -0,0 +1 @@
../../setup_acme/tasks/obtain-cert.yml

View File

@@ -0,0 +1,16 @@
---
- name: Check that certificate 1 was revoked
assert:
that:
- cert_1_revoke is changed
- cert_1_revoke is not failed
- name: Check that certificate 2 was revoked
assert:
that:
- cert_2_revoke is changed
- cert_2_revoke is not failed
- name: Check that certificate 3 was revoked
assert:
that:
- cert_3_revoke is changed
- cert_3_revoke is not failed

View File

@@ -0,0 +1,2 @@
shippable/cloud/group1
cloud/acme

View File

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

View File

@@ -0,0 +1,25 @@
---
- block:
- name: Create ECC256 account key
command: openssl ecparam -name prime256v1 -genkey -out {{ output_dir }}/account-ec256.pem
- name: Obtain cert 1
include_tasks: obtain-cert.yml
vars:
select_crypto_backend: auto
certgen_title: Certificate 1
certificate_name: cert-1
key_type: rsa
rsa_bits: 2048
subject_alt_name: "DNS:example.com"
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"
when: openssl_version.stdout is version('1.0.0', '>=') or cryptography_version.stdout is version('1.5', '>=')

View File

@@ -0,0 +1 @@
../../setup_acme/tasks/obtain-cert.yml

View File

@@ -0,0 +1,2 @@
shippable/cloud/group1
cloud/acme

View File

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

View File

@@ -0,0 +1,151 @@
---
- name: Generate account key
command: openssl ecparam -name prime256v1 -genkey -out {{ output_dir }}/accountkey.pem
- name: Parse account key (to ease debugging some test failures)
command: openssl ec -in {{ output_dir }}/accountkey.pem -noout -text
- name: Get directory
acme_inspect:
acme_directory: https://{{ acme_host }}:14000/dir
acme_version: 2
validate_certs: no
method: directory-only
register: directory
- debug: var=directory
- name: Create an account
acme_inspect:
acme_directory: https://{{ acme_host }}:14000/dir
acme_version: 2
validate_certs: no
account_key_src: "{{ output_dir }}/accountkey.pem"
url: "{{ directory.directory.newAccount}}"
method: post
content: '{"termsOfServiceAgreed":true}'
register: account_creation
# account_creation.headers.location contains the account URI
# if creation was successful
- debug: var=account_creation
- name: Get account information
acme_inspect:
acme_directory: https://{{ acme_host }}:14000/dir
acme_version: 2
validate_certs: no
account_key_src: "{{ output_dir }}/accountkey.pem"
account_uri: "{{ account_creation.headers.location }}"
url: "{{ account_creation.headers.location }}"
method: get
register: account_get
- debug: var=account_get
- name: Update account contacts
acme_inspect:
acme_directory: https://{{ acme_host }}:14000/dir
acme_version: 2
validate_certs: no
account_key_src: "{{ output_dir }}/accountkey.pem"
account_uri: "{{ account_creation.headers.location }}"
url: "{{ account_creation.headers.location }}"
method: post
content: '{{ account_info | to_json }}'
vars:
account_info:
# For valid values, see
# https://www.rfc-editor.org/rfc/rfc8555.html#section-7.3
contact:
- mailto:me@example.com
register: account_update
- debug: var=account_update
- name: Create certificate order
acme_inspect:
acme_directory: https://{{ acme_host }}:14000/dir
acme_version: 2
validate_certs: no
account_key_src: "{{ output_dir }}/accountkey.pem"
account_uri: "{{ account_creation.headers.location }}"
url: "{{ directory.directory.newOrder }}"
method: post
content: '{{ create_order | to_json }}'
vars:
create_order:
# For valid values, see
# https://www.rfc-editor.org/rfc/rfc8555.html#section-7.4 and
# https://www.rfc-editor.org/rfc/rfc8738.html
identifiers:
- type: dns
value: example.com
- type: dns
value: example.org
register: new_order
- debug: var=new_order
- name: Get order information
acme_inspect:
acme_directory: https://{{ acme_host }}:14000/dir
acme_version: 2
validate_certs: no
account_key_src: "{{ output_dir }}/accountkey.pem"
account_uri: "{{ account_creation.headers.location }}"
url: "{{ new_order.headers.location }}"
method: get
register: order
- debug: var=order
- name: Get authzs for order
acme_inspect:
acme_directory: https://{{ acme_host }}:14000/dir
acme_version: 2
validate_certs: no
account_key_src: "{{ output_dir }}/accountkey.pem"
account_uri: "{{ account_creation.headers.location }}"
url: "{{ item }}"
method: get
loop: "{{ order.output_json.authorizations }}"
register: authz
- debug: var=authz
- name: Get HTTP-01 challenge for authz
acme_inspect:
acme_directory: https://{{ acme_host }}:14000/dir
acme_version: 2
validate_certs: no
account_key_src: "{{ output_dir }}/accountkey.pem"
account_uri: "{{ account_creation.headers.location }}"
url: "{{ (item.challenges | selectattr('type', 'equalto', 'http-01') | list)[0].url }}"
method: get
register: http01challenge
loop: "{{ authz.results | map(attribute='output_json') | list }}"
- debug: var=http01challenge
- name: Activate HTTP-01 challenge manually
acme_inspect:
acme_directory: https://{{ acme_host }}:14000/dir
acme_version: 2
validate_certs: no
account_key_src: "{{ output_dir }}/accountkey.pem"
account_uri: "{{ account_creation.headers.location }}"
url: "{{ item.url }}"
method: post
content: '{}'
register: activation
loop: "{{ http01challenge.results | map(attribute='output_json') | list }}"
- debug: var=activation
- name: Get HTTP-01 challenge results
acme_inspect:
acme_directory: https://{{ acme_host }}:14000/dir
acme_version: 2
validate_certs: no
account_key_src: "{{ output_dir }}/accountkey.pem"
account_uri: "{{ account_creation.headers.location }}"
url: "{{ item.url }}"
method: get
register: validation_result
loop: "{{ http01challenge.results | map(attribute='output_json') | list }}"
until: "validation_result.output_json.status != 'pending'"
retries: 20
delay: 1
- debug: var=validation_result

View File

@@ -0,0 +1,31 @@
---
- block:
- name: Running tests with OpenSSL backend
include_tasks: impl.yml
vars:
select_crypto_backend: openssl
- import_tasks: ../tests/validate.yml
# Old 0.9.8 versions have insufficient CLI support for signing with EC keys
when: openssl_version.stdout is version('1.0.0', '>=')
- name: Remove output directory
file:
path: "{{ output_dir }}"
state: absent
- name: Re-create output directory
file:
path: "{{ output_dir }}"
state: directory
- block:
- name: Running tests with cryptography backend
include_tasks: impl.yml
vars:
select_crypto_backend: cryptography
- import_tasks: ../tests/validate.yml
when: cryptography_version.stdout is version('1.5', '>=')

View File

@@ -0,0 +1,131 @@
---
- name: Check directory output
assert:
that:
- directory is not changed
- "'directory' in directory"
- "'newAccount' in directory.directory"
- "'newOrder' in directory.directory"
- "'newNonce' in directory.directory"
- "'headers' not in directory"
- "'output_text' not in directory"
- "'output_json' not in directory"
- name: Check account creation output
assert:
that:
- account_creation is changed
- "'directory' in account_creation"
- "'headers' in account_creation"
- "'output_text' in account_creation"
- "'output_json' in account_creation"
- account_creation.headers.status == 201
- "'location' in account_creation.headers"
- account_creation.output_json.status == 'valid'
- not (account_creation.output_json.contact | default([]))
- account_creation.output_text | from_json == account_creation.output_json
- name: Check account get output
assert:
that:
- account_get is not changed
- "'directory' in account_get"
- "'headers' in account_get"
- "'output_text' in account_get"
- "'output_json' in account_get"
- account_get.headers.status == 200
- account_get.output_json == account_creation.output_json
- name: Check account update output
assert:
that:
- account_update is changed
- "'directory' in account_update"
- "'headers' in account_update"
- "'output_text' in account_update"
- "'output_json' in account_update"
- account_update.output_json.status == 'valid'
- account_update.output_json.contact | length == 1
- account_update.output_json.contact[0] == 'mailto:me@example.com'
- name: Check certificate request output
assert:
that:
- new_order is changed
- "'directory' in new_order"
- "'headers' in new_order"
- "'output_text' in new_order"
- "'output_json' in new_order"
- new_order.output_json.authorizations | length == 2
- new_order.output_json.identifiers | length == 2
- new_order.output_json.status == 'pending'
- "'finalize' in new_order.output_json"
- name: Check get order output
assert:
that:
- order is not changed
- "'directory' in order"
- "'headers' in order"
- "'output_text' in order"
- "'output_json' in order"
# The order of identifiers and authorizations is randomized!
# - new_order.output_json == order.output_json
- name: Check get authz output
assert:
that:
- item is not changed
- "'directory' in item"
- "'headers' in item"
- "'output_text' in item"
- "'output_json' in item"
- item.output_json.challenges | length >= 3
- item.output_json.identifier.type == 'dns'
- item.output_json.status == 'pending'
loop: "{{ authz.results }}"
- name: Check get challenge output
assert:
that:
- item is not changed
- "'directory' in item"
- "'headers' in item"
- "'output_text' in item"
- "'output_json' in item"
- item.output_json.status == 'pending'
- item.output_json.type == 'http-01'
- item.output_json.url == item.invocation.module_args.url
- "'token' in item.output_json"
loop: "{{ http01challenge.results }}"
- name: Check challenge activation output
assert:
that:
- item is changed
- "'directory' in item"
- "'headers' in item"
- "'output_text' in item"
- "'output_json' in item"
- item.output_json.status == 'pending'
- item.output_json.type == 'http-01'
- item.output_json.url == item.invocation.module_args.url
- "'token' in item.output_json"
loop: "{{ activation.results }}"
- name: Check validation result
assert:
that:
- item is not changed
- "'directory' in item"
- "'headers' in item"
- "'output_text' in item"
- "'output_json' in item"
- item.output_json.status == 'invalid'
- item.output_json.type == 'http-01'
- item.output_json.url == item.invocation.module_args.url
- "'token' in item.output_json"
- "'validated' in item.output_json"
- "'error' in item.output_json"
- item.output_json.error.type == 'urn:ietf:params:acme:error:unauthorized'
loop: "{{ validation_result.results }}"

View File

@@ -0,0 +1,2 @@
shippable/posix/group1
skip/aix

View File

@@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDnzCCAyWgAwIBAgIQWyXOaQfEJlVm0zkMmalUrTAKBggqhkjOPQQDAzCBhTEL
MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT
IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwOTI1MDAw
MDAwWhcNMjkwOTI0MjM1OTU5WjCBkjELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy
ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N
T0RPIENBIExpbWl0ZWQxODA2BgNVBAMTL0NPTU9ETyBFQ0MgRG9tYWluIFZhbGlk
YXRpb24gU2VjdXJlIFNlcnZlciBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD
QgAEAjgZgTrJaYRwWQKOqIofMN+83gP8eR06JSxrQSEYgur5PkrkM8wSzypD/A7y
ZADA4SVQgiTNtkk4DyVHkUikraOCAWYwggFiMB8GA1UdIwQYMBaAFHVxpxlIGbyd
nepBR9+UxEh3mdN5MB0GA1UdDgQWBBRACWFn8LyDcU/eEggsb9TUK3Y9ljAOBgNV
HQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEF
BQcDAQYIKwYBBQUHAwIwGwYDVR0gBBQwEjAGBgRVHSAAMAgGBmeBDAECATBMBgNV
HR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9FQ0ND
ZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDByBggrBgEFBQcBAQRmMGQwOwYIKwYB
BQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NPTU9ET0VDQ0FkZFRydXN0
Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC5jb21vZG9jYTQuY29tMAoG
CCqGSM49BAMDA2gAMGUCMQCsaEclgBNPE1bAojcJl1pQxOfttGHLKIoKETKm4nHf
EQGJbwd6IGZrGNC5LkP3Um8CMBKFfI4TZpIEuppFCZRKMGHRSdxv6+ctyYnPHmp8
7IXOMCVZuoFwNLg0f+cB0eLLUg==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,51 @@
-----BEGIN CERTIFICATE-----
MIIFBTCCBKugAwIBAgIQL+c9oQXpvdcOD3BKAncbgDAKBggqhkjOPQQDAjCBkjEL
MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxODA2BgNVBAMT
L0NPTU9ETyBFQ0MgRG9tYWluIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQSAy
MB4XDTE4MDcxMTAwMDAwMFoXDTE5MDExNzIzNTk1OVowbDEhMB8GA1UECxMYRG9t
YWluIENvbnRyb2wgVmFsaWRhdGVkMSEwHwYDVQQLExhQb3NpdGl2ZVNTTCBNdWx0
aS1Eb21haW4xJDAiBgNVBAMTG3NzbDgwMzAyNS5jbG91ZGZsYXJlc3NsLmNvbTBZ
MBMGByqGSM49AgEGCCqGSM49AwEHA0IABMap9sMZnCzTXID1chTOmtOk8p6+SHbG
3fmyJJljI7sN9RddlLKar9VBS48WguVv1R6trvERIYj8TzKCVBzu9mmjggMGMIID
AjAfBgNVHSMEGDAWgBRACWFn8LyDcU/eEggsb9TUK3Y9ljAdBgNVHQ4EFgQUd/6a
t8j7v5DsL7xWacf8VyzOLJcwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAw
HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCME8GA1UdIARIMEYwOgYLKwYB
BAGyMQECAgcwKzApBggrBgEFBQcCARYdaHR0cHM6Ly9zZWN1cmUuY29tb2RvLmNv
bS9DUFMwCAYGZ4EMAQIBMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwuY29t
b2RvY2E0LmNvbS9DT01PRE9FQ0NEb21haW5WYWxpZGF0aW9uU2VjdXJlU2VydmVy
Q0EyLmNybDCBiAYIKwYBBQUHAQEEfDB6MFEGCCsGAQUFBzAChkVodHRwOi8vY3J0
LmNvbW9kb2NhNC5jb20vQ09NT0RPRUNDRG9tYWluVmFsaWRhdGlvblNlY3VyZVNl
cnZlckNBMi5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLmNvbW9kb2NhNC5j
b20wSAYDVR0RBEEwP4Ibc3NsODAzMDI1LmNsb3VkZmxhcmVzc2wuY29tghAqLmhz
Y29zY2RuNDAubmV0gg5oc2Nvc2NkbjQwLm5ldDCCAQMGCisGAQQB1nkCBAIEgfQE
gfEA7wB2AO5Lvbd1zmC64UJpH6vhnmajD35fsHLYgwDEe4l6qP3LAAABZIbVA88A
AAQDAEcwRQIhANtN489Izy3iss/eF8rUw/gir8rqyA2t3lpxnco+J2NlAiBBku5M
iGD8whW5/31byPj0/ype1MmG0QYrq3qWvYiQ3QB1AHR+2oMxrTMQkSGcziVPQnDC
v/1eQiAIxjc1eeYQe8xWAAABZIbVBB4AAAQDAEYwRAIgSjcL7B4cbgm2XED69G7/
iFPe2zkWhxnkgGISSwuXw1gCICzwPmfbjEfwDNXEuBs7JXkPRaT1pi7hZ9aR5wJJ
TKH9MAoGCCqGSM49BAMCA0gAMEUCIQDqxmFLcme3Ldd+jiMQf7fT5pSezZfMOL0S
cNmfGvNtPQIgec3sO/ylnnaztCy5KDjYsnh+rm01bxs+nz2DnOPF+xo=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDnzCCAyWgAwIBAgIQWyXOaQfEJlVm0zkMmalUrTAKBggqhkjOPQQDAzCBhTEL
MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT
IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwOTI1MDAw
MDAwWhcNMjkwOTI0MjM1OTU5WjCBkjELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy
ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N
T0RPIENBIExpbWl0ZWQxODA2BgNVBAMTL0NPTU9ETyBFQ0MgRG9tYWluIFZhbGlk
YXRpb24gU2VjdXJlIFNlcnZlciBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD
QgAEAjgZgTrJaYRwWQKOqIofMN+83gP8eR06JSxrQSEYgur5PkrkM8wSzypD/A7y
ZADA4SVQgiTNtkk4DyVHkUikraOCAWYwggFiMB8GA1UdIwQYMBaAFHVxpxlIGbyd
nepBR9+UxEh3mdN5MB0GA1UdDgQWBBRACWFn8LyDcU/eEggsb9TUK3Y9ljAOBgNV
HQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEF
BQcDAQYIKwYBBQUHAwIwGwYDVR0gBBQwEjAGBgRVHSAAMAgGBmeBDAECATBMBgNV
HR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9FQ0ND
ZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDByBggrBgEFBQcBAQRmMGQwOwYIKwYB
BQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NPTU9ET0VDQ0FkZFRydXN0
Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC5jb21vZG9jYTQuY29tMAoG
CCqGSM49BAMDA2gAMGUCMQCsaEclgBNPE1bAojcJl1pQxOfttGHLKIoKETKm4nHf
EQGJbwd6IGZrGNC5LkP3Um8CMBKFfI4TZpIEuppFCZRKMGHRSdxv6+ctyYnPHmp8
7IXOMCVZuoFwNLg0f+cB0eLLUg==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,16 @@
-----BEGIN CERTIFICATE-----
MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL
MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT
IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw
MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy
ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N
T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv
biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR
FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J
cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW
BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm
fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv
GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,29 @@
-----BEGIN CERTIFICATE-----
MIIFBTCCBKugAwIBAgIQL+c9oQXpvdcOD3BKAncbgDAKBggqhkjOPQQDAjCBkjEL
MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxODA2BgNVBAMT
L0NPTU9ETyBFQ0MgRG9tYWluIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQSAy
MB4XDTE4MDcxMTAwMDAwMFoXDTE5MDExNzIzNTk1OVowbDEhMB8GA1UECxMYRG9t
YWluIENvbnRyb2wgVmFsaWRhdGVkMSEwHwYDVQQLExhQb3NpdGl2ZVNTTCBNdWx0
aS1Eb21haW4xJDAiBgNVBAMTG3NzbDgwMzAyNS5jbG91ZGZsYXJlc3NsLmNvbTBZ
MBMGByqGSM49AgEGCCqGSM49AwEHA0IABMap9sMZnCzTXID1chTOmtOk8p6+SHbG
3fmyJJljI7sN9RddlLKar9VBS48WguVv1R6trvERIYj8TzKCVBzu9mmjggMGMIID
AjAfBgNVHSMEGDAWgBRACWFn8LyDcU/eEggsb9TUK3Y9ljAdBgNVHQ4EFgQUd/6a
t8j7v5DsL7xWacf8VyzOLJcwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAw
HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCME8GA1UdIARIMEYwOgYLKwYB
BAGyMQECAgcwKzApBggrBgEFBQcCARYdaHR0cHM6Ly9zZWN1cmUuY29tb2RvLmNv
bS9DUFMwCAYGZ4EMAQIBMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwuY29t
b2RvY2E0LmNvbS9DT01PRE9FQ0NEb21haW5WYWxpZGF0aW9uU2VjdXJlU2VydmVy
Q0EyLmNybDCBiAYIKwYBBQUHAQEEfDB6MFEGCCsGAQUFBzAChkVodHRwOi8vY3J0
LmNvbW9kb2NhNC5jb20vQ09NT0RPRUNDRG9tYWluVmFsaWRhdGlvblNlY3VyZVNl
cnZlckNBMi5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLmNvbW9kb2NhNC5j
b20wSAYDVR0RBEEwP4Ibc3NsODAzMDI1LmNsb3VkZmxhcmVzc2wuY29tghAqLmhz
Y29zY2RuNDAubmV0gg5oc2Nvc2NkbjQwLm5ldDCCAQMGCisGAQQB1nkCBAIEgfQE
gfEA7wB2AO5Lvbd1zmC64UJpH6vhnmajD35fsHLYgwDEe4l6qP3LAAABZIbVA88A
AAQDAEcwRQIhANtN489Izy3iss/eF8rUw/gir8rqyA2t3lpxnco+J2NlAiBBku5M
iGD8whW5/31byPj0/ype1MmG0QYrq3qWvYiQ3QB1AHR+2oMxrTMQkSGcziVPQnDC
v/1eQiAIxjc1eeYQe8xWAAABZIbVBB4AAAQDAEYwRAIgSjcL7B4cbgm2XED69G7/
iFPe2zkWhxnkgGISSwuXw1gCICzwPmfbjEfwDNXEuBs7JXkPRaT1pi7hZ9aR5wJJ
TKH9MAoGCCqGSM49BAMCA0gAMEUCIQDqxmFLcme3Ldd+jiMQf7fT5pSezZfMOL0S
cNmfGvNtPQIgec3sO/ylnnaztCy5KDjYsnh+rm01bxs+nz2DnOPF+xo=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,32 @@
-----BEGIN CERTIFICATE-----
MIIFjTCCA3WgAwIBAgIRANOxciY0IzLc9AUoUSrsnGowDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTYxMDA2MTU0MzU1
WhcNMjExMDA2MTU0MzU1WjBKMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
RW5jcnlwdDEjMCEGA1UEAxMaTGV0J3MgRW5jcnlwdCBBdXRob3JpdHkgWDMwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCc0wzwWuUuR7dyXTeDs2hjMOrX
NSYZJeG9vjXxcJIvt7hLQQWrqZ41CFjssSrEaIcLo+N15Obzp2JxunmBYB/XkZqf
89B4Z3HIaQ6Vkc/+5pnpYDxIzH7KTXcSJJ1HG1rrueweNwAcnKx7pwXqzkrrvUHl
Npi5y/1tPJZo3yMqQpAMhnRnyH+lmrhSYRQTP2XpgofL2/oOVvaGifOFP5eGr7Dc
Gu9rDZUWfcQroGWymQQ2dYBrrErzG5BJeC+ilk8qICUpBMZ0wNAxzY8xOJUWuqgz
uEPxsR/DMH+ieTETPS02+OP88jNquTkxxa/EjQ0dZBYzqvqEKbbUC8DYfcOTAgMB
AAGjggFnMIIBYzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADBU
BgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEBATAwMC4GCCsGAQUFBwIB
FiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQub3JnMB0GA1UdDgQWBBSo
SmpjBH3duubRObemRWXv86jsoTAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3Js
LnJvb3QteDEubGV0c2VuY3J5cHQub3JnMHIGCCsGAQUFBwEBBGYwZDAwBggrBgEF
BQcwAYYkaHR0cDovL29jc3Aucm9vdC14MS5sZXRzZW5jcnlwdC5vcmcvMDAGCCsG
AQUFBzAChiRodHRwOi8vY2VydC5yb290LXgxLmxldHNlbmNyeXB0Lm9yZy8wHwYD
VR0jBBgwFoAUebRZ5nu25eQBc4AIiMgaWPbpm24wDQYJKoZIhvcNAQELBQADggIB
ABnPdSA0LTqmRf/Q1eaM2jLonG4bQdEnqOJQ8nCqxOeTRrToEKtwT++36gTSlBGx
A/5dut82jJQ2jxN8RI8L9QFXrWi4xXnA2EqA10yjHiR6H9cj6MFiOnb5In1eWsRM
UM2v3e9tNsCAgBukPHAg1lQh07rvFKm/Bz9BCjaxorALINUfZ9DD64j2igLIxle2
DPxW8dI/F2loHMjXZjqG8RkqZUdoxtID5+90FgsGIfkMpqgRS05f4zPbCEHqCXl1
eO5HyELTgcVlLXXQDgAWnRzut1hFJeczY1tjQQno6f6s+nMydLN26WuU4s3UYvOu
OsUxRlJu7TSRHqDC3lSE5XggVkzdaPkuKGQbGpny+01/47hfXXNB7HntWNZ6N2Vw
p7G6OfY+YQrZwIaQmhrIqJZuigsrbe3W+gdn5ykE9+Ky0VgVUsfxo52mwFYs1JKY
2PGDuWx8M6DlS6qQkvHaRUo0FMd8TsSlbF0/v965qGFKhSDeQoMpYnwcmQilRh/0
ayLThlHLN81gSkJjVrPI0Y8xCVPB4twb1PFUd2fPM3sA1tJ83sZ5v8vgFv2yofKR
PB0t6JzUA81mSqM3kxl5e+IZwhYAyO0OTg3/fs8HqGTNKd9BqoUwSRBzp06JMg5b
rUCGwbCUDI0mxadJ3Bz4WxR6fyNpBK2yAinWEsikxqEt
-----END CERTIFICATE-----

View File

@@ -0,0 +1,31 @@
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,72 @@
-----BEGIN CERTIFICATE-----
MIIH5jCCBs6gAwIBAgISA2gSCm/BtvCR2e2bIap5YbXaMA0GCSqGSIb3DQEBCwUA
MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODA3MjcxNzMxMjdaFw0x
ODEwMjUxNzMxMjdaMB4xHDAaBgNVBAMTE3d3dy5sZXRzZW5jcnlwdC5vcmcwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDpL8ZjVL0MUkUAIbYO9+ZCni+c
ghGd9WhM2Ztaay6Wyh6lNoCdltdqTwUhE4O+d7UFModjM3G/KMyfuujr06c5iGKL
3saPmIzLaRPIEOUlB2rKgasKhe8mDRyRLzQSXXgnsaKcTBBuhIHvtP51ZMr05nJJ
sX/5FGjj96w+KJel6E/Ux1a1ZDOFkAYNSIrJJhA5jjIvUPr+Ri6Oc6UlhF9oueKI
uWBILxQpC778tBWdHoZeBCNTHA1VvtwC53OeuHvdZm1jB/e30Mgf5DtVizYpFXVD
mztkrd6z/3B6ZwPyfCE4KgzSf70/byOz971OJxNKTUVWedKHHDlrMxfsPclbAgMB
AAGjggTwMIIE7DAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEG
CCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFG1w4j/KDrYSFu7m9DPE
xRR0E5gzMB8GA1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMG8GCCsGAQUF
BwEBBGMwYTAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNy
eXB0Lm9yZzAvBggrBgEFBQcwAoYjaHR0cDovL2NlcnQuaW50LXgzLmxldHNlbmNy
eXB0Lm9yZy8wggHxBgNVHREEggHoMIIB5IIbY2VydC5pbnQteDEubGV0c2VuY3J5
cHQub3JnghtjZXJ0LmludC14Mi5sZXRzZW5jcnlwdC5vcmeCG2NlcnQuaW50LXgz
LmxldHNlbmNyeXB0Lm9yZ4IbY2VydC5pbnQteDQubGV0c2VuY3J5cHQub3Jnghxj
ZXJ0LnJvb3QteDEubGV0c2VuY3J5cHQub3Jngh9jZXJ0LnN0YWdpbmcteDEubGV0
c2VuY3J5cHQub3Jngh9jZXJ0LnN0Zy1pbnQteDEubGV0c2VuY3J5cHQub3JngiBj
ZXJ0LnN0Zy1yb290LXgxLmxldHNlbmNyeXB0Lm9yZ4ISY3AubGV0c2VuY3J5cHQu
b3JnghpjcC5yb290LXgxLmxldHNlbmNyeXB0Lm9yZ4ITY3BzLmxldHNlbmNyeXB0
Lm9yZ4IbY3BzLnJvb3QteDEubGV0c2VuY3J5cHQub3Jnghtjcmwucm9vdC14MS5s
ZXRzZW5jcnlwdC5vcmeCD2xldHNlbmNyeXB0Lm9yZ4IWb3JpZ2luLmxldHNlbmNy
eXB0Lm9yZ4IXb3JpZ2luMi5sZXRzZW5jcnlwdC5vcmeCFnN0YXR1cy5sZXRzZW5j
cnlwdC5vcmeCE3d3dy5sZXRzZW5jcnlwdC5vcmcwgf4GA1UdIASB9jCB8zAIBgZn
gQwBAgEwgeYGCysGAQQBgt8TAQEBMIHWMCYGCCsGAQUFBwIBFhpodHRwOi8vY3Bz
LmxldHNlbmNyeXB0Lm9yZzCBqwYIKwYBBQUHAgIwgZ4MgZtUaGlzIENlcnRpZmlj
YXRlIG1heSBvbmx5IGJlIHJlbGllZCB1cG9uIGJ5IFJlbHlpbmcgUGFydGllcyBh
bmQgb25seSBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIENlcnRpZmljYXRlIFBvbGlj
eSBmb3VuZCBhdCBodHRwczovL2xldHNlbmNyeXB0Lm9yZy9yZXBvc2l0b3J5LzCC
AQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2AMEWSuCnctLUOS3ICsEHcNTwxJvemRpI
QMH6B1Fk9jNgAAABZN0ChToAAAQDAEcwRQIgblal8oXnfoopr1+dWVhvBx+sqHT0
eLYxJHBTaRp3j1QCIQDhFQqMk6DDXUgcU12K36zLVFwJTdAJI4RBisnX+g+W0AB2
ACk8UZZUyDlluqpQ/FgH1Ldvv1h6KXLcpMMM9OVFR/R4AAABZN0Chz4AAAQDAEcw
RQIhAImOjvkritUNKJZB7dcUtjoyIbfNwdCspvRiEzXuvVQoAiAZryoyg3TcMun5
Gb2dEn1cttMnPW9u670/JdRjvjU/wTANBgkqhkiG9w0BAQsFAAOCAQEAGepCmckP
Tn9Sz268FEwkdD+6wWaPfeYlh+9nacFh90nQ35EYQMOK8a+X7ixHGbRz19On3Wt4
1fcbPa9SefocTjAintMwwreCxpRTmwGACYojd7vRWEmA6q7+/HO2BfZahWzclOjw
mSDBycDEm8R0ZK52vYjzVno8x0mrsmSO0403S/6syYB/guH6P17kIBw+Tgx6/i/c
I1C6MoFkuaAKUUcZmgGGBgE+L/7cWtWjbkVXyA3ZQQy9G7rcBT+N/RrDfBh4iZDq
jAN5UIIYL8upBhjiMYVuoJrH2nklzEwr5SWKcccJX5eWkGLUwlcY9LGAA8+17l2I
l1Ou20Dm9TxnNw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
-----END CERTIFICATE-----

View File

@@ -0,0 +1,45 @@
-----BEGIN CERTIFICATE-----
MIIH5jCCBs6gAwIBAgISA2gSCm/BtvCR2e2bIap5YbXaMA0GCSqGSIb3DQEBCwUA
MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODA3MjcxNzMxMjdaFw0x
ODEwMjUxNzMxMjdaMB4xHDAaBgNVBAMTE3d3dy5sZXRzZW5jcnlwdC5vcmcwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDpL8ZjVL0MUkUAIbYO9+ZCni+c
ghGd9WhM2Ztaay6Wyh6lNoCdltdqTwUhE4O+d7UFModjM3G/KMyfuujr06c5iGKL
3saPmIzLaRPIEOUlB2rKgasKhe8mDRyRLzQSXXgnsaKcTBBuhIHvtP51ZMr05nJJ
sX/5FGjj96w+KJel6E/Ux1a1ZDOFkAYNSIrJJhA5jjIvUPr+Ri6Oc6UlhF9oueKI
uWBILxQpC778tBWdHoZeBCNTHA1VvtwC53OeuHvdZm1jB/e30Mgf5DtVizYpFXVD
mztkrd6z/3B6ZwPyfCE4KgzSf70/byOz971OJxNKTUVWedKHHDlrMxfsPclbAgMB
AAGjggTwMIIE7DAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEG
CCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFG1w4j/KDrYSFu7m9DPE
xRR0E5gzMB8GA1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMG8GCCsGAQUF
BwEBBGMwYTAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNy
eXB0Lm9yZzAvBggrBgEFBQcwAoYjaHR0cDovL2NlcnQuaW50LXgzLmxldHNlbmNy
eXB0Lm9yZy8wggHxBgNVHREEggHoMIIB5IIbY2VydC5pbnQteDEubGV0c2VuY3J5
cHQub3JnghtjZXJ0LmludC14Mi5sZXRzZW5jcnlwdC5vcmeCG2NlcnQuaW50LXgz
LmxldHNlbmNyeXB0Lm9yZ4IbY2VydC5pbnQteDQubGV0c2VuY3J5cHQub3Jnghxj
ZXJ0LnJvb3QteDEubGV0c2VuY3J5cHQub3Jngh9jZXJ0LnN0YWdpbmcteDEubGV0
c2VuY3J5cHQub3Jngh9jZXJ0LnN0Zy1pbnQteDEubGV0c2VuY3J5cHQub3JngiBj
ZXJ0LnN0Zy1yb290LXgxLmxldHNlbmNyeXB0Lm9yZ4ISY3AubGV0c2VuY3J5cHQu
b3JnghpjcC5yb290LXgxLmxldHNlbmNyeXB0Lm9yZ4ITY3BzLmxldHNlbmNyeXB0
Lm9yZ4IbY3BzLnJvb3QteDEubGV0c2VuY3J5cHQub3Jnghtjcmwucm9vdC14MS5s
ZXRzZW5jcnlwdC5vcmeCD2xldHNlbmNyeXB0Lm9yZ4IWb3JpZ2luLmxldHNlbmNy
eXB0Lm9yZ4IXb3JpZ2luMi5sZXRzZW5jcnlwdC5vcmeCFnN0YXR1cy5sZXRzZW5j
cnlwdC5vcmeCE3d3dy5sZXRzZW5jcnlwdC5vcmcwgf4GA1UdIASB9jCB8zAIBgZn
gQwBAgEwgeYGCysGAQQBgt8TAQEBMIHWMCYGCCsGAQUFBwIBFhpodHRwOi8vY3Bz
LmxldHNlbmNyeXB0Lm9yZzCBqwYIKwYBBQUHAgIwgZ4MgZtUaGlzIENlcnRpZmlj
YXRlIG1heSBvbmx5IGJlIHJlbGllZCB1cG9uIGJ5IFJlbHlpbmcgUGFydGllcyBh
bmQgb25seSBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIENlcnRpZmljYXRlIFBvbGlj
eSBmb3VuZCBhdCBodHRwczovL2xldHNlbmNyeXB0Lm9yZy9yZXBvc2l0b3J5LzCC
AQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2AMEWSuCnctLUOS3ICsEHcNTwxJvemRpI
QMH6B1Fk9jNgAAABZN0ChToAAAQDAEcwRQIgblal8oXnfoopr1+dWVhvBx+sqHT0
eLYxJHBTaRp3j1QCIQDhFQqMk6DDXUgcU12K36zLVFwJTdAJI4RBisnX+g+W0AB2
ACk8UZZUyDlluqpQ/FgH1Ldvv1h6KXLcpMMM9OVFR/R4AAABZN0Chz4AAAQDAEcw
RQIhAImOjvkritUNKJZB7dcUtjoyIbfNwdCspvRiEzXuvVQoAiAZryoyg3TcMun5
Gb2dEn1cttMnPW9u670/JdRjvjU/wTANBgkqhkiG9w0BAQsFAAOCAQEAGepCmckP
Tn9Sz268FEwkdD+6wWaPfeYlh+9nacFh90nQ35EYQMOK8a+X7ixHGbRz19On3Wt4
1fcbPa9SefocTjAintMwwreCxpRTmwGACYojd7vRWEmA6q7+/HO2BfZahWzclOjw
mSDBycDEm8R0ZK52vYjzVno8x0mrsmSO0403S/6syYB/guH6P17kIBw+Tgx6/i/c
I1C6MoFkuaAKUUcZmgGGBgE+L/7cWtWjbkVXyA3ZQQy9G7rcBT+N/RrDfBh4iZDq
jAN5UIIYL8upBhjiMYVuoJrH2nklzEwr5SWKcccJX5eWkGLUwlcY9LGAA8+17l2I
l1Ou20Dm9TxnNw==
-----END CERTIFICATE-----

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB
gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV
BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw
MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl
YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P
RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0
aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3
UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI
2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8
Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp
+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+
DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O
nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW
/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g
PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u
QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY
SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv
IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4
zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd
BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB
ZQ==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,16 @@
-----BEGIN CERTIFICATE-----
MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL
MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT
IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw
MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy
ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N
T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv
biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR
FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J
cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW
BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm
fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv
GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,34 @@
-----BEGIN CERTIFICATE-----
MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB
hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5
MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT
EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh
dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR
6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X
pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC
9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV
/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf
Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z
+pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w
qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah
SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC
u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf
Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq
crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E
FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB
/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl
wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM
4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV
2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna
FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ
CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK
boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke
jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL
S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb
QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl
0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB
NVOFBkpdn627G190
-----END CERTIFICATE-----

View File

@@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
-----END CERTIFICATE-----

View File

@@ -0,0 +1,31 @@
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
-----END CERTIFICATE-----

View File

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

View File

@@ -0,0 +1,81 @@
- name: register cryptography version
command: '{{ ansible_python.executable }} -c ''import cryptography; print(cryptography.__version__)'''
register: cryptography_version
- block:
- name: Archive test files
community.general.archive:
path: '{{ role_path }}/files/'
dest: '{{ output_dir }}/files.tgz'
- name: Create temporary directory to store files
file:
state: directory
path: '{{ remote_tmp_dir }}/files/'
- name: Unarchive test files on testhost
unarchive:
src: '{{ output_dir }}/files.tgz'
dest: '{{ remote_tmp_dir }}/files/'
- name: Find root for cert 1
certificate_complete_chain:
input_chain: '{{ lookup(''file'', ''cert1-fullchain.pem'', rstrip=False) }}'
root_certificates:
- '{{ remote_tmp_dir }}/files/roots/'
register: cert1_root
- name: Verify root for cert 1
assert:
that:
- cert1_root.complete_chain | join('') == (lookup('file', 'cert1.pem', rstrip=False) ~ lookup('file', 'cert1-chain.pem', rstrip=False) ~ lookup('file', 'cert1-root.pem', rstrip=False))
- 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) }}'
intermediate_certificates:
- '{{ remote_tmp_dir }}/files/cert1-chain.pem'
root_certificates:
- '{{ remote_tmp_dir }}/files/roots.pem'
register: cert1_rootchain
- name: Verify rootchain for cert 1
assert:
that:
- cert1_rootchain.complete_chain | join('') == (lookup('file', 'cert1.pem', rstrip=False) ~ lookup('file', 'cert1-chain.pem', rstrip=False) ~ lookup('file', 'cert1-root.pem', rstrip=False))
- cert1_rootchain.chain[:-1] | join('') == lookup('file', 'cert1-chain.pem', rstrip=False)
- 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) }}'
root_certificates:
- '{{ remote_tmp_dir }}/files/roots/'
register: cert2_root
- name: Verify root for cert 2
assert:
that:
- cert2_root.complete_chain | join('') == (lookup('file', 'cert2.pem', rstrip=False) ~ lookup('file', 'cert2-chain.pem', rstrip=False) ~ lookup('file', 'cert2-root.pem', rstrip=False))
- 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) }}'
intermediate_certificates:
- '{{ remote_tmp_dir }}/files/cert2-chain.pem'
root_certificates:
- '{{ remote_tmp_dir }}/files/roots.pem'
register: cert2_rootchain
- name: Verify rootchain for cert 2
assert:
that:
- cert2_rootchain.complete_chain | join('') == (lookup('file', 'cert2.pem', rstrip=False) ~ lookup('file', 'cert2-chain.pem', rstrip=False) ~ lookup('file', 'cert2-root.pem', rstrip=False))
- cert2_rootchain.chain[:-1] | join('') == lookup('file', 'cert2-chain.pem', rstrip=False)
- 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) }}'
intermediate_certificates:
- '{{ remote_tmp_dir }}/files/cert2-altchain.pem'
root_certificates:
- '{{ remote_tmp_dir }}/files/roots.pem'
register: cert2_rootchain_alt
- name: Verify rootchain for cert 2
assert:
that:
- cert2_rootchain_alt.complete_chain | join('') == (lookup('file', 'cert2.pem', rstrip=False) ~ lookup('file', 'cert2-altchain.pem', rstrip=False) ~ lookup('file', 'cert2-altroot.pem', rstrip=False))
- cert2_rootchain_alt.chain[:-1] | join('') == lookup('file', 'cert2-altchain.pem', rstrip=False)
- cert2_rootchain_alt.root == lookup('file', 'cert2-altroot.pem', rstrip=False)
when: cryptography_version.stdout is version('1.5', '>=')

View File

@@ -0,0 +1,15 @@
# Not enabled due to lack of access to test environments. May be enabled using custom integration_config.yml
# Example integation_config.yml
# ---
# entrust_api_user:
# entrust_api_key:
# entrust_api_client_cert_path: /var/integration-testing/publicCert.pem
# entrust_api_client_cert_key_path: /var/integration-testing/privateKey.pem
# entrust_api_ip_address: 127.0.0.1
# entrust_cloud_ip_address: 127.0.0.1
# # Used for certificate path validation of QA environments - we chose not to support disabling path validation ever.
# cacerts_bundle_path_local: /var/integration-testing/cacerts
### WARNING: This test will update HOSTS file and CERTIFICATE STORE of target host, in order to be able to validate
# to a QA environment. ###
unsupported

View File

@@ -0,0 +1,2 @@
---
# defaults file for test_ecs_certificate

View File

@@ -0,0 +1,3 @@
dependencies:
- prepare_tests
- setup_openssl

View File

@@ -0,0 +1,215 @@
---
## Verify that integration_config was specified
- block:
- assert:
that:
- entrust_api_user is defined
- entrust_api_key is defined
- entrust_api_ip_address is defined
- entrust_cloud_ip_address is defined
- entrust_api_client_cert_path is defined or entrust_api_client_cert_contents is defined
- entrust_api_client_cert_key_path is defined or entrust_api_client_cert_key_contents
- cacerts_bundle_path_local is defined
## SET UP TEST ENVIRONMENT ########################################################################
- name: copy the files needed for verifying test server certificate to the host
copy:
src: '{{ cacerts_bundle_path_local }}/'
dest: '{{ cacerts_bundle_path }}'
- name: Update the CA certificates for our QA certs (collection may need updating if new QA environments used)
command: c_rehash {{ cacerts_bundle_path }}
- name: Update hosts file
lineinfile:
path: /etc/hosts
state: present
regexp: 'api.entrust.net$'
line: '{{ entrust_api_ip_address }} api.entrust.net'
- name: Update hosts file
lineinfile:
path: /etc/hosts
state: present
regexp: 'cloud.entrust.net$'
line: '{{ entrust_cloud_ip_address }} cloud.entrust.net'
- name: Clear out the temporary directory for storing the API connection information
file:
path: '{{ tmpdir_path }}'
state: absent
- name: Create a directory for storing the API connection Information
file:
path: '{{ tmpdir_path }}'
state: directory
- name: Copy the files needed for the connection to entrust API to the host
copy:
src: '{{ entrust_api_client_cert_path }}'
dest: '{{ entrust_api_cert }}'
- name: Copy the files needed for the connection to entrust API to the host
copy:
src: '{{ entrust_api_client_cert_key_path }}'
dest: '{{ entrust_api_cert_key }}'
## SETUP CSR TO REQUEST
- name: Generate a 2048 bit RSA private key
openssl_privatekey:
path: '{{ privatekey_path }}'
passphrase: '{{ privatekey_passphrase }}'
cipher: auto
type: RSA
size: 2048
- name: Generate a certificate signing request using the generated key
openssl_csr:
path: '{{ csr_path }}'
privatekey_path: '{{ privatekey_path }}'
privatekey_passphrase: '{{ privatekey_passphrase }}'
common_name: '{{ common_name }}'
organization_name: '{{ organization_name | default(omit) }}'
organizational_unit_name: '{{ organizational_unit_name | default(omit) }}'
country_name: '{{ country_name | default(omit) }}'
state_or_province_name: '{{ state_or_province_name | default(omit) }}'
digest: sha256
- block:
- name: Have ECS generate a signed certificate
ecs_certificate:
backup: True
path: '{{ example1_cert_path }}'
full_chain_path: '{{ example1_chain_path }}'
csr: '{{ csr_path }}'
cert_type: '{{ example1_cert_type }}'
requester_name: '{{ entrust_requester_name }}'
requester_email: '{{ entrust_requester_email }}'
requester_phone: '{{ entrust_requester_phone }}'
entrust_api_user: '{{ entrust_api_user }}'
entrust_api_key: '{{ entrust_api_key }}'
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
register: example1_result
- assert:
that:
- example1_result is not failed
- example1_result.changed
- example1_result.tracking_id > 0
- example1_result.serial_number is string
# Internal CA refuses to issue certificates with the same DN in a short time frame
- name: Sleep for 5 seconds so we don't run into duplicate-request errors
pause:
seconds: 5
- name: Attempt to have ECS generate a signed certificate, but existing one is valid
ecs_certificate:
backup: True
path: '{{ example1_cert_path }}'
full_chain_path: '{{ example1_chain_path }}'
csr: '{{ csr_path }}'
cert_type: '{{ example1_cert_type }}'
requester_name: '{{ entrust_requester_name }}'
requester_email: '{{ entrust_requester_email }}'
requester_phone: '{{ entrust_requester_phone }}'
entrust_api_user: '{{ entrust_api_user }}'
entrust_api_key: '{{ entrust_api_key }}'
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
register: example2_result
- assert:
that:
- example2_result is not failed
- not example2_result.changed
- example2_result.backup_file is undefined
- example2_result.backup_full_chain_file is undefined
- example2_result.serial_number == example1_result.serial_number
- example2_result.tracking_id == example1_result.tracking_id
# Internal CA refuses to issue certificates with the same DN in a short time frame
- name: Sleep for 5 seconds so we don't run into duplicate-request errors
pause:
seconds: 5
- name: Force a reissue with no CSR, verify that contents changed
ecs_certificate:
backup: True
force: True
path: '{{ example1_cert_path }}'
full_chain_path: '{{ example1_chain_path }}'
cert_type: '{{ example1_cert_type }}'
request_type: reissue
requester_name: '{{ entrust_requester_name }}'
requester_email: '{{ entrust_requester_email }}'
requester_phone: '{{ entrust_requester_phone }}'
entrust_api_user: '{{ entrust_api_user }}'
entrust_api_key: '{{ entrust_api_key }}'
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
register: example3_result
- assert:
that:
- example3_result is not failed
- example3_result.changed
- example3_result.backup_file is string
- example3_result.backup_full_chain_file is string
- example3_result.tracking_id > 0
- example3_result.tracking_id != example1_result.tracking_id
- example3_result.serial_number != example1_result.serial_number
# Internal CA refuses to issue certificates with the same DN in a short time frame
- name: Sleep for 5 seconds so we don't run into duplicate-request errors
pause:
seconds: 5
- name: Test a request with all of the various optional possible fields populated
ecs_certificate:
path: '{{ example4_cert_path }}'
full_chain_path: '{{ example4_full_chain_path }}'
csr: '{{ csr_path }}'
subject_alt_name: '{{ example4_subject_alt_name }}'
eku: '{{ example4_eku }}'
ct_log: True
cert_type: '{{ example4_cert_type }}'
org: '{{ example4_org }}'
ou: '{{ example4_ou }}'
tracking_info: '{{ example4_tracking_info }}'
additional_emails: '{{ example4_additional_emails }}'
custom_fields: '{{ example4_custom_fields }}'
cert_expiry: '{{ example4_cert_expiry }}'
requester_name: '{{ entrust_requester_name }}'
requester_email: '{{ entrust_requester_email }}'
requester_phone: '{{ entrust_requester_phone }}'
entrust_api_user: '{{ entrust_api_user }}'
entrust_api_key: '{{ entrust_api_key }}'
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
register: example4_result
- assert:
that:
- example4_result is not failed
- example4_result.changed
- example4_result.backup_file is undefined
- example4_result.backup_full_chain_file is undefined
- example4_result.tracking_id > 0
- example4_result.serial_number is string
# For bug 61738, verify that the full chain is valid
- name: Verify that the full chain path can be successfully imported
command: openssl verify "{{ example4_full_chain_path }}"
register: openssl_result
- assert:
that:
- "' OK' in openssl_result.stdout_lines[0]"
always:
- name: clean-up temporary folder
file:
path: '{{ tmpdir_path }}'
state: absent

View File

@@ -0,0 +1,52 @@
---
# vars file for test_ecs_certificate
# Path on various hosts that cacerts need to be put as a prerequisite to API server cert validation.
# May need to be customized for some environments based on SSL implementations
# that ansible "urls" module utility is using as a backing.
cacerts_bundle_path: /etc/pki/tls/certs
common_name: '{{ ansible_date_time.epoch }}.ansint.testcertificates.com'
organization_name: CMS API, Inc.
organizational_unit_name: RSA
country_name: US
state_or_province_name: MA
privatekey_passphrase: Passphrase452!
tmpdir_path: /tmp/ecs_cert_test/{{ ansible_date_time.epoch }}
privatekey_path: '{{ tmpdir_path }}/testcertificates.key'
entrust_api_cert: '{{ tmpdir_path }}/authcert.cer'
entrust_api_cert_key: '{{ tmpdir_path }}/authkey.cer'
csr_path: '{{ tmpdir_path }}/request.csr'
entrust_requester_name: C Trufan
entrust_requester_email: CTIntegrationTests@entrustdatacard.com
entrust_requester_phone: 1-555-555-5555 # e.g. 15555555555
# TEST 1
example1_cert_path: '{{ tmpdir_path }}/issuedcert_1.pem'
example1_chain_path: '{{ tmpdir_path }}/issuedcert_1_chain.pem'
example1_cert_type: EV_SSL
example4_cert_path: '{{ tmpdir_path }}/issuedcert_2.pem'
example4_subject_alt_name:
- ansible.testcertificates.com
- www.testcertificates.com
example4_eku: SERVER_AND_CLIENT_AUTH
example4_cert_type: UC_SSL
# Test a secondary org and special characters
example4_org: Cañon City, Inc.
example4_ou:
- StringrsaString
example4_tracking_info: Submitted via Ansible Integration
example4_additional_emails:
- itsupport@testcertificates.com
- jsmith@ansible.com
example4_custom_fields:
text1: Admin
text2: Invoice 25
number1: 342
date3: '2018-01-01'
email2: sales@ansible.testcertificates.com
dropdown2: Dropdown 2 Value 1
example4_cert_expiry: 2020-08-15
example4_full_chain_path: '{{ tmpdir_path }}/issuedcert_2_chain.pem'

View File

@@ -0,0 +1,15 @@
# Not enabled due to lack of access to test environments. May be enabled using custom integration_config.yml
# Example integation_config.yml
# ---
# entrust_api_user:
# entrust_api_key:
# entrust_api_client_cert_path: /var/integration-testing/publicCert.pem
# entrust_api_client_cert_key_path: /var/integration-testing/privateKey.pem
# entrust_api_ip_address: 127.0.0.1
# entrust_cloud_ip_address: 127.0.0.1
# # Used for certificate path validation of QA environments - we chose not to support disabling path validation ever.
# cacerts_bundle_path_local: /var/integration-testing/cacerts
### WARNING: This test will update HOSTS file and CERTIFICATE STORE of target host, in order to be able to validate
# to a QA environment. ###
unsupported

View File

@@ -0,0 +1,2 @@
---
# defaults file for test_ecs_domain

View File

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

View File

@@ -0,0 +1,270 @@
---
## Verify that integration_config was specified
- block:
- assert:
that:
- entrust_api_user is defined
- entrust_api_key is defined
- entrust_api_ip_address is defined
- entrust_cloud_ip_address is defined
- entrust_api_client_cert_path is defined or entrust_api_client_cert_contents is defined
- entrust_api_client_cert_key_path is defined or entrust_api_client_cert_key_contents
- cacerts_bundle_path_local is defined
## SET UP TEST ENVIRONMENT ########################################################################
- name: copy the files needed for verifying test server certificate to the host
copy:
src: '{{ cacerts_bundle_path_local }}/'
dest: '{{ cacerts_bundle_path }}'
- name: Update the CA certificates for our QA certs (collection may need updating if new QA environments used)
command: c_rehash {{ cacerts_bundle_path }}
- name: Update hosts file
lineinfile:
path: /etc/hosts
state: present
regexp: 'api.entrust.net$'
line: '{{ entrust_api_ip_address }} api.entrust.net'
- name: Update hosts file
lineinfile:
path: /etc/hosts
state: present
regexp: 'cloud.entrust.net$'
line: '{{ entrust_cloud_ip_address }} cloud.entrust.net'
- name: Clear out the temporary directory for storing the API connection information
file:
path: '{{ tmpdir_path }}'
state: absent
- name: Create a directory for storing the API connection Information
file:
path: '{{ tmpdir_path }}'
state: directory
- name: Copy the files needed for the connection to entrust API to the host
copy:
src: '{{ entrust_api_client_cert_path }}'
dest: '{{ entrust_api_cert }}'
- name: Copy the files needed for the connection to entrust API to the host
copy:
src: '{{ entrust_api_client_cert_key_path }}'
dest: '{{ entrust_api_cert_key }}'
- block:
- name: Have ECS request a domain validation via dns
ecs_domain:
domain_name: dns.{{ common_name }}
verification_method: dns
entrust_api_user: '{{ entrust_api_user }}'
entrust_api_key: '{{ entrust_api_key }}'
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
register: dns_result
- assert:
that:
- dns_result is not failed
- dns_result.changed
- dns_result.domain_status == 'INITIAL_VERIFICATION'
- dns_result.verification_method == 'dns'
- dns_result.dns_location is string
- dns_result.dns_contents is string
- dns_result.dns_resource_type is string
- dns_result.file_location is undefined
- dns_result.file_contents is undefined
- dns_result.emails is undefined
- name: Have ECS request a domain validation via web_server
ecs_domain:
domain_name: FILE.{{ common_name }}
verification_method: web_server
entrust_api_user: '{{ entrust_api_user }}'
entrust_api_key: '{{ entrust_api_key }}'
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
register: file_result
- assert:
that:
- file_result is not failed
- file_result.changed
- file_result.domain_status == 'INITIAL_VERIFICATION'
- file_result.verification_method == 'web_server'
- file_result.dns_location is undefined
- file_result.dns_contents is undefined
- file_result.dns_resource_type is undefined
- file_result.file_location is string
- file_result.file_contents is string
- file_result.emails is undefined
- name: Have ECS request a domain validation via email
ecs_domain:
domain_name: email.{{ common_name }}
verification_method: email
verification_email: admin@testcertificates.com
entrust_api_user: '{{ entrust_api_user }}'
entrust_api_key: '{{ entrust_api_key }}'
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
register: email_result
- assert:
that:
- email_result is not failed
- email_result.changed
- email_result.domain_status == 'INITIAL_VERIFICATION'
- email_result.verification_method == 'email'
- email_result.dns_location is undefined
- email_result.dns_contents is undefined
- email_result.dns_resource_type is undefined
- email_result.file_location is undefined
- email_result.file_contents is undefined
- email_result.emails[0] == 'admin@testcertificates.com'
- name: Have ECS request a domain validation via email with no address provided
ecs_domain:
domain_name: email2.{{ common_name }}
verification_method: email
entrust_api_user: '{{ entrust_api_user }}'
entrust_api_key: '{{ entrust_api_key }}'
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
register: email_result2
- assert:
that:
- email_result2 is not failed
- email_result2.changed
- email_result2.domain_status == 'INITIAL_VERIFICATION'
- email_result2.verification_method == 'email'
- email_result2.dns_location is undefined
- email_result2.dns_contents is undefined
- email_result2.dns_resource_type is undefined
- email_result2.file_location is undefined
- email_result2.file_contents is undefined
- email_result2.emails is defined
- name: Have ECS request a domain validation via manual
ecs_domain:
domain_name: manual.{{ common_name }}
verification_method: manual
entrust_api_user: '{{ entrust_api_user }}'
entrust_api_key: '{{ entrust_api_key }}'
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
register: manual_result
- assert:
that:
- manual_result is not failed
- manual_result.changed
- manual_result.domain_status == 'INITIAL_VERIFICATION'
- manual_result.verification_method == 'manual'
- manual_result.dns_location is undefined
- manual_result.dns_contents is undefined
- manual_result.dns_resource_type is undefined
- manual_result.file_location is undefined
- manual_result.file_contents is undefined
- manual_result.emails is undefined
- name: Have ECS request a domain validation via dns that remains unchanged
ecs_domain:
domain_name: dns.{{ common_name }}
verification_method: dns
entrust_api_user: '{{ entrust_api_user }}'
entrust_api_key: '{{ entrust_api_key }}'
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
register: dns_result2
- assert:
that:
- dns_result2 is not failed
- not dns_result2.changed
- dns_result2.domain_status == 'INITIAL_VERIFICATION'
- dns_result2.verification_method == 'dns'
- dns_result2.dns_location is string
- dns_result2.dns_contents is string
- dns_result2.dns_resource_type is string
- dns_result2.file_location is undefined
- dns_result2.file_contents is undefined
- dns_result2.emails is undefined
- name: Have ECS request a domain validation via FILE for dns, to change verification method
ecs_domain:
domain_name: dns.{{ common_name }}
verification_method: web_server
entrust_api_user: '{{ entrust_api_user }}'
entrust_api_key: '{{ entrust_api_key }}'
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
register: dns_result_now_file
- assert:
that:
- dns_result_now_file is not failed
- dns_result_now_file.changed
- dns_result_now_file.domain_status == 'INITIAL_VERIFICATION'
- dns_result_now_file.verification_method == 'web_server'
- dns_result_now_file.dns_location is undefined
- dns_result_now_file.dns_contents is undefined
- dns_result_now_file.dns_resource_type is undefined
- dns_result_now_file.file_location is string
- dns_result_now_file.file_contents is string
- dns_result_now_file.emails is undefined
- name: Request revalidation of an approved domain
ecs_domain:
domain_name: '{{ existing_domain_common_name }}'
verification_method: manual
entrust_api_user: '{{ entrust_api_user }}'
entrust_api_key: '{{ entrust_api_key }}'
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
register: manual_existing_domain
- assert:
that:
- manual_existing_domain is not failed
- not manual_existing_domain.changed
- manual_existing_domain.domain_status == 'RE_VERIFICATION'
- manual_existing_domain.dns_location is undefined
- manual_existing_domain.dns_contents is undefined
- manual_existing_domain.dns_resource_type is undefined
- manual_existing_domain.file_location is undefined
- manual_existing_domain.file_contents is undefined
- manual_existing_domain.emails is undefined
- name: Request revalidation of an approved domain
ecs_domain:
domain_name: '{{ existing_domain_common_name }}'
verification_method: web_server
entrust_api_user: '{{ entrust_api_user }}'
entrust_api_key: '{{ entrust_api_key }}'
entrust_api_client_cert_path: '{{ entrust_api_cert }}'
entrust_api_client_cert_key_path: '{{ entrust_api_cert_key }}'
register: file_existing_domain_revalidate
- assert:
that:
- file_existing_domain_revalidate is not failed
- file_existing_domain_revalidate.changed
- file_existing_domain_revalidate.domain_status == 'RE_VERIFICATION'
- file_existing_domain_revalidate.verification_method == 'web_server'
- file_existing_domain_revalidate.dns_location is undefined
- file_existing_domain_revalidate.dns_contents is undefined
- file_existing_domain_revalidate.dns_resource_type is undefined
- file_existing_domain_revalidate.file_location is string
- file_existing_domain_revalidate.file_contents is string
- file_existing_domain_revalidate.emails is undefined
always:
- name: clean-up temporary folder
file:
path: '{{ tmpdir_path }}'
state: absent

View File

@@ -0,0 +1,15 @@
---
# vars file for test_ecs_certificate
# Path on various hosts that cacerts need to be put as a prerequisite to API server cert validation.
# May need to be customized for some environments based on SSL implementations
# that ansible "urls" module utility is using as a backing.
cacerts_bundle_path: /etc/pki/tls/certs
common_name: '{{ ansible_date_time.epoch }}.testcertificates.com'
existing_domain_common_name: 'testcertificates.com'
tmpdir_path: /tmp/ecs_cert_test/{{ ansible_date_time.epoch }}
entrust_api_cert: '{{ tmpdir_path }}/authcert.cer'
entrust_api_cert_key: '{{ tmpdir_path }}/authkey.cer'

View File

@@ -0,0 +1,4 @@
shippable/posix/group1
destructive
needs/httptester
skip/aix

View File

@@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC+DCCAeACCQCWuDvGDH3otTANBgkqhkiG9w0BAQsFADA+MQswCQYDVQQGEwJV
UzEOMAwGA1UECAwFQm9ndXMxEDAOBgNVBAcMB0JhbG9uZXkxDTALBgNVBAoMBEFD
TUUwHhcNMTgwNzEyMTgxNDA0WhcNMjMwNzExMTgxNDA0WjA+MQswCQYDVQQGEwJV
UzEOMAwGA1UECAwFQm9ndXMxEDAOBgNVBAcMB0JhbG9uZXkxDTALBgNVBAoMBEFD
TUUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLTGCpn8b+/2qdpkvK
iwXU8PMOXBOmRa+GmzxsxMr1QZcY0m6pY3uuIvqErMFf4qp4BMxQF+VpDLVJUJX/
1oKCM7J3hEfgmKRD4RmKhBlnWVv5YGZmvlXRJBl1AsDTONZy8iKJB5NYnB3ZyrJq
H2GAgyJ55aYckoU55vwjRzKp49dZmzX5YS04Kzzzw/SmOuW8kMypZV5TJH+NXqKc
pw3u3cJ4yJ9DHSU5pnhC5BeKl8XDMO42jRWt5/7C7JDiCbZ9lu5jQiv/4DhsRsHF
A8/Lgl47sNDaBMbha786I9laPHLlVycpYaP6pwtizhN9ZRTdDOHmWi/vjiamERLL
FjjLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAA+1uj3tHaCai+A1H/kOgTN5e0eW
/wmaxu8gNK5eiHrecNJNAlFxVTrCwhvv4nUW7NXVcW/1WUqSO0QMiPJhCsSLVAMF
8MuYH73B+ctRqAGdeOAWF+ftCywZTEj5h5F0XiWB+TmkPlTVNShMiPFelDJpLy7u
9MfiPEJjo4sZotQl8/pZ6R9cY6GpEXWnttcuhLJCEuiB8fWO7epiWYCt/Ak+CVmZ
OzfI/euV6Upaen22lNu8V3ZwWEFtmU5CioKJ3S8DK5Mw/LJIJw1ZY9E+fTtn8x0k
xlI4e7urD2FYhTdv2fFUG8Z5arb/3bICgsUYQZ+G1c3wjWtJg9zcy8hpnZQ=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,28 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from sys import argv
from subprocess import Popen, PIPE, STDOUT
p = Popen(["openssl", "s_client", "-host", argv[1], "-port", "443", "-prexit", "-showcerts"], stdin=PIPE, stdout=PIPE, stderr=STDOUT)
stdout = p.communicate(input=b'\n')[0]
data = stdout.decode()
certs = []
cert = ""
capturing = False
for line in data.split('\n'):
if line == '-----BEGIN CERTIFICATE-----':
capturing = True
if capturing:
cert = "{0}{1}\n".format(cert, line)
if line == '-----END CERTIFICATE-----':
capturing = False
certs.append(cert)
cert = ""
with open(argv[2], 'w') as f:
for cert in set(certs):
f.write(cert)

View File

@@ -0,0 +1,3 @@
dependencies:
- setup_openssl
- prepare_http_tests

View File

@@ -0,0 +1,42 @@
---
- block:
- name: Get servers certificate with backend auto-detection
get_certificate:
host: "{{ httpbin_host }}"
port: 443
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))
- block:
- include_tasks: ../tests/validate.yml
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
- block:
- include_tasks: ../tests/validate.yml
vars:
select_crypto_backend: cryptography
# 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)

View File

@@ -0,0 +1,106 @@
---
- name: Get servers certificate
get_certificate:
host: "{{ httpbin_host }}"
port: 443
select_crypto_backend: "{{ select_crypto_backend }}"
register: result
- debug: var=result
- assert:
that:
# This module should never change anything
- result is not changed
- result is not failed
# We got the correct ST from the cert
- "'North Carolina' == result.subject.ST"
- name: Connect to http port (will fail because there is no SSL cert to get)
get_certificate:
host: "{{ httpbin_host }}"
port: 80
select_crypto_backend: "{{ select_crypto_backend }}"
register: result
ignore_errors: true
- assert:
that:
- result is not changed
- result is failed
# We got the expected error message
- "'The handshake operation timed out' in result.msg or 'unknown protocol' in result.msg or 'wrong version number' in result.msg"
- name: Test timeout option
get_certificate:
host: "{{ httpbin_host }}"
port: 1234
timeout: 1
select_crypto_backend: "{{ select_crypto_backend }}"
register: result
ignore_errors: true
- assert:
that:
- result is not changed
- result is failed
# We got the expected error message
- "'Failed to get cert from port with error: timed out' == result.msg or 'Connection refused' in result.msg"
- name: Test failure if ca_cert is not a valid file
get_certificate:
host: "{{ httpbin_host }}"
port: 443
ca_cert: dn.e
select_crypto_backend: "{{ select_crypto_backend }}"
register: result
ignore_errors: true
- assert:
that:
- result is not changed
- result is failed
# We got the correct response from the module
- "'ca_cert file does not exist' == result.msg"
- name: Download CA Cert as pem from server
get_url:
url: "http://ansible.http.tests/cacert.pem"
dest: "{{ output_dir }}/temp.pem"
- name: Get servers certificate comparing it to its own ca_cert file
get_certificate:
ca_cert: '{{ output_dir }}/temp.pem'
host: "{{ httpbin_host }}"
port: 443
select_crypto_backend: "{{ select_crypto_backend }}"
register: result
- assert:
that:
- 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"
dest: "{{ my_temp_dir.path }}/bogus_ca.pem"
- name: Get servers certificate comparing it to an invalid ca_cert file
get_certificate:
ca_cert: '{{ my_temp_dir.path }}/bogus_ca.pem'
host: "{{ httpbin_host }}"
port: 443
select_crypto_backend: "{{ select_crypto_backend }}"
register: result
ignore_errors: true
- assert:
that:
- result is not changed
- result.failed

View File

@@ -0,0 +1,2 @@
hidden

View File

@@ -0,0 +1,40 @@
---
- name: Include OS-specific variables
include_vars: '{{ ansible_os_family }}.yml'
when: not ansible_os_family == "Darwin"
- name: Install OpenSSL
become: True
package:
name: '{{ openssl_package_name }}'
when: not ansible_os_family == 'Darwin'
- name: Install pyOpenSSL (Python 3)
become: True
package:
name: '{{ pyopenssl_package_name_python3 }}'
when: not ansible_os_family == 'Darwin' and ansible_python_version is version('3.0', '>=')
- name: Install pyOpenSSL (Python 2)
become: True
package:
name: '{{ pyopenssl_package_name }}'
when: not ansible_os_family == 'Darwin' and ansible_python_version is version('3.0', '<')
- name: Install pyOpenSSL (Darwin)
become: True
pip:
name: pyOpenSSL
when: ansible_os_family == 'Darwin'
- name: register pyOpenSSL version
command: "{{ ansible_python.executable }} -c 'import OpenSSL; print(OpenSSL.__version__)'"
register: pyopenssl_version
- name: register openssl version
shell: "openssl version | cut -d' ' -f2"
register: openssl_version
- name: register cryptography version
command: "{{ ansible_python.executable }} -c 'import cryptography; print(cryptography.__version__)'"
register: cryptography_version

View File

@@ -0,0 +1,3 @@
pyopenssl_package_name: python-openssl
pyopenssl_package_name_python3: python3-openssl
openssl_package_name: openssl

View File

@@ -0,0 +1,3 @@
pyopenssl_package_name: py27-openssl
pyopenssl_package_name_python3: py36-openssl
openssl_package_name: openssl

View File

@@ -0,0 +1,3 @@
pyopenssl_package_name: pyOpenSSL
pyopenssl_package_name_python3: python3-pyOpenSSL
openssl_package_name: openssl

View File

@@ -0,0 +1,3 @@
pyopenssl_package_name: python-pyOpenSSL
pyopenssl_package_name_python3: python3-pyOpenSSL
openssl_package_name: openssl

View File

@@ -0,0 +1,4 @@
x509_crl_info
shippable/posix/incidental
destructive
skip/aix

View File

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

View File

@@ -0,0 +1,289 @@
---
- name: Create CRL 1 (check mode)
x509_crl:
path: '{{ output_dir }}/ca-crl1.crl'
privatekey_path: '{{ output_dir }}/ca.key'
issuer:
CN: Ansible
last_update: 20191013000000Z
next_update: 20191113000000Z
revoked_certificates:
- path: '{{ output_dir }}/cert-1.pem'
revocation_date: 20191013000000Z
- path: '{{ output_dir }}/cert-2.pem'
revocation_date: 20191013000000Z
reason: key_compromise
reason_critical: yes
invalidity_date: 20191012000000Z
- serial_number: 1234
revocation_date: 20191001000000Z
check_mode: yes
register: crl_1_check
- name: Create CRL 1
x509_crl:
path: '{{ output_dir }}/ca-crl1.crl'
privatekey_path: '{{ output_dir }}/ca.key'
issuer:
CN: Ansible
last_update: 20191013000000Z
next_update: 20191113000000Z
revoked_certificates:
- path: '{{ output_dir }}/cert-1.pem'
revocation_date: 20191013000000Z
- path: '{{ output_dir }}/cert-2.pem'
revocation_date: 20191013000000Z
reason: key_compromise
reason_critical: yes
invalidity_date: 20191012000000Z
- serial_number: 1234
revocation_date: 20191001000000Z
register: crl_1
- name: Retrieve CRL 1 infos
x509_crl_info:
path: '{{ output_dir }}/ca-crl1.crl'
register: crl_1_info_1
- name: Retrieve CRL 1 infos via file content
x509_crl_info:
content: '{{ lookup("file", output_dir ~ "/ca-crl1.crl") }}'
register: crl_1_info_2
- name: Create CRL 1 (idempotent, check mode)
x509_crl:
path: '{{ output_dir }}/ca-crl1.crl'
privatekey_path: '{{ output_dir }}/ca.key'
issuer:
CN: Ansible
last_update: 20191013000000Z
next_update: 20191113000000Z
revoked_certificates:
- path: '{{ output_dir }}/cert-1.pem'
revocation_date: 20191013000000Z
- path: '{{ output_dir }}/cert-2.pem'
revocation_date: 20191013000000Z
reason: key_compromise
reason_critical: yes
invalidity_date: 20191012000000Z
- serial_number: 1234
revocation_date: 20191001000000Z
check_mode: yes
register: crl_1_idem_check
- name: Create CRL 1 (idempotent)
x509_crl:
path: '{{ output_dir }}/ca-crl1.crl'
privatekey_path: '{{ output_dir }}/ca.key'
issuer:
CN: Ansible
last_update: 20191013000000Z
next_update: 20191113000000Z
revoked_certificates:
- path: '{{ output_dir }}/cert-1.pem'
revocation_date: 20191013000000Z
- path: '{{ output_dir }}/cert-2.pem'
revocation_date: 20191013000000Z
reason: key_compromise
reason_critical: yes
invalidity_date: 20191012000000Z
- serial_number: 1234
revocation_date: 20191001000000Z
register: crl_1_idem
- name: Create CRL 1 (idempotent with content, check mode)
x509_crl:
path: '{{ output_dir }}/ca-crl1.crl'
privatekey_content: "{{ lookup('file', output_dir ~ '/ca.key') }}"
issuer:
CN: Ansible
last_update: 20191013000000Z
next_update: 20191113000000Z
revoked_certificates:
- content: "{{ lookup('file', output_dir ~ '/cert-1.pem') }}"
revocation_date: 20191013000000Z
- content: "{{ lookup('file', output_dir ~ '/cert-2.pem') }}"
revocation_date: 20191013000000Z
reason: key_compromise
reason_critical: yes
invalidity_date: 20191012000000Z
- serial_number: 1234
revocation_date: 20191001000000Z
check_mode: yes
register: crl_1_idem_content_check
- name: Create CRL 1 (idempotent with content)
x509_crl:
path: '{{ output_dir }}/ca-crl1.crl'
privatekey_content: "{{ lookup('file', output_dir ~ '/ca.key') }}"
issuer:
CN: Ansible
last_update: 20191013000000Z
next_update: 20191113000000Z
revoked_certificates:
- content: "{{ lookup('file', output_dir ~ '/cert-1.pem') }}"
revocation_date: 20191013000000Z
- content: "{{ lookup('file', output_dir ~ '/cert-2.pem') }}"
revocation_date: 20191013000000Z
reason: key_compromise
reason_critical: yes
invalidity_date: 20191012000000Z
- serial_number: 1234
revocation_date: 20191001000000Z
register: crl_1_idem_content
- name: Create CRL 2 (check mode)
x509_crl:
path: '{{ output_dir }}/ca-crl2.crl'
privatekey_path: '{{ output_dir }}/ca.key'
issuer:
CN: Ansible
last_update: +0d
next_update: +0d
revoked_certificates:
- path: '{{ output_dir }}/cert-1.pem'
- path: '{{ output_dir }}/cert-2.pem'
reason: key_compromise
reason_critical: yes
invalidity_date: 20191012000000Z
- serial_number: 1234
check_mode: yes
register: crl_2_check
- name: Create CRL 2
x509_crl:
path: '{{ output_dir }}/ca-crl2.crl'
privatekey_path: '{{ output_dir }}/ca.key'
issuer:
CN: Ansible
last_update: +0d
next_update: +0d
revoked_certificates:
- path: '{{ output_dir }}/cert-1.pem'
- path: '{{ output_dir }}/cert-2.pem'
reason: key_compromise
reason_critical: yes
invalidity_date: 20191012000000Z
- serial_number: 1234
register: crl_2
- name: Create CRL 2 (idempotent, check mode)
x509_crl:
path: '{{ output_dir }}/ca-crl2.crl'
privatekey_path: '{{ output_dir }}/ca.key'
issuer:
CN: Ansible
last_update: +0d
next_update: +0d
revoked_certificates:
- path: '{{ output_dir }}/cert-1.pem'
- path: '{{ output_dir }}/cert-2.pem'
reason: key_compromise
reason_critical: yes
invalidity_date: 20191012000000Z
- serial_number: 1234
ignore_timestamps: yes
check_mode: yes
register: crl_2_idem_check
- name: Create CRL 2 (idempotent)
x509_crl:
path: '{{ output_dir }}/ca-crl2.crl'
privatekey_path: '{{ output_dir }}/ca.key'
issuer:
CN: Ansible
last_update: +0d
next_update: +0d
revoked_certificates:
- path: '{{ output_dir }}/cert-1.pem'
- path: '{{ output_dir }}/cert-2.pem'
reason: key_compromise
reason_critical: yes
invalidity_date: 20191012000000Z
- serial_number: 1234
ignore_timestamps: yes
register: crl_2_idem
- name: Create CRL 2 (idempotent update, check mode)
x509_crl:
path: '{{ output_dir }}/ca-crl2.crl'
privatekey_path: '{{ output_dir }}/ca.key'
issuer:
CN: Ansible
last_update: +0d
next_update: +0d
revoked_certificates:
- serial_number: 1235
ignore_timestamps: yes
mode: update
check_mode: yes
register: crl_2_idem_update_change_check
- name: Create CRL 2 (idempotent update)
x509_crl:
path: '{{ output_dir }}/ca-crl2.crl'
privatekey_path: '{{ output_dir }}/ca.key'
issuer:
CN: Ansible
last_update: +0d
next_update: +0d
revoked_certificates:
- serial_number: 1235
ignore_timestamps: yes
mode: update
register: crl_2_idem_update_change
- name: Create CRL 2 (idempotent update, check mode)
x509_crl:
path: '{{ output_dir }}/ca-crl2.crl'
privatekey_path: '{{ output_dir }}/ca.key'
issuer:
CN: Ansible
last_update: +0d
next_update: +0d
revoked_certificates:
- path: '{{ output_dir }}/cert-2.pem'
reason: key_compromise
reason_critical: yes
invalidity_date: 20191012000000Z
ignore_timestamps: yes
mode: update
check_mode: yes
register: crl_2_idem_update_check
- name: Create CRL 2 (idempotent update)
x509_crl:
path: '{{ output_dir }}/ca-crl2.crl'
privatekey_path: '{{ output_dir }}/ca.key'
issuer:
CN: Ansible
last_update: +0d
next_update: +0d
revoked_certificates:
- path: '{{ output_dir }}/cert-2.pem'
reason: key_compromise
reason_critical: yes
invalidity_date: 20191012000000Z
ignore_timestamps: yes
mode: update
register: crl_2_idem_update
- name: Create CRL 2 (changed timestamps, check mode)
x509_crl:
path: '{{ output_dir }}/ca-crl2.crl'
privatekey_path: '{{ output_dir }}/ca.key'
issuer:
CN: Ansible
last_update: +0d
next_update: +0d
revoked_certificates:
- path: '{{ output_dir }}/cert-2.pem'
reason: key_compromise
reason_critical: yes
invalidity_date: 20191012000000Z
ignore_timestamps: no
mode: update
check_mode: yes
register: crl_2_change_check
- name: Create CRL 2 (changed timestamps)
x509_crl:
path: '{{ output_dir }}/ca-crl2.crl'
privatekey_path: '{{ output_dir }}/ca.key'
issuer:
CN: Ansible
last_update: +0d
next_update: +0d
revoked_certificates:
- path: '{{ output_dir }}/cert-2.pem'
reason: key_compromise
reason_critical: yes
invalidity_date: 20191012000000Z
ignore_timestamps: no
mode: update
return_content: yes
register: crl_2_change

View File

@@ -0,0 +1,83 @@
---
- set_fact:
certificates:
- name: ca
subject:
commonName: Ansible
is_ca: yes
- name: ca-2
subject:
commonName: Ansible Other CA
is_ca: yes
- name: cert-1
subject_alt_name:
- DNS:ansible.com
- name: cert-2
subject_alt_name:
- DNS:example.com
- name: cert-3
subject_alt_name:
- DNS:example.org
- IP:1.2.3.4
- name: cert-4
subject_alt_name:
- DNS:test.ansible.com
- DNS:b64.ansible.com
- name: Generate private keys
openssl_privatekey:
path: '{{ output_dir }}/{{ item.name }}.key'
type: ECC
curve: secp256r1
loop: "{{ certificates }}"
- name: Generate CSRs
openssl_csr:
path: '{{ output_dir }}/{{ item.name }}.csr'
privatekey_path: '{{ output_dir }}/{{ item.name }}.key'
subject: "{{ item.subject | default(omit) }}"
subject_alt_name: "{{ item.subject_alt_name | default(omit) }}"
basic_constraints: "{{ 'CA:TRUE' if item.is_ca | default(false) else omit }}"
use_common_name_for_san: no
loop: "{{ certificates }}"
- name: Generate CA certificates
openssl_certificate:
path: '{{ output_dir }}/{{ item.name }}.pem'
csr_path: '{{ output_dir }}/{{ item.name }}.csr'
privatekey_path: '{{ output_dir }}/{{ item.name }}.key'
provider: selfsigned
loop: "{{ certificates }}"
when: item.is_ca | default(false)
- name: Generate other certificates
openssl_certificate:
path: '{{ output_dir }}/{{ item.name }}.pem'
csr_path: '{{ output_dir }}/{{ item.name }}.csr'
provider: ownca
ownca_path: '{{ output_dir }}/ca.pem'
ownca_privatekey_path: '{{ output_dir }}/ca.key'
loop: "{{ certificates }}"
when: not (item.is_ca | default(false))
- name: Get certificate infos
openssl_certificate_info:
path: '{{ output_dir }}/{{ item }}.pem'
loop:
- cert-1
- cert-2
- cert-3
- cert-4
register: certificate_infos
- block:
- name: Running tests with cryptography backend
include_tasks: impl.yml
vars:
select_crypto_backend: cryptography
- import_tasks: ../tests/validate.yml
vars:
select_crypto_backend: cryptography
when: cryptography_version.stdout is version('1.2', '>=')

View File

@@ -0,0 +1,61 @@
---
- name: Validate CRL 1
assert:
that:
- crl_1_check is changed
- crl_1 is changed
- crl_1_idem_check is not changed
- crl_1_idem is not changed
- crl_1_idem_content_check is not changed
- crl_1_idem_content is not changed
- name: Validate CRL 1 info
assert:
that:
- crl_1_info_1 == crl_1_info_2
- crl_1_info_1.digest == 'ecdsa-with-SHA256'
- crl_1_info_1.issuer | length == 1
- crl_1_info_1.issuer.commonName == 'Ansible'
- crl_1_info_1.issuer_ordered | length == 1
- crl_1_info_1.last_update == '20191013000000Z'
- crl_1_info_1.next_update == '20191113000000Z'
- crl_1_info_1.revoked_certificates | length == 3
- crl_1_info_1.revoked_certificates[0].invalidity_date is none
- crl_1_info_1.revoked_certificates[0].invalidity_date_critical == false
- crl_1_info_1.revoked_certificates[0].issuer is none
- crl_1_info_1.revoked_certificates[0].issuer_critical == false
- crl_1_info_1.revoked_certificates[0].reason is none
- crl_1_info_1.revoked_certificates[0].reason_critical == false
- crl_1_info_1.revoked_certificates[0].revocation_date == '20191013000000Z'
- crl_1_info_1.revoked_certificates[0].serial_number == certificate_infos.results[0].serial_number
- crl_1_info_1.revoked_certificates[1].invalidity_date == '20191012000000Z'
- crl_1_info_1.revoked_certificates[1].invalidity_date_critical == false
- crl_1_info_1.revoked_certificates[1].issuer is none
- crl_1_info_1.revoked_certificates[1].issuer_critical == false
- crl_1_info_1.revoked_certificates[1].reason == 'key_compromise'
- crl_1_info_1.revoked_certificates[1].reason_critical == true
- crl_1_info_1.revoked_certificates[1].revocation_date == '20191013000000Z'
- crl_1_info_1.revoked_certificates[1].serial_number == certificate_infos.results[1].serial_number
- crl_1_info_1.revoked_certificates[2].invalidity_date is none
- crl_1_info_1.revoked_certificates[2].invalidity_date_critical == false
- crl_1_info_1.revoked_certificates[2].issuer is none
- crl_1_info_1.revoked_certificates[2].issuer_critical == false
- crl_1_info_1.revoked_certificates[2].reason is none
- crl_1_info_1.revoked_certificates[2].reason_critical == false
- crl_1_info_1.revoked_certificates[2].revocation_date == '20191001000000Z'
- crl_1_info_1.revoked_certificates[2].serial_number == 1234
- name: Validate CRL 2
assert:
that:
- crl_2_check is changed
- crl_2 is changed
- crl_2_idem_check is not changed
- crl_2_idem is not changed
- crl_2_idem_update_change_check is changed
- crl_2_idem_update_change is changed
- crl_2_idem_update_check is not changed
- crl_2_idem_update is not changed
- crl_2_change_check is changed
- crl_2_change is changed
- crl_2_change.crl == lookup('file', output_dir ~ '/ca-crl2.crl', rstrip=False)

View File

@@ -0,0 +1,7 @@
shippable/posix/group4
skip/aix
skip/osx
skip/freebsd
skip/docker
needs/root
destructive

View File

@@ -0,0 +1 @@
asdf

View File

@@ -0,0 +1 @@
test1234

View File

@@ -0,0 +1,36 @@
---
- 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
- name: Create lookback device
command: losetup -f {{ output_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
become: yes
register: cryptfile_device_output
- set_fact:
cryptfile_device: "{{ cryptfile_device_output.stdout_lines[1] }}"
cryptfile_passphrase1: "uNiJ9vKG2mUOEWDiQVuBHJlfMHE"
cryptfile_passphrase2: "HW4Ak2HtE2vvne0qjJMPTtmbV4M"
cryptfile_passphrase3: "qQJqsjabO9pItV792k90VvX84MM"
- block:
- include_tasks: run-test.yml
with_fileglob:
- "tests/*.yml"
always:
- name: Make sure LUKS device is gone
luks_device:
device: "{{ cryptfile_device }}"
state: absent
become: yes
ignore_errors: yes
- command: losetup -d "{{ cryptfile_device }}"
become: yes
- file:
dest: "{{ output_dir }}/cryptfile"
state: absent

View File

@@ -0,0 +1,8 @@
---
- name: Make sure LUKS device is gone
luks_device:
device: "{{ cryptfile_device }}"
state: absent
become: yes
- name: "Loading tasks from {{ item }}"
include_tasks: "{{ item }}"

View File

@@ -0,0 +1,187 @@
---
- name: Create (check)
luks_device:
device: "{{ cryptfile_device }}"
state: present
keyfile: "{{ role_path }}/files/keyfile1"
check_mode: yes
become: yes
register: create_check
- name: Create
luks_device:
device: "{{ cryptfile_device }}"
state: present
keyfile: "{{ role_path }}/files/keyfile1"
become: yes
register: create
- name: Create (idempotent)
luks_device:
device: "{{ cryptfile_device }}"
state: present
keyfile: "{{ role_path }}/files/keyfile1"
become: yes
register: create_idem
- name: Create (idempotent, check)
luks_device:
device: "{{ cryptfile_device }}"
state: present
keyfile: "{{ role_path }}/files/keyfile1"
check_mode: yes
become: yes
register: create_idem_check
- assert:
that:
- create_check is changed
- create is changed
- create_idem is not changed
- create_idem_check is not changed
- name: Open (check)
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile1"
check_mode: yes
become: yes
register: open_check
- name: Open
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile1"
become: yes
register: open
- name: Open (idempotent)
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile1"
become: yes
register: open_idem
- name: Open (idempotent, check)
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile1"
check_mode: yes
become: yes
register: open_idem_check
- assert:
that:
- open_check is changed
- open is changed
- open_idem is not changed
- open_idem_check is not changed
- name: Closed (via name, check)
luks_device:
name: "{{ open.name }}"
state: closed
check_mode: yes
become: yes
register: close_check
- name: Closed (via name)
luks_device:
name: "{{ open.name }}"
state: closed
become: yes
register: close
- name: Closed (via name, idempotent)
luks_device:
name: "{{ open.name }}"
state: closed
become: yes
register: close_idem
- name: Closed (via name, idempotent, check)
luks_device:
name: "{{ open.name }}"
state: closed
check_mode: yes
become: yes
register: close_idem_check
- assert:
that:
- close_check is changed
- close is changed
- close_idem is not changed
- close_idem_check is not changed
- name: Re-open
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile1"
become: yes
- name: Closed (via device, check)
luks_device:
device: "{{ cryptfile_device }}"
state: closed
check_mode: yes
become: yes
register: close_check
- name: Closed (via device)
luks_device:
device: "{{ cryptfile_device }}"
state: closed
become: yes
register: close
- name: Closed (via device, idempotent)
luks_device:
device: "{{ cryptfile_device }}"
state: closed
become: yes
register: close_idem
- name: Closed (via device, idempotent, check)
luks_device:
device: "{{ cryptfile_device }}"
state: closed
check_mode: yes
become: yes
register: close_idem_check
- assert:
that:
- close_check is changed
- close is changed
- close_idem is not changed
- close_idem_check is not changed
- name: Re-opened
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile1"
become: yes
- name: Absent (check)
luks_device:
device: "{{ cryptfile_device }}"
state: absent
check_mode: yes
become: yes
register: absent_check
- name: Absent
luks_device:
device: "{{ cryptfile_device }}"
state: absent
become: yes
register: absent
- name: Absent (idempotence)
luks_device:
device: "{{ cryptfile_device }}"
state: absent
become: yes
register: absent_idem
- name: Absent (idempotence, check)
luks_device:
device: "{{ cryptfile_device }}"
state: absent
check_mode: yes
become: yes
register: absent_idem_check
- assert:
that:
- absent_check is changed
- absent is changed
- absent_idem is not changed
- absent_idem_check is not changed

View File

@@ -0,0 +1,48 @@
---
- name: Create with invalid device name (check)
luks_device:
device: /dev/asdfasdfasdf
state: present
keyfile: "{{ role_path }}/files/keyfile1"
check_mode: yes
ignore_errors: yes
become: yes
register: create_check
- name: Create with invalid device name
luks_device:
device: /dev/asdfasdfasdf
state: present
keyfile: "{{ role_path }}/files/keyfile1"
ignore_errors: yes
become: yes
register: create
- assert:
that:
- create_check is failed
- create is failed
- "'o such file or directory' in create_check.msg"
- "'o such file or directory' in create.msg"
- name: Create with something which is not a device (check)
luks_device:
device: /tmp/
state: present
keyfile: "{{ role_path }}/files/keyfile1"
check_mode: yes
ignore_errors: yes
become: yes
register: create_check
- name: Create with something which is not a device
luks_device:
device: /tmp/
state: present
keyfile: "{{ role_path }}/files/keyfile1"
ignore_errors: yes
become: yes
register: create
- assert:
that:
- create_check is failed
- create is failed
- "'is not a device' in create_check.msg"
- "'is not a device' in create.msg"

View File

@@ -0,0 +1,168 @@
---
- name: Create with keyfile1
luks_device:
device: "{{ cryptfile_device }}"
state: closed
keyfile: "{{ role_path }}/files/keyfile1"
become: yes
# Access: keyfile1
- name: Try to open with keyfile1
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile1"
become: yes
ignore_errors: yes
register: open_try
- assert:
that:
- open_try is not failed
- name: Close
luks_device:
device: "{{ cryptfile_device }}"
state: closed
become: yes
- name: Try to open with keyfile2
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile2"
become: yes
ignore_errors: yes
register: open_try
- assert:
that:
- open_try is failed
- name: Give access to keyfile2
luks_device:
device: "{{ cryptfile_device }}"
state: closed
keyfile: "{{ role_path }}/files/keyfile1"
new_keyfile: "{{ role_path }}/files/keyfile2"
become: yes
# Access: keyfile1 and keyfile2
- name: Try to open with keyfile2
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile2"
become: yes
ignore_errors: yes
register: open_try
- assert:
that:
- open_try is not failed
- name: Close
luks_device:
device: "{{ cryptfile_device }}"
state: closed
become: yes
- name: Dump LUKS header
command: "cryptsetup luksDump {{ cryptfile_device }}"
become: yes
- name: Remove access from keyfile1
luks_device:
device: "{{ cryptfile_device }}"
state: closed
keyfile: "{{ role_path }}/files/keyfile1"
remove_keyfile: "{{ role_path }}/files/keyfile1"
become: yes
# Access: keyfile2
- name: Try to open with keyfile1
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile1"
become: yes
ignore_errors: yes
register: open_try
- assert:
that:
- open_try is failed
- name: Try to open with keyfile2
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile2"
become: yes
ignore_errors: yes
register: open_try
- assert:
that:
- open_try is not failed
- name: Close
luks_device:
device: "{{ cryptfile_device }}"
state: closed
become: yes
- name: Dump LUKS header
command: "cryptsetup luksDump {{ cryptfile_device }}"
become: yes
- name: Remove access from keyfile2
luks_device:
device: "{{ cryptfile_device }}"
state: closed
keyfile: "{{ role_path }}/files/keyfile2"
remove_keyfile: "{{ role_path }}/files/keyfile2"
become: yes
ignore_errors: yes
register: remove_last_key
- assert:
that:
- remove_last_key is failed
- "'force_remove_last_key' in remove_last_key.msg"
# Access: keyfile2
- name: Try to open with keyfile2
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile2"
become: yes
ignore_errors: yes
register: open_try
- assert:
that:
- open_try is not failed
- name: Close
luks_device:
device: "{{ cryptfile_device }}"
state: closed
become: yes
- name: Remove access from keyfile2
luks_device:
device: "{{ cryptfile_device }}"
state: closed
keyfile: "{{ role_path }}/files/keyfile2"
remove_keyfile: "{{ role_path }}/files/keyfile2"
force_remove_last_key: yes
become: yes
# Access: none
- name: Try to open with keyfile2
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile2"
become: yes
ignore_errors: yes
register: open_try
- assert:
that:
- open_try is failed

View File

@@ -0,0 +1,41 @@
---
- name: Create with keysize
luks_device:
device: "{{ cryptfile_device }}"
state: present
keyfile: "{{ role_path }}/files/keyfile1"
keysize: 256
become: yes
register: create_with_keysize
- name: Create with keysize (idempotent)
luks_device:
device: "{{ cryptfile_device }}"
state: present
keyfile: "{{ role_path }}/files/keyfile1"
keysize: 256
become: yes
register: create_idem_with_keysize
- name: Create with different keysize (idempotent since we do not update keysize)
luks_device:
device: "{{ cryptfile_device }}"
state: present
keyfile: "{{ role_path }}/files/keyfile1"
keysize: 512
become: yes
register: create_idem_with_diff_keysize
- name: Create with ambiguous arguments
luks_device:
device: "{{ cryptfile_device }}"
state: present
keyfile: "{{ role_path }}/files/keyfile1"
passphrase: "{{ cryptfile_passphrase1 }}"
ignore_errors: yes
become: yes
register: create_with_ambiguous
- assert:
that:
- create_with_keysize is changed
- create_idem_with_keysize is not changed
- create_idem_with_diff_keysize is not changed
- create_with_ambiguous is failed

View File

@@ -0,0 +1,181 @@
---
- name: Create with passphrase1
luks_device:
device: "{{ cryptfile_device }}"
state: closed
passphrase: "{{ cryptfile_passphrase1 }}"
become: yes
- name: Open with passphrase1
luks_device:
device: "{{ cryptfile_device }}"
state: opened
passphrase: "{{ cryptfile_passphrase1 }}"
become: yes
ignore_errors: yes
register: open_try
- assert:
that:
- open_try is not failed
- name: Close
luks_device:
device: "{{ cryptfile_device }}"
state: closed
become: yes
- name: Give access with ambiguous new_ arguments
luks_device:
device: "{{ cryptfile_device }}"
state: closed
passphrase: "{{ cryptfile_passphrase1 }}"
new_passphrase: "{{ cryptfile_passphrase2 }}"
new_keyfile: "{{ role_path }}/files/keyfile1"
become: yes
ignore_errors: yes
register: new_try
- assert:
that:
- new_try is failed
- name: Try to open with passphrase2
luks_device:
device: "{{ cryptfile_device }}"
state: opened
passphrase: "{{ cryptfile_passphrase2 }}"
become: yes
ignore_errors: yes
register: open_try
- assert:
that:
- open_try is failed
- name: Give access to passphrase2
luks_device:
device: "{{ cryptfile_device }}"
state: closed
passphrase: "{{ cryptfile_passphrase1 }}"
new_passphrase: "{{ cryptfile_passphrase2 }}"
become: yes
- name: Open with passphrase2
luks_device:
device: "{{ cryptfile_device }}"
state: opened
passphrase: "{{ cryptfile_passphrase2 }}"
become: yes
ignore_errors: yes
register: open_try
- assert:
that:
- open_try is not failed
- name: Close
luks_device:
device: "{{ cryptfile_device }}"
state: closed
become: yes
- name: Try to open with keyfile1
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile1"
become: yes
ignore_errors: yes
register: open_try
- assert:
that:
- open_try is failed
- name: Give access to keyfile1 from passphrase1
luks_device:
device: "{{ cryptfile_device }}"
state: closed
passphrase: "{{ cryptfile_passphrase1 }}"
new_keyfile: "{{ role_path }}/files/keyfile1"
become: yes
- name: Remove access with ambiguous remove_ arguments
luks_device:
device: "{{ cryptfile_device }}"
state: closed
remove_keyfile: "{{ role_path }}/files/keyfile1"
remove_passphrase: "{{ cryptfile_passphrase1 }}"
become: yes
ignore_errors: yes
register: remove_try
- assert:
that:
- remove_try is failed
- name: Open with keyfile1
luks_device:
device: "{{ cryptfile_device }}"
state: opened
keyfile: "{{ role_path }}/files/keyfile1"
become: yes
ignore_errors: yes
register: open_try
- assert:
that:
- open_try is not failed
- name: Close
luks_device:
device: "{{ cryptfile_device }}"
state: closed
become: yes
- name: Remove access for passphrase1
luks_device:
device: "{{ cryptfile_device }}"
state: closed
remove_passphrase: "{{ cryptfile_passphrase1 }}"
become: yes
- name: Try to open with passphrase1
luks_device:
device: "{{ cryptfile_device }}"
state: opened
passphrase: "{{ cryptfile_passphrase1 }}"
become: yes
ignore_errors: yes
register: open_try
- assert:
that:
- open_try is failed
- name: Try to open with passphrase3
luks_device:
device: "{{ cryptfile_device }}"
state: opened
passphrase: "{{ cryptfile_passphrase3 }}"
become: yes
ignore_errors: yes
register: open_try
- assert:
that:
- open_try is failed
- name: Give access to passphrase3 from keyfile1
luks_device:
device: "{{ cryptfile_device }}"
state: closed
keyfile: "{{ role_path }}/files/keyfile1"
new_passphrase: "{{ cryptfile_passphrase3 }}"
become: yes
- name: Open with passphrase3
luks_device:
device: "{{ cryptfile_device }}"
state: opened
passphrase: "{{ cryptfile_passphrase3 }}"
become: yes
ignore_errors: yes
register: open_try
- assert:
that:
- open_try is not failed
- name: Close
luks_device:
device: "{{ cryptfile_device }}"
state: closed
become: yes

View File

@@ -0,0 +1,3 @@
shippable/posix/group1
destructive
skip/aix

View File

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

View File

@@ -0,0 +1,408 @@
- name: openssh_cert integration tests
when: not (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6")
block:
- name: Generate keypair (check mode)
openssh_keypair:
path: '{{ output_dir }}/id_key'
type: rsa
check_mode: yes
- name: Generate keypair
openssh_keypair:
path: '{{ output_dir }}/id_key'
type: rsa
- name: Generate keypair (idempotent)
openssh_keypair:
path: '{{ output_dir }}/id_key'
type: rsa
- name: Generate keypair (idempotent, check mode)
openssh_keypair:
path: '{{ output_dir }}/id_key'
type: rsa
check_mode: yes
- name: Generate always valid cert (check mode)
openssh_cert:
type: user
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
valid_from: always
valid_to: forever
check_mode: yes
- name: Generate always valid cert
openssh_cert:
type: user
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
valid_from: always
valid_to: forever
- name: Generate always valid cert (idempotent)
openssh_cert:
type: user
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
valid_from: always
valid_to: forever
- name: Generate always valid cert (idempotent, check mode)
openssh_cert:
type: user
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
valid_from: always
valid_to: forever
check_mode: yes
- name: Generate restricted validity cert with valid_at (check mode)
openssh_cert:
type: host
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
valid_from: +0s
valid_to: +32w
valid_at: +2w
check_mode: yes
- name: Generate restricted validity cert with valid_at
openssh_cert:
type: host
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
valid_from: +0s
valid_to: +32w
valid_at: +2w
- name: Generate restricted validity cert with valid_at (idempotent)
openssh_cert:
type: host
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
valid_from: +0s
valid_to: +32w
valid_at: +2w
- name: Generate restricted validity cert with valid_at (idempotent, check mode)
openssh_cert:
type: host
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
valid_from: +0s
valid_to: +32w
valid_at: +2w
check_mode: yes
- name: Generate always valid cert only for example.com and examplehost (check mode)
openssh_cert:
type: host
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
valid_from: always
valid_to: forever
principals:
- example.com
- examplehost
check_mode: yes
- name: Generate always valid cert only for example.com and examplehost
openssh_cert:
type: host
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
valid_from: always
valid_to: forever
principals:
- example.com
- examplehost
- name: Generate always valid cert only for example.com and examplehost (idempotent)
openssh_cert:
type: host
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
valid_from: always
valid_to: forever
principals:
- example.com
- examplehost
- name: Generate always valid cert only for example.com and examplehost (idempotent, check mode)
openssh_cert:
type: host
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
valid_from: always
valid_to: forever
principals:
- example.com
- examplehost
check_mode: yes
- name: Generate always valid cert only for example.com and examplehost (idempotent, switch)
openssh_cert:
type: host
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
valid_from: always
valid_to: forever
principals:
- examplehost
- example.com
- name: Generate OpenSSH host Certificate that is valid from 21.1.2001 to 21.1.2019 (check mode)
openssh_cert:
type: host
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
valid_from: "2001-01-21"
valid_to: "2019-01-21"
check_mode: yes
- name: Generate OpenSSH host Certificate that is valid from 21.1.2001 to 21.1.2019
openssh_cert:
type: host
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
valid_from: "2001-01-21"
valid_to: "2019-01-21"
- name: Generate OpenSSH host Certificate that is valid from 21.1.2001 to 21.1.2019 (idempotent)
openssh_cert:
type: host
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
valid_from: "2001-01-21"
valid_to: "2019-01-21"
- name: Generate OpenSSH host Certificate that is valid from 21.1.2001 to 21.1.2019 (idempotent, check mode)
openssh_cert:
type: host
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
valid_from: "2001-01-21"
valid_to: "2019-01-21"
check_mode: yes
- name: Generate an OpenSSH user Certificate with clear and force-command option (check mode)
openssh_cert:
type: user
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
options:
- "clear"
- "force-command=/tmp/bla/foo"
valid_from: "2001-01-21"
valid_to: "2019-01-21"
check_mode: yes
- name: Generate an OpenSSH user Certificate with clear and force-command option
openssh_cert:
type: user
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
options:
- "clear"
- "force-command=/tmp/bla/foo"
valid_from: "2001-01-21"
valid_to: "2019-01-21"
- name: Generate an OpenSSH user Certificate with clear and force-command option (idempotent)
openssh_cert:
type: user
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
options:
- "clear"
- "force-command=/tmp/bla/foo"
valid_from: "2001-01-21"
valid_to: "2019-01-21"
- name: Generate an OpenSSH user Certificate with clear and force-command option (idempotent, check mode)
openssh_cert:
type: user
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
options:
- "clear"
- "force-command=/tmp/bla/foo"
valid_from: "2001-01-21"
valid_to: "2019-01-21"
check_mode: yes
- name: Generate an OpenSSH user Certificate with clear and force-command option (idempotent, switch)
openssh_cert:
type: user
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert'
options:
- "force-command=/tmp/bla/foo"
- "clear"
valid_from: "2001-01-21"
valid_to: "2019-01-21"
- name: Generate cert without serial
openssh_cert:
type: user
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert_no_serial'
valid_from: always
valid_to: forever
register: rc_no_serial_number
- name: check default serial
assert:
that:
- "'Serial: 0' in rc_no_serial_number.info"
msg: OpenSSH user certificate contains the default serial number.
- name: Generate cert without serial (idempotent)
openssh_cert:
type: user
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert_no_serial'
valid_from: always
valid_to: forever
register: rc_no_serial_number_idempotent
- name: check idempotent
assert:
that:
- rc_no_serial_number_idempotent is not changed
msg: OpenSSH certificate generation without serial number is idempotent.
- name: Generate cert with serial 42
openssh_cert:
type: user
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert_serial_42'
valid_from: always
valid_to: forever
serial_number: 42
register: rc_serial_number
- name: check serial 42
assert:
that:
- "'Serial: 42' in rc_serial_number.info"
msg: OpenSSH user certificate contains the serial number from the params.
- name: Generate cert with serial 42 (idempotent)
openssh_cert:
type: user
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert_serial_42'
valid_from: always
valid_to: forever
serial_number: 42
register: rc_serial_number_idempotent
- name: check idempotent
assert:
that:
- rc_serial_number_idempotent is not changed
msg: OpenSSH certificate generation with serial number is idempotent.
- name: Generate cert with changed serial number
openssh_cert:
type: user
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert_serial_42'
valid_from: always
valid_to: forever
serial_number: 1337
register: rc_serial_number_changed
- name: check changed
assert:
that:
- rc_serial_number_changed is changed
msg: OpenSSH certificate regenerated upon serial number change.
- name: Generate cert with removed serial number
openssh_cert:
type: user
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert_serial_42'
valid_from: always
valid_to: forever
serial_number: 0
register: rc_serial_number_removed
- name: check changed
assert:
that:
- rc_serial_number_removed is changed
msg: OpenSSH certificate regenerated upon serial number removal.
- name: Generate a new cert with serial number
openssh_cert:
type: user
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert_serial_ignore'
valid_from: always
valid_to: forever
serial_number: 42
- name: Generate cert again, omitting the parameter serial_number (idempotent)
openssh_cert:
type: user
signing_key: '{{ output_dir }}/id_key'
public_key: '{{ output_dir }}/id_key.pub'
path: '{{ output_dir }}/id_cert_serial_ignore'
valid_from: always
valid_to: forever
register: rc_serial_number_ignored
- name: check idempotent
assert:
that:
- rc_serial_number_ignored is not changed
msg: OpenSSH certificate generation with omitted serial number is idempotent.
- name: Remove certificate (check mode)
openssh_cert:
state: absent
path: '{{ output_dir }}/id_cert'
#type: user
#signing_key: '{{ output_dir }}/id_key'
#public_key: '{{ output_dir }}/id_key.pub'
#valid_from: "2001-01-21"
#valid_to: "2019-01-21"
check_mode: yes
- name: Remove certificate
openssh_cert:
state: absent
path: '{{ output_dir }}/id_cert'
#type: user
#signing_key: '{{ output_dir }}/id_key'
#public_key: '{{ output_dir }}/id_key.pub'
#valid_from: "2001-01-21"
#valid_to: "2019-01-21"
- name: Remove certificate (idempotent)
openssh_cert:
state: absent
path: '{{ output_dir }}/id_cert'
#type: user
#signing_key: '{{ output_dir }}/id_key'
#public_key: '{{ output_dir }}/id_key.pub'
#valid_from: "2001-01-21"
#valid_to: "2019-01-21"
- name: Remove certificate (idempotent, check mode)
openssh_cert:
state: absent
path: '{{ output_dir }}/id_cert'
#type: user
#signing_key: '{{ output_dir }}/id_key'
#public_key: '{{ output_dir }}/id_key.pub'
#valid_from: "2001-01-21"
#valid_to: "2019-01-21"
check_mode: yes
- name: Remove keypair (check mode)
openssh_keypair:
path: '{{ output_dir }}/id_key'
state: absent
check_mode: yes
- name: Remove keypair
openssh_keypair:
path: '{{ output_dir }}/id_key'
state: absent
- name: Remove keypair (idempotent)
openssh_keypair:
path: '{{ output_dir }}/id_key'
state: absent
- name: Remove keypair (idempotent, check mode)
openssh_keypair:
path: '{{ output_dir }}/id_key'
state: absent
check_mode: yes

View File

@@ -0,0 +1,3 @@
shippable/posix/group1
destructive
skip/aix

View File

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

View File

@@ -0,0 +1,375 @@
---
- name: Generate privatekey1 - standard
openssh_keypair:
path: '{{ output_dir }}/privatekey1'
register: privatekey1_result
- name: Generate privatekey1 - standard (idempotent)
openssh_keypair:
path: '{{ output_dir }}/privatekey1'
register: privatekey1_idem_result
- name: Generate privatekey2 - size 2048
openssh_keypair:
path: '{{ output_dir }}/privatekey2'
size: 2048
- name: Generate privatekey3 - type dsa
openssh_keypair:
path: '{{ output_dir }}/privatekey3'
type: dsa
- name: Generate privatekey4 - standard
openssh_keypair:
path: '{{ output_dir }}/privatekey4'
- name: Delete privatekey4 - standard
openssh_keypair:
state: absent
path: '{{ output_dir }}/privatekey4'
- name: Generate privatekey5 - standard
openssh_keypair:
path: '{{ output_dir }}/privatekey5'
register: publickey_gen
- name: Generate privatekey6
openssh_keypair:
path: '{{ output_dir }}/privatekey6'
type: rsa
- name: Regenerate privatekey6 via force
openssh_keypair:
path: '{{ output_dir }}/privatekey6'
type: rsa
force: yes
register: output_regenerated_via_force
- name: Create broken key
copy:
dest: '{{ item }}'
content: ''
mode: '0700'
loop:
- '{{ output_dir }}/privatekeybroken'
- '{{ output_dir }}/privatekeybroken.pub'
- name: Regenerate broken key - should fail
openssh_keypair:
path: '{{ output_dir }}/privatekeybroken'
type: rsa
register: output_broken
ignore_errors: yes
- name: Regenerate broken key with force
openssh_keypair:
path: '{{ output_dir }}/privatekeybroken'
type: rsa
force: yes
register: output_broken_force
- name: Generate read-only private key
openssh_keypair:
path: '{{ output_dir }}/privatekeyreadonly'
type: rsa
mode: '0200'
- name: Regenerate read-only private key via force
openssh_keypair:
path: '{{ output_dir }}/privatekeyreadonly'
type: rsa
force: yes
register: output_read_only
- name: Generate privatekey7 - standard with comment
openssh_keypair:
path: '{{ output_dir }}/privatekey7'
comment: 'test@privatekey7'
register: privatekey7_result
- name: Modify privatekey7 comment
openssh_keypair:
path: '{{ output_dir }}/privatekey7'
comment: 'test_modified@privatekey7'
register: privatekey7_modified_result
- name: Generate password protected key
command: 'ssh-keygen -f {{ output_dir }}/privatekey8 -N password'
- name: Try to modify the password protected key - should fail
openssh_keypair:
path: '{{ output_dir }}/privatekey8'
register: privatekey8_result
ignore_errors: yes
- name: Try to modify the password protected key with force=yes
openssh_keypair:
path: '{{ output_dir }}/privatekey8'
force: yes
register: privatekey8_result_force
- import_tasks: ../tests/validate.yml
# Test regenerate option
- name: Regenerate - setup simple keys
openssh_keypair:
path: '{{ output_dir }}/regenerate-a-{{ item }}'
type: rsa
size: 1024
loop: "{{ regenerate_values }}"
- name: Regenerate - setup password protected keys
command: 'ssh-keygen -f {{ output_dir }}/regenerate-b-{{ item }} -N password'
loop: "{{ regenerate_values }}"
- name: Regenerate - setup broken keys
copy:
dest: '{{ output_dir }}/regenerate-c-{{ item.0 }}{{ item.1 }}'
content: 'broken key'
mode: '0700'
with_nested:
- "{{ regenerate_values }}"
- [ '', '.pub' ]
- name: Regenerate - modify broken keys (check mode)
openssh_keypair:
path: '{{ output_dir }}/regenerate-c-{{ item }}'
type: rsa
size: 1024
regenerate: '{{ item }}'
check_mode: yes
loop: "{{ regenerate_values }}"
ignore_errors: yes
register: result
- assert:
that:
- result.results[0] is failed
- "'Unable to read the key. The key is protected with a passphrase or broken. Will not proceed.' in result.results[0].msg"
- result.results[1] is failed
- "'Unable to read the key. The key is protected with a passphrase or broken. Will not proceed.' in result.results[1].msg"
- result.results[2] is failed
- "'Unable to read the key. The key is protected with a passphrase or broken. Will not proceed.' in result.results[2].msg"
- result.results[3] is changed
- result.results[4] is changed
- name: Regenerate - modify broken keys
openssh_keypair:
path: '{{ output_dir }}/regenerate-c-{{ item }}'
type: rsa
size: 1024
regenerate: '{{ item }}'
loop: "{{ regenerate_values }}"
ignore_errors: yes
register: result
- assert:
that:
- result.results[0] is failed
- "'Unable to read the key. The key is protected with a passphrase or broken. Will not proceed.' in result.results[0].msg"
- result.results[1] is failed
- "'Unable to read the key. The key is protected with a passphrase or broken. Will not proceed.' in result.results[1].msg"
- result.results[2] is failed
- "'Unable to read the key. The key is protected with a passphrase or broken. Will not proceed.' in result.results[2].msg"
- result.results[3] is changed
- result.results[4] is changed
- name: Regenerate - modify password protected keys (check mode)
openssh_keypair:
path: '{{ output_dir }}/regenerate-b-{{ item }}'
type: rsa
size: 1024
regenerate: '{{ item }}'
check_mode: yes
loop: "{{ regenerate_values }}"
ignore_errors: yes
register: result
- assert:
that:
- result.results[0] is failed
- "'Unable to read the key. The key is protected with a passphrase or broken. Will not proceed.' in result.results[0].msg"
- result.results[1] is failed
- "'Unable to read the key. The key is protected with a passphrase or broken. Will not proceed.' in result.results[1].msg"
- result.results[2] is failed
- "'Unable to read the key. The key is protected with a passphrase or broken. Will not proceed.' in result.results[2].msg"
- result.results[3] is changed
- result.results[4] is changed
- name: Regenerate - modify password protected keys
openssh_keypair:
path: '{{ output_dir }}/regenerate-b-{{ item }}'
type: rsa
size: 1024
regenerate: '{{ item }}'
loop: "{{ regenerate_values }}"
ignore_errors: yes
register: result
- assert:
that:
- result.results[0] is failed
- "'Unable to read the key. The key is protected with a passphrase or broken. Will not proceed.' in result.results[0].msg"
- result.results[1] is failed
- "'Unable to read the key. The key is protected with a passphrase or broken. Will not proceed.' in result.results[1].msg"
- result.results[2] is failed
- "'Unable to read the key. The key is protected with a passphrase or broken. Will not proceed.' in result.results[2].msg"
- result.results[3] is changed
- result.results[4] is changed
- name: Regenerate - not modify regular keys (check mode)
openssh_keypair:
path: '{{ output_dir }}/regenerate-a-{{ item }}'
type: rsa
size: 1024
regenerate: '{{ item }}'
check_mode: yes
loop: "{{ regenerate_values }}"
register: result
- assert:
that:
- result.results[0] is not changed
- result.results[1] is not changed
- result.results[2] is not changed
- result.results[3] is not changed
- result.results[4] is changed
- name: Regenerate - not modify regular keys
openssh_keypair:
path: '{{ output_dir }}/regenerate-a-{{ item }}'
type: rsa
size: 1024
regenerate: '{{ item }}'
loop: "{{ regenerate_values }}"
register: result
- assert:
that:
- result.results[0] is not changed
- result.results[1] is not changed
- result.results[2] is not changed
- result.results[3] is not changed
- result.results[4] is changed
- name: Regenerate - adjust key size (check mode)
openssh_keypair:
path: '{{ output_dir }}/regenerate-a-{{ item }}'
type: rsa
size: 1048
regenerate: '{{ item }}'
check_mode: yes
loop: "{{ regenerate_values }}"
ignore_errors: yes
register: result
- assert:
that:
- result.results[0] is success and result.results[0] is not changed
- result.results[1] is failed
- "'Key has wrong type and/or size. Will not proceed.' in result.results[1].msg"
- result.results[2] is changed
- result.results[3] is changed
- result.results[4] is changed
- name: Regenerate - adjust key size
openssh_keypair:
path: '{{ output_dir }}/regenerate-a-{{ item }}'
type: rsa
size: 1048
regenerate: '{{ item }}'
loop: "{{ regenerate_values }}"
ignore_errors: yes
register: result
- assert:
that:
- result.results[0] is success and result.results[0] is not changed
- result.results[1] is failed
- "'Key has wrong type and/or size. Will not proceed.' in result.results[1].msg"
- result.results[2] is changed
- result.results[3] is changed
- result.results[4] is changed
- name: Regenerate - redistribute keys
copy:
src: '{{ output_dir }}/regenerate-a-always{{ item.1 }}'
dest: '{{ output_dir }}/regenerate-a-{{ item.0 }}{{ item.1 }}'
remote_src: true
with_nested:
- "{{ regenerate_values }}"
- [ '', '.pub' ]
when: "item.0 != 'always'"
- name: Regenerate - adjust key type (check mode)
openssh_keypair:
path: '{{ output_dir }}/regenerate-a-{{ item }}'
type: dsa
size: 1024
regenerate: '{{ item }}'
check_mode: yes
loop: "{{ regenerate_values }}"
ignore_errors: yes
register: result
- assert:
that:
- result.results[0] is success and result.results[0] is not changed
- result.results[1] is failed
- "'Key has wrong type and/or size. Will not proceed.' in result.results[1].msg"
- result.results[2] is changed
- result.results[3] is changed
- result.results[4] is changed
- name: Regenerate - adjust key type
openssh_keypair:
path: '{{ output_dir }}/regenerate-a-{{ item }}'
type: dsa
size: 1024
regenerate: '{{ item }}'
loop: "{{ regenerate_values }}"
ignore_errors: yes
register: result
- assert:
that:
- result.results[0] is success and result.results[0] is not changed
- result.results[1] is failed
- "'Key has wrong type and/or size. Will not proceed.' in result.results[1].msg"
- result.results[2] is changed
- result.results[3] is changed
- result.results[4] is changed
- name: Regenerate - redistribute keys
copy:
src: '{{ output_dir }}/regenerate-a-always{{ item.1 }}'
dest: '{{ output_dir }}/regenerate-a-{{ item.0 }}{{ item.1 }}'
remote_src: true
with_nested:
- "{{ regenerate_values }}"
- [ '', '.pub' ]
when: "item.0 != 'always'"
- name: Regenerate - adjust comment (check mode)
openssh_keypair:
path: '{{ output_dir }}/regenerate-a-{{ item }}'
type: dsa
size: 1024
comment: test comment
regenerate: '{{ item }}'
check_mode: yes
loop: "{{ regenerate_values }}"
ignore_errors: yes
register: result
- assert:
that:
- result is changed
- name: Regenerate - adjust comment
openssh_keypair:
path: '{{ output_dir }}/regenerate-a-{{ item }}'
type: dsa
size: 1024
comment: test comment
regenerate: '{{ item }}'
loop: "{{ regenerate_values }}"
register: result
- assert:
that:
- result is changed
# for all values but 'always', the key should have not been regenerated.
# verify this by comparing fingerprints:
- result.results[0].fingerprint == result.results[1].fingerprint
- result.results[0].fingerprint == result.results[2].fingerprint
- result.results[0].fingerprint == result.results[3].fingerprint
- result.results[0].fingerprint != result.results[4].fingerprint

View File

@@ -0,0 +1,132 @@
---
- name: Log privatekey1 return values
debug:
var: privatekey1_result
- name: Validate privatekey1 return fingerprint
assert:
that:
- privatekey1_result["fingerprint"] is string
- privatekey1_result["fingerprint"].startswith("SHA256:")
# only distro old enough that it still gives md5 with no prefix
when: ansible_distribution != 'CentOS' and ansible_distribution_major_version != '6'
- name: Validate privatekey1 return public_key
assert:
that:
- privatekey1_result["public_key"] is string
- privatekey1_result["public_key"].startswith("ssh-rsa ")
- name: Validate privatekey1 return size value
assert:
that:
- privatekey1_result["size"]|type_debug == 'int'
- privatekey1_result["size"] == 4096
- name: Validate privatekey1 return key type
assert:
that:
- privatekey1_result["type"] is string
- privatekey1_result["type"] == "rsa"
- name: Validate privatekey1 (test - RSA key with size 4096 bits)
shell: "ssh-keygen -lf {{ output_dir }}/privatekey1 | grep -o -E '^[0-9]+'"
register: privatekey1
- name: Validate privatekey1 (assert - RSA key with size 4096 bits)
assert:
that:
- privatekey1.stdout == '4096'
- name: Validate privatekey1 idempotence
assert:
that:
- privatekey1_idem_result is not changed
- name: Validate privatekey2 (test - RSA key with size 2048 bits)
shell: "ssh-keygen -lf {{ output_dir }}/privatekey2 | grep -o -E '^[0-9]+'"
register: privatekey2
- name: Validate privatekey2 (assert - RSA key with size 2048 bits)
assert:
that:
- privatekey2.stdout == '2048'
- name: Validate privatekey3 (test - DSA key with size 1024 bits)
shell: "ssh-keygen -lf {{ output_dir }}/privatekey3 | grep -o -E '^[0-9]+'"
register: privatekey3
- name: Validate privatekey3 (assert - DSA key with size 4096 bits)
assert:
that:
- privatekey3.stdout == '1024'
- name: Validate privatekey4 (test - Ensure key has been removed)
stat:
path: '{{ output_dir }}/privatekey4'
register: privatekey4
- name: Validate privatekey4 (assert - Ensure key has been removed)
assert:
that:
- privatekey4.stat.exists == False
- name: Validate privatekey5 (assert - Public key module output equal to the public key on host)
assert:
that:
- "publickey_gen.public_key == lookup('file', output_dir ~ '/privatekey5.pub').strip('\n')"
- name: Verify that privatekey6 will be regenerated via force
assert:
that:
- output_regenerated_via_force is changed
- name: Verify that broken key will cause failure
assert:
that:
- output_broken is failed
- "'Unable to read the key. The key is protected with a passphrase or broken.' in output_broken.msg"
- name: Verify that broken key will be regenerated if force=yes is specified
assert:
that:
- output_broken_force is changed
- name: Verify that read-only key will be regenerated
assert:
that:
- output_read_only is changed
- name: Validate privatekey7 (assert - Public key remains the same after comment change)
assert:
that:
- privatekey7_result.public_key == privatekey7_modified_result.public_key
- name: Validate privatekey7 comment on creation
assert:
that:
- privatekey7_result.comment == 'test@privatekey7'
- name: Validate privatekey7 comment update
assert:
that:
- privatekey7_modified_result.comment == 'test_modified@privatekey7'
- name: Check that password protected key made module fail
assert:
that:
- privatekey8_result is failed
- "'Unable to read the key. The key is protected with a passphrase or broken.' in privatekey8_result.msg"
- name: Check that password protected key was regenerated with force=yes
assert:
that:
- privatekey8_result_force is changed

View File

@@ -0,0 +1,7 @@
---
regenerate_values:
- never
- fail
- partial_idempotence
- full_idempotence
- always

View File

@@ -0,0 +1,3 @@
shippable/posix/group5
destructive
skip/aix

View File

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

View File

@@ -0,0 +1,152 @@
---
- name: (Assertonly, {{select_crypto_backend}}) - Generate privatekey
openssl_privatekey:
path: '{{ output_dir }}/privatekey.pem'
- name: (Assertonly, {{select_crypto_backend}}) - Generate privatekey with password
openssl_privatekey:
path: '{{ output_dir }}/privatekeypw.pem'
passphrase: hunter2
cipher: auto
select_crypto_backend: cryptography
- name: (Assertonly, {{select_crypto_backend}}) - Generate CSR (no extensions)
openssl_csr:
path: '{{ output_dir }}/csr_noext.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
subject:
commonName: www.example.com
useCommonNameForSAN: no
- name: (Assertonly, {{select_crypto_backend}}) - Generate CSR (with SANs)
openssl_csr:
path: '{{ output_dir }}/csr_sans.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
subject:
commonName: www.example.com
subject_alt_name:
- "DNS:ansible.com"
- "IP:127.0.0.1"
- "IP:::1"
useCommonNameForSAN: no
- name: (Assertonly, {{select_crypto_backend}}) - Generate selfsigned certificate (no extensions)
openssl_certificate:
path: '{{ output_dir }}/cert_noext.pem'
csr_path: '{{ output_dir }}/csr_noext.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
provider: selfsigned
selfsigned_digest: sha256
select_crypto_backend: '{{ select_crypto_backend }}'
- name: (Assertonly, {{select_crypto_backend}}) - Generate selfsigned certificate (with SANs)
openssl_certificate:
path: '{{ output_dir }}/cert_sans.pem'
csr_path: '{{ output_dir }}/csr_sans.csr'
privatekey_path: '{{ output_dir }}/privatekey.pem'
provider: selfsigned
selfsigned_digest: sha256
select_crypto_backend: '{{ select_crypto_backend }}'
- name: (Assertonly, {{select_crypto_backend}}) - Assert that subject_alt_name is there (should fail)
openssl_certificate:
path: '{{ output_dir }}/cert_noext.pem'
provider: assertonly
subject_alt_name:
- "DNS:example.com"
select_crypto_backend: '{{ select_crypto_backend }}'
ignore_errors: yes
register: extension_missing_san
- name: (Assertonly, {{select_crypto_backend}}) - Assert that subject_alt_name is there
openssl_certificate:
path: '{{ output_dir }}/cert_sans.pem'
provider: assertonly
subject_alt_name:
- "DNS:ansible.com"
- "IP:127.0.0.1"
- "IP:::1"
select_crypto_backend: '{{ select_crypto_backend }}'
register: extension_san
- name: (Assertonly, {{select_crypto_backend}}) - Assert that subject_alt_name is there (strict)
openssl_certificate:
path: '{{ output_dir }}/cert_sans.pem'
provider: assertonly
subject_alt_name:
- "DNS:ansible.com"
- "IP:127.0.0.1"
- "IP:::1"
subject_alt_name_strict: yes
select_crypto_backend: '{{ select_crypto_backend }}'
register: extension_san_strict
- name: (Assertonly, {{select_crypto_backend}}) - Assert that key_usage is there (should fail)
openssl_certificate:
path: '{{ output_dir }}/cert_noext.pem'
provider: assertonly
key_usage:
- digitalSignature
select_crypto_backend: '{{ select_crypto_backend }}'
ignore_errors: yes
register: extension_missing_ku
- name: (Assertonly, {{select_crypto_backend}}) - Assert that extended_key_usage is there (should fail)
openssl_certificate:
path: '{{ output_dir }}/cert_noext.pem'
provider: assertonly
extended_key_usage:
- biometricInfo
select_crypto_backend: '{{ select_crypto_backend }}'
ignore_errors: yes
register: extension_missing_eku
- assert:
that:
- extension_missing_san is failed
- "'Found no subjectAltName extension' in extension_missing_san.msg"
- extension_san is succeeded
- extension_san_strict is succeeded
- extension_missing_ku is failed
- "'Found no keyUsage extension' in extension_missing_ku.msg"
- extension_missing_eku is failed
- "'Found no extendedKeyUsage extension' in extension_missing_eku.msg"
- name: (Assertonly, {{select_crypto_backend}}) - Check private key passphrase fail 1
openssl_certificate:
path: '{{ output_dir }}/cert_noext.pem'
privatekey_path: '{{ output_dir }}/privatekey.pem'
privatekey_passphrase: hunter2
provider: assertonly
select_crypto_backend: '{{ select_crypto_backend }}'
ignore_errors: yes
register: passphrase_error_1
- name: (Assertonly, {{select_crypto_backend}}) - Check private key passphrase fail 2
openssl_certificate:
path: '{{ output_dir }}/cert_noext.pem'
privatekey_path: '{{ output_dir }}/privatekeypw.pem'
privatekey_passphrase: wrong_password
provider: assertonly
select_crypto_backend: '{{ select_crypto_backend }}'
ignore_errors: yes
register: passphrase_error_2
- name: (Assertonly, {{select_crypto_backend}}) - Check private key passphrase fail 3
openssl_certificate:
path: '{{ output_dir }}/cert_noext.pem'
privatekey_path: '{{ output_dir }}/privatekeypw.pem'
provider: assertonly
select_crypto_backend: '{{ select_crypto_backend }}'
ignore_errors: yes
register: passphrase_error_3
- name: (Assertonly, {{select_crypto_backend}}) -
assert:
that:
- passphrase_error_1 is failed
- "'assphrase' in passphrase_error_1.msg or 'assword' in passphrase_error_1.msg"
- passphrase_error_2 is failed
- "'assphrase' in passphrase_error_2.msg or 'assword' in passphrase_error_2.msg or 'serializ' in passphrase_error_2.msg"
- passphrase_error_3 is failed
- "'assphrase' in passphrase_error_3.msg or 'assword' in passphrase_error_3.msg or 'serializ' in passphrase_error_3.msg"

View File

@@ -0,0 +1,48 @@
---
- name: (Expired, {{select_crypto_backend}}) Generate privatekey
openssl_privatekey:
path: '{{ output_dir }}/has_expired_privatekey.pem'
- name: (Expired, {{select_crypto_backend}}) Generate CSR
openssl_csr:
path: '{{ output_dir }}/has_expired_csr.csr'
privatekey_path: '{{ output_dir }}/has_expired_privatekey.pem'
subject:
commonName: www.example.com
- name: (Expired, {{select_crypto_backend}}) Generate expired selfsigned certificate
openssl_certificate:
path: '{{ output_dir }}/has_expired_cert.pem'
csr_path: '{{ output_dir }}/has_expired_csr.csr'
privatekey_path: '{{ output_dir }}/has_expired_privatekey.pem'
provider: selfsigned
selfsigned_digest: sha256
selfsigned_not_after: "-1s"
selfsigned_not_before: "-100s"
select_crypto_backend: '{{ select_crypto_backend }}'
when: select_crypto_backend == 'pyopenssl' # cryptography won't allow creating expired certificates
- name: (Expired, {{select_crypto_backend}}) Generate expired selfsigned certificate
command: "openssl x509 -req -days -1 -in {{ output_dir }}/has_expired_csr.csr -signkey {{ output_dir }}/has_expired_privatekey.pem -out {{ output_dir }}/has_expired_cert.pem"
when: select_crypto_backend == 'cryptography' # So we create it with 'command'
- name: "(Expired) Check task fails because cert is expired (has_expired: false)"
openssl_certificate:
provider: assertonly
path: "{{ output_dir }}/has_expired_cert.pem"
has_expired: false
select_crypto_backend: '{{ select_crypto_backend }}'
ignore_errors: true
register: expired_cert_check
- name: (Expired, {{select_crypto_backend}}) Ensure previous task failed
assert:
that: expired_cert_check is failed
- name: "(Expired) Check expired cert check is ignored (has_expired: true)"
openssl_certificate:
provider: assertonly
path: "{{ output_dir }}/has_expired_cert.pem"
has_expired: true
select_crypto_backend: '{{ select_crypto_backend }}'
register: expired_cert_skip

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