Hi,
I’ve been looking at adding support for Kerberos for deployments to Windows hosts in Ansible/Ansible Tower.
There are 2 open PR on the subject:
-
#8345: Suppport for kerberos\domain authentication for winrm
- #8914: Add support for using windows domain or active directory users for WinRM connections
The first one suggested that we support kerberos authentication by changing the ansible_ssh_user to “ansible_kerberos”. Ansible would then use the current default kerberos principal set by a previous call to kinit.
As pointed in the PR discussion, there is actually a need for non-default kerberos credentials; ie you might want to run a playbook with some tasks for server A as user alice@ad.domain.com and server B as bob@as.domain.com
To cater for that ianclegg suggested we use the following convention:
Kerberos single sign on
ansible_ssh_user: <not specified>
ansible_ssh_pass: <not specified>
K****erberos with a specific user (UPN)
ansible_ssh_user: user@realm
ansible_ssh_pass:
Kerberos with a specific username password
ansible_ssh_user: user@realm
ansible_ssh_pass: password
I think we should support all 3 cases, and this suggestion seems reasonable.
Unfortunately this PR went a bit quiet, and nothing happened in the last few weeks. In particular no suggestion was made as to how to implement this.
#8914 was then submitted and suggested to have Ansible itself call kinit to ensure the provided credentials could be used in the Kerberos authentication.
One thing I really like about it is that it also adds an “ansible_authorization_type” variable, which explicitly specifies the required authentication mechanism, which I think is clearer than simply rely on the username to decide whether to use Kerberos. As an added bonus it would allow 2 other ways to indicate a user on the default domain:
Kerberos with a specific user on the default domain
ansible_ssh_user: user
ansible_ssh_pass:
ansible_authorization_type: kerberos
Kerberos with a specific username/password on the default domain
ansible_ssh_user: user
ansible_ssh_pass: password
ansible_authorization_type: kerberos
Regarding the call to kinit, I took a different approach and updated pywinrm to support username and password (which are currently ignored if you’re using Kerberos with it).
My ansible repository is https://github.com/nicodeslandes/ansible, and the changes to pywinrm are available there: https://github.com/nicodeslandes/pywinrm/commits/alt_credentials
These changes unfortunately also required some changes to the underlying pykerberos library, so that it would accept a password. That change is here: https://github.com/nicodeslandes/pykerberos/commits/kerberos_passwords_spike.
With these changes, there’s no need to call kinit. pywinrm/pykerberos take care of requesting a TGT for the username/password provided.
This was necessary for me for 2 reasons:
- In the project I’m working on we plan to use Ansible Tower to automate Ansible deployment. So we cannot call kinit ahead of a deployement
- For some reason the kerberos usernames in my client’s production environment start with a hyphen; so kinit doesnt’ work there, as it takes the username for an option (!).
I also added an option to allow the delegation of the user’s credentials on the remote server. Useful if for instance you need to access a network share from the Windows server you’re accessing.
Now both the proposed solution in #8914 and the one I implemented in pywinrm/pykerberos have a big security problem in my scenario (using Tower):
If user A provides a password for a Kerberos principal, the TGT for this principal gets added to the credential cache of whichever user executes ansible (‘awx’ in that case).
That means that user B may then start a deployment for the same kerberos principal without having to provide a password, and still have access to a TGT for it from the credential cache.
I haven’t found a solution to this issue yet, but we would need a sort of transient credential cache that would only be used for a specific Ansible playbook run.
I should also mention a comment from AdmiralNemo in the GitHub discussion for #8914, that is very relevant to this discussion:
Also, pywinrm may end up having native support for requesting the tgt given a principal and password[1], so having Ansible call kinit directly would not be necessary in that case.
What do people think?
Does this seem like a good way to add support for domain authentication in Ansible?
Does anyone have any idea how to tackle the security issue with cached credentials?
Thanks,
Nico