Your SSH Keys
Are Already Stale

Nick Taylor @nickytonline

Nick Taylor @nickytonline

Someone joins the team

“Here’s my SSH public key.”

Add it to authorized_keys.
On every server account they need.

They can now SSH into those servers.

Nick Taylor @nickytonline

Someone leaves the team

Find their SSH public key.
Remove it from every authorized_keys file.

“They shouldn’t have access anymore… right?”

Nick Taylor @nickytonline

There must be a better way.

What is an identity-aware proxy?

Every request proves who’s asking — not just where it’s coming from.

Access is decided by policy, evaluated per request.

Nothing is trusted by default. Verification is continuous.

Nick Taylor @nickytonline

Pomerium: an identity-aware proxy

Pomerium is an identity-aware proxy between a user’s browser or client and internal resources. An Identity Provider (IdP) supplies sign-in. Pomerium checks identity and policy: the Allow path reaches web apps, SSH servers, MCP servers, or other resources; the Deny path stops at Access denied outside the internal-resources boundary.
Nick Taylor @nickytonline

SSH certificates

What if servers trusted
an SSH user CA instead
of individual user keys?

Nick Taylor @nickytonline

What is a certificate authority?

A certificate authority (CA) is a trusted signer.

Its private key signs certificates.
Its public key verifies those signatures.

An SSH user certificate binds your public key to permitted login identities
and a validity period, making it ephemeral by design. The client still proves it holds the private key.

Nick Taylor @nickytonline

One SSH user CA to trust on your servers

Pomerium holds Each server holds
The CA private key The CA public key
Signs user certificates with the CA private key sshd verifies the signature with the CA public key

The server also checks the certificate’s validity period and permitted login identity.

Nick Taylor @nickytonline

Traditional SSH CA complexity

  1. Stand up and secure a CA server — protect its private key.
  2. Distribute the CA public key to every target server.
  3. Users request certificates manually, or scripts manage it.
  4. Admins push a list of revoked user certificates to every server when access changes.

Pomerium removes three of these four burdens.

Nick Taylor @nickytonline

Pomerium Native SSH: two connections

SSH clientYour OS’s native client→PomeriumIdentity + policy→SSH serverTrusts Pomerium’s User CA

Your native client’s connection terminates at Pomerium.

Pomerium is itself an SSH client on the second leg — its own internal client, not your OS’s — authenticating to the target with a signed certificate.

Nick Taylor @nickytonline

The SSH client you already use

Your operating system’s native SSH client.

ssh demo@jump@demo.iamdeveloper.com

demo: Linux account on the target
jump: Pomerium route
demo.iamdeveloper.com: Pomerium SSH proxy address

First connection: browser sign-in.
Later connections can reuse the identity session.

Nick Taylor @nickytonline

Your SSH key meets your identity

  1. Your SSH client proves who you are to Pomerium.
  2. Pomerium prompts a browser sign-in when needed.
  3. A client binding links that proof to your identity session.

Later connections can reuse that binding.
Every connection still needs authorization.

Nick Taylor @nickytonline

Authorization changes with context

Every connection triggers a policy check — identity, server, Linux user, and additional criteria.

Allowed when you connected.
Still allowed now?

Nick Taylor @nickytonline

Identity and permission

Authentication
“This is Nick.”

Authorization
“Nick may access the jump route as the Linux user demo.”

Pomerium checks the route’s policy before granting access.

Nick Taylor @nickytonline

The certificate handoff

  1. Pomerium authorizes access to the route.
  2. Pomerium signs a short-lived user certificate — the user’s public key plus the allowed Linux username.
  3. Pomerium uses it to authenticate to the target.
  4. The target validates it against the trusted User CA.

SSH login succeeds only if the target accepts the certificate.

Nick Taylor @nickytonline

Before: access allowed

routes:
  - from: ssh://jump
    to: ssh://sshd:2222
    policy:
      - allow:
          and:
            - email:
                is: nick@nickyt.co
            - ssh_username:
                is: demo

This identity can use this route as demo.

Nick Taylor @nickytonline

After: access revoked

routes:
  - from: ssh://jump
    to: ssh://sshd:2222
    policy:
      - allow:
          and:
            - email:
                is: nick@nickyt.co.revoked
            - ssh_username:
                is: demo

The same identity no longer matches the policy.

Nick Taylor @nickytonline

Authorization continues during SSH

Policy update: recheck active connections.

Session or client binding revoked: close associated connections.

Periodic check: reevaluate authorization every minute.

Pomerium closes the connection when authorization fails.

Nick Taylor @nickytonline

Certificates and ongoing access

Mechanism What it controls
Short-lived certificate Authentication to the target — blocks new logins once expired
Ongoing policy checks Whether proxied access continues — revokes active sessions immediately

SSH itself does not end sessions on certificate expiry.
Pomerium ends the connection the moment policy fails.

Nick Taylor @nickytonline

Demo Time

Access follows identity and policy

The server trusts Pomerium’s User CA.

Pomerium checks who you are and what you can access.

When the decision changes from allow to deny, Pomerium ends that session.

Nick Taylor @nickytonline

Try it yourself

Scan to open the interactive Native SSH Access with Pomerium tutorial.

go.pomerium.com/nerd26-tutorial

Nick Taylor @nickytonline

Resources

Nick Taylor @nickytonline

¡GRACIAS!

Nick Taylor · @nickytonline

0:00–0:20 · 20 seconds Open with the server-access story. The title refers to stale permission, not broken cryptography.

0:20–1:10 · 50 seconds Tell the onboarding story: a teammate sends a public key, and someone distributes it to the server accounts they need. Configuration management helps, but the access inventory still needs an owner. Use one quick show of hands here; skip a second audience poll.

1:10–2:10 · 60 seconds Tell the offboarding story. Which servers have that key? Are we sure we removed every copy? “The key still works; the permission it represents may be out of date. That’s what I mean by stale.”

2:10–2:35 · 25 seconds “Conveniently, yes. Otherwise, this would be a very short talk.” Introduce yourself: Nick Taylor, developer advocate at Pomerium. Move directly into the proxy diagram.

2:35–3:00 · 25 seconds Three ideas before the diagram: identity replaces network location as the basis for trust, policy — not a static ACL — makes the call, and that call is re-checked rather than granted once and forgotten. This sets up “continuous” before the demo revisits it under Authorization continues during SSH.

3:00–3:55 · 55 seconds Pomerium is an open-source identity-aware proxy between the client and internal resources. Trace identity-provider sign-in, the policy decision, and the allowed path. For SSH, servers trust a certificate authority and Pomerium enforces access while the connection is open.

3:55–4:40 · 45 seconds “What if our servers trusted an SSH user certificate authority instead of individual user keys?” “You may already use SSH certificates. They avoid installing each person’s public key on every server. We still need to issue credentials and manage access.” If needed: “A server may already trust CAs for HTTPS. SSH user authentication has its own trust configuration. Here we explicitly configure OpenSSH to trust an SSH User CA using TrustedUserCAKeys.” Transition: “First, a quick explanation of what that trusted signer does.” Source: https://www.pomerium.com/docs/capabilities/native-ssh-access

4:40–5:25 · 45 seconds “A CA is a trusted signer. Its private key signs; its public key verifies.” The certificate says which key can log in as which account, and for how long. The client still proves it holds the private key. We configure the server to trust the signer; certificates do not eliminate keys. Stop at that trust model; skip the comparison and direct-client walkthrough. Sources: https://www.pomerium.com/docs/capabilities/native-ssh-access https://www.pomerium.com/changelog/native-ssh-access

5:25–6:10 · 45 seconds Pomerium holds the CA private key; targets receive only the CA public key. This replaces distributing every new user key to every target. We still maintain Linux accounts and rotate CA keys; avoid repeating the certificate checks from the previous slide. Transition: what does maintaining that trust look like without Pomerium? Sources: https://www.pomerium.com/docs/capabilities/native-ssh-access https://www.pomerium.com/changelog/native-ssh-access

6:10–7:00 · 50 seconds Running an SSH CA yourself means owning every one of these steps: standing up and protecting the CA server, distributing its public key to every target, handling certificate requests, and revoking access server-by-server when someone leaves. Pomerium holds the CA, automates issuance through the identity provider, and enforces revocation through policy instead of per-server changes. The one step that doesn’t disappear: each target still needs Pomerium’s CA public key installed once — a one-time setup, not a per-user one. Transition: “Here’s what actually happens on the wire when someone connects.”

7:00–8:40 · 100 seconds Trace the two SSH connections. The native client connects to Pomerium; Pomerium connects to the target on the user’s behalf. Traffic is encrypted on both network connections, but Pomerium terminates SSH in the middle. That position lets it enforce access throughout the connection. The shell runs on the target. Keep it at that: Pomerium makes and maintains the authorization decision while it proxies. Skip Envoy/internals detail — it doesn't change what the audience needs to take away. Sources: https://www.pomerium.com/docs/capabilities/native-ssh-access

8:40–9:50 · 70 seconds Read the address from the right: demo.iamdeveloper.com is the proxy. The client sends demo@jump as its username: demo selects the target Linux account; jump selects the route. First login prompts browser sign-in. Later connections can reuse the identity session, but must still pass authorization. Sources: https://www.pomerium.com/docs/capabilities/native-ssh-access

9:50–11:00 · 70 seconds The local private key stays on the laptop. Browser sign-in associates its public key with an identity session through a client binding. A valid binding can be reused; authorization is still required for every connection. The laptop key authenticates to Pomerium. Pomerium uses separate certificate credentials upstream. Sources: https://www.pomerium.com/docs/capabilities/native-ssh-access https://github.com/pomerium/pomerium/blob/416fab08459e882705b76e5068865034f97df795/pkg/ssh/auth.go

11:00–12:00 · 60 seconds Our example checks email and requested SSH username. Changing the allow rule leaves me authenticated but no longer authorized. The answer can change after login. External identity changes must reach Pomerium before it can act. Sources: https://www.pomerium.com/docs/capabilities/native-ssh-access https://github.com/pomerium/pomerium/blob/416fab08459e882705b76e5068865034f97df795/pkg/ssh/stream.go

12:00–12:55 · 55 seconds “Authentication answers: is this Nick? Authorization answers a more specific question: may Nick use this route as demo?” “Those names describe different things. Nick is my identity-provider user. demo is the Linux account I’m requesting on the target.” “The policy can require my email to match and the requested SSH username to be demo. Signing in successfully doesn’t give me permission to ask for root.” Transition: “Once that policy allows the request, Pomerium needs a credential the target server will accept.” Source: https://github.com/pomerium/pomerium/blob/416fab08459e882705b76e5068865034f97df795/pkg/ssh/auth.go

12:55–13:55 · 60 seconds Follow the four steps once: allow, sign, present, verify. Pomerium acts as the SSH client to the target; the user does not download that upstream certificate. The target must still accept authentication before a shell opens. Avoid repeating the CA explanation. On the target: the Linux account must already exist, and direct SSH access should be restricted so it can’t bypass Pomerium. Sources: https://www.pomerium.com/changelog/native-ssh-access https://www.pomerium.com/docs/capabilities/native-ssh-access

13:55–14:55 · 60 seconds Walk through route, upstream, email and requested Linux account. The upstream sshd:2222 is illustrative; use the actual deployment value in the demo. “This is the permission we just granted. Now let’s remove it.” Advance to the matching after slide so the audience can see exactly what changes. Keep secrets off screen. Sources: https://www.pomerium.com/docs/capabilities/native-ssh-access

14:55–15:40 · 45 seconds “Now Nick leaves the team. We change the allow rule so his identity no longer matches.” Point to the .revoked suffix: it is a deliberate demo change to the email matcher, not a disabled identity-provider account. Keep the route and Linux account unchanged. Apply the policy without restarting Pomerium. “New connections should be denied. But what about the shell I already have open?” Pause for that question before explaining ongoing authorization on the next slide. This is the before-and-after change the audience will watch in the demo. Source: https://labs.iximiuz.com/tutorials/native-ssh-access-with-pomerium-747d04bb

15:40–17:10 · 90 seconds Answer the open-shell question from the previous slide: Pomerium remains in the connection, so it can end access after login. Policy updates trigger fresh evaluation; session or binding revocation closes associated connections when the update arrives. A separate periodic check reevaluates every minute. That interval does not mean policy updates always wait a minute. External identity changes first have to reach Pomerium. Failed authorization closes the proxied connection. Sources: https://github.com/pomerium/pomerium/blob/416fab08459e882705b76e5068865034f97df795/pkg/ssh/manager.go https://github.com/pomerium/pomerium/blob/416fab08459e882705b76e5068865034f97df795/pkg/ssh/stream.go

17:10–18:10 · 60 seconds Certificate validity limits authentication time. Expiry alone does not close an already established SSH session. Ongoing policy enforcement controls whether proxied access continues. “We now know what to expect: changing that allow rule should close my open shell and deny a retry. Restoring it should let me back in.” The demo tests those predictions; it is not waiting for a certificate to expire. Sources: https://www.pomerium.com/changelog/native-ssh-access https://github.com/pomerium/pomerium/blob/416fab08459e882705b76e5068865034f97df795/pkg/ssh/stream.go

18:10–23:10 · 300 seconds Five-minute demo; stop at 5:00. Introduce the test in one sentence: “You have seen the policy change; now let’s see what happens to a real connection.” 0:00–0:30 — Show the prepared route and allow rule. 0:30–1:30 — Connect, complete browser sign-in if needed, run whoami and hostname. 1:30–2:30 — Change the email matcher so this identity no longer matches; apply without restarting Pomerium. Observe the open connection close. 2:30–3:15 — Retry and show that a cached identity session does not bypass policy. 3:15–4:15 — Restore the matcher, apply, reconnect and run whoami. 4:15–5:00 — Show the already-filtered disconnection log if ready; recap allowed, disconnected, denied, restored. Keep policy control and logs outside the revoked connection. Pre-open browser, editor and terminals. Use actual deployment values and rehearsed client output. If a step stalls for 30 seconds, switch to a prepared recording if available; otherwise use the illustrative backup slides and label them as such. Skip log inspection first when behind. Do not debug live past the five-minute demo allocation. Sources: https://labs.iximiuz.com/tutorials/native-ssh-access-with-pomerium-747d04bb

23:10–23:25 · 15 seconds Be precise: changing a policy does not deny everyone. It matters when the change affects the authorization decision for this identity, route, and Linux username. In the demo, the matcher changes for Nick, so the proxied session ends, the retry is denied, and restoring policy allows access again. The operational shift is changing one policy instead of removing a user key from every server.

23:25–23:40 · 15 seconds Invite the audience to try the interactive tutorial. Leave the QR code up for the full 20 seconds; keep the invitation to one sentence.

23:40–23:50 · 10 seconds Point out that the links are available from the published deck. Keep this to a quick pointer before the closing slide.

23:50–23:55 · 5 seconds Close on the Gracias slide. Q&A has no prepared slides; stay here for questions.