Files
kodekloud-engineer/100 - days of devops/devops-86.md

5.8 KiB

Assignment

The Nautilus DevOps team is planning to test several Ansible playbooks on different app servers in Stratos DC. Before that, some pre-requisites must be met. Essentially, the team needs to set up a password-less SSH connection between Ansible controller and Ansible managed nodes. One of the tickets is assigned to you; please complete the task as per details mentioned below:

a. Jump host is our Ansible controller, and we are going to run Ansible playbooks through thor user from jump host.

b. There is an inventory file /home/thor/ansible/inventory on jump host. Using that inventory file test Ansible ping from jump host to App Server 2, make sure ping works.

Solution

Passwordless SSH — jump host (thor) → App Server 2 (stapp02)

Set up key-based SSH from the Ansible controller to App Server 2, then confirm with an Ansible ping.

Note: this is an Ansible/SSH task, not Kubernetes — no manifests to pipe into kubectl. Heredocs are used for the files; the key-copy step is interactive by design.

Step 1 — Generate an SSH key pair for thor (if none exists)

# Check first — don't overwrite an existing key
ls -l ~/.ssh/id_rsa.pub 2>/dev/null || ssh-keygen -t rsa -b 4096 -N "" -f ~/.ssh/id_rsa
  • -N "" — empty passphrase, so SSH never prompts (that's the whole point of password-less).
  • -f ~/.ssh/id_rsa — the default location Ansible/SSH look in, so no extra config is needed.

Step 2 — Copy the public key to App Server 2

ssh-copy-id steve@stapp02

This prompts for steve's password once — that's expected and unavoidable; it's the one-time bootstrap that establishes trust. Accept the host-key fingerprint if asked (yes).

Verify the username for App Server 2 against your lab's wiki. steve follows the common Stratos DC pattern, but confirm rather than assume.

Confirm it worked — this should log in with no password prompt:

ssh steve@stapp02 hostname
exit

Step 3 — Inventory

The inventory already exists and may contain password variables. With key-based auth in place, those are no longer needed:

# Inspect what's there first
cat /home/thor/ansible/inventory
cat > /home/thor/ansible/inventory <<'EOF'
[app_servers]
stapp02 ansible_user=steve ansible_connection=ssh
EOF

Step 4 — Test the Ansible ping

cd /home/thor/ansible
ansible -i inventory stapp02 -m ping

Expected:

stapp02 | SUCCESS => {
    "ansible_facts": {...},
    "changed": false,
    "ping": "pong"
}

How it works

What "password-less" actually means

SSH supports several auth methods. Password auth requires a secret typed (or supplied via sshpass/ansible_ssh_pass) on every connection. Public-key auth instead proves identity cryptographically:

  1. ssh-keygen creates a key pair on the controller — a private key (~/.ssh/id_rsa, stays on the jump host, never shared) and a public key (~/.ssh/id_rsa.pub).
  2. ssh-copy-id appends that public key to ~/.ssh/authorized_keys on the managed node.
  3. On each later connection, the server challenges the client to prove it holds the matching private key. No password crosses the wire, and nothing needs to be typed.

That one-time password prompt in Step 2 exists because you must authenticate somehow to install the key. After that, it's never needed again.

Why the inventory drops ansible_ssh_pass

With the key installed, Ansible connects over SSH using thor's private key automatically — it's at the default path, so no ansible_ssh_private_key_file is required either. Leaving a stale ansible_ssh_pass in the inventory isn't fatal, but removing it is the point of the exercise: authentication is now key-based, and the inventory should reflect that.

What remains:

Variable Purpose
ansible_user=steve Still required — it tells Ansible which remote account to log in as. Key auth proves who you are, not whom you connect as.
ansible_connection=ssh Transport plugin; the default for remote hosts, stated explicitly.

stapp02 resolves from the jump host, so the inventory name doubles as the connection target — no ansible_host needed. Confirm with getent hosts stapp02 if unsure.

Why the ping module is the right test

ansible -m ping isn't ICMP — it opens a real SSH connection, runs a trivial Python module on the target, and returns pong. So a SUCCESS result proves the entire chain works: hostname resolution, SSH key authentication, the remote user, and Python on the managed node. That's exactly what requirement (b) asks you to demonstrate.

Host key checking

The first connection prompts to accept the host's fingerprint. Doing it manually in Step 2 (via ssh-copy-id/ssh) gets it into ~/.ssh/known_hosts before Ansible runs, which is the cleanest approach. If Ansible still trips on it, add an ansible.cfg beside the inventory:

cat > /home/thor/ansible/ansible.cfg <<'EOF'
[defaults]
host_key_checking = False
EOF

Verify

# Key exists on the controller
ls -l ~/.ssh/id_rsa ~/.ssh/id_rsa.pub

# Key installed on the target (should list thor's key)
ssh steve@stapp02 "cat ~/.ssh/authorized_keys"

# Passwordless login works
ssh steve@stapp02 hostname

# The required check
cd /home/thor/ansible && ansible -i inventory stapp02 -m ping

Expected — both key files present, thor@jump_host visible in the target's authorized_keys, SSH logging in without a prompt, and the ping returning SUCCESS with "ping": "pong".

Still prompted for a password? Permissions are the usual culprit: on the target, ~/.ssh must be 700 and ~/.ssh/authorized_keys 600 — SSH silently refuses keys on loosely-permissioned files. On the controller, ~/.ssh/id_rsa must be 600.