docs: add 100 Days of DevOps challenge notes
This commit is contained in:
158
100 - days of devops/devops-86.md
Normal file
158
100 - days of devops/devops-86.md
Normal file
@@ -0,0 +1,158 @@
|
||||
# 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`.
|
||||
Reference in New Issue
Block a user