* Start of migration to argparse
* various fixes and improvements
* Linting fixes
* Test fixes
* Fix vault_password_files
* Add PrependAction for argparse
* A bunch of additional tweak/fixes
* Fix ansible-config tests
* Fix man page generation
* linting fix
* More adhoc pattern fixes
* Add changelog fragment
* Add support for argcomplete
* Enable argcomplete global completion
* Rename PrependAction to PrependListAction to better describe what it does
* Add documentation for installing and configuring argcomplete
* Address rebase issues
* Fix display encoding for vault
* Fix line length
* Address rebase issues
* Handle rebase issues
* Use mutually exclusive group instead of handling manually
* Fix rebase issues
* Address rebase issue
* Update version added for argcomplete support
* -e must be given a value
* ci_complete
* Remove misleading statement passwords must be same
Since 2.4 Ansible has supported multiple vault passwords:
<https://docs.ansible.com/ansible/latest/user_guide/vault.html#multiple-vault-passwords>
Meaning lines like the following are misleading:
> The password used with vault currently must be the same for all files you wish
> to use together at the same time.
-- `docs/docsite/rst/user_guide/vault.rst`
To demonstrate this with Ansible 2.7, save the following as `example.yaml`:
```
- name: Display output from two vaults with different passwords
hosts: localhost
connection: local
vars_files: [one.yaml, two.yaml]
tasks:
- name: View secret from one.yaml vault
debug: { var: one }
- name: View secret from two.yaml vault
debug: { var: two }
```
Then run the three following commands choosing two different passwords:
```
$ echo 'one: 1' | ansible-vault encrypt --vault-id id1@prompt --output=one.yaml
$ echo 'two: 2' | ansible-vault encrypt --vault-id id2@prompt --output=two.yaml
$ ansible-playbook --vault-id id1@prompt --vault-id id2@prompt example.yaml
```
`ansible-vault` stores an ID in plain text in the vault file.
* Remove note about default in Ansible 2.1
As requested by gundalow in https://github.com/ansible/ansible/pull/49798
* Note: Python2 is not as intelligent at detecting false import loops as
Python3. context_objects.py cannot be added to cli/arguments because it
would set up an import loop between cli/__init__.py,
cli/arguments/context_objects.py, and context.py on Python2.
ci_complete
* Mark methods which are really functions as staticmethod
* Fix calls to other staticmethods to use the subclass rather than the
base class so that any inheritance overriding will be honored.
* Remove unnecessary logic and dead code
* Fix a typo in a docstring of how to implement subclass init_parser()
methods
* Call superclass's post_process_args in ansible-doc
* Fix copyright comment according to suggested practice
The goal of breaking apart the base_parser() function is to get rid of
a bunch of conditionals and parameters in the code and, instead, make
code look like simple composition.
When splitting, a choice had to be made as to whether this would operate
by side effect (modifying a passed in parser) or side effect-free
(returning a new parser everytime).
Making a version that's side-effect-free appears to be fighting with the
optparse API (it wants to work by creating a parser object, configuring
the object, and then parsing the arguments with it) so instead, make it
clear that our helper functions are modifying the passed in parser by
(1) not returning the parser and (2) changing the function names to be
more clear that it is operating by side-effect.
Also move all of the generic optparse code, along with the argument
context classes, into a new subdirectory.
* Once cli args are parsed, they're constant. So, save the parsed args
into the global context for everyone else to use them from now on.
* Port cli scripts to use the CLIARGS in the context
* Refactor call to parse cli args into the run() method
* Fix unittests for changes to the internals of CLI arg parsing
* Port callback plugins to use context.CLIARGS
* Got rid of the private self._options attribute
* Use context.CLIARGS in the individual callback plugins instead.
* Also output positional arguments in default and unixy plugins
* Code has been simplified since we're now dealing with a dict rather
than Optparse.Value
* Fix 'New Vault password' on vault 'edit'
ffe0ddea96 introduce a
change on 'ansible-vault edit' that tried to check
for --encrypt-vault-id in that mode. But '--encrypt-vault-id'
is not intended for 'edit' since the 'edit' should always
reuse the vault secret that was used to decrypt the text.
Change cli to not check for --encrypt-vault-id on 'edit'.
VaultLib.decrypt_and_get_vault_id() was change to return
the vault secret used to decrypt (in addition to vault_id
and the plaintext).
VaultEditor.edit_file() will now use 'vault_secret_used'
as returned from decrypt_and_get_vault_id() so that
an edited file always gets reencrypted with the same
secret, regardless of any vault id configuration or
cli options.
Fixes#35834
Enforce that there can be only one --new-vault-id or
--new-vault-password-file and use this instead of
--encrypt-vault-id
* Add a config option for default vault encrypt id
`ansible-vault` is the only cli command which knows how to handle the
rekey options `--new-vault-id` and `--new-vault-password-file`. No
point in exposing those rekey options to any of the other ansible
commands.
On a practical level I think this matters most in ensuring that
`--help` doesn't produce any false/unhelpful output.
This is to catch vault secrets from config and
cli. Previously vault_password_file in config was
missed since it was added by setup_vault_secrets,
so check after setup_vault_secrets.
* Don't ask for password confirm on 'ansible-vault edit'
This is to match the 2.3 behavior on:
ansible-vault edit encrypted_file.yml
Previously, the above command would consider that a 'new password'
scenario and prompt accordingly, ie:
$ ansible-vault edit encrypted_file.yml
New Password:
Confirm New Password:
The bug was cause by 'create_new_password' being used for
'edit' action. This also causes the previous implicit 'auto prompt'
to get triggered and prompt the user.
Fix is to make auto prompt explicit in the calling code to handle
the 'edit' case where we want to auto prompt but we do not want
to request a password confirm.
Fixes#30491
* module and vault fixes
- fix module_path cli option and usage, which fixes#29653
- move --output to be in subset of vault cli, no need for all vault enabled cli to use it
- added debug to loader to see directories added
* Add config option for a default list of vault-ids
This is the vault-id equilivent of ANSIBLE_DEFAULT_PASSWORD_FILE
except ANSIBLE_DEFAULT_VAULT_IDENTITY_LIST is a list.
* rm unneeded parens following assert
* rm unused parse_vaulttext_envelope from yaml.constructor
* No longer need index/enumerate over vault_ids
* rm unnecessary else
* rm unused VaultCli.secrets
* rm unused vault_id arg on VaultAES.decrypt()
pylint: Unused argument 'vault_id'
pylint: Unused parse_vaulttext_envelope imported from ansible.parsing.vault
pylint: Unused variable 'index'
pylint: Unnecessary parens after 'assert' keyword
pylint: Unnecessary "else" after "return" (no-else-return)
pylint: Attribute 'editor' defined outside __init__
* use 'dummy' for unused variables instead of _
Based on pylint unused variable warnings.
Existing code use '_' for this, but that is old
and busted. The hot new thing is 'dummy'. It
is so fetch.
Except for where we get warnings for reusing
the 'dummy' var name inside of a list comprehension.
* Add super().__init__ call to PromptVaultSecret.__init__
pylint: __init__ method from base class 'VaultSecret' is not called (super-init-not-called)
* Make FileVaultSecret.read_file reg method again
The base class read_file() doesnt need self but
the sub classes do.
Rm now unneeded loader arg to read_file()
* Fix err msg string literal that had no effect
pylint: String statement has no effect
The indent on the continuation of the msg_format was wrong
so the second half was dropped.
There was also no need to join() filename (copy/paste from
original with a command list I assume...)
* Use local cipher_name in VaultEditor.edit_file not instance
pylint: Unused variable 'cipher_name'
pylint: Unused variable 'b_ciphertext'
Use the local cipher_name returned from parse_vaulttext_envelope()
instead of the instance self.cipher_name var.
Since there is only one valid cipher_name either way, it was
equilivent, but it will not be with more valid cipher_names
* Rm unused b_salt arg on VaultAES256._encrypt*
pylint: Unused argument 'b_salt'
Previously the methods computed the keys and iv themselves
so needed to be passed in the salt, but now the key/iv
are built before and passed in so b_salt arg is not used
anymore.
* rm redundant import of call from subprocess
pylint: Imports from package subprocess are not grouped
use via subprocess module now instead of direct
import.
* self._bytes is set in super init now, rm dup
* Make FileVaultSecret.read_file() -> _read_file()
_read_file() is details of the implementation of
load(), so now 'private'.
Fixes#13243
** Add --vault-id to name/identify multiple vault passwords
Use --vault-id to indicate id and path/type
--vault-id=prompt # prompt for default vault id password
--vault-id=myorg@prompt # prompt for a vault_id named 'myorg'
--vault-id=a_password_file # load ./a_password_file for default id
--vault-id=myorg@a_password_file # load file for 'myorg' vault id
vault_id's are created implicitly for existing --vault-password-file
and --ask-vault-pass options.
Vault ids are just for UX purposes and bookkeeping. Only the vault
payload and the password bytestring is needed to decrypt a
vault blob.
Replace passing password around everywhere with
a VaultSecrets object.
If we specify a vault_id, mention that in password prompts
Specifying multiple -vault-password-files will
now try each until one works
** Rev vault format in a backwards compatible way
The 1.2 vault format adds the vault_id to the header line
of the vault text. This is backwards compatible with older
versions of ansible. Old versions will just ignore it and
treat it as the default (and only) vault id.
Note: only 2.4+ supports multiple vault passwords, so while
earlier ansible versions can read the vault-1.2 format, it
does not make them magically support multiple vault passwords.
use 1.1 format for 'default' vault_id
Vaulted items that need to include a vault_id will be
written in 1.2 format.
If we set a new DEFAULT_VAULT_IDENTITY, then the default will
use version 1.2
vault will only use a vault_id if one is specified. So if none
is specified and C.DEFAULT_VAULT_IDENTITY is 'default'
we use the old format.
** Changes/refactors needed to implement multiple vault passwords
raise exceptions on decrypt fail, check vault id early
split out parsing the vault plaintext envelope (with the
sha/original plaintext) to _split_plaintext_envelope()
some cli fixups for specifying multiple paths in
the unfrack_paths optparse callback
fix py3 dict.keys() 'dict_keys object is not indexable' error
pluralize cli.options.vault_password_file -> vault_password_files
pluralize cli.options.new_vault_password_file -> new_vault_password_files
pluralize cli.options.vault_id -> cli.options.vault_ids
** Add a config option (vault_id_match) to force vault id matching.
With 'vault_id_match=True' and an ansible
vault that provides a vault_id, then decryption will require
that a matching vault_id is required. (via
--vault-id=my_vault_id@password_file, for ex).
In other words, if the config option is true, then only
the vault secrets with matching vault ids are candidates for
decrypting a vault. If option is false (the default), then
all of the provided vault secrets will be selected.
If a user doesn't want all vault secrets to be tried to
decrypt any vault content, they can enable this option.
Note: The vault id used for the match is not encrypted or
cryptographically signed. It is just a label/id/nickname used
for referencing a specific vault secret.
* Retain vault password as bytes in 2.2
Prior to 2.2.1, the vault password was read in as byes and then remained
bytes all the way through the code. A bug existed where bytes and text
were mixed, leading to a traceback with non-ascii passwords. In devel,
this was fixed by changing the read in password to text type to match
with our overall strategy of converting at the borders. This was
backported to stable-2.2 for the 2.2.1 release.
On reflection, this should not have been backported as it causes
passwords which were originally non-utf-8 to become utf-8. People will
then have their working 2.2.x vault files become in-accessible.
this commit pipes bytes all the way through the system for vault
password. That way if a password is read in as a non-utf-8 character
sequence, it will continue to work in 2.2.2+. This change is only for
the 2.2 branch, not for 2.3 and beyond.
Why not everywhere? The reason is that non-utf-8 passwords will cause
problems when vault files are shared between systems or users. If the
password is read from the prompt and one user/machine has a latin1
encoded locale while a second one has utf-8, the non-ascii password
typed in won't match between machines. Deal with this by making sure
that when we encrypt the data, we always use valid utf-8.
Fixes#20398
(cherry picked from commit 5dcce0666a81917c68b76286685642fd72d84327)
'encrypt_string' only options were being referenced when using
other vault subcommands. That code is moved inside a check
for 'encrypt_string' action now.
* Add a vault 'encrypt_string' command.
The command will encrypt the string on the command
line and print out the yaml block that can be included
in a playbook.
To be prompted for a string to encrypt:
ansible-vault encrypt_string --prompt
To specify a string on the command line:
ansible-vault encrypt_string "some string to encrypt"
To read a string from stdin to encrypt:
echo "the plaintext to encrypt" | ansible-vault encrypt_string
If a --name or --stdin-name is provided, the output will include that name in yaml key value format:
$ ansible-vault encrypt_string "42" --name "the_answer"
the_answer: !vault-encrypted |
$ANSIBLE_VAULT;1.1;AES256
<vault cipher text here>
plaintext provided via prompt, cli, and/or stdin can be mixed:
$ ansible-vault encrypt_string "42" --name "the_answer" --prompt
Vault password:
Variable name (enter for no name): some_variable
String to encrypt: microfiber
# The encrypted version of variable ("some_variable", the string #1 from the interactive prompt).
some_variable: !vault-encrypted |
$ANSIBLE_VAULT;1.1;AES256
< vault cipher text here>
# The encrypted version of variable ("the_answer", the string #2 from the command line args).
the_answer: !vault-encrypted |
$ANSIBLE_VAULT;1.1;AES256
< vault cipher text here>
Encryption successful
* add stdin and prompting to vault 'encrypt_string'
* add a --name to encrypt_string to optional specify a var name
* prompt for a var name to use with --prompt
* add a --stdin-name for the var name for value read from stdin
if ANSIBLE_VAULT_PASSWORD_FILE is set, 'ansible-vault rekey myvault.yml'
will fail to prompt for the new vault password file, and will use
None.
Fix is to split out 'ask_vault_passwords' into 'ask_vault_passwords'
and 'ask_new_vault_passwords' to make the logic simpler. And then
make sure new_vault_pass is always set for 'rekey', and if not, then
call ask_new_vault_passwords() to set it.
ask_vault_passwords() would return values for vault_pass and new
vault_pass, and vault cli previously would not prompt for new_vault_pass
if there was a vault_pass set via a vault password file.
Fixes#18247
Implement tag and skip_tag handling in the CLI() class. Change tag and
skip_tag command line options to be accepted multiple times on the CLI
and add them together rather than overwrite.
* Make it configurable whether to merge or overwrite multiple --tags arguments
* Make the base CLI class an abstractbaseclass so we can implement
functionality in parse() but still make subclasses implement it.
* Deprecate the overwrite feature of --tags with a message that the
default will change in 2.4 and go away in 2.5.
* Add documentation for merge_multiple_cli_flags
* Fix galaxy search so its tags argument does not conflict with generic tags
* Unit tests and more integration tests for tags
We couldn't copy to_unicode, to_bytes, to_str into module_utils because
of licensing. So once created it we had two sets of functions that did
the same things but had different implementations. To remedy that, this
change removes the ansible.utils.unicode versions of those functions.
The module docs and vault changes solve issues where tracebacks can
happen. The galaxy changes are mostly refactoring to be more pythonic
with a small chance that a unicode traceback could have occurred there
without the changes. The change in __init__.py when we actually call
the pager makes things more robust but could hide places where we had
bytes coming in already so I didn't want to change that without auditing
where the text was coming from.
Fixes#14178
CLI already provides a pager() method that feeds $PAGER on stdin, so we
just feed that the plaintext from the vault file. We can also eliminate
the redundant and now-unused shell_pager_command method in VaultEditor.