├── .ansible-lint ├── .github ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── galaxy.yml │ └── molecule.yml ├── .gitignore ├── .travis.yml ├── .yamllint ├── README.md ├── defaults └── main.yml ├── handlers └── main.yml ├── meta └── main.yml ├── molecule └── default │ ├── INSTALL.rst │ ├── converge.yml │ ├── create.yml │ ├── destroy.yml │ ├── incus-create.yml │ ├── incus-destroy.yml │ ├── molecule.yml │ └── tests │ ├── conftest.py │ └── test_default.py ├── tasks ├── debian11-var.yml ├── debian11.yml ├── debian12-var.yml ├── debian12.yml ├── main.yml ├── ubuntu22-var.yml └── ubuntu22.yml └── vars └── main.yml /.ansible-lint: -------------------------------------------------------------------------------- 1 | warn_list: # or 'skip_list' to silence them completely 2 | - command-instead-of-shell # Use shell only when shell functionality is required. 3 | - experimental # all rules tagged as experimental -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Expected Behavior 4 | 5 | 6 | 7 | ## Current Behavior 8 | 9 | 10 | 11 | ## Possible Solution 12 | 13 | 14 | 15 | ## Steps to Reproduce (for bugs) 16 | 17 | 18 | 1. 19 | 2. 20 | 3. 21 | 4. 22 | 23 | ## Context 24 | 25 | 26 | 27 | ## Your Environment 28 | 29 | * Version used: 30 | * Operating System and Ansible version: 31 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | 6 | ## Motivation and Context 7 | 8 | 9 | 10 | ## How Has This Been Tested? 11 | 12 | 13 | 14 | 15 | ## Screenshots (if appropriate) 16 | 17 | ## Types of Changes 18 | 19 | - [ ] Bug fix (non-breaking change that fixes an issue) 20 | - [ ] New feature (non-breaking change that adds functionality) 21 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 22 | 23 | ## Checklist 24 | 25 | 26 | - [ ] My code follows the code style of this project. 27 | - [ ] My change requires a change to the documentation. 28 | - [ ] I have updated the documentation accordingly. 29 | -------------------------------------------------------------------------------- /.github/workflows/galaxy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Import role on Ansible Galaxy 3 | 4 | on: # yamllint disable-line rule:truthy 5 | release: 6 | types: 7 | - released 8 | jobs: 9 | release: 10 | runs-on: ubuntu-20.04 11 | steps: 12 | - name: galaxy 13 | uses: robertdebock/galaxy-action@1.2.1 14 | with: 15 | galaxy_api_key: ${{ secrets.galaxy_api_key }} 16 | git_branch: main 17 | -------------------------------------------------------------------------------- /.github/workflows/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | # Ansible managed 4 | # 5 | 6 | name: Ansible Molecule 7 | 8 | on: 9 | push: 10 | tags_ignore: 11 | - '*' 12 | pull_request: 13 | schedule: 14 | - cron: '1 1 1 * *' 15 | 16 | jobs: 17 | lint: 18 | runs-on: ubuntu-20.04 19 | steps: 20 | - name: checkout 21 | uses: actions/checkout@v3 22 | with: 23 | path: "${{ github.repository }}" 24 | - name: molecule 25 | uses: robertdebock/molecule-action@4.0.7 26 | with: 27 | command: lint 28 | test: 29 | needs: 30 | - lint 31 | runs-on: ubuntu-20.04 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | config: 36 | - image: "debian" 37 | tag: "latest" 38 | - image: "ubuntu" 39 | tag: "latest" 40 | steps: 41 | - name: checkout 42 | uses: actions/checkout@v3 43 | with: 44 | path: "${{ github.repository }}" 45 | # - name: disable apparmor for mysql 46 | # run: sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/ 47 | # - name: parse apparmor for mysql 48 | # run: sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld 49 | - name: molecule 50 | uses: robertdebock/molecule-action@4.0.7 51 | with: 52 | image: ${{ matrix.config.image }} 53 | tag: ${{ matrix.config.tag }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig 2 | # Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,linux,ansible,python 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,linux,ansible,python 4 | 5 | ### Ansible ### 6 | *.retry 7 | 8 | ### Linux ### 9 | *~ 10 | 11 | # temporary files which can be created if a process still has a handle open of a deleted file 12 | .fuse_hidden* 13 | 14 | # KDE directory preferences 15 | .directory 16 | 17 | # Linux trash folder which might appear on any partition or disk 18 | .Trash-* 19 | 20 | # .nfs files are created when an open file is removed but is still being accessed 21 | .nfs* 22 | 23 | ### Python ### 24 | # Byte-compiled / optimized / DLL files 25 | __pycache__/ 26 | *.py[cod] 27 | *$py.class 28 | 29 | # C extensions 30 | *.so 31 | 32 | # Distribution / packaging 33 | .Python 34 | build/ 35 | develop-eggs/ 36 | dist/ 37 | downloads/ 38 | eggs/ 39 | .eggs/ 40 | lib/ 41 | lib64/ 42 | parts/ 43 | sdist/ 44 | var/ 45 | wheels/ 46 | share/python-wheels/ 47 | *.egg-info/ 48 | .installed.cfg 49 | *.egg 50 | MANIFEST 51 | 52 | # PyInstaller 53 | # Usually these files are written by a python script from a template 54 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 55 | *.manifest 56 | *.spec 57 | 58 | # Installer logs 59 | pip-log.txt 60 | pip-delete-this-directory.txt 61 | 62 | # Unit test / coverage reports 63 | htmlcov/ 64 | .tox/ 65 | .nox/ 66 | .coverage 67 | .coverage.* 68 | .cache 69 | nosetests.xml 70 | coverage.xml 71 | *.cover 72 | *.py,cover 73 | .hypothesis/ 74 | .pytest_cache/ 75 | cover/ 76 | 77 | # Translations 78 | *.mo 79 | *.pot 80 | 81 | # Django stuff: 82 | *.log 83 | local_settings.py 84 | db.sqlite3 85 | db.sqlite3-journal 86 | 87 | # Flask stuff: 88 | instance/ 89 | .webassets-cache 90 | 91 | # Scrapy stuff: 92 | .scrapy 93 | 94 | # Sphinx documentation 95 | docs/_build/ 96 | 97 | # PyBuilder 98 | .pybuilder/ 99 | target/ 100 | 101 | # Jupyter Notebook 102 | .ipynb_checkpoints 103 | 104 | # IPython 105 | profile_default/ 106 | ipython_config.py 107 | 108 | # pyenv 109 | # For a library or package, you might want to ignore these files since the code is 110 | # intended to run in multiple environments; otherwise, check them in: 111 | # .python-version 112 | 113 | # pipenv 114 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 115 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 116 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 117 | # install all needed dependencies. 118 | #Pipfile.lock 119 | 120 | # poetry 121 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 122 | # This is especially recommended for binary packages to ensure reproducibility, and is more 123 | # commonly ignored for libraries. 124 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 125 | #poetry.lock 126 | 127 | # pdm 128 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 129 | #pdm.lock 130 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 131 | # in version control. 132 | # https://pdm.fming.dev/#use-with-ide 133 | .pdm.toml 134 | 135 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 136 | __pypackages__/ 137 | 138 | # Celery stuff 139 | celerybeat-schedule 140 | celerybeat.pid 141 | 142 | # SageMath parsed files 143 | *.sage.py 144 | 145 | # Environments 146 | .env 147 | .venv 148 | env/ 149 | venv/ 150 | ENV/ 151 | env.bak/ 152 | venv.bak/ 153 | 154 | # Spyder project settings 155 | .spyderproject 156 | .spyproject 157 | 158 | # Rope project settings 159 | .ropeproject 160 | 161 | # mkdocs documentation 162 | /site 163 | 164 | # mypy 165 | .mypy_cache/ 166 | .dmypy.json 167 | dmypy.json 168 | 169 | # Pyre type checker 170 | .pyre/ 171 | 172 | # pytype static type analyzer 173 | .pytype/ 174 | 175 | # Cython debug symbols 176 | cython_debug/ 177 | 178 | # PyCharm 179 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 180 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 181 | # and can be added to the global gitignore or merged into this file. For a more nuclear 182 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 183 | #.idea/ 184 | 185 | ### VisualStudioCode ### 186 | .vscode/* 187 | !.vscode/settings.json 188 | !.vscode/tasks.json 189 | !.vscode/launch.json 190 | !.vscode/extensions.json 191 | !.vscode/*.code-snippets 192 | 193 | # Local History for Visual Studio Code 194 | .history/ 195 | 196 | # Built Visual Studio Code Extensions 197 | *.vsix 198 | 199 | ### VisualStudioCode Patch ### 200 | # Ignore all local history of files 201 | .history 202 | .ionide 203 | 204 | # Support for Project snippet scope 205 | .vscode/*.code-snippets 206 | 207 | # Ignore code-workspaces 208 | *.code-workspace 209 | 210 | # End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,linux,ansible,python 211 | 212 | # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) 213 | 214 | molecule/vagrant/*.html 215 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: python 3 | python: "2.7" 4 | 5 | # Use the new container infrastructure 6 | sudo: false 7 | 8 | # Install ansible 9 | addons: 10 | apt: 11 | packages: 12 | - python-pip 13 | 14 | install: 15 | # Install ansible 16 | - pip install ansible 17 | 18 | # Check ansible version 19 | - ansible --version 20 | 21 | # Create ansible.cfg with correct roles_path 22 | - printf '[defaults]\nroles_path=../' >ansible.cfg 23 | 24 | script: 25 | # Basic role syntax check 26 | - ansible-playbook tests/test.yml -i tests/inventory --syntax-check 27 | 28 | notifications: 29 | webhooks: https://galaxy.ansible.com/api/v1/notifications/ -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | # Based on ansible-lint config 3 | extends: default 4 | 5 | rules: 6 | braces: 7 | max-spaces-inside: 1 8 | level: error 9 | brackets: 10 | max-spaces-inside: 1 11 | level: error 12 | colons: 13 | max-spaces-after: -1 14 | level: error 15 | commas: 16 | max-spaces-after: -1 17 | level: error 18 | comments: disable 19 | comments-indentation: disable 20 | document-start: disable 21 | empty-lines: 22 | max: 3 23 | level: error 24 | hyphens: 25 | level: error 26 | indentation: disable 27 | key-duplicates: enable 28 | line-length: disable 29 | new-line-at-end-of-file: disable 30 | new-lines: 31 | type: unix 32 | trailing-spaces: disable 33 | truthy: disable 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # stephrobert.openscap 2 | 3 | [![Maintainer](https://img.shields.io/badge/maintained%20by-stephrobert-e00000?style=flat-square)](https://github.com/stephrobert) 4 | [![License](https://img.shields.io/github/license/stephrobert/ansible-role-openscap?style=flat-square)](https://github.com/stephrobert/ansible-role-openscap/blob/main/LICENSE) 5 | [![Release](https://img.shields.io/github/v/release/stephrobert/ansible-role-openscap?style=flat-square)](https://github.com/stephrobert/ansible-role-openscap/releases) 6 | [![Status](https://img.shields.io/github/workflow/status/stephrobert/ansible-role-openscap/Ansible%20Molecule?style=flat-square&label=tests)](https://github.com/stephrobert/ansible-role-openscap/actions?query=workflow%3A%22Ansible+Molecule%22) 7 | [![Ansible Galaxy](https://img.shields.io/badge/ansible-galaxy-black.svg?style=flat-square&logo=ansible)](https://galaxy.ansible.com/stephrobert/openscap)[![Ansible version](https://img.shields.io/badge/ansible-%3E%3D2.10-black.svg?style=flat-square&logo=ansible)](https://github.com/ansible/ansible) 8 | 9 | ⭐ Star us on GitHub — it motivates us a lot! 10 | 11 | Install Oscap 12 | 13 | **Platforms Supported**: 14 | 15 | | Platform | Versions | 16 | |----------|----------| 17 | | Debian | bullseye | 18 | | Ubuntu | jammy | 19 | 20 | ## ⚠️ Requirements 21 | 22 | Ansible >= 2.11. 23 | 24 | ### Ansible role dependencies 25 | 26 | None. 27 | 28 | ## ⚡ Installation 29 | 30 | ### Install with Ansible Galaxy 31 | 32 | ```shell 33 | ansible-galaxy install stephrobert.openscap 34 | ``` 35 | 36 | ### Install with git 37 | 38 | If you do not want a global installation, clone it into your `roles_path`. 39 | 40 | ```bash 41 | git clone https://github.com/stephrobert/ansible-role-openscap.git stephrobert.openscap 42 | ``` 43 | 44 | But I often add it as a submodule in a given `playbook_dir` repository. 45 | 46 | ```bash 47 | git submodule add https://github.com/stephrobert/ansible-role-openscap.git roles/stephrobert.openscap 48 | ``` 49 | 50 | As the role is not managed by Ansible Galaxy, you do not have to specify the 51 | github user account. 52 | 53 | ### ✏️ Example Playbook 54 | 55 | Basic usage is: 56 | 57 | ```yaml 58 | - hosts: all 59 | roles: 60 | - role: stephrobert.openscap 61 | vars: 62 | content_version: 0.1.74 63 | install_content: false 64 | install_oscap: true 65 | oscap_version: 1.4.0 66 | reports_folder: /opt/openscap-reports 67 | scan: false 68 | 69 | ``` 70 | 71 | ## ⚙️ Role Variables 72 | 73 | Variables are divided in three types. 74 | 75 | The **default vars** section shows you which variables you may 76 | override in your ansible inventory. As a matter of fact, all variables should 77 | be defined there for explicitness, ease of documentation as well as overall 78 | role manageability. 79 | 80 | The **context variables** are shown in section below hint you 81 | on how runtime context may affects role execution. 82 | 83 | ### Default variables 84 | Role default variables from `defaults/main.yml`. 85 | 86 | | Variable Name | Value | 87 | |---------------|-------| 88 | | install_content | False | 89 | | install_oscap | True | 90 | | oscap_version | 1.4.0 | 91 | | content_version | 0.1.74 | 92 | | scan | False | 93 | | reports_folder | /opt/openscap-reports | 94 | 95 | ### Context variables 96 | 97 | Those variables from `vars/*.{yml,json}` are loaded dynamically during task 98 | runtime using the `include_vars` module. 99 | 100 | Variables loaded from `vars/main.yml`. 101 | 102 | 103 | 104 | 105 | ## Author Information 106 | 107 | none -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | install_content: false 3 | install_oscap: true 4 | oscap_version: 1.4.0 5 | content_version: 0.1.74 6 | scan: false 7 | reports_folder: /opt/openscap-reports -------------------------------------------------------------------------------- /handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for hardening 3 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: Stephane ROBERT 4 | role_name: openscap 5 | namespace: stephrobert 6 | description: Install Oscap 7 | company: none 8 | license: MLP2 9 | min_ansible_version: "2.11" 10 | platforms: 11 | - name: Debian 12 | versions: 13 | - bullseye 14 | - name: Ubuntu 15 | versions: 16 | - jammy 17 | galaxy_tags: 18 | - hardening 19 | dependencies: [] 20 | -------------------------------------------------------------------------------- /molecule/default/INSTALL.rst: -------------------------------------------------------------------------------- 1 | ********************************* 2 | Vagrant driver installation guide 3 | ********************************* 4 | 5 | Requirements 6 | ============ 7 | 8 | * Vagrant 9 | * Virtualbox, Parallels, VMware Fusion, VMware Workstation or VMware Desktop 10 | 11 | Install 12 | ======= 13 | 14 | Please refer to the `Virtual environment`_ documentation for installation best 15 | practices. If not using a virtual environment, please consider passing the 16 | widely recommended `'--user' flag`_ when invoking ``pip``. 17 | 18 | .. _Virtual environment: https://virtualenv.pypa.io/en/latest/ 19 | .. _'--user' flag: https://packaging.python.org/tutorials/installing-packages/#installing-to-the-user-site 20 | 21 | .. code-block:: bash 22 | 23 | $ pip install 'molecule_vagrant' 24 | -------------------------------------------------------------------------------- /molecule/default/converge.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Converge 3 | hosts: all 4 | tasks: 5 | - name: Include role 6 | ansible.builtin.include_role: 7 | name: ansible-role-openscap 8 | vars: 9 | - install_content: true 10 | - scan: true -------------------------------------------------------------------------------- /molecule/default/create.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Create 3 | hosts: localhost 4 | connection: local 5 | gather_facts: false 6 | no_log: "{{ molecule_no_log }}" 7 | vars: 8 | default_private_key_path: "{{ lookup('env', 'HOME') }}/.ssh/id_ed25519" 9 | default_public_key_path: "{{ default_private_key_path }}.pub" 10 | default_ssh_user: bob 11 | default_ssh_port: 22 12 | default_memory: 1024 13 | default_cpus: 1 14 | 15 | platform_defaults: 16 | private_key_path: "{{ default_private_key_path }}" 17 | public_key_path: "{{ default_public_key_path }}" 18 | ssh_user: "{{ default_ssh_user }}" 19 | ssh_port: "{{ default_ssh_port }}" 20 | image_name: "" 21 | name: "" 22 | memory: "{{ default_memory }}" 23 | cpus: "{{ default_cpus }}" 24 | 25 | # Merging defaults into a list of dicts is, it turns out, not straightforward 26 | platforms: >- 27 | {{ [platform_defaults | dict2items] 28 | | product(molecule_yml.platforms | map('dict2items') | list) 29 | | map('flatten', levels=1) 30 | | list 31 | | map('items2dict') 32 | | list }} 33 | 34 | tasks: 35 | - name: Create 36 | ansible.builtin.include_tasks: incus-create.yml 37 | loop: '{{ platforms }}' 38 | loop_control: 39 | loop_var: platform 40 | -------------------------------------------------------------------------------- /molecule/default/destroy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Destroy 3 | hosts: localhost 4 | connection: local 5 | gather_facts: false 6 | no_log: "{{ molecule_no_log }}" 7 | tasks: 8 | # Developer must implement. 9 | # Mandatory configuration for Molecule to function. 10 | 11 | - name: Check instance config file exist 12 | ansible.builtin.stat: 13 | path: "{{ molecule_instance_config }}" 14 | register: file_exist 15 | 16 | - name: Destroy VM 17 | when: file_exist.stat.exists 18 | block: 19 | - name: Load Instance config File 20 | ansible.builtin.set_fact: 21 | instance_conf: "{{ lookup('file', molecule_instance_config) | from_yaml }}" 22 | 23 | - name: Destroy 24 | ansible.builtin.include_tasks: incus-destroy.yml 25 | loop: '{{ instance_conf }}' 26 | loop_control: 27 | loop_var: platform -------------------------------------------------------------------------------- /molecule/default/incus-create.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Test if VM already Exist 3 | ansible.builtin.shell: 4 | cmd: "incus list -f json {{ platform.name }}" 5 | register: instance_exist 6 | - name: Convert to JSON 7 | ansible.builtin.set_fact: 8 | instance: "{{ instance_exist.stdout | from_json }}" 9 | - block: 10 | - name: Provision instance {{ platform.name }} 11 | ansible.builtin.shell: 12 | cmd: "incus launch {{ platform.image }} {{ platform.name }} --config limits.cpu={{ platform.cpus }} --config limits.memory={{ platform.memory }}MiB" 13 | - name: Pause 5s 14 | ansible.builtin.pause: 15 | seconds: 5 16 | when: instance | length == 0 17 | - name: Test if VM already Exist 18 | ansible.builtin.shell: 19 | cmd: "incus list -f json {{ platform.name }}" 20 | register: instance_exist 21 | - name: Convert to JSON 22 | ansible.builtin.set_fact: 23 | state: "{{ instance_exist.stdout | from_json }}" 24 | - name: Create instance config file 25 | ansible.builtin.file: 26 | path: "{{ lookup('env', 'MOLECULE_EPHEMERAL_DIRECTORY') }}/instance_config.yml" 27 | state: touch 28 | mode: "0644" 29 | - name: Get IP 30 | vars: 31 | jmesquery: "[*].state.network.eth0.addresses[?family==`inet`].address[]" 32 | ansible.builtin.set_fact: 33 | ip: "{{ state | community.general.json_query(jmesquery) | first }}" 34 | - name: Register instance config for VM {{ platform.name }} 35 | ansible.builtin.blockinfile: 36 | path: "{{ lookup('env', 'MOLECULE_EPHEMERAL_DIRECTORY') }}/instance_config.yml" 37 | block: "- { address: {{ ip }} , identity_file: {{ platform.private_key_path }}, instance: {{ platform.name }}, port: {{ platform.ssh_port }}, user: {{ platform.ssh_user }} }" 38 | marker: '# {mark} Instance : {{ platform.name }}' 39 | marker_begin: 'BEGIN' 40 | marker_end: 'END' 41 | - name: Add to group molecule_hosts {{ platform.name }} 42 | ansible.builtin.add_host: 43 | name: "{{ ip }}" 44 | groups: molecule_hosts 45 | -------------------------------------------------------------------------------- /molecule/default/incus-destroy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Destroy VM 3 | ansible.builtin.shell: 4 | cmd: "incus delete {{ platform.instance }} --force" 5 | -------------------------------------------------------------------------------- /molecule/default/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependency: 3 | name: galaxy 4 | driver: 5 | name: default 6 | platforms: 7 | - name: ubuntu-openscap 8 | image: ubuntu_ansible 9 | memory: 2048 10 | cpus: 3 11 | ssh_user: ansible 12 | provisioner: 13 | name: ansible 14 | 15 | verifier: 16 | name: testinfra 17 | 18 | lint: 19 | set -e 20 | yamllint . 21 | ansible-lint 22 | flake8 23 | 24 | scenario: 25 | test_sequence: 26 | - destroy 27 | - create 28 | - converge 29 | # - idempotence 30 | - lint 31 | - verify -------------------------------------------------------------------------------- /molecule/default/tests/conftest.py: -------------------------------------------------------------------------------- 1 | """PyTest Fixtures.""" 2 | from __future__ import absolute_import 3 | 4 | import os 5 | 6 | import pytest 7 | 8 | 9 | def pytest_runtest_setup(item): 10 | """Run tests only when under molecule with testinfra installed.""" 11 | try: 12 | import testinfra 13 | except ImportError: 14 | pytest.skip("Test requires testinfra", allow_module_level=True) 15 | if "MOLECULE_INVENTORY_FILE" in os.environ: 16 | pytest.testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( 17 | os.environ["MOLECULE_INVENTORY_FILE"] 18 | ).get_hosts("all") 19 | else: 20 | pytest.skip( 21 | "Test should run only from inside molecule.", allow_module_level=True 22 | ) 23 | -------------------------------------------------------------------------------- /molecule/default/tests/test_default.py: -------------------------------------------------------------------------------- 1 | """Role testing files using testinfra.""" 2 | 3 | 4 | def test_hosts_file(host): 5 | """Validate /etc/hosts file.""" 6 | f = host.file("/etc/hosts") 7 | assert f.exists 8 | assert f.user == "root" 9 | assert f.group == "root" 10 | 11 | def test_python_is_installed(host): 12 | distribution=host.system_info.distribution 13 | if distribution in ['debian','fedora','ubuntu']: 14 | python = host.package("python3") 15 | else: 16 | python = host.package("python") 17 | 18 | assert python.is_installed 19 | -------------------------------------------------------------------------------- /tasks/debian11-var.yml: -------------------------------------------------------------------------------- 1 | --- 2 | openscap_profile: "xccdf_org.ssgproject.content_profile_anssi_np_nt28_restrictive" 3 | openscap_security_policy: "ssg-debian11-ds.xml" -------------------------------------------------------------------------------- /tasks/debian11.yml: -------------------------------------------------------------------------------- 1 | - name: Update apt cache 2 | ansible.builtin.apt: 3 | update_cache: yes 4 | when: ansible_pkg_mgr == "apt" 5 | become: true 6 | - name: Install package to build oscap 7 | ansible.builtin.package: 8 | name: 9 | - git 10 | - cmake 11 | - libdbus-1-dev 12 | - libdbus-glib-1-dev 13 | - libcurl4-openssl-dev 14 | - libgcrypt20-dev 15 | - libselinux1-dev 16 | - libxslt1-dev 17 | - libgconf2-dev 18 | - libacl1-dev 19 | - libblkid-dev 20 | - libcap-dev 21 | - libxml2-dev 22 | - libldap2-dev 23 | - libpcre3-dev 24 | - python-dev 25 | - swig 26 | - libxml-parser-perl 27 | - libxml-xpath-perl 28 | - libperl-dev 29 | - libbz2-dev 30 | - librpm-dev 31 | - g++ 32 | - libapt-pkg-dev 33 | - libyaml-dev 34 | - libxmlsec1-dev 35 | - libxmlsec1-openssl 36 | - unzip 37 | state: present 38 | become: true 39 | -------------------------------------------------------------------------------- /tasks/debian12-var.yml: -------------------------------------------------------------------------------- 1 | --- 2 | openscap_profile: "xccdf_org.ssgproject.content_profile_anssi_np_nt28_restrictive" 3 | openscap_security_policy: "ssg-debian12-ds.xml" -------------------------------------------------------------------------------- /tasks/debian12.yml: -------------------------------------------------------------------------------- 1 | - name: Update apt cache 2 | ansible.builtin.apt: 3 | update_cache: yes 4 | when: ansible_pkg_mgr == "apt" 5 | become: true 6 | - name: Install package to build oscap 7 | ansible.builtin.package: 8 | name: 9 | - git 10 | - cmake 11 | - libdbus-1-dev 12 | - libdbus-glib-1-dev 13 | - libcurl4-openssl-dev 14 | - libgcrypt20-dev 15 | - libselinux1-dev 16 | - libxslt1-dev 17 | - libgconf2-dev 18 | - libacl1-dev 19 | - libblkid-dev 20 | - libcap-dev 21 | - libxml2-dev 22 | - libldap2-dev 23 | - libpcre3-dev 24 | - python3-dev 25 | - swig 26 | - libxml-parser-perl 27 | - libxml-xpath-perl 28 | - libperl-dev 29 | - libbz2-dev 30 | - librpm-dev 31 | - g++ 32 | - libapt-pkg-dev 33 | - libyaml-dev 34 | - libxmlsec1-dev 35 | - libxmlsec1-openssl 36 | - unzip 37 | state: present 38 | become: true 39 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Include variables 3 | ansible.builtin.include_vars: "{{ ansible_distribution | lower }}{{ ansible_distribution_major_version }}-var.yml" 4 | - name: Test version 5 | ansible.builtin.shell: 6 | cmd: oscap --version | head -1 | awk '{print $6}' 7 | register: version 8 | failed_when: false 9 | changed_when: version.stdout != oscap_version 10 | - name: Build oscap 11 | when: version.changed and true 12 | block: 13 | - name: Include task 14 | ansible.builtin.include_tasks: 15 | file: "{{ ansible_distribution | lower }}{{ ansible_distribution_major_version }}.yml" 16 | - name: Clone oscap project 17 | ansible.builtin.git: 18 | repo: https://github.com/OpenSCAP/openscap.git 19 | dest: /tmp/openscap 20 | version: "{{ oscap_version }}" 21 | recursive: true 22 | force: true 23 | - name: Cmake 24 | ansible.builtin.shell: 25 | cmd: cmake .. -DCMAKE_INSTALL_PREFIX=/usr 26 | chdir: /tmp/openscap/build 27 | register: my_output 28 | changed_when: my_output.rc != 0 29 | tags: 30 | - skip_ansible_lint 31 | - name: Build OpenScap 32 | ansible.builtin.shell: 33 | cmd: make install 34 | chdir: /tmp/openscap/build 35 | become: true 36 | register: my_output 37 | changed_when: my_output.rc != 0 38 | tags: 39 | - skip_ansible_lint 40 | - name: Install 41 | ansible.builtin.shell: 42 | cmd: make install 43 | chdir: /tmp/openscap/build 44 | become: true 45 | register: my_output 46 | changed_when: my_output.rc != 0 47 | tags: 48 | - skip_ansible_lint 49 | - name: Create folder to put ComplianceAsCode project 50 | ansible.builtin.file: 51 | mode: "0755" 52 | owner: root 53 | path: "{{ item }}" 54 | state: directory 55 | become: true 56 | with_items: 57 | - /opt/openscap-content 58 | - /tmp/openscap-reports 59 | - name: Test folder existence 60 | ansible.builtin.lineinfile: 61 | name: /opt/openscap-content/ubuntu2204-script-standard.sh 62 | regex: "# Benchmark Version: {{ content_version }}" 63 | line: "# Benchmark Version: {{ content_version }}" 64 | state: present 65 | register: test_content 66 | ignore_errors: true 67 | become: true 68 | - name: Install Content Block 69 | when: install_content and (test_content.changed or 'rc' in test_content) 70 | block: 71 | - name: Unzip ComplianceAsCode project 72 | ansible.builtin.unarchive: 73 | src: https://github.com/ComplianceAsCode/content/releases/download/v{{ content_version }}/scap-security-guide-{{ content_version }}.zip 74 | dest: /opt/openscap-content/ 75 | remote_src: true 76 | extra_opts: -j 77 | become: true 78 | - name: Scan 79 | when: scan 80 | block: 81 | - name: Scan 82 | ansible.builtin.shell: 83 | cmd: oscap xccdf eval --fetch-remote-resources --profile {{ openscap_profile }} --results-arf /tmp/openscap-reports/arf-{{ ansible_distribution | lower }}-{{ 84 | ansible_distribution_major_version }}.xml --report /tmp/openscap-reports/report-{{ ansible_distribution | lower }}-{{ ansible_distribution_major_version 85 | }}.html /opt/openscap-content/{{ openscap_security_policy }} 86 | become: true 87 | register: result 88 | failed_when: result.rc == 1 89 | changed_when: false 90 | tags: 91 | - skip_ansible_lint 92 | - name: Get reports 93 | ansible.builtin.fetch: 94 | src: "{{ item }}" 95 | dest: ./ 96 | flat: true 97 | become: true 98 | with_items: 99 | - /tmp/openscap-reports/report-{{ ansible_distribution | lower }}-{{ ansible_distribution_major_version }}.html 100 | - /tmp/openscap-reports/arf-{{ ansible_distribution | lower }}-{{ ansible_distribution_major_version }}.xml 101 | -------------------------------------------------------------------------------- /tasks/ubuntu22-var.yml: -------------------------------------------------------------------------------- 1 | --- 2 | openscap_profile: "xccdf_org.ssgproject.content_profile_cis_level2_server" 3 | openscap_security_policy: "ssg-ubuntu2204-ds.xml" -------------------------------------------------------------------------------- /tasks/ubuntu22.yml: -------------------------------------------------------------------------------- 1 | - name: Update apt cache 2 | ansible.builtin.apt: 3 | update_cache: yes 4 | when: ansible_pkg_mgr == "apt" 5 | become: true 6 | - name: Install package to build oscap 7 | ansible.builtin.package: 8 | name: 9 | - cmake 10 | - libdbus-1-dev 11 | - libdbus-glib-1-dev 12 | - libcurl4-openssl-dev 13 | - libgcrypt20-dev 14 | - libselinux1-dev 15 | - libxslt1-dev 16 | - libgconf2-dev 17 | - libacl1-dev 18 | - libblkid-dev 19 | - libcap-dev 20 | - libxml2-dev 21 | - libldap2-dev 22 | - libpcre3-dev 23 | - python3-dev 24 | - swig 25 | - libxml-parser-perl 26 | - libxml-xpath-perl 27 | - libperl-dev 28 | - libbz2-dev 29 | - librpm-dev 30 | - g++ 31 | - libapt-pkg-dev 32 | - libyaml-dev 33 | - libxmlsec1-dev 34 | - libxmlsec1-openssl 35 | - unzip 36 | - git 37 | state: present 38 | become: true 39 | -------------------------------------------------------------------------------- /vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | --------------------------------------------------------------------------------