Files

158 lines
5.8 KiB
Markdown

# 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)
```bash
# 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
```bash
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**:
```bash
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:
```bash
# Inspect what's there first
cat /home/thor/ansible/inventory
```
```bash
cat > /home/thor/ansible/inventory <<'EOF'
[app_servers]
stapp02 ansible_user=steve ansible_connection=ssh
EOF
```
## Step 4 — Test the Ansible ping
```bash
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:
```bash
cat > /home/thor/ansible/ansible.cfg <<'EOF'
[defaults]
host_key_checking = False
EOF
```
## Verify
```bash
# 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`.