How to apply Signed SSH Certificates to ansible?

Hello,

I follow this guide about Signed SSH Certificates.
I can use SSH CA key signed with private key to SSH server. But I’m stucking when apply this to ansible.

ssh -o StrictHostKeyChecking=no -i cicd-signed-key.pub -i privatekey username@servername “hostname” => It’s Ok.
but how to I config in ansible to get both the SSH CA key signed and private key?
I can’t do it or find anything documents/guides.

Please help me.
Thank you.

You could have the Ansible process generate a private/public key pair before getting the public key signed by Vault.

Alternatively you could store the private and public keys in Vault’s KV and retrieve them before signing the public key and when complete attempt to SSH to the destination.

There may be other options as well, but I’ve seen both of these work in similar situations.

No no, I got it.
But I want to use this key to deploy to other server.

You followed Step 3 in the Signing Key & Role Configuration? This would be applied on your target host.

According to https://man.openbsd.org/ssh :

If no certificates have been explicitly specified by the CertificateFile directive, ssh will also try to load certificate information from the filename obtained by appending -cert.pub to identity filenames.

So you should ensure your signed certificate is saved to such a file name, so that when Ansible runs SSH, it is found using this logic.

Hi,

This is how i do it:

Generate the key:

We will append the username to the keys for better managability.

ssh-keygen -o -a 100 -t ed25519 -C “tsiamer@allttech.uk” -f $HOME/.ssh/$USER-linux.key -q -N “” 0>&-

This will translate to this:

ssh-keygen -o -a 100 -t ed25519 -C “tsiamer@allttech.uk” -f /home/tsiamer/.ssh/tsiamer-linux.key -q -N “” 0>&-

It will generate the files as so:

tsiamer-linux.key
tsiamer-linux.key.pub

Sign the keys:

vault write -field=signed_key ssh-client-signer/sign/tsiamer public_key=@$HOME/.ssh/$USER-linux.key.pub valid_principals=tsiamer > $HOME/.ssh/$USER-signed-key.pub

tsiamer-linux.key.pub
tsiamer-signed-key.pub

Or like so:

vault write -field=signed_key ssh-client-signer/sign/tsiamer public_key=@$HOME/.ssh/tsiamer-linux.key.pub valid_principals=tsiamer > /home/tsiamer/.ssh/ivo-signed-key.pub

Now to integrate with ansible,

In the inventory file we use the below, in production “real life” we have many sysadmins with different usernames, how to achieve that with ansible we could use this but:

[MDCDomainControllers:vars]
ansible_ssh_user=tsiamer
ansible_ssh_private_key_file=/home/tsiamer/.ssh/tsiamer-signed-key.pub
group_name=k8snodes

Unfortunatly not everyone “initial surname” is tsiamer, and ansible will not work as we have to append vault ssh pvt key.

So the way we would achieve this:

[MDCDomainControllers:vars]
ansible_user= “{{ lookup(‘env’, ‘USER’) }}”
ansible_ssh_private_key_file= “{{ lookup(‘env’, ‘HOME’) }}/.ssh/{{ lookup(‘env’, ‘USER’) }}-linux.key”
ansible_ssh_extra_args= " -i {{ lookup(‘env’, ‘HOME’) }}/.ssh/{{ lookup(‘env’, ‘USER’) }}-signed-key.pub"

So now we could enumerate any logged user "ansible_user= “{{ lookup(‘env’, ‘USER’) }}”, 2nd line to get the private key, 3rd line - important we append this ansible_ssh_extra_args= " -i and lookup the signed public key for the current user.

now running:

ansible-playbook blabla.yml

Above will work for any logged user as long as he/she are authorised and have cert signed by Vault.

Then depending on your environment, if you want implement the same for all inventory groups.

To summarise only add this to the inventory or whatever suits you.

[MDCDomainControllers:vars]
ansible_user= “{{ lookup(‘env’, ‘USER’) }}”
ansible_ssh_private_key_file= “{{ lookup(‘env’, ‘HOME’) }}/.ssh/{{ lookup(‘env’, ‘USER’) }}-linux.key”
ansible_ssh_extra_args= " -i {{ lookup(‘env’, ‘HOME’) }}/.ssh/{{ lookup(‘env’, ‘USER’) }}-signed-key.pub"

Hope this help,

Regards

Siamert

1 Like

A really simple and elegant way is to generate an ssh keypair with each ansible run with the intention of disposing of the public and private key. You are signing the public key with another identity anyway so there’s no need to store or manage ssh keypairs anywhere.

Once the public key is signed, make sure to load them into memory with ssh-add.

At this point Ansible will just work with ssh without any extra fuss.