Introduction

Ansible Core 2.22.0 was published on 2026-11-02, succeeding 2.21.5. This is a major release that introduces automatic secret masking across display output, module logging, and callback plugin task results, along with controller Python version changes. The full changelog is available at CHANGELOG-v2.22.rst, and the porting guide covers the upgrade path in detail.

Whats New

Secret Masking

The headline feature of this release is automatic secret masking. Ansible now redacts known secret values from any output it generates, including display output (verbose, warning, deprecation, and error messages), module logging, and task results passed to callback plugins. Masking is non-destructive: the real value stays available to tasks, conditionals, and registered variables, but anything rendered to the user is replaced with $REDACTED$.

Key points about this feature:

  • A new public API, ansible.module_utils.secrets, exposes register_secret and register_secrets to manually register values for redaction, plus mask_secrets to redact registered secrets from a string. This works both on the controller and inside Python modules.
  • PowerShell modules get an equivalent via the new Ansible.Secrets C# module_util, with [Ansible.Secrets.SecretMasker]::RegisterSecret() and MaskString().
  • Secrets registered inside a module or worker process propagate back to the controller, so they are masked there too.
  • Callback plugins now always receive task results with registered secrets replaced by $REDACTED$. The ANSIBLE_SUPPORTS_MASKING callback class attribute, introduced in 2.22.0b1 for plugins that wanted unmasked results, has been removed and is now ignored.
  • The minimum and maximum secret length limits from 2.22.0b1 betas have been removed. Secrets of any length are registered and redacted wherever they appear; short secrets are no longer restricted to whole-word matches, and long secrets are matched on their full value instead of being truncated to the first 65536 characters. Surrounding whitespace is still stripped before registration, and empty-after-stripping values are ignored.
  • A new internal config option, _SECRETS_INPUT_FILES, pre-seeds values to redact from ansible, ansible-playbook, and ansible-console output. Each file is YAML or JSON with a version key (currently 1) and a secrets key listing string values to mask. If the file has the executable bit set, it is run instead of read, and its stdout is parsed as the document.

The following values are now automatically registered as secrets and redacted from masked output:

  • Vault passwords supplied by prompt, file, or script
  • The decrypted plaintext of vault-encrypted values, and every string or numeric value in a vault-encrypted vars file
  • Passwords entered for --ask-pass and --ask-become-pass
  • no_log module option values
  • The become_pass option of the sudo, su, and runas become plugins
  • The password, private_key, and private_key_passphrase options of the ssh connection plugin
  • The password option of the winrm and psrp connection plugins, and the certificate_key_password option of psrp
  • The password option of the url lookup
  • Values returned by the password and unvault lookups
  • The secret passed to the vault and unvault filters
  • User input of the pause action when echo is false
  • Values entered for a play vars_prompt when private is true (the default, unchanged)

Python Support Changes

  • Adds support for Python 3.15.
  • Drops support for Python 3.12 on the controller.

Other Minor Changes

  • A new OrderedSet class is available for situations where a unique, ordered list is needed.
  • Role and play argument spec validation now supports no_log. Variables labeled no_log are redacted from masked output (issue #84498).
  • ansible-galaxy now sorts FILES.json when building a collection, for reproducible build artifacts.

Release Artifacts

ArtifactSizeSHA256
ansible_core-2.22.0-py3-none-any.whl2488530 bytes8285d4cc81c3e3eb2d954e75531724fe0ae154d228475638123451f034a74657
ansible_core-2.22.0.tar.gz3476434 bytesbf50b4a0cfa985e30585c7ba301897ea7050d224ca49d2816cab10e33a160e1c

How to Install and Test

Ansible Core 2.22.0 requires a controller running Python 3.13 or newer, since Python 3.12 support on the controller has been dropped. Verify the Python version before upgrading, then install in a virtual environment to test alongside existing installations.

# check current Python version on the controller
python3 --version

# create an isolated virtual environment for testing
python3 -m venv ansible-2.22-test
source ansible-2.22-test/bin/activate

# install ansible-core 2.22.0 explicitly
pip install ansible-core==2.22.0

# verify the installed version
ansible --version

# optionally verify the downloaded wheel checksum
sha256sum ansible_core-2.22.0-py3-none-any.whl

# run a quick playbook to confirm secret masking behavior
ansible-playbook -i localhost, -c local test-secrets.yml --ask-vault-pass

When testing, pay particular attention to any custom callback plugins. Plugins relying on ANSIBLE_SUPPORTS_MASKING to receive unmasked results will now always get masked output, since that attribute has been removed and is ignored in 2.22.0. Review _SECRETS_INPUT_FILES if pre-seeding additional secrets for redaction is needed, and consult the porting guide for the complete list of breaking changes before rolling this out to production control nodes.