Skip to main content

ssh-agent-keyring

ssh-agent-keyring is a Python keyring backend that keeps secrets encrypted at rest and unlocks them transparently through ssh-agent.

It is designed for SSH-first environments such as headless Linux servers, remote development machines, and terminal-centric workflows where desktop keyring services are not available or not desirable.

Why this exists

On a plain SSH server, the usual choices are often unsatisfying:

  • desktop-oriented keyring backends are unavailable
  • file-based backends usually require a separate keyring password
  • plaintext storage is convenient, but unacceptable for real secrets

ssh-agent-keyring takes a different approach:

  • secrets are stored encrypted at rest
  • unlock happens through a configured SSH key already available in ssh-agent
  • keyring set/get/del work in ordinary SSH sessions without a second keyring password

Features

  • keyring backend implementation: ssh_agent_keyring.backend.SSHAgentKeyring
  • encrypted local store
  • no plaintext secret storage
  • no plaintext service / username metadata in the store
  • no root or system service dependency
  • works well in SSH sessions when SSH_AUTH_SOCK is available
  • simple user-space configuration

How it works

The backend stores a random data-encryption key (DEK) in wrapped form. To unwrap it, the backend:

  1. signs a backend-specific challenge directly through the ssh-agent wire protocol (via paramiko), producing output byte-for-byte identical to ssh-keygen -Y sign with a configured SSH public key
  2. relies on ssh-agent to produce a deterministic signature over that challenge
  3. derives a key-encryption key from that signature with HKDF-SHA256
  4. unwraps the DEK
  5. uses the DEK to encrypt and decrypt secret records with ChaCha20Poly1305

Record identifiers are derived with HMAC, so the on-disk store does not expose service and username pairs in plaintext.

Because the key-encryption key is derived from the raw signature bytes, only key types with deterministic signing are supported: ssh-ed25519 and ssh-rsa. ECDSA (ecdsa-*) and security-key (sk-*) types are rejected — OpenSSH's ECDSA signing uses a random per-signature nonce (no RFC 6979), so the same challenge does not yield the same signature and the store could not be unlocked reliably.

Security notes

This package improves on plaintext file storage, but it intentionally shifts trust to the SSH agent session.

Important implications:

  • anyone able to use your SSH_AUTH_SOCK can potentially unlock the keyring during that session
  • agent forwarding policy matters: a remote host that receives a forwarded agent socket can proxy and inspect its traffic, even if it cannot read the SSH private key
  • the security of the backend depends on the security of the selected SSH key and the agent socket
  • this is not a hardware-backed secret manager or multi-user secret vault
  • the derived signature (which acts as the store's master key) is only as safe as the agent process itself; a compromised or malicious ssh-agent on the other end of SSH_AUTH_SOCK can always observe what it is asked to sign, regardless of how the request reaches it

In particular, an interceptor that sees the deterministic unlock signature and has a copy of the store can derive the key-encryption key, unwrap the data-encryption key, and decrypt the stored records, see PoC. It does not need to extract the SSH private key. Do not forward an agent to an untrusted host while using this backend, and treat a forwarded agent socket as granting access to the keyring store.

Requirements

  • Python 3.10+
  • keyring
  • cryptography
  • paramiko
  • a running ssh-agent
  • SSH_AUTH_SOCK set in the current environment
  • the configured SSH key loaded in the agent

Installation

From PyPI:

pip install ssh-agent-keyring

If you are installing in a user environment on a remote machine, a typical setup is:

python3 -m pip install --user ssh-agent-keyring

Configuration

The backend reads configuration from:

~/.config/ssh-agent-keyring/config.json

Example:

{
  "public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExampleBase64KeyMaterial",
  "store_path": "~/.local/share/ssh-agent-keyring/store.json"
}

Then select the backend in:

~/.config/python_keyring/keyringrc.cfg
[backend]
default-keyring=ssh_agent_keyring.backend.SSHAgentKeyring

Configuration fields

  • public_key: SSH public key to use for unlocking the store
  • public_key_path: path to a public key file; useful instead of embedding the key in JSON
  • store_path: path to the encrypted JSON store

Environment variable overrides

These override file-based configuration:

  • SSH_AGENT_KEYRING_PUBLIC_KEY
  • SSH_AGENT_KEYRING_PUBLIC_KEY_PATH
  • SSH_AGENT_KEYRING_STORE_PATH

Usage

With the Python API:

import keyring

keyring.set_password("example-service", "alice", "s3cr3t")
print(keyring.get_password("example-service", "alice"))
keyring.delete_password("example-service", "alice")

With the CLI:

keyring set example-service alice
keyring get example-service alice
keyring del example-service alice

With this backend, keyring set prompts only for the secret being stored. It does not prompt for a separate keyring password.

Limitations

  • this backend depends on the standard ssh-agent wire protocol
  • it is aimed at Unix-like environments
  • it does not provide secret sharing, rotation workflows, audit logs, or remote synchronization
  • it assumes the configured SSH key can be used for agent-backed signing

Testing

Run the test suite with:

python3 -m unittest discover -s tests -v

The project includes tests for roundtrips, tampering, key mismatch, signer failures, and store handling edge cases.

tests/test_real_agent.py additionally spins up a real ssh-agent and verifies, against real ssh-keygen -Y sign output, that the backend's own agent-protocol signing is byte-for-byte compatible. It's skipped automatically if ssh-agent/ssh-keygen/ssh-add aren't on PATH.

Development

Project layout:

  • ssh_agent_keyring/agent.py - agent and signing integration
  • ssh_agent_keyring/crypto.py - key derivation and encryption helpers
  • ssh_agent_keyring/backend.py - keyring backend implementation
  • tests/test_backend.py - automated test suite
  • tests/test_real_agent.py - real ssh-agent/ssh-keygen compatibility tests

License

License information has not been added yet.

Metadata

Release files for ssh-agent-keyring 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distribution (wheel)

Table of built distributions (wheels) for ssh-agent-keyring 0.6.0
File Interpreter ABI Platform
ssh_agent_keyring-0.6.0-py3-none-any.whl Python 3 none any Details

Release files / ssh_agent_keyring-0.6.0-py3-none-any.whl

Download URL ssh_agent_keyring-0.6.0-py3-none-any.whl
Size 10.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dadad7cce48b842fc41e360de7c0035acd842a92804974ae59eb64a4c4797610
BLAKE2b-256 checksum
How to use checksums
e98ebcb20c685937217f4fb77b1dfc4f9cb5fa9cdad4c250df59fe427aabb2b5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 23, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.6.0 This release

1 release file

0.5.0

1 release file

0.4.0

1 release file

0.3.0

1 release file

0.2.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page