项目作者: ansible-collections

项目描述 :
Simple and flexible tool for managing secrets
高级语言: Python
项目地址: git://github.com/ansible-collections/community.sops.git
创建时间: 2020-06-16T08:23:48Z
项目社区:https://github.com/ansible-collections/community.sops

开源协议:GNU General Public License v3.0

下载


Community SOPS Collection

Documentation
CI
Codecov
REUSE status

The community.sops collection allows integrating CNCF SOPS (getsops/sops) in Ansible.

getsops/sops is a tool for encryption and decryption of files using secure keys (GPG, KMS, age). It can be leveraged in Ansible to provide an easy to use and flexible to manage way to manage ecrypted secrets’ files.

Please note that this collection does not support Windows targets.

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. 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 SOPS versions
main branch 3.5.0, 3.6.0, 3.6.1, 3.7.0, 3.7.3, 3.8.0, 3.8.1, 3.9.0, 3.9.1, 3.9.2, 3.9.3, 3.10.0

Code of Conduct

We follow Ansible Code of Conduct in all our interactions within this project.

If you encounter abusive behavior violating the Ansible Code of Conduct, please refer to the policy violations section of the Code of Conduct for information on how to raise a complaint.

Communication

  • Join the Ansible forum:

  • The Ansible Bullhorn newsletter: used to announce releases and important changes.

For more information about communication, see the Ansible communication guide.

Tested with Ansible

Tested with the current ansible-core 2.15, ansible-core 2.16, ansible-core 2.17, and ansible-core 2.18 releases and the current development version of ansible-core. Ansible versions before 2.15.0 are not supported.

External requirements

You will need to install the sops CLI tool manually before using plugins provided by this
collection.

Collection Documentation

Browsing the latest collection documentation will show docs for the latest version released in the Ansible package, not the latest version of the collection released on Galaxy.

Browsing the devel collection documentation shows docs for the latest version released on Galaxy.

We also separately publish latest commit collection documentation which shows docs for the latest commit in the main branch.

If you use the Ansible package and do not update collections independently, use latest. If you install or update this collection directly from Galaxy, use devel. If you are looking to contribute, use latest commit.

Included content

This collection provides:

  • a lookup plugin community.sops.sops that allows looking up a SOPS-encrypted file content;
  • a filter plugin community.sops.decrypt that allows decrypting SOPS-encrypted data;
  • a vars plugin community.sops.sops that allows loading Ansible vars from SOPS-encrypted files for hosts and groups;
  • an action plugin community.sops.load_vars that allows loading Ansible vars from a SOPS-encrypted file dynamically during a playbook or role;
  • a module community.sops.sops_encrypt which allows to encrypt data with SOPS.
  • a role community.sops.install which allows to install SOPS and GNU Privacy Guard.
  • two playbooks community.sops.install and community.sops.install_localhost which allow to install SOPS and GNU Privacy Guard.

Using this collection

Installing SOPS

To install SOPS, you can use the community.sops.install role. The role also installs GNU Privacy Guard (GPG).

Examples:

  1. tasks:
  2. # To use the sops_encrypt module on a remote host, you need to install SOPS on it:
  3. - name: Install SOPS on remote hosts
  4. ansible.builtin.include_role:
  5. name: community.sops.install
  6. vars:
  7. sops_version: 2.7.0 # per default installs the latest version
  8. # To use the lookup plugin, filter plugin, vars plugin, or the load_vars action,
  9. # you need SOPS installed on localhost:
  10. - name: Install SOPS on localhost
  11. ansible.builtin.include_role:
  12. name: community.sops.install
  13. vars:
  14. sops_install_on_localhost: true

lookup plugin

The lookup plugin can be accessed with the community.sops.sops key.

Examples:

  1. tasks:
  2. - name: Output secrets to screen (BAD IDEA!)
  3. ansible.builtin.debug:
  4. msg: "Content: {{ lookup('community.sops.sops', '/path/to/sops-encrypted-file.enc.yaml') }}"
  5. - name: Add SSH private key
  6. ansible.builtin.copy:
  7. content: "{{ lookup('community.sops.sops', user + '-id_rsa') }}"
  8. dest: /home/{{ user }}/.ssh/id_rsa
  9. owner: "{{ user }}"
  10. group: "{{ user }}"
  11. mode: 0600
  12. no_log: true # avoid content to be written to log

See Lookup Plugins for more details on lookup plugins.

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.

Example:

  1. tasks:
  2. - name: Load SOPS encrypted data
  3. ansible.builtin.set_fact:
  4. encrypted_data: "{{ lookup('file', '/path/to/sops-encrypted-file.enc.yaml') }}"
  5. - name: Output secrets to screen (BAD IDEA!)
  6. ansible.builtin.debug:
  7. msg: "Content: {{ encrypted_data | community.sops.decrypt(output_type='yaml') }}"

See Filter Plugins for more details on filters.

Please note that if you put a Jinja2 expression in a variable, it will be evaluated every time it is used. Decrypting data takes a certain amount of time. If you need to use an expression multiple times, it is better to store its evaluated form as a fact with ansible.bulitin.set_fact first:

  1. tasks:
  2. - name: Decrypt data once
  3. ansible.builtin.set_fact:
  4. decrypted_data: "{{ encrypted_data | community.sops.decrypt }}"
  5. run_once: true # if encrypted_data is identical on all hosts
  6. - name: Use decrypted secrets multiple times
  7. ansible.builtin.openssl_privatekey:
  8. path: "/path/to/private_{{ item }}.pem"
  9. passphrase: "{{ decrypted_data }}"
  10. cipher: auto
  11. loop:
  12. - foo
  13. - bar
  14. - baz

By using {{ encrypted_data | community.sops.decrypt }} instead of {{ decrypted_data }} in the openssl_privatekey task, the data would be decrypted three times for every host this is executed for. With the ansible.builtin.set_fact and run_once: true, it is evaluated only once.

vars plugin

Vars plugins only work in ansible >= 2.10 and require explicit enabling. One
way to enable the plugin is by adding the following to the defaults section of
your ansible.cfg:

  1. vars_plugins_enabled = host_group_vars,community.sops.sops

See VARIABLE_PLUGINS_ENABLED for more details.

After the plugin is enabled, correctly named group and host vars files will be
transparently decrypted with SOPS.

The files must end with one of these extensions:

  • .sops.yaml
  • .sops.yml
  • .sops.json

(These extensions can be adjusted, check out the vars plugin’s options for details.) Here is an example file structure:

  1. ├── inventory/
  2. ├── group_vars/
  3. └── all.sops.yml
  4. ├── host_vars/
  5. ├── server1.sops.yml
  6. └── server2/
  7. └── data.sops.yml
  8. └── hosts
  9. ├── playbooks/
  10. └── setup-server.yml
  11. └── ansible.cfg

You could execute the playbook in this example with the following command. The
SOPS-encrypted vars files would be decrypted and used.

  1. $ ansible-playbook playbooks/setup-server.yml -i inventory/hosts

Determine when to load variables

Ansible 2.10 allows to determine when vars plugins load the data.

To run the SOPS vars plugin right after importing inventory, you can add the following to ansible.cfg:

  1. [community.sops]
  2. vars_stage = inventory

Caching variable files

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:

  1. [community.sops]
  2. vars_cache = false

Please note that when using vars plugin staging, this setting only has effect if the variables are not only loaded during the inventory stage. See the documentation of the community.sops.sops vars plugin for more details.

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. This is a restriction imposed by ansible-core. The plugin does allow to evaluate expressions on load-time, though.

Examples:

  1. tasks:
  2. - name: Load variables from file and store them in a variable
  3. community.sops.load_vars:
  4. file: path/to/sops-encrypted-file.sops.yaml
  5. name: variable_to_store_contents_in
  6. - name: Load variables from file into global namespace, and evaluate Jinja2 expressions
  7. community.sops.load_vars:
  8. file: path/to/sops-encrypted-file-with-jinja2-expressions.sops.yaml
  9. # The following allows to use Jinja2 expressions in the encrypted file!
  10. # They are evaluated right now, i.e. not later like when loaded with include_vars.
  11. 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.

Examples:

  1. tasks:
  2. - name: Store secret text SOPS-encrypted
  3. community.sops.sops_encrypt:
  4. path: path/to/sops-encrypted-file.sops
  5. content_text: This is some secret text.
  6. - name: Store secret binary data SOPS-encrypted
  7. community.sops.sops_encrypt:
  8. path: path/to/sops-encrypted-file.sops
  9. content_binary: "{{ some_secret_binary_data | b64encode }}"
  10. - name: Store secret JSON data
  11. community.sops.sops_encrypt:
  12. path: path/to/sops-encrypted-file.sops.json
  13. content_json:
  14. key1: value1
  15. key2:
  16. - value2
  17. - key3: value3
  18. key4: value5
  19. - name: Store secret YAML data
  20. community.sops.sops_encrypt:
  21. path: path/to/sops-encrypted-file.sops.yaml
  22. content_yaml:
  23. key1: value1
  24. key2:
  25. - value2
  26. - key3: value3
  27. key4: value5

Troubleshooting

Spurious failures during encryption and decryption with gpg

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

  1. Failed to get the data key required to decrypt the SOPS file.
  2. Group 0: FAILED
  3. D13xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx: FAILED
  4. - | could not decrypt data key with PGP key:
  5. | golang.org/x/crypto/openpgp error: Reading PGP message
  6. | failed: openpgp: incorrect key; GPG binary error: exit
  7. | status 2
  8. 828xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx: FAILED
  9. - | could not decrypt data key with PGP key:
  10. | golang.org/x/crypto/openpgp error: Reading PGP message
  11. | failed: openpgp: incorrect key; GPG binary error: exit
  12. | status 2
  13. Recovery failed because no master key was able to decrypt the file. In
  14. order for SOPS to recover the file, at least one key has to be successful,
  15. but none were.

This is a limitation of gpg-agent which can be fixed by adding auto-expand-secmem to ~/.gnupg/gpg-agent.conf (reference on option, reference on config file).

(See https://github.com/ansible-collections/community.sops/issues/34 and https://dev.gnupg.org/T4146 for more details.)

Contributing to this collection

See CONTRIBUTING.md

Release notes

See CHANGELOG.md.

Releasing, Versioning and Deprecation

This collection follows Semantic Versioning. More details on versioning can be found in the Ansible docs.

We plan to regularly release new minor or bugfix versions once new features or bugfixes have been implemented.

Releasing the current major version happens from the main branch. We will create a stable-1 branch for 1.x.y versions once we start working on a 2.0.0 release, to allow backporting bugfixes and features from the 2.0.0 branch (main) to stable-1. A stable-2 branch will be created once we work on a 3.0.0 release, and so on.

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.

More information

Licensing

This collection is primarily licensed and distributed as a whole under the GNU General Public License v3.0 or later.

See LICENSES/GPL-3.0-or-later.txt for the full text.

Parts of the collection are licensed under the BSD 2-Clause license.

All files have a machine readable SDPX-License-Identifier: comment denoting its respective license(s) or an equivalent entry in an accompanying .license file. Only changelog fragments (which will not be part of a release) are covered by a blanket statement in .reuse/dep5. This conforms to the REUSE specification.