DrLime2k10
DrLime2k10

Reputation: 272

Ansible GCP VM with Application Default Credentials

I've created a VM in GCP with some OpenTofu and now I'd like to manage it with Ansible.

I'd like to use "Application Default Credentials" so I can avoid making extraneous service accounts. It should be supported in the gcp_compute-plugin. but I'm getting the following error and I don't know how to troubleshoot further:

$ ansible -i gcp_compute.gcp.yml vm-xyz -m ping
...
vm-xyz | UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: ubuntu@<external-ip>: Permission denied (publickey).",
    "unreachable": true
}

I authenticate using,

$ gcloud auth application-default login

And have configured:

# ansible.cfg
[inventory]
enable_plugins = gcp_compute
# gcp_compute.gcp.yml

plugin: gcp_compute
projects:
  - myproject
auth_kind: application
hostnames:
  - name
compose:
  ansible_host: networkInterfaces[0].accessConfigs[0].natIP

Similar to the example in: https://docs.ansible.com/ansible/latest/collections/google/cloud/gcp_compute_instance_module.html


I tested enabling OS Logins, but that didn't do anything other than infer my username when I regularly SSH'd to the machine using gcloud compute ssh ...


I can successfully run

$ ansible -i gcp_compute.gcp.yml --list-hosts all
...
  hosts (1):
    vm-zyx

And I also successfully get a tsunami of information from:

$ ansible-inventory --list -i gcp_compute.gcp.yml

So I know that I'm properly authenticated.


It's probably trivial to use a ServiceAccount, that's not the question I'm asking about.

I'm specifically asking, how do I use auth_kind: application to SSH to a VM running in GCP, with Ansible.

I've looked in the docs, I've looked on Google, there are no references to using "auth_kind: application" other than the docs saying that "it's supported" .. and It ~works. I can print the inventory. I just can't access or configure anything.

Everyone uses service accounts, even for just running stuff from their own machines, because I guess, it works..

This blogpost is doing wild things with SSH Wrappers, for IAP SSH access on internal IPs: https://medium.com/google-cloud/gaining-secure-access-to-bastion-hosts-from-ansible-using-iap-7c92e7ebf4da

This blogpost has "auth_kind: application" (YES!) .. but is otherwise absolutely sparse on information about how to get it to work.. https://alexdutton.co.uk/blog/authenticating-to-google-cloud-as-oneself-within-ansible/


My current workaround is to use gcloud compute ssh to exchange an SSH key with the VM like so:

$ gcloud compute ssh \
  --ssh-key-expire-after=1h \
  --project=myproject \
  --zone=myzone \
  username@vm-xyz

And then use the key/username in my ansible.cfg:

# ansible.cfg
[inventory]
private_key_file = "/home/<user>/.ssh/google_compute_engine"
user = "<username>"

And manully register the host, (no gcp_compute-plugin)

# hosts.yml
all:
  hosts:
    vm-xyz:
      ansible_host: <external-ip>
$ ansible -i hosts.yml vm-xyz -m ping
vm-xyz | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3.10"
    },
    "changed": false,
    "ping": "pong"
}

.. and honestly, that works. It's just.. The other thing was also supposed to just work.

Upvotes: 0

Views: 33

Answers (1)

Monkey.D Amith
Monkey.D Amith

Reputation: 47

Your authentication using Application Default Credentials (ADC) is working for inventory fetching, but SSH access fails because ADC doesn't automatically provide SSH credentials. Here's what's happening and how you can fix it:


Why is SSH failing?

  1. ADC does not manage SSH keys

    • gcloud auth application-default login only grants access to GCP APIs but does not automatically add SSH keys to your instances.
    • gcloud compute ssh does manage SSH keys by automatically adding them to the VM metadata before connecting.
  2. Ansible requires an SSH key to authenticate

    • The gcp_compute plugin retrieves instance details but doesn't configure SSH access.
    • You need an SSH key that the VM recognizes.

Solution: Automatically Inject SSH Keys

Since you don't want to use a service account, the best way is to configure OS Login or manually inject SSH keys.

Option 1: Use OS Login (Recommended)

OS Login lets GCP manage SSH access using IAM roles.

  1. Enable OS Login on your VM:

    gcloud compute instances add-metadata vm-xyz --metadata enable-oslogin=TRUE
    
  2. Ensure your user has the necessary IAM roles:

    gcloud projects add-iam-policy-binding myproject \
        --member=user:<your-email>@gmail.com \
        --role=roles/compute.osLogin
    gcloud projects add-iam-policy-binding myproject \
        --member=user:<your-email>@gmail.com \
        --role=roles/compute.osAdminLogin
    
  3. Now, your Google account email becomes the SSH username, and Ansible should connect using:

    [defaults]
    remote_user=<your-email>@gmail.com
    private_key_file=~/.ssh/google_compute_engine
    

Option 2: Manually Inject SSH Keys (Alternative)

If OS Login is not an option, manually inject your SSH key using:

gcloud compute instances add-metadata vm-xyz \
    --metadata ssh-keys="$(whoami):$(cat ~/.ssh/google_compute_engine.pub)"

This allows Ansible to SSH in using:

[defaults]
remote_user=$(whoami)
private_key_file=~/.ssh/google_compute_engine

Final Verification

After setting up OS Login or injecting keys:

ansible -i gcp_compute.gcp.yml vm-xyz -m ping

If OS Login is enabled, it should work with auth_kind: application.

Upvotes: -2

Related Questions