ssoossh.yaml reference
Every setting in the client’s ssoossh.yaml, grouped as the file itself groups
them. Only server has no working default, so a usable file can be
one line.
For where the file is looked for, how several of them combine, and which source
wins, see Client configuration. The same
content ships as the ssoossh.yaml(5) man page and as the annotated
/etc/ssoossh/ssoossh.yaml installed by the .deb and .rpm packages.
Server and trust
Section titled “Server and trust”| Key | Type | Default |
|---|---|---|
server |
string | empty |
capubkey |
string or list | empty |
insecure_skip_verify |
bool | false |
request_timeout |
duration | 2m |
server
Section titled “server”string, default empty
Base URL of the ssoosshd server, including the scheme. If the scheme is
omitted, https is assumed. There is no default, and every command that talks
to the server fails without it. --server overrides it for one invocation.
server: "https://ssh.example.com"capubkey
Section titled “capubkey”string or list of strings, default empty
The server’s CA public key, in authorized_keys format. When set, the client
skips asking the server for the CA key entirely, which pins the key rather than
trusting a fetched one, and is the only form reported to the server as a
trusted CA so an approval page can warn before this client refuses a
certificate.
capubkey: "ecdsa-sha2-nistp384 AAAAE2VjZHNh... ssoossh-ca"A list holds more than one, which is what a CA rotation needs: both keys are live at once while the old one ages out, and a client trusting only one would refuse half the certificates issued in between.
capubkey: - "ecdsa-sha2-nistp384 AAAAE2VjZHNh... ssoossh-ca-old" - "ecdsa-sha2-nistp384 AAAAE2VjZHNh... ssoossh-ca-new"When empty, the client fetches the key from the server and caches it, so later commands neither pay a round trip nor fail while the server is restarting. See the CA key cache.
The CA key cache
Section titled “The CA key cache”With no capubkey set, the client stores the keys it fetched and reuses them
for a day before asking again. This is what keeps a client working while the
server is down: an already-valid certificate is reused without any network
call, where before the client failed at startup fetching a key it already
had.
| Platform | Path |
|---|---|
| Linux, macOS | $XDG_CACHE_HOME/ssoossh/ca.json, else ~/.cache/ssoossh/ca.json |
| Windows | %LocalAppData%\ssoossh\ca.json |
Deliberately not the configuration file. The per-user config outranks the
system one, so a cached key written there would silently shadow a capubkey
an administrator set in /etc/ssoossh/ssoossh.yaml afterwards.
A refresh that fails changes nothing: the cached keys stay in use and the
command carries on. A refresh with something already cached is given two
seconds, because the client runs from Match exec with ssh waiting on it.
It is a cache, not a trust decision. The keys are used only to recognise this
client’s own certificates, never to verify a host, and they are never
reported to the server as pinned. If the server’s key set is ever replaced
outright the client adopts the new one and warns, since it cannot tell a
rotation it slept through from a server rebuilt around a new CA. Set
capubkey to refuse a change instead of adopting it.
insecure_skip_verify
Section titled “insecure_skip_verify”bool, default false
Skip TLS certificate verification when talking to server. For development
against a self-signed certificate only; it defeats the point of pinning
capubkey above.
insecure_skip_verify: falserequest_timeout
Section titled “request_timeout”duration, default 2m
The longest one ordinary call to the server may take, from connect to the
last byte of the answer. Without it, a server that accepts the connection and
never answers would hang the client, and under Match exec that hangs ssh.
It does not limit the wait for a browser approval, which the server bounds
with its own cert_options.client_timeout.
A service certificate retrieval waits on signing, which the server bounds at
a tenth of cert_options.client_timeout (30 seconds with the server’s default
of 5 minutes). Raise request_timeout if that server setting is above 20
minutes. Zero and negative values are refused.
request_timeout: 2mKey storage
Section titled “Key storage”| Key | Type | Default |
|---|---|---|
use_agent |
bool | true |
fallback_file_agent |
bool | true |
key_filename |
string | id_ssoossh |
use_agent
Section titled “use_agent”bool, default true
Keep keys and certificates in a running ssh-agent rather than in files. This is
the recommended mode, and the only mode ssoossh ssh proxycommand supports:
ssh reads key files once at startup and never sees a certificate written
after that.
Setting it to false means the agent is not consulted at all, not merely
deprioritized – keys and certificates always go to the files named by
key_filename.
use_agent: truefallback_file_agent
Section titled “fallback_file_agent”bool, default true
What to do when an agent was wanted but none could be reached: fall back to key
files (true), or fail the command (false). It has no effect when
use_agent is false, since file storage is already in use in that case.
--debug reports both the preference and the backend that actually resolved,
so a use_agent: true that ended up on files is visible rather than silent.
fallback_file_agent: truekey_filename
Section titled “key_filename”string, default id_ssoossh
Base name (or path) for the key and certificate files, used when use_agent is
false or when the fallback above took effect. A bare name resolves inside
~/.ssh, a ~/... path is expanded, and an absolute path is used as given.
The public key and certificate are written beside it as <name>.pub and
<name>-cert.pub.
key_filename: id_ssoosshKey generation
Section titled “Key generation”A fresh keypair is generated for every certificate request, so this is not a
long-lived identity file. Both sshkey sub-keys are optional.
| Key | Type | Default |
|---|---|---|
sshkey.type |
string | ecdsa |
sshkey.size |
int | 0 (per-algorithm default) |
fips |
bool | unset |
sshkey.type
Section titled “sshkey.type”string, default ecdsa
The key algorithm: ed25519, ecdsa, or rsa. The default is ECDSA P-384
unconditionally, whether or not FIPS steering is in effect. --key-type
overrides it for ssoossh ssh login.
ed25519 stays selectable but is not the default: it only entered FIPS 186-5
in 2023 and several FIPS policies still reject it outright. While FIPS steering
is in effect, choosing an algorithm that is not FIPS-approved (ecdsa and
rsa are the approved ones) is a hard error at config-load time, not a
warning. The way around it is to disable fips, not to pick a different type
while it stays on.
sshkey: type: ecdsasshkey.size
Section titled “sshkey.size”int, default 0 (per-algorithm default)
What this means depends on type:
type |
size means |
Accepted | Default |
|---|---|---|---|
ed25519 |
nothing; it has one size | – | ignored, and a nonzero value produces a warning |
ecdsa |
the NIST curve | 256, 384, 521 | 384 |
rsa |
the modulus in bits | at least 2048 | 3072 |
RSA key generation costs on the order of hundreds of milliseconds and is highly
variable; ecdsa and ed25519 are effectively instant. Since a fresh key is
generated on every certificate request, that cost is paid every time rather
than once. --key-size overrides this for ssoossh ssh login.
sshkey: size: 384bool, default unset
Steers key generation toward algorithms that SSH implementations running in
FIPS mode accept. When in effect, a non-approved sshkey.type is a hard error
at config-load time.
Left unset deliberately, in which case it follows whether the running binary is
itself in Go’s FIPS 140-3 mode. Set it explicitly to target a FIPS-mode server
from a client that is not itself in FIPS mode, or to false as the escape
hatch – unless a system enforce file locks fips: true, which wins
regardless.
This setting only affects the client’s own algorithm checks. Unlike the server,
there is no per-install hook here that also sets GODEBUG=fips140=only in the
binary’s environment; an operator wanting runtime-layer enforcement beneath
these checks sets it themselves, in the shell profile or wrapper that invokes
ssoossh.
fips: trueCertificate extensions
Section titled “Certificate extensions”| Key | Type | Default |
|---|---|---|
certificate_extensions.no_pty |
bool | false |
certificate_extensions.no_agent_forwarding |
bool | false |
certificate_extensions.no_port_forwarding |
bool | false |
certificate_extensions.no_x11_forwarding |
bool | false |
certificate_extensions.no_user_rc |
bool | false |
certificate_extensions
Section titled “certificate_extensions”ssoossh ssh login requests the full interactive extension set by default:
permit-pty, permit-agent-forwarding, permit-port-forwarding,
permit-X11-forwarding, and permit-user-rc. Each key below is an opt-out
from that set: false (the default) requests the extension, true does not.
The effective set is the default, minus these config opt-outs, minus the
matching --no-* flags, minus anything platform-native policy forbids – in
that order. A flag cannot re-add what policy forbids.
Requesting the full set is always safe: the server narrows the request against its own configuration before signing, and the approval page shows what survived. Requesting nothing is not useful, because narrowing is an intersection – an empty request yields a certificate carrying no extensions at all, which cannot open an interactive session.
certificate_extensions: no_pty: false no_agent_forwarding: false no_port_forwarding: false no_x11_forwarding: false no_user_rc: falsecertificate_extensions.no_pty
Section titled “certificate_extensions.no_pty”bool, default false
Do not request permit-pty. Without that extension the certificate cannot open
an interactive terminal. Overridden by --no-pty.
certificate_extensions: no_pty: falsecertificate_extensions.no_agent_forwarding
Section titled “certificate_extensions.no_agent_forwarding”bool, default false
Do not request permit-agent-forwarding. Overridden by
--no-agent-forwarding.
certificate_extensions: no_agent_forwarding: falsecertificate_extensions.no_port_forwarding
Section titled “certificate_extensions.no_port_forwarding”bool, default false
Do not request permit-port-forwarding. Overridden by --no-port-forwarding.
certificate_extensions: no_port_forwarding: falsecertificate_extensions.no_x11_forwarding
Section titled “certificate_extensions.no_x11_forwarding”bool, default false
Do not request permit-X11-forwarding. Overridden by --no-x11-forwarding.
certificate_extensions: no_x11_forwarding: falsecertificate_extensions.no_user_rc
Section titled “certificate_extensions.no_user_rc”bool, default false
Do not request permit-user-rc, which is what lets ~/.ssh/rc run on login.
Overridden by --no-user-rc.
certificate_extensions: no_user_rc: falseBrowser, administration, and reserved keys
Section titled “Browser, administration, and reserved keys”| Key | Type | Default |
|---|---|---|
try_open_browser |
bool | false |
enforce |
string | empty |
username |
string | empty |
try_open_browser
Section titled “try_open_browser”bool, default false
Make a best-effort attempt to launch the system browser at the approval URL
during ssoossh ssh login. Strictly best-effort: the URL is always printed
first, so a headless machine with no browser can still complete a login by
hand, and a launch failure is reported and otherwise ignored.
try_open_browser: trueenforce
Section titled “enforce”string, default empty
Names another YAML file whose settings a user cannot override: it is merged
after the per-user file and --config.
Only honored when read from the machine-wide file
(/etc/ssoossh/ssoossh.yaml, or %ProgramData%\ssoossh\ssoossh.yaml on
Windows). A bare filename resolves next to that file, so naming one cannot
reach a file the user controls. Setting enforce anywhere else has no special
effect. A missing or malformed target is a hard startup error, unlike the
optional files above.
A guardrail, not a security boundary: the client runs as the user, who can
always supply their own binary. The one limit enforced beyond client
cooperation is cert_options.*.valid_duration on the server. Windows and macOS
can lock the same settings through Group Policy and managed preferences instead
– see Client settings enforcement.
# /etc/ssoossh/ssoossh.yaml onlyenforce: ssoossh-locked.yamlusername
Section titled “username”string, default empty
Present in the schema and read by nothing. It was intended to name a service account, but that is chosen by the approver in the web UI instead: enrollment requests are unauthenticated, so the client has no session against which to validate one. Setting it changes nothing.
#username: # has no effect