Solved: ansible-lint on macOS “FATAL: Ansible CLI and python module versions do not match.”

My Problem

While attempting to run ansible-lint on macOS, I received the error:

FATAL: Ansible CLI (2.10.8) and python module (2.11.5) versions do not match. This indicates a broken execution environment.

My Solution

I ran the following destructive command, but before you even think about running it yourself, please familiarize yourself with what it will do:

brew link --overwrite ansible

The Long Story

While attempting to lint some Ansible .yml files, I realized that the specific macOS machine I was on didn’t have ansible-lint. I begrudgingly use Homebrew on it to manage packages formulae. I ran brew install ansible-lint in a hurry, and attempted to immediately use it. I then received this error:

FATAL: Ansible CLI (2.10.8) and python module (2.11.5) versions do not match. This indicates a broken execution environment.

My first thought was to check if the ansible command corroborated that it was indeed 2.10.8 and it did:

ansible --version
ansible 2.10.8
config file = None
configured module search path = ['/Users/username/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/lib/python3.9/site-packages/ansible
executable location = /usr/local/bin/ansible
python version = 3.9.7 (default, Sep 3 2021, 12:37:55) [Clang 12.0.5 (clang-1205.0.22.9)]

Then, I checked pip list and saw:

ansible-base 2.10.8

I even checked the file:

grep __version__ /usr/local/lib/python3.9/site-packages/ansible/ __version__ = '2.10.8'

Clearly there’s a different version of Ansible somewhere, so I brute-forced the situation by searching for every file named that was in a path with the word ansible in it:

mdfind "kMDItemDisplayName == ''c"


Hold up. There appears to be two Ansibles installed. One is in the standard filesystem paths, and another is in Homebrew’s Cellar path. Let’s check the Homebrew version:

grep __version__ /usr/local/Cellar/ansible/4.6.0/libexec/lib/python3.9/site-packages/ansible/
__version__ = '2.11.5'

Because I used Homebrew to install ansible-lint, it also installed ansible in Homebrew’s path. In the past, I had installed Ansible using pip which installed binaries in standard OS paths.

If I had paid attention when I was installing ansible-lint I would have noticed this very informative error:

==> Pouring ansible--4.6.0.big_sur.bottle.tar.gz
Error: The brew link step did not complete successfully
The formula built, but is not symlinked into /usr/local
Could not symlink bin/ansible
Target /usr/local/bin/ansible
already exists. You may want to remove it:
rm '/usr/local/bin/ansible'

To force the link and overwrite all conflicting files:
brew link --overwrite ansible

To list all files that would be deleted:
brew link --overwrite --dry-run ansible

Possible conflicting files are:

When considering the situation, I realized that I’d rather be managing all of Ansible’s binaries in Homebrew, so I was comfortable with running brew link --overwrite ansible. The problem was solved, and I could continue on until the next problem.

Solving ‘UseKeychain’ Not Working for Password Protected SSH Key Logins on macOS

My Problem

Using macOS 10.15, attempting to automatically load a password protected SSH key into ssh-agent by using the SSH configuration option UseKeychain was not working. I had the SSH key’s password stored in the macOS Keychain, and if I manually ran ssh-add -K /path/to/private/key it would load the key without asking me to input a password, proving that they key’s password did exist in the keychain. However, when attempting to SSH to a host that required that private key, I was still being asked for the password to the private key. This is in direct opposition to the intended behavior of using UseKeychain in one’s SSH config file.

I did not want to put ssh-add -A or some variant of ssh-add in my .bashrc file, even though that would have “solved” the problem. The version of OpenSSH that macOS uses has a configuration option provided for just such a desire, and that option is UseKeychain.

My Solution

Of course, first make sure that your SSH config file includes the following:

  UseKeychain yes
  AddKeysToAgent yes

Then, when adding the key to Keychain with ssh-add -K, use the full filesystem path to the key file, not a relative path.

For example, do not use ssh-add -K ~/.ssh/private.key, rather you should use ssh-add -K /Users/username/.ssh/private.key. You may also want to remove all relative pathed entries to the same SSH key from Keychain:

The Long Story

Let’s sort out some terms and get a few things straight. If you’re going to use SSH with public / private keypairs, you have the option of password protecting the private key in the pair. This means that you cannot decrypt the private key to then authenticate your identity to other systems without being in possession of the password. Without a password on the private key, mere possession of the file is good enough to prove your identity, which isn’t really comfortably secure. Any person or software that has access to your filesystem could theoretically snatch that file and masquerade as you. A password protected private key is a type of two-factor authentication. You must have possession of the file and knowledge of the password.

This is great, except if you perform tasks that require the repetitive use of the private key. Such as shelling into a remote system (Ansible, anyone?) or using git. Just an hour or two of using git pull, git push, or git fetch will wear out your keyboard and have you reconsidering your career.

This is where ssh-agent comes in, which keeps track of your private SSH key identities and their passwords. You’d then use ssh-add to stick the identities into ssh-agent. A fuller discussion of these tools is beyond the scope of this post, but suffice it to say that in theory this should reduce your need for typing SSH key passwords to an absolute minimum per reboot.

Apple’s Keychain can store SSH key passwords securely, and Apple’s version of OpenSSH includes an option that you can include in your config file named UseKeychain. This will further reduce your need for typing passwords, even across reboots. It’s possible to virtually never need to type your SSH key’s password again. Except when it doesn’t work.

Some people, myself included, have had an issue where no amount of UseKeychain under any Host * or Host hostname heading in one’s SSH config file would seem to work. After a reboot, ssh-add -l shows now known identities, which is expected. However, ssh user@host should trigger UseKeychain to find the proper key file’s password in keychain and simply allow one to log in to the remote system without providing the local private key’s password. After the first access to a host that needs your private key identity, ssh-add -l should show that the identity is now loaded even though you didn’t type the password.

Opening up the “Keychain Access” application on macOS and then searching for any login with the word ssh in it may reveal that the SSH key identities that are known are all referred to with relative paths. It’s common to see ~/.ssh/private.key or even ../.ssh/private.key depending on where you were in your filesystem when you realized you needed to add the key to Keychain. For some people, this appears to work. Not for me (and others) however.

You may want to try first adding your key with ssh-add -K using the full filesystem path to the key. Then you may want to remove any other references to the key file in Keychain Access that use relative paths.