diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f93d641..de89654d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# Community Sops Release Notes +# Community SOPS Release Notes **Topics** diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5859f4c6..9499f1d6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,5 +1,5 @@ ============================ -Community Sops Release Notes +Community SOPS Release Notes ============================ .. contents:: Topics diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 56ecce67..538d071f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,20 +18,20 @@ Please [search in the issue list](https://github.com/ansible-collections/communi ## 🏗 To contribute -A more extensive walk-through can be found in [Ansible's Contributing to collections](https://docs.ansible.com/ansible/latest/dev_guide/developing_collections.html#hacking-collections). +A more extensive walk-through can be found in [Ansible's Contributing to collections](https://docs.ansible.com/ansible/devel/dev_guide/developing_collections.html#hacking-collections). -1. Fork this repo (when checking it out, see [here](https://docs.ansible.com/ansible/latest/dev_guide/developing_collections.html#contributing-to-collections) for how to place the checkout correctly) +1. Fork this repo (when checking it out, see [here](https://docs.ansible.com/ansible/devel/dev_guide/developing_collections.html#contributing-to-collections) for how to place the checkout correctly) 1. Create a feature branch 1. Commit and push your code. To make the process faster, please ensure: - the tests are green. Tests runs using [GitHub Actions](https://help.github.com/en/actions) - - you added a [changelog fragment](https://docs.ansible.com/ansible/latest/community/development_process.html#changelogs-how-to) + - you added a [changelog fragment](https://docs.ansible.com/ansible/devel/community/collection_development_process.html#creating-a-changelog-fragment) -Please note that all PRs that are not strictly documentation, testing, or add a new plugin or module, require a changelog fragment. See [Creating a changelog fragment](https://docs.ansible.com/ansible/latest/community/development_process.html#changelogs-how-to) for information on that. +Please note that all PRs that are not strictly documentation, testing, or add a new plugin or module, require a changelog fragment. See [Creating a changelog fragment](https://docs.ansible.com/ansible/devel/community/collection_development_process.html#creating-a-changelog-fragment) for information on that. Further resources: -- [Ansible Developer guide: developing collections](https://docs.ansible.com/ansible/latest/dev_guide/developing_collections.html) -- [Ansible Developer guide](https://docs.ansible.com/ansible/latest/dev_guide/index.html) +- [Ansible Developer guide: developing collections](https://docs.ansible.com/ansible/devel/dev_guide/developing_collections.html) +- [Ansible Developer guide](https://docs.ansible.com/ansible/devel/dev_guide/index.html) -This repository adheres to the [Ansible Community code of conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html) +This repository adheres to the [Ansible Community code of conduct](https://docs.ansible.com/ansible/devel/community/code_of_conduct.html) diff --git a/README.md b/README.md index b137c71e..af646b32 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://w SPDX-License-Identifier: GPL-3.0-or-later --> -# Community Sops Collection +# Community SOPS Collection [![CI](https://github.com/ansible-collections/community.sops/workflows/CI/badge.svg?event=push)](https://github.com/ansible-collections/community.sops/actions) [![Codecov](https://img.shields.io/codecov/c/github/ansible-collections/community.sops)](https://codecov.io/gh/ansible-collections/community.sops) [![REUSE status](https://api.reuse.software/badge/github.com/ansible-collections/community.sops)](https://api.reuse.software/info/github.com/ansible-collections/community.sops) @@ -16,11 +16,11 @@ The `community.sops` collection allows integrating [`getsops/sops`](https://gith Please note that this collection does **not** support Windows targets. -**Sops version compatibility** +**SOPS version compatibility** -The following table shows which versions of sops were tested with which versions of the collection. Older (or newer) versions of sops can still work fine, it just means that we did not test them. In some cases, it could be that a minimal required version of sops is explicitly documented for a specific feature. Right now, that is not the case. +The following table shows which versions of SOPS were tested with which versions of the collection. Older (or newer) versions of SOPS can still work fine, it just means that we did not test them. In some cases, it could be that a minimal required version of SOPS is explicitly documented for a specific feature. This is the case from community.sops 1.8.0 on; from that version on the collection automatically detects the SOPS version to determine whether a feature is supported or not. -|`community.sops` version|`getsops/sops` version| +|`community.sops` version|SOPS version| |---|---| |0.1.0|`3.5.0+`| |1.0.6|`3.5.0+`| @@ -36,7 +36,7 @@ The vars plugin requires ansible-base 2.10 or later. -You will need to install [`sops`](https://github.com/getsops/sops) manually before using plugins provided by this +You will need to install [the `sops` CLI tool](https://github.com/getsops/sops) manually before using plugins provided by this collection. ## Collection Documentation @@ -55,33 +55,33 @@ If you use the Ansible package and do not update collections independently, use This collection provides: -- a [lookup plugin](https://docs.ansible.com/ansible/latest/user_guide/playbooks_lookups.html#playbooks-lookups) `sops` that allows looking up a sops-encrypted file content; -- a [vars plugin](https://docs.ansible.com/ansible/latest/plugins/vars.html) `sops` that allows loading Ansible vars from sops-encrypted files for hosts and groups; -- an [action plugin](https://docs.ansible.com/ansible/latest/plugins/action.html) `load_vars` that allows loading Ansible vars from a sops-encrypted file dynamically during a playbook or role; -- a [module](https://docs.ansible.com/ansible/latest/user_guide/basic_concepts.html#modules) `sops_encrypt` which allows to encrypt data with sops. -- a [role](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html) `install` which allows to install sops and GNU Privacy Guard. -- two [playbooks](https://docs.ansible.com/ansible/latest/user_guide/playbooks_intro.html) `install` and `install_localhost` which allow to install sops and GNU Privacy Guard. +- a [lookup plugin](https://docs.ansible.com/ansible/latest/user_guide/playbooks_lookups.html#playbooks-lookups) `community.sops.sops` that allows looking up a SOPS-encrypted file content; +- a [vars plugin](https://docs.ansible.com/ansible/latest/plugins/vars.html) `community.sops.sops` that allows loading Ansible vars from SOPS-encrypted files for hosts and groups; +- an [action plugin](https://docs.ansible.com/ansible/latest/plugins/action.html) `community.sops.load_vars` that allows loading Ansible vars from a SOPS-encrypted file dynamically during a playbook or role; +- a [module](https://docs.ansible.com/ansible/latest/user_guide/basic_concepts.html#modules) `community.sops.sops_encrypt` which allows to encrypt data with SOPS. +- a [role](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html) `community.sops.install` which allows to install SOPS and GNU Privacy Guard. +- two [playbooks](https://docs.ansible.com/ansible/latest/user_guide/playbooks_intro.html) `community.sops.install` and `install_localhost` which allow to install SOPS and GNU Privacy Guard. ## Using this collection -### Installing sops +### Installing SOPS -To install sops, you can use the ``community.sops.install`` role. The role also installs [GNU Privacy Guard (GPG)](https://en.wikipedia.org/wiki/GNU_Privacy_Guard). +To install SOPS, you can use the `community.sops.install` role. The role also installs [GNU Privacy Guard (GPG)](https://en.wikipedia.org/wiki/GNU_Privacy_Guard). Examples: ```yaml tasks: - # To use the sops_encrypt module on a remote host, you need to install sops on it: - - name: Install sops on remote hosts + # To use the sops_encrypt module on a remote host, you need to install SOPS on it: + - name: Install SOPS on remote hosts ansible.builtin.include_role: name: community.sops.install vars: sops_version: 2.7.0 # per default installs the latest version # To use the lookup plugin, filter plugin, vars plugin, or the load_vars action, - # you need sops installed on localhost: - - name: Install sops on localhost + # you need SOPS installed on localhost: + - name: Install SOPS on localhost ansible.builtin.include_role: name: community.sops.install vars: @@ -98,15 +98,15 @@ Examples: tasks: - name: Output secrets to screen (BAD IDEA!) ansible.builtin.debug: - msg: "Content: {{ lookup('community.sops.sops', '/path/to/sops-encrypted-file.enc.yaml') }}" + msg: "Content: {{ lookup('community.sops.sops', '/path/to/sops-encrypted-file.enc.yaml') }}" - name: Add SSH private key ansible.builtin.copy: - content: "{{ lookup('community.sops.sops', user + '-id_rsa') }}" - dest: /home/{{ user }}/.ssh/id_rsa - owner: "{{ user }}" - group: "{{ user }}" - mode: 0600 + content: "{{ lookup('community.sops.sops', user + '-id_rsa') }}" + dest: /home/{{ user }}/.ssh/id_rsa + owner: "{{ user }}" + group: "{{ user }}" + mode: 0600 no_log: true # avoid content to be written to log ``` @@ -114,13 +114,13 @@ See [Lookup Plugins](https://docs.ansible.com/ansible/latest/plugins/lookup.html ### filter plugin -The filter plugin can be used in Jinja2 expressions by the name `community.sops.decrypt`. It can decrypt sops-encrypted data coming from other sources than files. +The filter plugin can be used in Jinja2 expressions by the name `community.sops.decrypt`. It can decrypt SOPS-encrypted data coming from other sources than files. Example: ```yaml tasks: - - name: Load sops encrypted data + - name: Load SOPS encrypted data ansible.builtin.set_fact: encrypted_data: "{{ lookup('file', '/path/to/sops-encrypted-file.enc.yaml') }}" @@ -166,7 +166,7 @@ vars_plugins_enabled = host_group_vars,community.sops.sops See [VARIABLE_PLUGINS_ENABLED](https://docs.ansible.com/ansible/devel/reference_appendices/config.html#variable-plugins-enabled) for more details. After the plugin is enabled, correctly named group and host vars files will be -transparently decrypted with sops. +transparently decrypted with SOPS. The files must end with one of these extensions: @@ -174,7 +174,7 @@ The files must end with one of these extensions: * `.sops.yml` * `.sops.json` -Here is an example file structure +(These extensions can be adjusted, check out the vars plugin's options for details.) Here is an example file structure: ``` ├── inventory/ @@ -191,7 +191,7 @@ Here is an example file structure ``` You could execute the playbook in this example with the following command. The -sops vars files would be decrypted and used. +SOPS-encrypted vars files would be decrypted and used. ```console $ ansible-playbook playbooks/setup-server.yml -i inventory/hosts @@ -201,7 +201,7 @@ $ ansible-playbook playbooks/setup-server.yml -i inventory/hosts Ansible 2.10 allows to determine [when vars plugins load the data](https://docs.ansible.com/ansible/latest/plugins/vars.html#using-vars-plugins). -To run the sops vars plugin right after importing inventory, you can add the following to `ansible.cfg`: +To run the SOPS vars plugin right after importing inventory, you can add the following to `ansible.cfg`: ```ini [community.sops] @@ -210,7 +210,7 @@ vars_stage = inventory #### Caching variable files -By default, the sops vars plugin caches decrypted files to avoid having to decrypt them every task. If this is not wanted, it can be explicitly disabled in `ansible.cfg`: +By default, the vars plugin caches decrypted files to avoid having to decrypt them every task. If this is not wanted, it can be explicitly disabled in `ansible.cfg`: ```ini [community.sops] @@ -221,7 +221,7 @@ Please note that when using vars plugin staging, this setting only has effect if ### load_vars action plugin -The `load_vars` action plugin can be used similarly to Ansible's `include_vars`, except that it right now only supports single files. Also, it does not allow to load proper variables (i.e. "unsafe" Jinja2 expressions which evaluate on usage), but only facts. It does allow to evaluate expressions on load-time though. +The `load_vars` action plugin can be used similarly to Ansible's `include_vars`, except that it right now only supports single files. Also, it does not allow to load proper variables (i.e. "unsafe" Jinja2 expressions which evaluate on usage), but only facts. This is a restriction imposed by ansible-core. The plugin does allow to evaluate expressions on load-time, though. Examples: @@ -229,61 +229,61 @@ Examples: tasks: - name: Load variables from file and store them in a variable community.sops.load_vars: - file: path/to/sops-encrypted-file.sops.yaml - name: variable_to_store_contents_in + file: path/to/sops-encrypted-file.sops.yaml + name: variable_to_store_contents_in - name: Load variables from file into global namespace, and evaluate Jinja2 expressions community.sops.load_vars: - file: path/to/sops-encrypted-file-with-jinja2-expressions.sops.yaml - # The following allows to use Jinja2 expressions in the encrypted file! - # They are evaluated right now, i.e. not later like when loaded with include_vars. - expressions: evaluate-on-load + file: path/to/sops-encrypted-file-with-jinja2-expressions.sops.yaml + # The following allows to use Jinja2 expressions in the encrypted file! + # They are evaluated right now, i.e. not later like when loaded with include_vars. + expressions: evaluate-on-load ``` ### sops_encrypt module -The `sops_encrypt` module can be used to create and update sops encrypted files. It assumes that sops is configured via environment variables or a `.sops.yaml` file. +The `sops_encrypt` module can be used to create and update SOPS-encrypted files. It assumes that SOPS is configured via environment variables or a `.sops.yaml` file. Examples: ```yaml tasks: - - name: Store secret text sops encrypted + - name: Store secret text SOPS-encrypted community.sops.sops_encrypt: - path: path/to/sops-encrypted-file.sops - content_text: This is some secret text. + path: path/to/sops-encrypted-file.sops + content_text: This is some secret text. - - name: Store secret binary data sops encrypted + - name: Store secret binary data SOPS-encrypted community.sops.sops_encrypt: - path: path/to/sops-encrypted-file.sops - content_binary: "{{ some_secret_binary_data | b64encode }}" + path: path/to/sops-encrypted-file.sops + content_binary: "{{ some_secret_binary_data | b64encode }}" - name: Store secret JSON data community.sops.sops_encrypt: - path: path/to/sops-encrypted-file.sops.json - content_json: - key1: value1 - key2: - - value2 - - key3: value3 - key4: value5 + path: path/to/sops-encrypted-file.sops.json + content_json: + key1: value1 + key2: + - value2 + - key3: value3 + key4: value5 - name: Store secret YAML data community.sops.sops_encrypt: - path: path/to/sops-encrypted-file.sops.yaml - content_yaml: - key1: value1 - key2: - - value2 - - key3: value3 - key4: value5 + path: path/to/sops-encrypted-file.sops.yaml + content_yaml: + key1: value1 + key2: + - value2 + - key3: value3 + key4: value5 ``` ## Troubleshooting ### Spurious failures during encryption and decryption with gpg -Sops calls `gpg` with `--use-agent`. When running multiple of these in parallel, for example when loading variables or looking up files for various hosts at once, some of these can randomly fail with messages such as +Older versions of SOPS calls `gpg` with `--use-agent`. When running multiple of these in parallel, for example when loading variables or looking up files for various hosts at once, some of these can randomly fail with messages such as ``` Failed to get the data key required to decrypt the SOPS file. @@ -312,7 +312,7 @@ This is a limitation of gpg-agent which can be fixed by adding `auto-expand-secm -See [CONTRIBUTING.md](./CONTRIBUTING.md) +See [CONTRIBUTING.md](https://github.com/ansible-collections/community.sops/blob/main/CONTRIBUTING.md) ## Release notes @@ -328,11 +328,6 @@ Releasing the current major version happens from the `main` branch. We will crea We currently are not planning any deprecations or new major releases like 2.0.0 containing backwards incompatible changes. If backwards incompatible changes are needed, we plan to deprecate the old behavior as early as possible. We also plan to backport at least bugfixes for the old major version for some time after releasing a new major version. We will not block community members from backporting other bugfixes and features from the latest stable version to older release branches, under the condition that these backports are of reasonable quality. -### TODO - -- add a role providing sops installation (with version pinning) -- a full test suite - ## Code of Conduct This repository adheres to the [Ansible Community code of conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html) diff --git a/changelogs/config.yaml b/changelogs/config.yaml index a8c51d53..72181315 100644 --- a/changelogs/config.yaml +++ b/changelogs/config.yaml @@ -33,7 +33,7 @@ sections: - Bugfixes - - known_issues - Known Issues -title: Community Sops +title: Community SOPS trivial_section_name: trivial use_fqcn: true add_plugin_period: true diff --git a/docs/docsite/rst/guide.rst b/docs/docsite/rst/guide.rst index 8f7118d8..7384a294 100644 --- a/docs/docsite/rst/guide.rst +++ b/docs/docsite/rst/guide.rst @@ -5,10 +5,10 @@ .. _ansible_collections.community.sops.docsite.guide: -Protecting Ansible secrets with Mozilla SOPS -============================================ +Protecting Ansible secrets with SOPS +==================================== -`Mozilla SOPS `_ allows to encrypt and decrypt files using various key sources (GPG, AWS KMS, GCP KMS, ...). For structured data, such as YAML, JSON, INI and ENV files, it will encrypt values, but not mapping keys. For YAML files, it also encrypts comments. This makes it a great tool for encrypting credentials with Ansible: you can easily see which files contain which variable, but the variables themselves are encrypted. +`CNCF SOPS `_ allows to encrypt and decrypt files using various key sources (GPG, AWS KMS, GCP KMS, ...). For structured data, such as YAML, JSON, INI and ENV files, it will encrypt values, but not mapping keys. For YAML files, it also encrypts comments. This makes it a great tool for encrypting credentials with Ansible: you can easily see which files contain which variable, but the variables themselves are encrypted. The ability to utilize various keysources makes it easier to use in complex environments than :ref:`Ansible Vault `. @@ -16,28 +16,28 @@ The ability to utilize various keysources makes it easier to use in complex envi :local: :depth: 1 -Installing sops +Installing SOPS --------------- You can find binaries and packages `on the project's release page `_. Depending on your operating system, you might also be able to install it with your system's package manager. -This collection provides a :ansplugin:`role community.sops.install ` which allows to install sops and `GNU Privacy Guard (GPG) `__. The role allows to install sops from the system's package manager or from GitHub. Both sops and GPG can be installed on the remote hosts or the Ansible controller. +This collection provides a :ansplugin:`role community.sops.install ` which allows to install SOPS and `GNU Privacy Guard (GPG) `__. The role allows to install SOPS from the system's package manager or from GitHub. Both SOPS and GPG can be installed on the remote hosts or the Ansible controller. .. code-block:: yaml - - name: Playbook to install sops + - name: Playbook to install SOPS hosts: all tasks: - # To use the sops_encrypt module on a remote host, you need to install sops on it: - - name: Install sops on remote hosts + # To use the sops_encrypt module on a remote host, you need to install SOPS on it: + - name: Install SOPS on remote hosts ansible.builtin.include_role: name: community.sops.install vars: sops_version: 2.7.0 # per default installs the latest version # To use the lookup plugin, filter plugin, vars plugin, or the load_vars action, - # you need sops installed on localhost: - - name: Install sops on localhost + # you need SOPS installed on localhost: + - name: Install SOPS on localhost ansible.builtin.include_role: name: community.sops.install vars: @@ -47,16 +47,16 @@ When using ansible-core 2.11 or later, you can also use two convenience playbook .. code-block:: bash - # Install sops on Ansible controller + # Install SOPS on Ansible controller $ ansible-playbook community.sops.install_localhost - # Install sops on remote servers + # Install SOPS on remote servers $ ansible-playbook community.sops.install --inventory /path/to/inventory Installing community.sops in an Execution Environment ----------------------------------------------------- -When building an execution environment containing community.sops, please note that by default sops is not automatically installed. This is due to a limitation of the dependency specification system for execution environments. If you are building an execution environment that contains community.sops, you should make sure that sops is installed in it. +When building an execution environment containing community.sops, please note that by default SOPS is not automatically installed. This is due to a limitation of the dependency specification system for execution environments. If you are building an execution environment that contains community.sops, you should make sure that SOPS is installed in it. The simplest way of ensuring this is to use the ``community.sops.install_localhost`` playbook. When defining an execution environment, you can add a ``RUN`` additional build step to your ``execution-environment.yml``: @@ -68,7 +68,7 @@ The simplest way of ensuring this is to use the ``community.sops.install_localho galaxy: requirements.yml additional_build_steps: append_final: - # Ensure that sops is installed in the EE, assuming the EE is for ansible-core 2.11 or newer + # Ensure that SOPS is installed in the EE, assuming the EE is for ansible-core 2.11 or newer - RUN ansible-playbook -v community.sops.install_localhost Note that this only works if the execution environment is built with ansible-core 2.11 or newer. When using an execution environment with Ansible 2.9, you have to use the :ansplugin:`community.sops.install#role` role manually. Also note that you need to make sure that Ansible 2.9 uses the correct Python interpreter to be able to install system packages with; in the below example we are assuming a RHEL/CentOS based execution environment base image: @@ -89,10 +89,10 @@ Note that this only works if the execution environment is built with ansible-cor Once this step has been taken care of, you can use all plugins and modules (on ``localhost``) from community.sops in the execution environment. -Setting up sops +Setting up SOPS --------------- -From now on this guide assumes that you have installed Mozilla SOPS. +From now on this guide assumes that you have installed SOPS. For simplicity, you can work with GPG keys. If you do not have one, or do not want to use yours, you can run ``gpg --quick-generate-key me@example.com`` to create a GPG key for the user ID ``me@example.com``. You will need its 40 hex-digit key ID that is printed at the end. The first step is to create a ``.sops.yaml`` file in the directory tree you are working in: @@ -101,7 +101,7 @@ For simplicity, you can work with GPG keys. If you do not have one, or do not wa creation_rules: - pgp: 'FBC7B9E2A4F9289AC0C1D4843D16CEE4A27381B4' -Here, ``FBC7B9E2A4F9289AC0C1D4843D16CEE4A27381B4`` is the 40 hex-digit key ID. With this file you can create a sops encrypted file by running the following in the directory where ``.sops.yaml`` was placed, or a subdirectory of it: +Here, ``FBC7B9E2A4F9289AC0C1D4843D16CEE4A27381B4`` is the 40 hex-digit key ID. With this file you can create a SOPS-encrypted file by running the following in the directory where ``.sops.yaml`` was placed, or a subdirectory of it: .. code-block:: bash @@ -117,7 +117,7 @@ This will open an editor window with an example YAML file. Put the following con - bar - baz -After closing the editor, sops will create ``test.sops.yaml`` with the encrypted contents: +After closing the editor, SOPS will create ``test.sops.yaml`` with the encrypted contents: .. code-block:: yaml @@ -160,9 +160,9 @@ At the end, the ``sops`` section contains metadata, which includes the private k Working with encrypted files ---------------------------- -You can decrypt sops-encrypted files with the :ansplugin:`community.sops.sops lookup plugin `, and dynamically encrypt data with the :ansplugin:`community.sops.sops_encrypt module `. Being able to encrypt is useful when you create or update secrets in your Ansible playbooks. +You can decrypt SOPS-encrypted files with the :ansplugin:`community.sops.sops lookup plugin `, and dynamically encrypt data with the :ansplugin:`community.sops.sops_encrypt module `. Being able to encrypt is useful when you create or update secrets in your Ansible playbooks. -Assume that you have an encrypted private key ``keys/private_key.pem.sops``, which was in PEM format before being encrypted by sops: +Assume that you have an encrypted private key ``keys/private_key.pem.sops``, which was in PEM format before being encrypted by SOPS: .. code-block:: bash @@ -175,13 +175,13 @@ To use it in a playbook, for example to pass it to the :ansplugin:`community.cry .. code-block:: yaml+jinja --- - - name: Load sops-encrypted private key + - name: Load SOPS-encrypted private key hosts: localhost gather_facts: false tasks: - name: Create CSR with encrypted private key community.crypto.openssl_csr: - # The private key is provided with sops: + # The private key is provided with SOPS: privatekey_content: "{{ lookup('community.sops.sops', 'keys/private_key.pem.sops') }}" # Store the CSR on disk unencrypted: path: ansible.com.csr @@ -195,7 +195,7 @@ This results in the following output: .. code-block:: ansible-output - PLAY [Load sops-encrypted private key] *************************************************************************** + PLAY [Load SOPS-encrypted private key] *************************************************************************** TASK [Create CSR with encrypted private key] ********************************************************************* ok: [localhost] @@ -210,7 +210,7 @@ If you want to use Ansible to generate (or update) the encrypted private key, yo .. code-block:: yaml+jinja --- - - name: Create sops-encrypted private key + - name: Create SOPS-encrypted private key hosts: localhost gather_facts: false tasks: @@ -237,7 +237,7 @@ This playbook creates a new key on every run. If you want the private key creati .. code-block:: yaml+jinja --- - - name: Create sops-encrypted private key + - name: Create SOPS-encrypted private key hosts: localhost gather_facts: false tasks: @@ -270,7 +270,7 @@ The :ansopt:`community.sops.sops#lookup:empty_on_not_exist=true` flag is needed .. code-block:: ansible-output - PLAY [Create sops-encrypted private key] ************************************************************************* + PLAY [Create SOPS-encrypted private key] ************************************************************************* TASK [Create private key] **************************************************************************************** ok: [localhost] @@ -418,7 +418,7 @@ See :ref:`VARIABLE_PLUGINS_ENABLED ` for more details - ``.sops.yml`` - ``.sops.json`` -The vars plugin will decrypt them and you can use their unencrypted content transparently. +(The list of extensions can be adjusted with :ansopt:`community.sops.sops#vars:_valid_extensions`.) The vars plugin will decrypt them and you can use their unencrypted content transparently. If you need to dynamically load encrypted variables, similar to the built-in :ansplugin:`ansible.builtin.include_vars action `, you can use the :ansplugin:`community.sops.load_vars action ` action. Please note that it is not a perfect replacement, since the built-in action relies on some hard-coded special casing in ansible-core which allows it to load the variables actually as variables (more precisely: as "unsafe" Jinja2 expressions which are automatically evaluated when used). Other action plugins, such as :ansplugin:`community.sops.load_vars#module`, cannot do that and have to load the variables as facts instead. @@ -436,7 +436,7 @@ Consider the following playbook: .. code-block:: yaml+jinja --- - - name: Create sops-encrypted private key + - name: Create SOPS-encrypted private key hosts: localhost gather_facts: false tasks: @@ -458,7 +458,7 @@ Running it produces: .. code-block:: ansible-output - PLAY [Create sops-encrypted private key] ************************************************************************* + PLAY [Create SOPS-encrypted private key] ************************************************************************* TASK [Load encrypted credentials] ******************************************************************************** ok: [localhost] diff --git a/galaxy.yml b/galaxy.yml index 21934415..73f4ff63 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -9,7 +9,7 @@ version: 1.8.0 readme: README.md authors: - Edoardo Tenani -description: "Support usage of getsops/sops from your Ansible playbooks" +description: "Support usage of SOPS (getsops/sops) from your Ansible playbooks" license: - GPL-3.0-or-later - BSD-2-Clause diff --git a/playbooks/install.yml b/playbooks/install.yml index faff3b99..479a5d86 100644 --- a/playbooks/install.yml +++ b/playbooks/install.yml @@ -3,10 +3,10 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -- name: Install sops +- name: Install SOPS gather_facts: true hosts: all tasks: - - name: Install sops on remote hosts + - name: Install SOPS on remote hosts ansible.builtin.include_role: name: community.sops.install diff --git a/playbooks/install_localhost.yml b/playbooks/install_localhost.yml index 55f65152..0dedf645 100644 --- a/playbooks/install_localhost.yml +++ b/playbooks/install_localhost.yml @@ -3,11 +3,11 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -- name: Install sops on localhost +- name: Install SOPS on localhost gather_facts: false hosts: localhost tasks: - - name: Install sops on localhost + - name: Install SOPS on localhost ansible.builtin.include_role: name: community.sops.install vars: diff --git a/plugins/doc_fragments/sops.py b/plugins/doc_fragments/sops.py index 94a49386..a20895d3 100644 --- a/plugins/doc_fragments/sops.py +++ b/plugins/doc_fragments/sops.py @@ -16,61 +16,61 @@ class ModuleDocFragment(object): options: sops_binary: description: - - Path to the sops binary. + - Path to the SOPS binary. - By default uses C(sops). type: path version_added: 1.0.0 age_key: description: - One or more age private keys that can be used to decrypt encrypted files. - - Will be set as the E(SOPS_AGE_KEY) environment variable when calling sops. + - Will be set as the E(SOPS_AGE_KEY) environment variable when calling SOPS. type: str version_added: 1.4.0 age_keyfile: description: - - The file containing the age private keys that sops can use to decrypt + - The file containing the age private keys that SOPS can use to decrypt encrypted files. - - Will be set as the E(SOPS_AGE_KEY_FILE) environment variable when calling sops. - - By default, sops looks for C(sops/age/keys.txt) inside your user configuration + - Will be set as the E(SOPS_AGE_KEY_FILE) environment variable when calling SOPS. + - By default, SOPS looks for C(sops/age/keys.txt) inside your user configuration directory. type: path version_added: 1.4.0 aws_profile: description: - The AWS profile to use for requests to AWS. - - This corresponds to the sops C(--aws-profile) option. + - This corresponds to the SOPS C(--aws-profile) option. type: str version_added: 1.0.0 aws_access_key_id: description: - The AWS access key ID to use for requests to AWS. - - Sets the environment variable E(AWS_ACCESS_KEY_ID) for the sops call. + - Sets the environment variable E(AWS_ACCESS_KEY_ID) for the SOPS call. type: str version_added: 1.0.0 aws_secret_access_key: description: - The AWS secret access key to use for requests to AWS. - - Sets the environment variable E(AWS_SECRET_ACCESS_KEY) for the sops call. + - Sets the environment variable E(AWS_SECRET_ACCESS_KEY) for the SOPS call. type: str version_added: 1.0.0 aws_session_token: description: - The AWS session token to use for requests to AWS. - - Sets the environment variable E(AWS_SESSION_TOKEN) for the sops call. + - Sets the environment variable E(AWS_SESSION_TOKEN) for the SOPS call. type: str version_added: 1.0.0 config_path: description: - - Path to the sops configuration file. - - If not set, sops will recursively search for the config file starting at + - Path to the SOPS configuration file. + - If not set, SOPS will recursively search for the config file starting at the file that is encrypted or decrypted. - - This corresponds to the sops C(--config) option. + - This corresponds to the SOPS C(--config) option. type: path version_added: 1.0.0 enable_local_keyservice: description: - - Tell sops to use local key service. - - This corresponds to the sops C(--enable-local-keyservice) option. + - Tell SOPS to use local key service. + - This corresponds to the SOPS C(--enable-local-keyservice) option. type: bool default: false version_added: 1.0.0 @@ -79,7 +79,7 @@ class ModuleDocFragment(object): - Specify key services to use next to the local one. - A key service must be specified in the form C(protocol://address), for example C(tcp://myserver.com:5000). - - This corresponds to the sops C(--keyservice) option. + - This corresponds to the SOPS C(--keyservice) option. type: list elements: str version_added: 1.0.0 @@ -217,28 +217,28 @@ class ModuleDocFragment(object): age: description: - Age fingerprints to use. - - This corresponds to the sops C(--age) option. + - This corresponds to the SOPS C(--age) option. type: list elements: str version_added: 1.4.0 kms: description: - List of KMS ARNs to use. - - This corresponds to the sops C(--kms) option. + - This corresponds to the SOPS C(--kms) option. type: list elements: str version_added: 1.0.0 gcp_kms: description: - GCP KMS resource IDs to use. - - This corresponds to the sops C(--gcp-kms) option. + - This corresponds to the SOPS C(--gcp-kms) option. type: list elements: str version_added: 1.0.0 azure_kv: description: - Azure Key Vault URLs to use. - - This corresponds to the sops C(--azure-kv) option. + - This corresponds to the SOPS C(--azure-kv) option. type: list elements: str version_added: 1.0.0 @@ -246,21 +246,21 @@ class ModuleDocFragment(object): description: - HashiCorp Vault key URIs to use. - For example, C(https://vault.example.org:8200/v1/transit/keys/dev). - - This corresponds to the sops C(--hc-vault-transit) option. + - This corresponds to the SOPS C(--hc-vault-transit) option. type: list elements: str version_added: 1.0.0 pgp: description: - PGP fingerprints to use. - - This corresponds to the sops C(--pgp) option. + - This corresponds to the SOPS C(--pgp) option. type: list elements: str version_added: 1.0.0 unencrypted_suffix: description: - Override the unencrypted key suffix. - - This corresponds to the sops C(--unencrypted-suffix) option. + - This corresponds to the SOPS C(--unencrypted-suffix) option. type: str version_added: 1.0.0 encrypted_suffix: @@ -268,27 +268,27 @@ class ModuleDocFragment(object): - Override the encrypted key suffix. - When set to an empty string, all keys will be encrypted that are not explicitly marked by O(unencrypted_suffix). - - This corresponds to the sops C(--encrypted-suffix) option. + - This corresponds to the SOPS C(--encrypted-suffix) option. type: str version_added: 1.0.0 unencrypted_regex: description: - Set the unencrypted key suffix. - When specified, only keys matching the regular expression will be left unencrypted. - - This corresponds to the sops C(--unencrypted-regex) option. + - This corresponds to the SOPS C(--unencrypted-regex) option. type: str version_added: 1.0.0 encrypted_regex: description: - Set the encrypted key suffix. - When specified, only keys matching the regular expression will be encrypted. - - This corresponds to the sops C(--encrypted-regex) option. + - This corresponds to the SOPS C(--encrypted-regex) option. type: str version_added: 1.0.0 encryption_context: description: - List of KMS encryption context pairs of format C(key:value). - - This corresponds to the sops C(--encryption-context) option. + - This corresponds to the SOPS C(--encryption-context) option. type: list elements: str version_added: 1.0.0 @@ -296,8 +296,8 @@ class ModuleDocFragment(object): description: - The number of distinct keys required to retrieve the data key with L(Shamir's Secret Sharing, https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing). - - If not set here and in the sops config file, will default to V(0). - - This corresponds to the sops C(--shamir-secret-sharing-threshold) option. + - If not set here and in the SOPS config file, will default to V(0). + - This corresponds to the SOPS C(--shamir-secret-sharing-threshold) option. type: int version_added: 1.0.0 ''' diff --git a/plugins/filter/decrypt.py b/plugins/filter/decrypt.py index 015d9388..2418cade 100644 --- a/plugins/filter/decrypt.py +++ b/plugins/filter/decrypt.py @@ -9,12 +9,12 @@ DOCUMENTATION = ''' name: decrpyt -short_description: Decrypt sops encrypted data +short_description: Decrypt SOPS-encrypted data version_added: 1.1.0 author: - Felix Fontein (@felixfontein) description: - - Decrypt sops encrypted data. + - Decrypt SOPS-encrypted data. - Allows to decrypt data that has been provided by an arbitrary source. - Note that due to Ansible lazy-evaluating expressions, it is better to use M(ansible.builtin.set_fact) to store the result of an evaluation in a fact to avoid recomputing the value every time the expression @@ -32,9 +32,9 @@ default: true input_type: description: - - Tell sops how to interpret the encrypted data. + - Tell SOPS how to interpret the encrypted data. - There is no auto-detection since we do not have a filename. By default - sops is told to treat the input as YAML. If that is wrong, please set this + SOPS is told to treat the input as YAML. If that is wrong, please set this option to the correct value. type: str choices: @@ -45,7 +45,7 @@ default: yaml output_type: description: - - Tell sops how to interpret the decrypted file. + - Tell SOPS how to interpret the decrypted file. - Please note that the output is always text or bytes, depending on the value of O(decode_output). To parse the resulting JSON or YAML, use corresponding filters such as P(ansible.builtin.from_json#filter) and P(ansible.builtin.from_yaml#filter). diff --git a/plugins/lookup/sops.py b/plugins/lookup/sops.py index 8d39432f..525f3d28 100644 --- a/plugins/lookup/sops.py +++ b/plugins/lookup/sops.py @@ -10,7 +10,7 @@ DOCUMENTATION = """ name: sops author: Edoardo Tenani (@endorama) - short_description: Read sops encrypted file contents + short_description: Read SOPS-encrypted file contents version_added: '0.1.0' description: - This lookup returns the contents from a file on the Ansible controller's file system. @@ -31,8 +31,8 @@ default: false input_type: description: - - Tell sops how to interpret the encrypted file. - - By default, sops will chose the input type from the file extension. + - Tell SOPS how to interpret the encrypted file. + - By default, SOPS will chose the input type from the file extension. If it detects the wrong type for a file, this could result in decryption failing. type: str @@ -43,8 +43,8 @@ - dotenv output_type: description: - - Tell sops how to interpret the decrypted file. - - By default, sops will chose the output type from the file extension. + - Tell SOPS how to interpret the decrypted file. + - By default, SOPS will chose the output type from the file extension. If it detects the wrong type for a file, this could result in decryption failing. type: str @@ -69,10 +69,10 @@ seealso: - plugin: community.sops.decrypt plugin_type: filter - description: The decrypt filter can be used to descrypt sops-encrypted in-memory data. + description: The decrypt filter can be used to descrypt SOPS-encrypted in-memory data. - plugin: community.sops.sops plugin_type: vars - description: The sops vars plugin can be used to load sops-encrypted host or group variables. + description: The sops vars plugin can be used to load SOPS-encrypted host or group variables. - module: community.sops.load_vars """ diff --git a/plugins/modules/load_vars.py b/plugins/modules/load_vars.py index 26366078..312462eb 100644 --- a/plugins/modules/load_vars.py +++ b/plugins/modules/load_vars.py @@ -13,10 +13,10 @@ --- author: Felix Fontein (@felixfontein) module: load_vars -short_description: Load sops-encrypted variables from files, dynamically within a task +short_description: Load SOPS-encrypted variables from files, dynamically within a task version_added: '0.1.0' description: - - Loads sops-encrypted YAML/JSON variables dynamically from a file during task runtime. + - Loads SOPS-encrypted YAML/JSON variables dynamically from a file during task runtime. - To assign included variables to a different host than C(inventory_hostname), use C(delegate_to) and set C(delegate_facts=true). options: @@ -38,7 +38,7 @@ in other words, when the file is loaded. - Unfortunately, there is no way for non-core modules to handle expressions "unsafe", in other words, evaluate them only on use. This can only achieved by M(ansible.builtin.include_vars), - which unfortunately cannot handle sops-encrypted files. + which unfortunately cannot handle SOPS-encrypted files. type: str default: ignore choices: @@ -71,13 +71,13 @@ description: More information related to task delegation. - plugin: community.sops.sops plugin_type: lookup - description: The sops lookup can be used decrypt sops-encrypted files. + description: The sops lookup can be used decrypt SOPS-encrypted files. - plugin: community.sops.decrypt plugin_type: filter - description: The decrypt filter can be used to descrypt sops-encrypted in-memory data. + description: The decrypt filter can be used to descrypt SOPS-encrypted in-memory data. - plugin: community.sops.sops plugin_type: vars - description: The sops vars plugin can be used to load sops-encrypted host or group variables. + description: The sops vars plugin can be used to load SOPS-encrypted host or group variables. ''' EXAMPLES = r''' diff --git a/plugins/modules/sops_encrypt.py b/plugins/modules/sops_encrypt.py index ba5fb54c..9920b90e 100644 --- a/plugins/modules/sops_encrypt.py +++ b/plugins/modules/sops_encrypt.py @@ -13,14 +13,14 @@ --- author: Felix Fontein (@felixfontein) module: sops_encrypt -short_description: Encrypt data with sops +short_description: Encrypt data with SOPS version_added: '0.1.0' description: - - Allows to encrypt binary data (Base64 encoded), text data, JSON or YAML data with sops. + - Allows to encrypt binary data (Base64 encoded), text data, JSON or YAML data with SOPS. options: path: description: - - The sops encrypt file. + - The SOPS encrypt file. type: path required: true force: @@ -67,7 +67,7 @@ seealso: - plugin: community.sops.sops plugin_type: lookup - description: The sops lookup can be used decrypt sops-encrypted files. + description: The sops lookup can be used decrypt SOPS-encrypted files. ''' EXAMPLES = r''' diff --git a/plugins/vars/sops.py b/plugins/vars/sops.py index 8311d7b0..a514a83b 100644 --- a/plugins/vars/sops.py +++ b/plugins/vars/sops.py @@ -10,7 +10,7 @@ DOCUMENTATION = ''' name: sops author: Edoardo Tenani (@endorama) - short_description: Loading sops-encrypted vars files + short_description: Loading SOPS-encrypted vars files version_added: '0.1.0' description: - Load encrypted YAML files into corresponding groups/hosts in C(group_vars/) and C(host_vars/) directories. @@ -97,10 +97,10 @@ seealso: - plugin: community.sops.sops plugin_type: lookup - description: The sops lookup can be used decrypt sops-encrypted files. + description: The sops lookup can be used decrypt SOPS-encrypted files. - plugin: community.sops.decrypt plugin_type: filter - description: The decrypt filter can be used to descrypt sops-encrypted in-memory data. + description: The decrypt filter can be used to decrypt SOPS-encrypted in-memory data. - module: community.sops.load_vars ''' diff --git a/roles/_install_age/meta/main.yml b/roles/_install_age/meta/main.yml index 6e671781..28b22dce 100644 --- a/roles/_install_age/meta/main.yml +++ b/roles/_install_age/meta/main.yml @@ -6,6 +6,6 @@ galaxy_info: standalone: false description: > - [INTERNAL] Install age (https://github.com/FiloSottile/age/). + [INTERNAL] Install age (https://age-encryption.org/). dependencies: [] diff --git a/roles/install/meta/argument_specs.yml b/roles/install/meta/argument_specs.yml index 83c890a5..2224e2c0 100644 --- a/roles/install/meta/argument_specs.yml +++ b/roles/install/meta/argument_specs.yml @@ -5,10 +5,10 @@ argument_specs: main: - short_description: Install Mozilla sops + short_description: Install SOPS version_added: 1.5.0 description: - - This role installs L(Mozilla sops,https://github.com/getsops/sops) and Gnu Privacy Guard (GPG). + - This role installs L(SOPS,https://github.com/getsops/sops) and GNU Privacy Guard (GPG). - >- This role supports the following operating systems: Alpine (new enough), @@ -26,16 +26,16 @@ argument_specs: sops_version: default: latest description: - - The version of sops to install. + - The version of SOPS to install. - Should be a version like V(3.7.2). The special value V(latest) will select the latest version available form the given source. type: str sops_source: default: auto description: - - Determines the source from where sops is installed. - - The value V(github) will install sops from the Mozilla sops releases on GitHub (U(https://github.com/getsops/sops/releases/)). - - The value V(system) will install sops from the system packages. Note that not all system package repositories support sops. - - The value V(auto) will determine the best source to install sops from. Here, system package repositories are preferred over GitHub. + - Determines the source from where SOPS is installed. + - The value V(github) will install SOPS from the SOPS releases on GitHub (U(https://github.com/getsops/sops/releases/)). + - The value V(system) will install SOPS from the system packages. Note that not all system package repositories support SOPS. + - The value V(auto) will determine the best source to install SOPS from. Here, system package repositories are preferred over GitHub. type: str choices: - auto @@ -44,7 +44,7 @@ argument_specs: sops_install_on_localhost: default: false description: - - Installs sops on the Ansible controller (C(localhost)) instead of the remote host. + - Installs SOPS on the Ansible controller (C(localhost)) instead of the remote host. type: bool sops_become_on_install: default: true @@ -53,7 +53,7 @@ argument_specs: type: bool sops_github_latest_detection: description: - - When installing the latest sops version from GitHub, configures how the latest release is detected. + - When installing the latest SOPS version from GitHub, configures how the latest release is detected. - V(auto) tries V(api) first and then uses V(latest-release). - V(api) asks the GitHub API for a list of recent releases and picks the highest version. Pre-releases are avoided. - V(latest-release) uses a not fully documented URL to retrieve the release marked as "latest" by the repository maintainers. diff --git a/roles/install/meta/main.yml b/roles/install/meta/main.yml index 376d956b..79f041be 100644 --- a/roles/install/meta/main.yml +++ b/roles/install/meta/main.yml @@ -6,6 +6,6 @@ galaxy_info: standalone: false description: > - Install Mozilla sops (https://github.com/getsops/sops). + Install SOPS (https://github.com/getsops/sops). dependencies: [] diff --git a/roles/install/tasks/detect_source.yml b/roles/install/tasks/detect_source.yml index e31c0fa9..9e109bfd 100644 --- a/roles/install/tasks/detect_source.yml +++ b/roles/install/tasks/detect_source.yml @@ -3,14 +3,14 @@ # SPDX-License-Identifier: GPL-3.0-or-later # SPDX-FileCopyrightText: 2022, Felix Fontein -- name: Check whether system packages are a valid source of sops {{ sops_version }} +- name: Check whether system packages are a valid source of SOPS {{ sops_version }} when: - _community_sops_install_system_has_system - not (sops_version != 'latest' and _community_sops_install_system_has_system_latest_only) ansible.builtin.set_fact: _community_sops_install_effective_sops_source: system -- name: Check whether GitHub is a valid source of sops +- name: Check whether GitHub is a valid source of SOPS when: - _community_sops_install_system_has_github - _community_sops_install_effective_sops_source == 'auto' @@ -20,7 +20,7 @@ - name: Ensure that something was detected ansible.builtin.fail: msg: >- - Was not able to determine installation source for sops {{ sops_version }} + Was not able to determine installation source for SOPS {{ sops_version }} for {{ _community_sops_install_facts.distribution }} {{ _community_sops_install_facts.distribution_version }}. Please open an issue in https://github.com/ansible-collections/community.sops/issues if you think this should work. when: _community_sops_install_effective_sops_source == 'auto' diff --git a/roles/install/tasks/github.yml b/roles/install/tasks/github.yml index f5719220..1c5b6204 100644 --- a/roles/install/tasks/github.yml +++ b/roles/install/tasks/github.yml @@ -3,14 +3,14 @@ # SPDX-License-Identifier: GPL-3.0-or-later # SPDX-FileCopyrightText: 2022, Felix Fontein -- name: Make sure that sops can be installed from GitHub +- name: Make sure that SOPS can be installed from GitHub ansible.builtin.fail: msg: >- - Sops cannot be installed from GitHub for + SOPS cannot be installed from GitHub for {{ _community_sops_install_facts.distribution }} {{ _community_sops_install_facts.distribution_version }}. when: not _community_sops_install_system_has_github -- name: Start determining sops version +- name: Start determining SOPS version ansible.builtin.set_fact: _community_sops_install_effective_sops_version: '{{ "" if sops_version == "latest" else sops_version }}' @@ -37,7 +37,7 @@ - name: Show selected version ansible.builtin.debug: - msg: The latest sops version is sops {{ _community_sops_install_effective_sops_version }}. + msg: The latest SOPS version is SOPS {{ _community_sops_install_effective_sops_version }}. when: sops_version == 'latest' - name: Set variables diff --git a/roles/install/tasks/main.yml b/roles/install/tasks/main.yml index 38fffb73..775c3cf2 100644 --- a/roles/install/tasks/main.yml +++ b/roles/install/tasks/main.yml @@ -55,15 +55,15 @@ ansible.builtin.set_fact: _community_sops_install_effective_sops_source: '{{ sops_source }}' - - name: Auto-detect source to install sops from + - name: Auto-detect source to install SOPS from ansible.builtin.include_tasks: detect_source.yml when: _community_sops_install_effective_sops_source == 'auto' - - name: Install Mozilla sops from GitHub + - name: Install SOPS from GitHub ansible.builtin.include_tasks: github.yml when: _community_sops_install_effective_sops_source == 'github' - - name: Install Mozilla sops from system package repositories + - name: Install SOPS from system package repositories ansible.builtin.include_tasks: system.yml when: _community_sops_install_effective_sops_source == 'system' diff --git a/roles/install/tasks/system.yml b/roles/install/tasks/system.yml index bc82176c..ecde47ca 100644 --- a/roles/install/tasks/system.yml +++ b/roles/install/tasks/system.yml @@ -3,17 +3,17 @@ # SPDX-License-Identifier: GPL-3.0-or-later # SPDX-FileCopyrightText: 2022, Felix Fontein -- name: Make sure that sops can be installed from system packages +- name: Make sure that SOPS can be installed from system packages ansible.builtin.fail: msg: >- - Sops cannot be installed from system packages for + SOPS cannot be installed from system packages for {{ _community_sops_install_facts.distribution }} {{ _community_sops_install_facts.distribution_version }}. when: not _community_sops_install_system_has_system - name: Make sure that systems only supporting 'latest' are not told to install another version ansible.builtin.fail: msg: >- - Sops version {{ sops_version }} was requested, but we can only install latest sops from system packages. + SOPS version {{ sops_version }} was requested, but we can only install latest SOPS from system packages. when: sops_version != 'latest' and _community_sops_install_system_has_system_latest_only - name: Set variables