1Password Authentication — Home Lab
1Password is the single source of truth for all credentials in the home lab. It participates in three distinct authentication modes, each serving a different context. They are independent mechanisms — not a single unified flow.
Mode 1: SSH Authentication (1Password SSH Agent)
Used for: Mac → RPi, Mac → GitHub
The 1Password desktop app runs a built-in SSH agent (Settings → Developer → SSH Agent). The agent exposes a Unix socket and responds to the standard SSH agent protocol:
~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock
~/.zprofile exports SSH_AUTH_SOCK pointing to this socket, so ssh, git, VSCode,
and any other SSH agent-aware tool uses 1Password automatically.
When a connection is initiated, the agent presents sshkey.github from the Lab vault,
handles the signing challenge (private key never leaves 1Password’s process), and
prompts for Touch ID on first use in a session.
~/.ssh/config key settings:
Host *
IdentityAgent "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock"
AddKeysToAgent no
Host n8n homeassistant ha rpi rpicm5b 5b
ForwardAgent yes
Host github.com
User git
AddKeysToAgent no prevents ssh-add from populating the agent — 1Password manages
the key lifecycle directly.
The key: sshkey.github
| Attribute | Value |
|---|---|
| Name | sshkey.github |
| Type | Ed25519 |
| Fingerprint | SHA256:KRxIURcQzuXar... |
| Stored in | 1Password — Lab vault |
| Also on disk | ~/.ssh/id_ed25519 (Mac only; can eventually be removed) |
RPi authorized_keys
Each RPi host has sshkey.github’s public key in /home/ops/.ssh/authorized_keys.
A legacy RSA pubkey is also present for backwards compatibility. The tim user
account on RPis is deprecated — see
[ARD07: Account Strategy](../A30-Architectural Decisions/ard07-accounts.md).
Agent forwarding (RPi → GitHub)
With ForwardAgent yes, an ssh command run inside a Mac → RPi session tunnels back
to the Mac’s 1Password agent. The Pi’s git or ssh command can reach GitHub without
a locally stored key — 1Password signs on the Mac and returns only the signed response.
Note: During provisioning, provision-host.sh Phase 5 does place id_ed25519
(the same sshkey.github private key) on the Pi at /home/ops/.ssh/id_ed25519 using
op read (see Mode 2 below). This allows the Pi to reach GitHub independently, without
requiring an active forwarded session from the Mac.
Mode 2: op CLI — Interactive (Mac)
Used for: provisioning scripts run from the Mac (provision-host.sh,
provision-service.sh, gen-spec.sh)
The op CLI (installed via brew install --cask 1password-cli) integrates with the
1Password desktop app on macOS. When a script calls op, the CLI authenticates via
the running desktop app — biometric (Touch ID) in practice, no token required.
The CLI is used in provisioning scripts to:
-
Read the GitHub SSH private key and push it to a Pi during host setup:
op read "op://Lab/sshkey.github/private key?ssh-format=openssh" \ | ssh ops@rpicm5b "install -m 600 /dev/stdin /home/ops/.ssh/id_ed25519" -
Fetch the service account token for the target environment and install it on the Pi (see Mode 3):
OP_TOKEN=$(op item get "op-service-account" --vault devLab --fields credential --reveal) -
Read
server.*items from the Lab vault to generateservers.yaml.
This mode requires the 1Password desktop app to be running and unlocked. It is not used on the RPi — only on the Mac.
Mode 3: op CLI — Service Account (RPi)
Used for: service deployment on RPi hosts (provision-service.sh, gen-env.sh)
RPi hosts are headless — no desktop app, no biometric auth. Instead, provision-host.sh
Phase 5b places a service account token on each host during provisioning:
/home/ops/.op_env (mode 600)
Contents:
export OP_SERVICE_ACCOUNT_TOKEN=<token>When op sees OP_SERVICE_ACCOUNT_TOKEN in the environment, it authenticates directly
to the 1Password API using that token — no interactive prompt, no desktop app.
The token is scoped to a single vault:
| Environment | Vault | Token item |
|---|---|---|
| dev | devLab | op-service-account in devLab |
| prod | prodLab | op-service-account in prodLab |
provision-service.sh sources /home/ops/.op_env before calling gen-env.sh, which
then calls op item get <service-item> --vault <vault> to read fields prefixed env.
and write them as NAME=value pairs to the service’s .env file.
This is how secrets reach running Docker Compose services without ever being committed to the repo.
How the Modes Relate
The three modes are independent. They happen to all use 1Password as the backend, but they use different authentication paths and serve different phases of operation:
| Mode | Auth path | Used on | When |
|---|---|---|---|
| SSH agent | 1Password desktop app → socket | Mac | Every SSH/git connection |
| op CLI interactive | 1Password desktop app → CLI | Mac | Provisioning from workstation |
| op CLI service account | OP_SERVICE_ACCOUNT_TOKEN env var | RPi | Service deployment on host |
A typical provisioning run exercises all three in sequence:
- Mac SSHes into the Pi (Mode 1) to run remote commands
- Mac calls
op read/op item get(Mode 2) to fetch secrets and push them to the Pi - The Pi later sources
.op_envand callsop item get(Mode 3) to generate.env
Vault Layout
| Vault | Purpose |
|---|---|
Lab | Shared items: sshkey.github, server.* host specs |
devLab | Dev secrets: op-service-account, service.* items |
prodLab | Prod secrets: op-service-account, service.* items |
Related
- [ARD04: Secrets Management](../A30-Architectural Decisions/ard04-secrets.md)