Illustrative OpenSSH lesson with an engineer using a laptop beside a certificate-authentication diagram.

WIUNIX ACADEMY

OpenSSH user certificates: short-lived access and revocation in a loopback lab

Build a separate loopback-only sshd, verify its host key, issue a constrained user certificate and prove revocation affects new connections.

Advanced55 min readUpdated
Make this guide yours

YOUR SYSTEM. YOUR STEPS.

Where are you working?

Choose your OS and version. The prerequisites, commands and troubleshooting follow your environment.

Red Hat Enterprise Linux 9Reviewed against official documentation ·

USE YOUR OWN VALUES

Configure this tutorial

Set the example values for your environment; related explanations and copy panels update together. Never enter passwords, private keys or tokens. Values stay in this tab and are not sent to the server or share links. Check actual DNS, certificates and network policy before running commands.

Different IP addresses, domains or ports? Open the settings below, change the values and select “Apply to tutorial”, then copy the updated commands.

Set values for my environment4 editable values

THE OUTCOME

What will you have at the end?

Build a separate loopback-only sshd, verify its host key, issue a constrained user certificate and prove revocation affects new connections.

Supported operating systems and versions

Primary-documentation review; no production execution or universal installation test is claimed. Examples assume existing tools on Linux and must be adapted to authorized deployment context.

Before you begin

  • Authorized operator access, existing tools named in the panels, and a private place to retain diagnostic evidence.
  • Use a staging environment or an approved read-only production investigation; review disruptive changes separately.

Keep the CA experiment away from production login

This is a single-host disposable lab with an existing non-root account, not a production CA architecture. It does not edit the system SSH configuration, publish a new network port or change the account’s usual keys. Production signing needs separately protected CA custody, audited issuance, clock discipline and a reachable revocation distribution path. Certificates authenticate a public key; they do not remove the need to verify the server host key.

01

LET’S BUILD

Check the selected distribution and required tools first

Run on the authorized diagnostic host or disposable lab VM. Compare the installed OS and required packages below with the selected path. Obtain missing tools from the distribution’s enabled official repositories through your approved package-management process; this workflow does not reinstall an existing server or switch its repository.

Use an entitled RHEL repository or the matching official Rocky Linux/AlmaLinux repositories and a currently supported minor release. SELinux and system crypto policy remain enforced; do not weaken them to make a diagnostic pass.

The client package is openssh-clients. The normal sshd service is inspected only; this lab does not start/restart/reload it. Use an existing valid authorized non-root account. The Red Hat-family path generates RSA3072 lab keys because Ed25519 is unavailable in FIPS mode; this is not a claim of FIPS certification.

If the packaged privilege-separation prerequisite is missing, complete the native package setup on the disposable VM before this lab. Do not work around missing packaged privilege-separation prerequisites by weakening privilege separation or changing the administration daemon.

Current family packages place the privilege-separation directory at /usr/share/empty.sshd; confirm the installed package file list and permissions. The isolated server includes only the system crypto-policy backend, and the client reads only its crypto backend. Normal SSH connection/authorization configuration is not imported. Stop on a missing policy file, unsupported syntax or a policy that prohibits this certificate; inspect the installed package/policy rather than weakening it.

bash

Authorized terminal on the host identified in this section

cat /etc/os-release
rpm -q openssh-server openssh-clients iproute policycoreutils-python-utils audit
command -v ssh ssh-keygen ss
systemctl show sshd.service -p ActiveState -p FragmentPath
sudo test -x /usr/sbin/sshd
rpm -ql openssh-server | grep -E '/empty\.sshd$|/sshd-session$'
sudo stat -c '%U %G %a %n' /usr/share/empty.sshd
sudo test -r /etc/crypto-policies/back-ends/opensshserver.config || exit 1
sudo test -r /etc/crypto-policies/back-ends/openssh.config || exit 1
update-crypto-policies --show
How do I know it worked?

Required packages and tools are identified; resolve missing tools before continuing.

02

LET’S BUILD

Confirm the account, port and exclusive directory

Use a disposable VM with the OpenSSH server already installed and a known unlocked non-root lab account labuser. Keep your normal administration session open. A missing account, locked account or occupied port is a stop condition. The sample does not create/unlock accounts or alter PAM policy. Verify the chosen path is new and not a symlink, mount or application data directory.

bash

Authorized Linux terminal

date -u +'%Y-%m-%dT%H:%M:%SZ'
ssh -V
getent passwd 'labuser'
test "$(id -u 'labuser')" -ne 0 || exit 1
sudo ss -lntp 'sport = :22222'
sudo test ! -e '/var/lib/academy-ssh-cert-lab' || exit 1
sudo mkdir -m 0700 -- '/var/lib/academy-ssh-cert-lab'
How do I know it worked?

The existing non-root account is correct, the port is unoccupied and the new root-only lab directory exists.

03

LET’S BUILD

Create separate CA, user and host key roles

Generate three RSA3072 keys on this path. Protect the CA and user keys with interactive passphrases; the noninteractive lab host key remains root-only0600. Ed25519 is unavailable in FIPS mode; do not weaken system crypto policy. The host-key filename matches the standard SELinux host-key labeling pattern.

bash

Authorized Linux terminal

sudo ssh-keygen -t rsa -b 3072 -f '/var/lib/academy-ssh-cert-lab/user-ca' -C academy-lab-ca
sudo ssh-keygen -t rsa -b 3072 -f '/var/lib/academy-ssh-cert-lab/client' -C academy-lab-user
sudo ssh-keygen -t rsa -b 3072 -N '' -f '/var/lib/academy-ssh-cert-lab/ssh_host_rsa_key' -C academy-lab-host
sudo ssh-keygen -lf '/var/lib/academy-ssh-cert-lab/user-ca.pub'
sudo ssh-keygen -lf '/var/lib/academy-ssh-cert-lab/ssh_host_rsa_key.pub'
How do I know it worked?

Three independent keypairs exist with private files confined to the lab. Record public fingerprints, not private material.

04

LET’S BUILD

Create the explicit principal-to-account mapping

The privileged daemon reads a root-owned principals file for the selected account. It must contain exactly the allowed principal, not a wildcard. Initially the separate RevokedKeys file is an empty readable text file; later it will be atomically replaced by a KRL. An unreadable RevokedKeys file can fail all public-key authentication, so readability is a security and availability requirement.

AuthorizedPrincipalsFile may be opened after switching to the target account. Give the root-owned parent traverse-only access0711 and public principals0644 under0755; keep every private key root-owned0600. This exposes only known public paths, not directory listing or private keys, and prevents a false login failure caused by the initial0700 lab root.

bash

Authorized Linux terminal

sudo chmod 0600 '/var/lib/academy-ssh-cert-lab/user-ca' '/var/lib/academy-ssh-cert-lab/client' '/var/lib/academy-ssh-cert-lab/ssh_host_rsa_key'
sudo chmod 0711 '/var/lib/academy-ssh-cert-lab'
sudo install -d -m 0755 '/var/lib/academy-ssh-cert-lab/principals'
printf '%s\n' 'academy-operator' | sudo tee '/var/lib/academy-ssh-cert-lab/principals/labuser' >/dev/null
sudo chmod 0644 '/var/lib/academy-ssh-cert-lab/principals/labuser'
sudo install -m 0644 /dev/null '/var/lib/academy-ssh-cert-lab/revoked'
sudoedit '/var/lib/academy-ssh-cert-lab/sshd_config'
How do I know it worked?

A root-owned explicit account mapping and readable empty revocation file exist; edit only the new lab config.

Bind the isolated daemon only to loopback

Import only the system-generated crypto-policy algorithm backend, not the main sshd_config or its listener/authorization settings. The remaining explicit directives constrain this separate daemon to loopback, one existing account and a fixed command. Passwords, unsigned public keys, interactive shells and forwarding remain disabled for this listener. Never install this over administration SSH configuration.

text · /var/lib/academy-ssh-cert-lab/sshd_config

File contents — not a shell command

Include /etc/crypto-policies/back-ends/opensshserver.config
Port 22222
ListenAddress 127.0.0.1
HostKey /var/lib/academy-ssh-cert-lab/ssh_host_rsa_key
PidFile none
UsePAM yes
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
AuthenticationMethods publickey
AuthorizedKeysFile none
TrustedUserCAKeys /var/lib/academy-ssh-cert-lab/user-ca.pub
AuthorizedPrincipalsFile /var/lib/academy-ssh-cert-lab/principals/%u
RevokedKeys /var/lib/academy-ssh-cert-lab/revoked
AllowUsers labuser
PermitRootLogin no
DisableForwarding yes
X11Forwarding no
PermitTTY no
ForceCommand /usr/bin/id
LogLevel VERBOSE
Explore all tutorials ↗