ops(security): Codex SSH key delivery via ssh-agent with TTL — keep key off disk (Phase 1 Lite) #73
Labels
No labels
W6d-automerge-calibration
agent/claude-code
agent/codex
agent/hermes
agent/iskra
agent/ollama
agent/patchwarden
automerge-candidate
class/security-sensitive
cutover-gate
dependency/blocked
dependency/blocks-others
dependency/cross-repo
dependency/needs-confirmation
domain:agents
domain:ci
domain:docs
domain:forgejo
domain:infra
domain:memory
domain:runtime
domain:signal
domain:ux
flow/architecture
flow/blocked
flow/deployed
flow/done
flow/implementation
flow/intake
flow/maintained
flow/observed
flow/ready
flow/refining
flow/retired
flow/review
iterating
judge/codex-candidate
judge/hermes-candidate
judge/low-confidence
judge/needs-refinement
judge/operator-needed
judge/p0
judge/p1
judge/p2
judge/p3
judge/park
judge/patchwarden-candidate
judge/stale-priority
kind/adr
kind/bug
kind/chore
kind/feature
kind/infra
kind/ops
kind/refactor
kind/research
large-impact
merge/auto
merge/manual
merge/manual-dependency-conflict
merge/manual-failing-tests
merge/manual-merge-conflict
merge/manual-missing-review
merge/manual-operator-preference
merge/manual-red-zone
merge/manual-security-sensitive
merge/manual-unclear-scope
merge/manual-unknown
meta
mode:operator-only
mode:patchwarden-iskra-approved
mode:safe-auto
needs-operator-decision
needs-triage
not-ready
observed/erroring
observed/needs-followup
observed/pending
observed/retire-candidate
observed/unused
observed/used
operator-emotional
owner-attention
phase/02
phase/03
priority:p0
priority:p1
priority:p2
priority:p3
proposed
ready-for-agent
ready-for-operator
recovery
review:claude-reviewed
review:codex-reviewed
review:dziadek-reviewed
review:needs-human
risk/exposure
risk/process
risk/product
risk/runtime
safety:external-write
safety:no-prod-mutation
safety:prod-impact
safety:secret-touch
size/large
size/medium
size/small
size/tiny
size/unknown
source/adr
source/agent-generated
source/manual
source/operator-chat
source/voice-note
status:blocked
status:codex-ready
status:merged:pending-evidence
status:needs-evidence
status:operator-needed
status:parked
tier/full
tier/lite
tier/stacked
tier:0-platform-substrate
tier:1-iskra-value-layer
tier:2-tools-products-modules
type:bug
type:chore
type:docs
type:feat
type:policy
type:research
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
pdurlej/platform#73
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Migrated from
pdurlej/iskra-openclaw#47After Piotr's review tonight (2026-05-05 ~01:45 CEST): this issue was originally opened in
pdurlej/iskra-openclaw#47but the right home ispdurlej/platform, because:runbooks/infisical-*.md,env/infisical.*,scripts/infisical-*.sh,scripts/openclaw-infisical-render.sh,policy/security.rego,docs/dependency-migrations/infisical.md).docs(migrations): vault-to-infisical Phase 1-5 execution) is the parent topic — secrets management strategy.pdurlej/iskra-openclawPR #45) stays in iskra-openclaw because the allowlist is iskra-specific (iskra-canary,iskra-cockpit,continuity-pack). Delivery flow ≠ wrapper allowlist; only the wrapper allowlist is iskra-runtime-bound.This issue specifies delivery flow (cross-cutting credentials infrastructure). Closing the original
pdurlej/iskra-openclaw#47with a redirect comment.— Claude (post-hoc placement fix, 2026-05-05 ~01:45 CEST)
Origin
Po nocnej rozmowie Piotra z Oracle GPT 5.5 pro o 3-warstwowej architekturze secret management (
pdurlej/iskra-openclaw#43, will likely also migrate here) i overnight-deployed Path A SSH wrapper (pdurlej/iskra-openclaw#44+ PR #45), wracamy do delivery question: jak Codex's runtime ma dostać prywatny klucz tak, żeby:ssh, ale nie widzi raw bytes po fetch windowpdurlej/iskra-openclaw#43Recommended w
pdurlej/iskra-openclaw#44podejście (Bitwarden field +bw get itemna startup) działa, ale ma kilka paper cuts któressh-agent+ TTL pattern rozwiązuje strukturalnie. Ten issue specyfikuje delivery flow jako Phase 1 Lite — pomost między aktualnym Path A wrapper deploy a pełnym Phase 1 resolver z #64.Mission name from Piotr: "SSH agent locked dla Codexa".
Problem (current state per
pdurlej/iskra-openclaw#44thread)pdurlej/iskra-openclaw, smoke 5/5 pass)/tmp/codex-key-bundle/codex_iskra_openclaw_ed25519on Piotr's Mac, mode 0600vps1000 (codex)withssh_keyfield, fetched by Codex runtime viabw get item 'vps1000 (codex)' --session "$BW_SESSION" | jq -r '...'Limitations of recommended Bitwarden-direct-fetch
echo "$key" > /tmp/key && ssh -i /tmp/key). Even with cleanup, the key briefly exists on disk and possibly in shell history.ssh -i <(bw get...)keeps key in named pipe, but key is in Codex's process memory and the named pipe is readable by anyone with FD access during the fetch window.These aren't disasters individually. Sum of paper cuts > one structural fix.
Proposal: ssh-agent as locked vault, with TTL
Use OpenSSH's built-in
ssh-agentas the credential broker for Codex's audit access. Key lives only in ssh-agent's process memory, with a forced TTL viassh-add -t. Codex callsssh ...normally;SSH_AUTH_SOCKroutes to ssh-agent which signs the SSH handshake without exposing the key bytes.This is the "agent uses but never sees the secret" pattern from Oracle's Phase 3 brief, applied to the SSH-key-only special case using a mechanism that has been in OpenSSH since 1995, not a research-preview product.
Architecture
Concrete delivery flow (Bitwarden-backed Phase 1 Lite)
What this achieves:
~/.ssh/codex_key, no env var with key body).pdurlej/iskra-openclawPR #45 stays as-is).Phase 1 Lite vs. Phase 1 Full vs. Phase 3
openclaw-infisical-resolverssh-agent -tflagssh-agent -tflag + Infisical token TTLThe "Codex sees raw bytes once per TTL window" gap remains in Phase 1 Full and only closes in Phase 3. That's an honest limitation — Phase 1 Lite is not Phase 3 in disguise. But the gap is much smaller than current "key on disk indefinitely" state.
Migration path
When Phase 1 Full lands (#64 / Oracle 3-phase architecture), the Codex runtime startup script changes from:
to:
ssh-agent + TTL pattern is unchanged. Only the key source rotates from Bitwarden to Infisical.
When Phase 3 Agent Vault lands, the SSH access flow itself changes — Codex no longer holds a key at all, the broker proxies the SSH session.
Acceptance criteria
ssh-add -t 3600 -to load key from stdin (no tempfile)ssh openclaw@vps1000 ...succeeds within 1h of startup; fails after 1h until re-fetch (smoke: wait 3700s, retry)grep -E 'BEGIN OPENSSH PRIVATE KEY' codex.logreturns nothing)bw get item 'vps1000 (codex)'returns the key only whenBW_SESSIONis unlocked (relies on Bitwarden's own ACL)bw getto resolver-based fetch verifiedpdurlej/iskra-openclawdocs/security/codex-ssh-wrapper.mdcovering the in-memory-only invariantpdurlej/iskra-openclaw#10/#12/#13/#22/#33audit using the new delivery flowThreat model — diff vs. recommended Bitwarden-direct-fetch
iskra-openclaw#44)ssh -i /tmp/keyleaks path tops/audit logsssh openclaw@vps1000— no key path in argvWhat this does NOT protect
ptracessh-agent or read/proc/<pid>/maps. Same as any in-process secret. HSM is the structural fix; out of scope here./tmp/ssh-XXX/with mode 0600 owned by Codex's UID. Anyone with that UID (or root) can use the socket. Acceptable trade-off for read-only audit access — wrapper allowlist on vps1000 is the second wall.pdurlej/iskra-openclaw scripts/security/codex-ssh-wrapper.py) is the protection there, not this delivery mechanism.Open questions
bw get itemrate limit? Worth measuring.ssh-agent -asocket location: default/tmp/ssh-XXX/is fine for now. Future hardening could use/run/user/<uid>/ssh-agent.sockwith stricter unix permissions and tmpfs backing.Decision asks for Piotr
iskra-openclaw#44approach until Phase 1 Full lands? My read: Phase 1 Lite is ~0.5 day Codex work, removes 4 of 5 paper cuts permanently. Worth shipping now.iskra-openclaw#44), Infisical machine-identity SSH provisioning is its own design under #64.Related
docs(migrations): vault-to-infisical Phase 1-5 execution(Phase 1 Full target; this is Phase 1 Lite of that)pdurlej/iskra-openclaw#43— 3-phase secrets architecture (Oracle GPT 5.5 pro consult; also a candidate for migration to platform per the same audit)pdurlej/iskra-openclaw#44— Codex SSH access provisioning (also a candidate for migration to platform); this issue specifies delivery for that wrapperpdurlej/iskra-openclawPR #45 — wrapper deployment (stays in iskra-openclaw — allowlist is iskra-specific)pdurlej/iskra-openclaw#10,#12,#13,#22,#33— five audits unblocked by Path Apdurlej/iskra-openclaw#46— defense-in-depth for Agent Souls/ (sibling memory-sidecar follow-up; stays in iskra-openclaw)fix(identity): split Forgejo MCP identity per agent and disable admin MCP by default— adjacent agent-governance topicWhy "small, but ship now"
Każda warstwa to ~5–15 linii bash w startup script Codexa. Pattern jest production-grade (OpenSSH od ~30 lat). Path A→B migration path zachowany. Quick-win removes 4 paper cuts vs. plain Bitwarden fetch. Codex effort ~0.5 dnia.
— Claude (overnight pass on Piotr's "SSH agent locked dla Codexa" mission, 2026-05-05 noc, post-Oracle-GPT-5.5-pro-consult)
pdurlej/platformapdurlej/iskra-openclaw— co gdzie mieszka #74