From edbbd740407ec06dc660f2454747c9e779333dbc Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Sat, 16 Apr 2022 09:29:21 +0200 Subject: [PATCH] Add EE files. --- .github/workflows/ee.yml | 109 ++++++++++++++++++ changelogs/fragments/440-ee.yml | 2 + meta/ee-bindep.txt | 10 ++ meta/ee-requirements.txt | 1 + meta/execution-environment.yml | 5 + tests/ee/all.yml | 30 +++++ tests/ee/roles/crypto_info/tasks/main.yml | 27 +++++ tests/ee/roles/luks_device/tasks/main.yml | 45 ++++++++ tests/ee/roles/openssh_keypair/tasks/main.yml | 12 ++ tests/ee/roles/openssl_pkcs12/tasks/main.yml | 40 +++++++ .../roles/openssl_privatekey/tasks/main.yml | 11 ++ .../ee/roles/smoke/library/smoke_ipaddress.py | 48 ++++++++ tests/ee/roles/smoke/library/smoke_pyyaml.py | 48 ++++++++ tests/ee/roles/smoke/tasks/main.yml | 18 +++ .../ee/roles/x509_certificate/tasks/main.yml | 18 +++ tests/sanity/ignore-2.10.txt | 2 + tests/sanity/ignore-2.11.txt | 2 + tests/sanity/ignore-2.12.txt | 2 + tests/sanity/ignore-2.13.txt | 2 + tests/sanity/ignore-2.14.txt | 2 + tests/sanity/ignore-2.9.txt | 2 + 21 files changed, 436 insertions(+) create mode 100644 .github/workflows/ee.yml create mode 100644 changelogs/fragments/440-ee.yml create mode 100644 meta/ee-bindep.txt create mode 100644 meta/ee-requirements.txt create mode 100644 meta/execution-environment.yml create mode 100644 tests/ee/all.yml create mode 100644 tests/ee/roles/crypto_info/tasks/main.yml create mode 100644 tests/ee/roles/luks_device/tasks/main.yml create mode 100644 tests/ee/roles/openssh_keypair/tasks/main.yml create mode 100644 tests/ee/roles/openssl_pkcs12/tasks/main.yml create mode 100644 tests/ee/roles/openssl_privatekey/tasks/main.yml create mode 100644 tests/ee/roles/smoke/library/smoke_ipaddress.py create mode 100644 tests/ee/roles/smoke/library/smoke_pyyaml.py create mode 100644 tests/ee/roles/smoke/tasks/main.yml create mode 100644 tests/ee/roles/x509_certificate/tasks/main.yml diff --git a/.github/workflows/ee.yml b/.github/workflows/ee.yml new file mode 100644 index 00000000..61e78e33 --- /dev/null +++ b/.github/workflows/ee.yml @@ -0,0 +1,109 @@ +--- +name: execution environment +on: + # Run CI against all pushes (direct commits, also merged PRs), Pull Requests + push: + branches: + - main + - stable-* + pull_request: + # Run CI once per day (at 04:45 UTC) + # This ensures that even if there haven't been commits that we are still testing against latest version of ansible-builder + schedule: + - cron: '45 4 * * *' + +env: + NAMESPACE: community + COLLECTION_NAME: crypto + +jobs: + build: + name: Build and test EE (Ⓐ${{ matrix.runner_tag }}) + strategy: + matrix: + runner_tag: + - devel + - stable-2.12-latest + - stable-2.11-latest + - stable-2.9-latest + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v3 + with: + path: ansible_collections/${{ env.NAMESPACE }}/${{ env.COLLECTION_NAME }} + + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: '3.10' + + - name: Install ansible-builder and ansible-navigator + run: pip install ansible-builder ansible-navigator + + - name: Verify requirements + run: ansible-builder introspect --sanitize . + + - name: Make sure galaxy.yml has version entry + run: >- + python -c + 'import yaml ; + f = open("galaxy.yml", "rb") ; + data = yaml.safe_load(f) ; + f.close() ; + data["version"] = data.get("version") or "0.0.1" ; + f = open("galaxy.yml", "wb") ; + f.write(yaml.dump(data).encode("utf-8")) ; + f.close() ; + ' + working-directory: ansible_collections/${{ env.NAMESPACE }}/${{ env.COLLECTION_NAME }} + + - name: Build collection + run: | + ansible-galaxy collection build --output-path ../../../ + working-directory: ansible_collections/${{ env.NAMESPACE }}/${{ env.COLLECTION_NAME }} + + - name: Create files for building execution environment + run: | + COLLECTION_FILENAME="$(ls "${{ env.NAMESPACE }}-${{ env.COLLECTION_NAME }}"-*.tar.gz)" + + # EE config + cat > execution-environment.yml < requirements.yml < + ansible-navigator run + --mode stdout + --pull-policy never + --set-environment-variable ANSIBLE_PRIVATE_ROLE_VARS=true + --execution-environment-image test-ee:latest + -v + all.yml + working-directory: ansible_collections/${{ env.NAMESPACE }}/${{ env.COLLECTION_NAME }}/tests/ee diff --git a/changelogs/fragments/440-ee.yml b/changelogs/fragments/440-ee.yml new file mode 100644 index 00000000..e3253520 --- /dev/null +++ b/changelogs/fragments/440-ee.yml @@ -0,0 +1,2 @@ +minor_changes: + - "Prepare collection for inclusion in an Execution Environment by declaring its dependencies (https://github.com/ansible-collections/community.crypto/pull/440)." diff --git a/meta/ee-bindep.txt b/meta/ee-bindep.txt new file mode 100644 index 00000000..2a4fbe1b --- /dev/null +++ b/meta/ee-bindep.txt @@ -0,0 +1,10 @@ +cryptsetup [platform:dpkg] +cryptsetup [platform:rpm] +openssh-client [platform:dpkg] +openssh-clients [platform:rpm] +openssl [platform:dpkg] +openssl [platform:rpm] +python3-cryptography [platform:dpkg] +python3-cryptography [platform:rpm] +python3-openssl [platform:dpkg] +python3-pyOpenSSL [platform:rpm] diff --git a/meta/ee-requirements.txt b/meta/ee-requirements.txt new file mode 100644 index 00000000..5500f007 --- /dev/null +++ b/meta/ee-requirements.txt @@ -0,0 +1 @@ +PyYAML diff --git a/meta/execution-environment.yml b/meta/execution-environment.yml new file mode 100644 index 00000000..525b5ceb --- /dev/null +++ b/meta/execution-environment.yml @@ -0,0 +1,5 @@ +--- +version: 1 +dependencies: + python: meta/ee-requirements.txt + system: meta/ee-bindep.txt diff --git a/tests/ee/all.yml b/tests/ee/all.yml new file mode 100644 index 00000000..ab4af8c4 --- /dev/null +++ b/tests/ee/all.yml @@ -0,0 +1,30 @@ +- hosts: localhost + tasks: + - name: Determine output directory + set_fact: + output_path: "{{ 'output-%0x' % ((2**32) | random) }}" + + - name: Find all roles + ansible.builtin.find: + paths: + - "{{ (playbook_dir | default('.')) ~ '/roles' }}" + file_type: directory + depth: 1 + register: result + + - name: Create output directory + ansible.builtin.file: + path: "{{ output_path }}" + state: directory + + - block: + - name: Include all roles + ansible.builtin.include_role: + name: "{{ item }}" + loop: "{{ result.files | map(attribute='path') | map('regex_replace', '.*/', '') | sort }}" + + always: + - name: Remove output directory + ansible.builtin.file: + path: "{{ output_path }}" + state: absent diff --git a/tests/ee/roles/crypto_info/tasks/main.yml b/tests/ee/roles/crypto_info/tasks/main.yml new file mode 100644 index 00000000..36cb5f40 --- /dev/null +++ b/tests/ee/roles/crypto_info/tasks/main.yml @@ -0,0 +1,27 @@ +--- +- name: Run crypto_info + community.crypto.crypto_info: + register: result + +- name: Dump result + debug: + var: result + +- name: Validate result + assert: + that: + - result.openssl_present + - result.python_cryptography_installed + - result.python_cryptography_capabilities.has_dsa + - result.python_cryptography_capabilities.has_dsa_sign + - result.python_cryptography_capabilities.has_ec + - result.python_cryptography_capabilities.has_ec_sign + - result.python_cryptography_capabilities.has_ed25519 + - result.python_cryptography_capabilities.has_ed25519_sign + - result.python_cryptography_capabilities.has_ed448 + - result.python_cryptography_capabilities.has_ed448_sign + - result.python_cryptography_capabilities.has_rsa + - result.python_cryptography_capabilities.has_rsa_sign + - result.python_cryptography_capabilities.has_x25519 + - result.python_cryptography_capabilities.has_x25519_serialization + - result.python_cryptography_capabilities.has_x448 diff --git a/tests/ee/roles/luks_device/tasks/main.yml b/tests/ee/roles/luks_device/tasks/main.yml new file mode 100644 index 00000000..e57e1e7f --- /dev/null +++ b/tests/ee/roles/luks_device/tasks/main.yml @@ -0,0 +1,45 @@ +--- +- name: Run cryptsetup (smoke test) + ansible.builtin.command: cryptsetup --version + +- name: Determine cryptfile path + ansible.builtin.set_fact: + cryptfile_path: "{{ output_path }}/cryptfile" + keyfile_path: "{{ output_path }}/keyfile" + +- name: Create cryptfile + ansible.builtin.command: dd if=/dev/zero of={{ cryptfile_path }} bs=1M count=32 + +- name: Create keyfile + ansible.builtin.copy: + dest: "{{ keyfile_path }}" + content: hunter2 + +- # Creating devices doesn't work well. We will have to try this again when luks_device + # supports working with container files directly. + when: false + block: + - name: Create lookback device + command: losetup -f {{ cryptfile_path }} + + - name: Determine loop device name + command: losetup -j {{ cryptfile_path }} --output name + register: cryptfile_device_output + + - set_fact: + cryptfile_device: "{{ cryptfile_device_output.stdout_lines[1] }}" + + - name: Create LUKS container + community.crypto.luks_device: + device: "{{ cryptfile_device }}" + # device: "{{ cryptfile_path }}" + state: present + keyfile: "{{ keyfile_path }}" + pbkdf: + iteration_time: 0.1 + + - name: Destroy LUKS container + community.crypto.luks_device: + device: "{{ cryptfile_device }}" + # device: "{{ cryptfile_path }}" + state: absent diff --git a/tests/ee/roles/openssh_keypair/tasks/main.yml b/tests/ee/roles/openssh_keypair/tasks/main.yml new file mode 100644 index 00000000..117df086 --- /dev/null +++ b/tests/ee/roles/openssh_keypair/tasks/main.yml @@ -0,0 +1,12 @@ +--- +- name: Generate key with OpenSSH binary backend + community.crypto.openssh_keypair: + path: "{{ output_path }}/openssh-key-1" + size: 2048 + backend: opensshbin + +- name: Generate key with cryptography backend + community.crypto.openssh_keypair: + path: "{{ output_path }}/openssh-key-2" + size: 2048 + backend: cryptography diff --git a/tests/ee/roles/openssl_pkcs12/tasks/main.yml b/tests/ee/roles/openssl_pkcs12/tasks/main.yml new file mode 100644 index 00000000..95322089 --- /dev/null +++ b/tests/ee/roles/openssl_pkcs12/tasks/main.yml @@ -0,0 +1,40 @@ +--- +- name: Create private key + community.crypto.openssl_privatekey: + path: "{{ output_path }}/pkcs12-cert.key" + type: ECC + curve: secp256r1 + +- name: Create CSR + community.crypto.openssl_csr: + path: "{{ output_path }}/pkcs12-cert.csr" + privatekey_path: "{{ output_path }}/pkcs12-cert.key" + +- name: Create certificate + community.crypto.x509_certificate: + path: "{{ output_path }}/pkcs12-cert.pem" + csr_path: "{{ output_path }}/pkcs12-cert.csr" + privatekey_path: "{{ output_path }}/pkcs12-cert.key" + provider: selfsigned + +- name: Create PKCS#12 with cryptography backend + community.crypto.openssl_pkcs12: + action: export + path: "{{ output_path }}/pkcs12-1.p12" + mode: '0644' + friendly_name: foo + privatekey_path: "{{ output_path }}/pkcs12-cert.key" + certificate_path: "{{ output_path }}/pkcs12-cert.pem" + state: present + select_crypto_backend: cryptography + +- name: Create PKCS#12 with PyOpenSSL backend + community.crypto.openssl_pkcs12: + action: export + path: "{{ output_path }}/pkcs12-2.p12" + mode: '0644' + friendly_name: foo + privatekey_path: "{{ output_path }}/pkcs12-cert.key" + certificate_path: "{{ output_path }}/pkcs12-cert.pem" + state: present + select_crypto_backend: pyopenssl diff --git a/tests/ee/roles/openssl_privatekey/tasks/main.yml b/tests/ee/roles/openssl_privatekey/tasks/main.yml new file mode 100644 index 00000000..51018fac --- /dev/null +++ b/tests/ee/roles/openssl_privatekey/tasks/main.yml @@ -0,0 +1,11 @@ +--- +- name: Create RSA private key + community.crypto.openssl_privatekey: + path: "{{ output_path }}/privatekey-1" + size: 2048 + +- name: Create ECC private key + community.crypto.openssl_privatekey: + path: "{{ output_path }}/privatekey-2" + type: ECC + curve: secp256r1 diff --git a/tests/ee/roles/smoke/library/smoke_ipaddress.py b/tests/ee/roles/smoke/library/smoke_ipaddress.py new file mode 100644 index 00000000..a7373534 --- /dev/null +++ b/tests/ee/roles/smoke/library/smoke_ipaddress.py @@ -0,0 +1,48 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2022 Felix Fontein +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: smoke_ipaddress +short_description: Check whether ipaddress is present +author: + - Felix Fontein (@felixfontein) +description: + - Check whether C(ipaddress) is present. +options: {} +''' + +EXAMPLES = r''' # ''' + +RETURN = r''' # ''' + +import traceback + +from ansible.module_utils.basic import AnsibleModule, missing_required_lib + +try: + import ipaddress + HAS_IPADDRESS = True +except ImportError as exc: + IPADDRESS_IMP_ERR = traceback.format_exc() + HAS_IPADDRESS = False + + +def main(): + module = AnsibleModule(argument_spec=dict(), supports_check_mode=True) + + if not HAS_IPADDRESS: + module.fail_json(msg=missing_required_lib('ipaddress'), exception=IPADDRESS_IMP_ERR) + + module.exit_json(msg='Everything is ok') + + +if __name__ == '__main__': # pragma: no cover + main() # pragma: no cover diff --git a/tests/ee/roles/smoke/library/smoke_pyyaml.py b/tests/ee/roles/smoke/library/smoke_pyyaml.py new file mode 100644 index 00000000..954936c4 --- /dev/null +++ b/tests/ee/roles/smoke/library/smoke_pyyaml.py @@ -0,0 +1,48 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2022 Felix Fontein +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: smoke_pyyaml +short_description: Check whether PyYAML is present +author: + - Felix Fontein (@felixfontein) +description: + - Check whether C(yaml) is present. +options: {} +''' + +EXAMPLES = r''' # ''' + +RETURN = r''' # ''' + +import traceback + +from ansible.module_utils.basic import AnsibleModule, missing_required_lib + +try: + import yaml + HAS_PYYAML = True +except ImportError as exc: + PYYAML_IMP_ERR = traceback.format_exc() + HAS_PYYAML = False + + +def main(): + module = AnsibleModule(argument_spec=dict(), supports_check_mode=True) + + if not HAS_PYYAML: + module.fail_json(msg=missing_required_lib('PyYAML'), exception=PYYAML_IMP_ERR) + + module.exit_json(msg='Everything is ok') + + +if __name__ == '__main__': # pragma: no cover + main() # pragma: no cover diff --git a/tests/ee/roles/smoke/tasks/main.yml b/tests/ee/roles/smoke/tasks/main.yml new file mode 100644 index 00000000..d64aa890 --- /dev/null +++ b/tests/ee/roles/smoke/tasks/main.yml @@ -0,0 +1,18 @@ +--- +- name: Check whether ipaddress is present + smoke_ipaddress: + register: result + +- name: Validate result + assert: + that: + - result.msg == 'Everything is ok' + +- name: Check whether PyYAML is present + smoke_pyyaml: + register: result + +- name: Validate result + assert: + that: + - result.msg == 'Everything is ok' diff --git a/tests/ee/roles/x509_certificate/tasks/main.yml b/tests/ee/roles/x509_certificate/tasks/main.yml new file mode 100644 index 00000000..9ef93952 --- /dev/null +++ b/tests/ee/roles/x509_certificate/tasks/main.yml @@ -0,0 +1,18 @@ +--- +- name: Create private key + community.crypto.openssl_privatekey: + path: "{{ output_path }}/cert.key" + type: ECC + curve: secp256r1 + +- name: Create CSR + community.crypto.openssl_csr: + path: "{{ output_path }}/cert.csr" + privatekey_path: "{{ output_path }}/cert.key" + +- name: Create certificate + community.crypto.x509_certificate: + path: "{{ output_path }}/cert.pem" + csr_path: "{{ output_path }}/cert.csr" + privatekey_path: "{{ output_path }}/cert.key" + provider: selfsigned diff --git a/tests/sanity/ignore-2.10.txt b/tests/sanity/ignore-2.10.txt index 3cd4d393..56340b5b 100644 --- a/tests/sanity/ignore-2.10.txt +++ b/tests/sanity/ignore-2.10.txt @@ -5,3 +5,5 @@ .azure-pipelines/scripts/publish-codecov.py future-import-boilerplate .azure-pipelines/scripts/publish-codecov.py metaclass-boilerplate plugins/modules/acme_account_info.py validate-modules:return-syntax-error +tests/ee/roles/smoke/library/smoke_ipaddress.py shebang +tests/ee/roles/smoke/library/smoke_pyyaml.py shebang diff --git a/tests/sanity/ignore-2.11.txt b/tests/sanity/ignore-2.11.txt index 3cd4d393..56340b5b 100644 --- a/tests/sanity/ignore-2.11.txt +++ b/tests/sanity/ignore-2.11.txt @@ -5,3 +5,5 @@ .azure-pipelines/scripts/publish-codecov.py future-import-boilerplate .azure-pipelines/scripts/publish-codecov.py metaclass-boilerplate plugins/modules/acme_account_info.py validate-modules:return-syntax-error +tests/ee/roles/smoke/library/smoke_ipaddress.py shebang +tests/ee/roles/smoke/library/smoke_pyyaml.py shebang diff --git a/tests/sanity/ignore-2.12.txt b/tests/sanity/ignore-2.12.txt index 1f1babd0..c9b09ca4 100644 --- a/tests/sanity/ignore-2.12.txt +++ b/tests/sanity/ignore-2.12.txt @@ -1,2 +1,4 @@ .azure-pipelines/scripts/publish-codecov.py replace-urlopen plugins/modules/acme_account_info.py validate-modules:return-syntax-error +tests/ee/roles/smoke/library/smoke_ipaddress.py shebang +tests/ee/roles/smoke/library/smoke_pyyaml.py shebang diff --git a/tests/sanity/ignore-2.13.txt b/tests/sanity/ignore-2.13.txt index 2dc9aec2..ca127b4f 100644 --- a/tests/sanity/ignore-2.13.txt +++ b/tests/sanity/ignore-2.13.txt @@ -1 +1,3 @@ .azure-pipelines/scripts/publish-codecov.py replace-urlopen +tests/ee/roles/smoke/library/smoke_ipaddress.py shebang +tests/ee/roles/smoke/library/smoke_pyyaml.py shebang diff --git a/tests/sanity/ignore-2.14.txt b/tests/sanity/ignore-2.14.txt index 2dc9aec2..ca127b4f 100644 --- a/tests/sanity/ignore-2.14.txt +++ b/tests/sanity/ignore-2.14.txt @@ -1 +1,3 @@ .azure-pipelines/scripts/publish-codecov.py replace-urlopen +tests/ee/roles/smoke/library/smoke_ipaddress.py shebang +tests/ee/roles/smoke/library/smoke_pyyaml.py shebang diff --git a/tests/sanity/ignore-2.9.txt b/tests/sanity/ignore-2.9.txt index a0dc8066..ce2f4b66 100644 --- a/tests/sanity/ignore-2.9.txt +++ b/tests/sanity/ignore-2.9.txt @@ -4,3 +4,5 @@ .azure-pipelines/scripts/publish-codecov.py compile-3.5!skip # Uses Python 3.6+ syntax .azure-pipelines/scripts/publish-codecov.py future-import-boilerplate .azure-pipelines/scripts/publish-codecov.py metaclass-boilerplate +tests/ee/roles/smoke/library/smoke_ipaddress.py shebang +tests/ee/roles/smoke/library/smoke_pyyaml.py shebang