SSH Bastion Service – Implementation Plan
Overview
Add SSH bastion functionality to Plasma Shield, enabling operators and users to debug agents without storing SSH keys on the shield or giving agents lateral SSH access.
Phases
Phase 1: Core SSH Server
Goal: Basic SSH jump host that proxies connections to target agents.
Deliverables:
internal/bastion/server.go— SSH server usinggolang.org/x/crypto/sshinternal/bastion/proxy.go— Connection proxying to target hosts- Host key generation and storage
- Integration with
cmd/proxy/main.go(new-bastion-addrflag)
Acceptance:
./plasma-shield-router -bastion-addr :2222
# SSH through bastion (with pre-shared key for now)
ssh -J localhost:2222 root@target-agentEstimate: ~200 lines
Phase 2: Access Grant System
Goal: Time-limited, logged access grants that control who can SSH where.
Deliverables:
internal/bastion/grants.go— Grant storage (in-memory + JSON persistence)internal/bastion/types.go— Grant struct with expiration, scope, audit fields- API endpoints:
POST /grants,GET /grants,DELETE /grants/{id} - CLI commands:
plasma-shield access grant,access list,access revoke
Grant structure:
type Grant struct {
ID string `json:"id"`
Principal string `json:"principal"` // who can use this grant
Target string `json:"target"` // agent or fleet pattern
ExpiresAt time.Time `json:"expires_at"`
CreatedBy string `json:"created_by"` // audit trail
CreatedAt time.Time `json:"created_at"`
}Acceptance:
# Create grant
plasma-shield access grant --target sarai-chinwag --duration 30m
# List active grants
plasma-shield access list
# Revoke
plasma-shield access revoke <grant-id>Estimate: ~250 lines
Phase 3: Certificate Authority
Goal: Issue short-lived SSH certificates instead of managing keys.
Deliverables:
internal/bastion/ca.go— Certificate authority (signing, validation)- CA keypair generation and secure storage
- Certificate issuance tied to grants
- Client certificate validation on SSH connection
Flow:
- User requests access → grant created
- User authenticates to bastion (their existing key or token)
- Bastion issues short-lived cert (matches grant duration)
- Cert used for actual SSH to target
Acceptance:
# User gets cert automatically when connecting through bastion
ssh -J bastion:2222 target-agent
# Cert expires with grant, no long-lived credentialsEstimate: ~200 lines
Phase 4: Session Logging
Goal: Full audit trail of SSH sessions for compliance and debugging.
Deliverables:
internal/bastion/logger.go— Session event logging- Log connection start/end, target, duration
- Optional command logging (PTY capture)
- API endpoint:
GET /bastion/sessions - Integration with existing LogStore pattern
Log events:
type SessionEvent struct {
SessionID string `json:"session_id"`
GrantID string `json:"grant_id"`
Principal string `json:"principal"`
Target string `json:"target"`
Event string `json:"event"` // connect, disconnect, command
Timestamp time.Time `json:"timestamp"`
Data string `json:"data,omitempty"` // command text if captured
}Estimate: ~150 lines
Phase 5: Admin Panel Integration
Goal: Web UI for managing access grants and viewing sessions.
Deliverables:
- Grants section in dashboard (create, view, revoke)
- Session history view
- Active connections indicator
- Grant expiration countdown
UI Components:
- Grant creation form (target, duration)
- Active grants table with revoke buttons
- Session log viewer with filters
Estimate: ~300 lines (HTML/JS in embedded UI)
Dependencies
golang.org/x/crypto/ssh — SSH server and clientFile Structure
internal/bastion/
├── server.go # SSH server
├── proxy.go # Connection proxying
├── grants.go # Access grant storage
├── ca.go # Certificate authority
├── logger.go # Session logging
└── types.go # Shared types
cmd/proxy/main.go # Add -bastion-addr flagSecurity Considerations
- CA private key must be protected (file permissions, no agent access)
- Grants scoped to specific targets, no wildcards without explicit opt-in
- All sessions logged regardless of grant type
- Bastion binds to configurable interface (default: all, for jump host use)
- Admin API still localhost-only
Testing Strategy
Each phase includes tests:
- Phase 1: Connection proxying works
- Phase 2: Grant expiration enforced, persistence survives restart
- Phase 3: Invalid/expired certs rejected
- Phase 4: All events captured
- Phase 5: UI functional tests (manual)
Rollout
- Phases 1-2: Functional bastion with grant system
- Phase 3: Production-ready security (certs)
- Phases 4-5: Operational polish
Phases 1-2 can ship as "beta" for internal use. Phase 3 required for external/SaaS deployment.