opkssh is a tool which enables ssh to be used with OpenID Connect allowing SSH access to be managed via identities like [email protected]
instead of long-lived SSH keys.
It does not replace SSH, but instead generates SSH public keys containing PK Tokens and configures sshd to verify them. These PK Tokens contain standard OpenID Connect ID Tokens. This protocol builds on the OpenPubkey which adds user public keys to OpenID Connect without breaking compatibility with existing OpenID Provider.
Currently opkssh is compatible with Google, Microsoft/Azure, Gitlab, hello.dev, and Authelia OpenID Providers (OP). See below for the entire list. If you have a gmail, microsoft or a gitlab account you can ssh with that account.
To ssh with opkssh you first need to download the opkssh binary and then run:
opkssh login
This opens a browser window where you can authenticate to your OpenID Provider. This will generate an SSH key in ~/.ssh/id_ecdsa
which contains your OpenID Connect identity.
Then you can ssh under this identity to any ssh server which is configured to use opkssh to authenticate users using their OpenID Connect identities.
For updates and announcements join the OpenPubkey mailing list.
To ssh with opkssh, Alice first needs to install opkssh using homebrew or manually downloading the binary.
To install with homebrew run:
brew tap openpubkey/opkssh
brew install opkssh
To install with winget run:
winget install openpubkey.opkssh
To install manually, download the opkssh binary and run it:
Download URL | |
---|---|
π§ Linux (x86_64) | github.com/openpubkey/opkssh/releases/latest/download/opkssh-linux-amd64 |
π§ Linux (ARM64/aarch64) | github.com/openpubkey/opkssh/releases/latest/download/opkssh-linux-arm64 |
π OSX (x86_64) | github.com/openpubkey/opkssh/releases/latest/download/opkssh-osx-amd64 |
π OSX (ARM64/aarch64) | github.com/openpubkey/opkssh/releases/latest/download/opkssh-osx-arm64 |
β Win | github.com/openpubkey/opkssh/releases/latest/download/opkssh-windows-amd64.exe |
To install on Windows run:
curl https://github.com/openpubkey/opkssh/releases/latest/download/opkssh-windows-amd64.exe -o opkssh.exe
To install on OSX run:
curl -L https://github.com/openpubkey/opkssh/releases/latest/download/opkssh-osx-amd64 -o opkssh; chmod +x opkssh
To install on linux, run:
curl -L https://github.com/openpubkey/opkssh/releases/latest/download/opkssh-linux-amd64 -o opkssh; chmod +x opkssh
or for ARM
curl -L https://github.com/openpubkey/opkssh/releases/latest/download/opkssh-linux-arm64 -o opkssh; chmod +x opkssh
After downloading opkssh run:
opkssh login
This opens a browser window to select which OpenID Provider you want to authenticate against.
After successfully authenticating opkssh generates an SSH public key in ~/.ssh/id_ecdsa
which contains your PK Token.
By default this ssh key expires after 24 hours and you must run opkssh login
to generate a new ssh key.
Since your PK Token has been saved as an SSH key you can SSH as normal:
This works because SSH sends the public key written by opkssh in ~/.ssh/id_ecdsa
to the server and sshd running on the server will send the public key to the opkssh command to verify. This also works for other protocols that build on ssh like sftp or ssh tunnels.
sftp [email protected]
Instructions
Tell opkssh to store the name the key-pair opkssh_server_group1
opkssh login -i opkssh_server_group1
Tell ssh to use the generated key pair.
ssh -o "IdentitiesOnly=yes" -i ~/.ssh/opkssh_server_group1.pub -i ~/.ssh/opkssh_server_group1 [email protected]
We recommend specifying -o "IdentitiesOnly=yes"
as it tells ssh to only use the provided key. Otherwise ssh will cycle through other keys in ~/.ssh
first and may not get to the specified ones. Servers are configured to only allow 6 attempts by default the config key is MaxAuthTries 6
.
To configure a linux server to use opkssh simply run (with root level privileges):
wget -qO- "https://raw.githubusercontent.com/openpubkey/opkssh/main/scripts/install-linux.sh" | sudo bash
This downloads the opkssh binary, installs it as /usr/local/bin/opkssh
, and then configures ssh to use opkssh as an additional authentication mechanism.
To allow a user, [email protected]
, to ssh to your server as root
, run:
sudo opkssh add root [email protected] google
To allow a group, ssh-users
, to ssh to your server as root
, run:
sudo opkssh add root oidc:groups:ssh-users google
We use two features of SSH to make this work.
First we leverage the fact that SSH public keys can be SSH certificates and SSH Certificates support arbitrary extensions.
This allows us to smuggle your PK Token, which includes your ID Token, into the SSH authentication protocol via an extension field of the SSH certificate.
Second, we use the AuthorizedKeysCommand
configuration option in sshd_config
(see sshd_config manpage) so that the SSH server will send the SSH certificate to an installed program that knows how to verify PK Tokens.
OS | Supported | Tested | Version Tested | Possible Future Support |
---|---|---|---|---|
Linux | β | β | Ubuntu 24.04.1 LTS | - |
OSX | β | β | OSX 15.3.2 (Sequoia) | - |
Windows11 | β | β | Windows 11 | - |
OS | Supported | Tested | Version Tested | Possible Future Support |
---|---|---|---|---|
Linux | β | β | Ubuntu 24.04.1 LTS | - |
Linux | β | β | Centos 9 | - |
Linux | β | β | Arch Linux | - |
OSX | β | β | - | Likely |
Windows11 | β | β | - | Likely |
All opkssh configuration files are space delimited and live on the server.
/etc/opk/providers
contains a list of allowed OPs (OpenID Providers), a.k.a. IDPs.
This file functions as an access control list that enables admins to determine the OpenID Providers and Client IDs they wish to rely on.
- Column 1: Issuer URI of the OP
- Column 2: Client-ID, the audience claim in the ID Token
- Column 3: Expiration policy, options are:
24h
- user's ssh public key expires after 24 hours,48h
- user's ssh public key expires after 48 hours,1week
- user's ssh public key expires after 1 week,oidc
- user's ssh public key expires when the ID Token expiresoidc-refreshed
- user's ssh public key expires when their refreshed ID Token expires.
By default we use 24h
as it requires that the user authenticate to their OP once a day. Most OPs expire ID Tokens every one to two hours, so if oidc
the user will have to sign multiple times a day. oidc-refreshed
is supported but complex and not currently recommended unless you know what you are doing.
The default values for /etc/opk/providers
are:
# Issuer Client-ID expiration-policy
https://accounts.google.com 206584157355-7cbe4s640tvm7naoludob4ut1emii7sf.apps.googleusercontent.com 24h
https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0 096ce0a3-5e72-4da8-9c86-12924b294a01 24h
/etc/opk/providers
requires the following permissions (by default we create all configuration files with the correct permissions):
sudo chown root:opksshuser /etc/opk/providers
sudo chmod 640 /etc/opk/providers
/etc/opk/auth_id
is the global authorized identities file.
This is a server wide file where policies can be configured to determine which identities can assume what linux user accounts.
Linux user accounts are typically referred to in SSH as principals and we continue the use of this terminology.
- Column 1: The principal, i.e., the account the user wants to assume
- Column 2: Email address or subject ID of the user (choose one)
- Email - the email of the identity
- Subject ID - an unique ID for the user set by the OP. This is the
sub
claim in the ID Token. - Group - the name of the group that the user is part of. This uses the
groups
claim which is presumed to be an array. The group identifier uses a structured identifier. I.e.oidc:groups:{groupId}
. Replace thegroupId
with the id of your group.
- Column 3: Issuer URI
# email/sub principal issuer
alice [email protected] https://accounts.google.com
guest [email protected] https://accounts.google.com
root [email protected] https://accounts.google.com
dev [email protected] https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0
# Group identifier
dev oidc:groups:developer https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0
To add new rule run:
sudo opkssh add {USER} {EMAIL/SUB/GROUP} {ISSUER}
These auth_id
files can be edited by hand or you can use the add command to add new policies.
For convenience you can use the shorthand google
or azure
rather than specifying the entire issuer.
This is especially useful in the case of azure where the issuer contains a long and hard to remember random string. For instance:
sudo opkssh add dev [email protected] azure
/etc/opk/auth_id
requires the following permissions (by default we create all configuration files with the correct permissions):
sudo chown root:opksshuser /etc/opk/auth_id
sudo chmod 640 /etc/opk/auth_id
This is a local version of the auth_id file.
It lives in the user's home directory (/home/{USER}/.opk/auth_id
) and allows users to add or remove authorized identities without requiring root level permissions.
It can only be used for user/principal whose home directory it lives in.
That is, if it is in /home/alice/.opk/auth_id
it can only specify who can assume the principal alice
on the server.
# email/sub principal issuer
alice [email protected] https://accounts.google.com
# Group identifier
dev oidc:groups:developer https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0
It requires the following permissions:
chown {USER}:{USER} /home/{USER}/.opk/auth_id
chmod 600 /home/{USER}/.opk/auth_id
We use a low privilege user for the SSH AuthorizedKeysCommandUser. Our install script creates this user and group automatically by running:
sudo groupadd --system opksshuser
sudo useradd -r -M -s /sbin/nologin -g opksshuser opksshuser
We then add the following lines to /etc/ssh/sshd_config
AuthorizedKeysCommand /usr/local/bin/opkssh verify %u %k %t
AuthorizedKeysCommandUser opksshuser
To log in using a custom OpenID Provider, run:
opkssh login --provider="{ISSUER},{CLIENT_ID}"
or in the rare case that a client secret is required by the OpenID Provider:
opkssh login --provider="{ISSUER},{CLIENT_ID},{CLIENT_SECRET},{SCOPES}"
where ISSUER, CLIENT_ID and CLIENT_SECRET correspond to the issuer client ID and client secret of the custom OpenID Provider.
For example if the issuer is https://authentik.local/application/o/opkssh/
and the client ID was ClientID123
:
opkssh login --provider="https://authentik.local/application/o/opkssh/,ClientID123"
to specify scopes
opkssh login --provider="https://authentik.local/application/o/opkssh/,ClientID123,,openid profile email groups"
You can use this shortcut which will use a provider alias to find the provider.
opkssh login authentik
This alias to provider mapping be can configured using the OPKSSH_PROVIDERS environment variables.
Rather than type in the provider each time, you can create a client config file by running opkssh login --create-config
at
C:\Users\{USER}\AppData\Roaming\.opk\config.yml
on windows and ~/.opk/config.yml
on linux.
You can then edit this config file to add your provider.
config.yml
You can delete any providers you don't plan on using.
If you have a provider you want to open by default, change default_provider
to the name of your alias of your custom provider.
---
default_provider: webchooser
providers:
- alias: google
issuer: https://accounts.google.com
client_id: 206584157355-7cbe4s640tvm7naoludob4ut1emii7sf.apps.googleusercontent.com
client_secret: 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
scopes: openid email profile
access_type: offline
prompt: consent
redirect_uris:
- http://localhost:3000/login-callback
- http://localhost:10001/login-callback
- http://localhost:11110/login-callback
- alias: azure microsoft
issuer: https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0
client_id: 096ce0a3-5e72-4da8-9c86-12924b294a01
scopes: openid profile email offline_access
access_type: offline
prompt: consent
redirect_uris:
- http://localhost:3000/login-callback
- http://localhost:10001/login-callback
- http://localhost:11110/login-callback
- alias: gitlab
issuer: https://gitlab.com
client_id: 8d8b7024572c7fd501f64374dec6bba37096783dfcd792b3988104be08cb6923
scopes: openid email
access_type: offline
prompt: consent
redirect_uris:
- http://localhost:3000/login-callback
- http://localhost:10001/login-callback
- http://localhost:11110/login-callback
- alias: hello
issuer: https://issuer.hello.coop
client_id: app_xejobTKEsDNSRd5vofKB2iay_2rN
scopes: openid email
access_type: offline
prompt: consent
redirect_uris:
- http://localhost:3000/login-callback
- http://localhost:10001/login-callback
- http://localhost:11110/login-callback
Instead of using the opkssh login --provider
flag you can also configure the providers to use with environment variables.
The OPKSSH_PROVIDERS variable follow the standard format with ;
delimiting each provider and ,
delimiting fields with a provider for instance:
{alias},{issuer},{client_id},{client_secret},{scope};{alias},{issuer},{client_id},{client_secret},{scope}...
You can set them in your .bashrc
file so you don't have to type custom settings each time you run opk login
.
export OPKSSH_DEFAULT=WEBCHOOSER
export OPKSSH_PROVIDERS=google,https://accounts.google.com,206584157355-7cbe4s640tvm7naoludob4ut1emii7sf.apps.googleusercontent.com,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;microsoft,https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0,096ce0a3-5e72-4da8-9c86-12924b294a01;gitlab,https://gitlab.com,8d8b7024572c7fd501f64374dec6bba37096783dfcd792b3988104be08cb6923
export OPKSSH_PROVIDERS=$OPKSSH_PROVIDERS;authentik,https://authentik.io/application/o/opkssh/,client_id,,openid profile email
The OPKSSH_DEFAULT can be set to one of the provider's alias to set the default provider to use when running opkssh login
.
WEBCHOOSER will open a browser window to select the provider.
Currently opkssh supports the following redirect URIs. Make sure that the correct redirectURIs have been added at your OpenID Provider:
http://localhost:3000/login-callback
http://localhost:10001/login-callback
http://localhost:11110/login-callback
Do not reuse a client ID between opkssh and other OpenID Connect services. If the same client ID is used for opkssh as another OpenID Connect authentication service, then an SSH server could replay the ID Token sent in an opkssh SSH key to authenticate to that service. Such replay attacks can be ruled out by simply using a new client ID with opkssh.
Note that this requirement of using different client IDs for different audiences and uses is not unique to opkssh and is a best practice in OpenID Connect.
In the /etc/opk/providers
file, add the OpenID Provider as you would any OpenID Provider. For example:
https://authentik.local/application/o/opkssh/ ClientID123 24h
Then add identities to the policy to allow those identities SSH to the server:
opkssh add root [email protected] https://authentik.local/application/o/opkssh/
OpenID Provider | Tested | Notes |
---|---|---|
Authelia | β | Authelia Integration Guide |
Authentik | β | Do not add a certificate in the encryption section of the provider |
Zitadel | β | Check the UserInfo box on the Token Settings |
PocketID | β | Create a new OIDC Client and inside the new client, check "Public client" on OIDC Client Settings |
Do not use Confidential/Secret mode only client ID is needed.
We document how to manually install opkssh on a server here.