Projects sometimes need permission to use an SSH identity without retrieving its private key—for example, running git push with a developer's vault key or deploying with a dedicated repository key. Can we express that through existing secret declarations and have secretspec run provide an SSH-agent connection?
Related: #434 (hardware-backed SSH identities), #9 (secret generation), and #300 (notifications and approvals). Factorseal is one motivating provider, but the interface should accommodate other agents and hardware-backed keys.
Proposed configuration
Prefer an entry in the existing profile structure over requiring a separate [ssh-agent] section. Illustrative syntax only; the type name and reference semantics are open for discussion:
[providers]
identities = "factorseal://default"
[profiles.default]
WORK_SSH = { description = "SSH identity for Git access", type = "ssh", providers = ["identities"], ref = { item = "work-github" } }
WORK_SSH is the project's logical identity ID. Does the existing entry name suffice, or is there a reason to add an explicit id? My preference is to reuse the name.
- The existing
ref/refs mechanism could identify the provider's key, avoiding another key_id field. The example's item coordinate would need an agreed provider mapping; this is not currently supported Factorseal syntax.
- Consider
type = "ssh_identity" instead of "ssh" to make signing-only semantics clearer. SecretSpec already documents ssh_private_key for 0.21 generation/export workflows; existing declarations must retain their behavior.
- Multiple projects may reference the same developer identity. Dedicated deploy keys also fit; this does not require a new key per project. Personal provider/key mappings should be possible without committing a developer-specific key ID to a shared project.
Command behavior
For secretspec run -- git push:
- Resolve the active profile's SSH identity declarations through an agent-capable provider operation, separate from ordinary secret-value reads.
- Obtain an invocation-scoped agent endpoint exposing only the selected identities, and set
SSH_AUTH_SOCK for the child command. Multiple declarations should work through one endpoint; composition across providers needs a defined contract.
- When SSH requests a signature, let the provider enforce application/key authorization and obtain user approval when required. Providers may additionally constrain destination/user/forwarding information when available; a project name alone is not an authenticated security boundary.
- Keep private keys inside the provider. Do not export
WORK_SSH as private-key bytes or silently fetch a key into a temporary file or another agent.
- Close invocation-scoped resources when the command ends. Provider grant expiration, revocation, and vault locking must continue to take effect while it runs.
Design questions
- Is a new identity type sufficient, or should agent delivery be an explicit mode on an existing type? Can we keep this within the existing profile declarations without a separate section?
- How should provider/IPC capability negotiation represent identities and agent endpoints? Unsupported providers should return a clear error, with no automatic fallback to private-key export.
- What should
get, check, SDK resolution, and generated types return for a signing capability rather than a string secret? Value caching and composition must not accidentally turn this into ordinary secret retrieval.
- How should multiple providers, an inherited
SSH_AUTH_SOCK, Windows endpoints, and child-process lifetime be handled? Merely pointing at an unrestricted existing agent would not enforce the declared identity selection.
This would be optional project integration: normal use of an existing SSH agent should continue to work without any SSH declarations in secretspec.toml.
Projects sometimes need permission to use an SSH identity without retrieving its private key—for example, running
git pushwith a developer's vault key or deploying with a dedicated repository key. Can we express that through existing secret declarations and havesecretspec runprovide an SSH-agent connection?Related: #434 (hardware-backed SSH identities), #9 (secret generation), and #300 (notifications and approvals). Factorseal is one motivating provider, but the interface should accommodate other agents and hardware-backed keys.
Proposed configuration
Prefer an entry in the existing profile structure over requiring a separate
[ssh-agent]section. Illustrative syntax only; the type name and reference semantics are open for discussion:WORK_SSHis the project's logical identity ID. Does the existing entry name suffice, or is there a reason to add an explicitid? My preference is to reuse the name.ref/refsmechanism could identify the provider's key, avoiding anotherkey_idfield. The example'sitemcoordinate would need an agreed provider mapping; this is not currently supported Factorseal syntax.type = "ssh_identity"instead of"ssh"to make signing-only semantics clearer. SecretSpec already documentsssh_private_keyfor 0.21 generation/export workflows; existing declarations must retain their behavior.Command behavior
For
secretspec run -- git push:SSH_AUTH_SOCKfor the child command. Multiple declarations should work through one endpoint; composition across providers needs a defined contract.WORK_SSHas private-key bytes or silently fetch a key into a temporary file or another agent.Design questions
get,check, SDK resolution, and generated types return for a signing capability rather than a string secret? Value caching and composition must not accidentally turn this into ordinary secret retrieval.SSH_AUTH_SOCK, Windows endpoints, and child-process lifetime be handled? Merely pointing at an unrestricted existing agent would not enforce the declared identity selection.This would be optional project integration: normal use of an existing SSH agent should continue to work without any SSH declarations in
secretspec.toml.