Tools: OIDC SSH Login for Linux, Without the Gateway - Expert Insights

Tools: OIDC SSH Login for Linux, Without the Gateway - Expert Insights

Static SSH keys are the problem

prmana: direct-to-host OIDC with DPoP

Why DPoP matters

Hardware key support

What's in the repo

What it's not

Getting started

Feedback welcome TL;DR: prmana is a PAM module and agent that replaces static SSH keys with short-lived OIDC tokens, bound to proof-of-possession via DPoP (RFC 9449). Rust, Apache-2.0. No proxy, no SSH CA — just your IdP and your Linux hosts. Every org with more than a handful of Linux servers has the same issue: SSH keys everywhere, rotated never. That key a developer generated in 2021? Still works on production. The contractor who left six months ago? Their authorized_keys entry is probably still on a dozen servers. Your security team mandates MFA for email, but root access to your database server? Static key on a laptop. Each solves part of the problem. Each adds operational complexity. prmana brings OIDC authentication directly to the Linux host via PAM, and binds every token to a cryptographic proof that it hasn't been stolen. No gateway. No SSH CA. No static keys. Most OIDC-for-SSH approaches use bearer tokens. If someone intercepts the token — from a log, a compromised proxy, a memory dump — they can replay it from anywhere. DPoP (RFC 9449) changes that. Every authentication includes a proof signed by an ephemeral key pair. The token carries a thumbprint of the public key. The server verifies the proof matches. Token leaks? Useless without the key. That cnf.jkt field binds the token to a specific key pair. No key, no access. The name "prmana" comes from Sanskrit (प्रमाण) — "proof" and "means of knowledge." Felt appropriate for a tool whose whole point is cryptographic proof of possession. DPoP proofs are signed by a key pair. By default that's a software key. prmana also supports: When the DPoP key lives on hardware, the private key can't be exported. Compromised laptop? They have the token but can't sign a valid proof. Plus cross-language DPoP libraries in Go, Python, Java, and Rust. The PAM module plugs into OpenSSH's existing stack. No patches to sshd. Standard ssh on the client, standard sshd on the server. prmana does SSH login. It's not a session recorder, not a proxy, not a privileged access management suite. One job, done well. Docs cover setup for Keycloak, Entra ID, and Auth0. github.com/prodnull/prmana — Apache-2.0. What we'd find most useful: GitHub Discussions for questions and ideas. Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Code Block

Copy

Your Machine Linux Server ┌─────────────────┐ ┌──────────────────┐ │ prmana-agent │ SSH │ pam_prmana.so │ │ (OIDC + DPoP) │ ──────────────▶ │ (validate + bind)│ └─────────────────┘ └──────────────────┘ │ │ ▼ ▼ Your IdP JWKS verification (Keycloak/Okta/ + DPoP proof check Azure AD/Auth0) + replay protection Your Machine Linux Server ┌─────────────────┐ ┌──────────────────┐ │ prmana-agent │ SSH │ pam_prmana.so │ │ (OIDC + DPoP) │ ──────────────▶ │ (validate + bind)│ └─────────────────┘ └──────────────────┘ │ │ ▼ ▼ Your IdP JWKS verification (Keycloak/Okta/ + DPoP proof check Azure AD/Auth0) + replay protection Your Machine Linux Server ┌─────────────────┐ ┌──────────────────┐ │ prmana-agent │ SSH │ pam_prmana.so │ │ (OIDC + DPoP) │ ──────────────▶ │ (validate + bind)│ └─────────────────┘ └──────────────────┘ │ │ ▼ ▼ Your IdP JWKS verification (Keycloak/Okta/ + DPoP proof check Azure AD/Auth0) + replay protection { "sub": "alice", "iss": "https://idp.company.com", "cnf": { "jkt": "NKnABZgU1F7M5JW5uFrETiYx..." } } { "sub": "alice", "iss": "https://idp.company.com", "cnf": { "jkt": "NKnABZgU1F7M5JW5uFrETiYx..." } } { "sub": "alice", "iss": "https://idp.company.com", "cnf": { "jkt": "NKnABZgU1F7M5JW5uFrETiYx..." } } prmana-agent login --signer yubikey:9a # touch the key when it blinks, then SSH normally ssh server.example.com prmana-agent login --signer yubikey:9a # touch the key when it blinks, then SSH normally ssh server.example.com prmana-agent login --signer yubikey:9a # touch the key when it blinks, then SSH normally ssh server.example.com git clone https://github.com/prodnull/prmana.git cd prmana && cargo build --workspace # Install PAM module sudo cp target/release/libpam_prmana.so /lib/security/pam_prmana.so # Point to your IdP sudo mkdir -p /etc/prmana cat << 'EOF' | sudo tee /etc/prmana/policy.yaml issuers: - url: https://your-idp.com/realms/your-realm client_id: prmana audiences: ["prmana"] break_glass: enabled: true users: ["emergency-admin"] EOF # Login and SSH prmana-agent login --issuer https://your-idp.com/realms/your-realm ssh user@server git clone https://github.com/prodnull/prmana.git cd prmana && cargo build --workspace # Install PAM module sudo cp target/release/libpam_prmana.so /lib/security/pam_prmana.so # Point to your IdP sudo mkdir -p /etc/prmana cat << 'EOF' | sudo tee /etc/prmana/policy.yaml issuers: - url: https://your-idp.com/realms/your-realm client_id: prmana audiences: ["prmana"] break_glass: enabled: true users: ["emergency-admin"] EOF # Login and SSH prmana-agent login --issuer https://your-idp.com/realms/your-realm ssh user@server git clone https://github.com/prodnull/prmana.git cd prmana && cargo build --workspace # Install PAM module sudo cp target/release/libpam_prmana.so /lib/security/pam_prmana.so # Point to your IdP sudo mkdir -p /etc/prmana cat << 'EOF' | sudo tee /etc/prmana/policy.yaml issuers: - url: https://your-idp.com/realms/your-realm client_id: prmana audiences: ["prmana"] break_glass: enabled: true users: ["emergency-admin"] EOF # Login and SSH prmana-agent login --issuer https://your-idp.com/realms/your-realm ssh user@server - Access platforms — proxy or gateway in front of everything - SSH certificate authorities — new CA infrastructure to operate - PAM/OIDC modules — SSO but still bearer tokens (interceptable) - The agent gets a short-lived token from your identity provider - It generates a DPoP proof — a signed JWT proving you hold the private key - On SSH, the server's PAM module validates the token, checks expiry, verifies DPoP binding - If it all checks out and the username maps to a local account, you're in - YubiKey — PKCS#11 via PIV slot - TPM 2.0 — platform TPM on Linux - Security review — it's a PAM module. Poke holes. - IdP testing — tested against Keycloak, Auth0, Google, Entra ID. If yours does something unexpected with DPoP or device flow, we want to know. - Platform testing — Ubuntu 22.04/24.04 primary. RHEL, Rocky, Debian reports welcome.