Headless WebAuthn
Headless WebAuthn provides a secure way to authenticate with WebAuthn from a machine without access to a WebAuthn device. This enables the use of WebAuthn features which are usually not usable in WebAuthn-incompatible environments. For example:
- Logging into Teleport with WebAuthn from a remote dev box
- Connecting to a Teleport SSH Service from a remote dev box with per-session MFA
- Performing
tsh scp
from one Teleport SSH Service to another with per-session MFA - Logging into Teleport on a machine without a WebAuthn-compatible browser
Headless WebAuthn only supports the following tsh
commands:
tsh ls
tsh ssh
tsh scp
In the future, Headless WebAuthn will be extended to other tsh
commands.
Prerequisites
- A v12.2+ Teleport cluster with WebAuthn configured. See the Second Factor: WebAuthn guide.
- WebAuthn hardware device, such as YubiKey.
- Machines for Headless WebAuthn activities have Linux, macOS or Windows
tsh
binary v12.2+ installed. - Machines used to approve Headless WebAuthn requests have a Web browser with WebAuthn support or
tsh
binary v12.2+ installed. - Optional: Teleport Connect v13.3.1+ for seamless Headless WebAuthn approval.
Step 1/3. Configuration
A v12.2+ Teleport cluster capable of WebAuthn is automatically capable of Headless WebAuthn without any additional configuration.
Optional: make Headless WebAuthn the default auth connector
To make Headless WebAuthn the default authentication method for your Teleport
Cluster, add connector_name: headless
to your cluster configuration.
Create a cap.yaml
file or get the existing configuration using
tctl get cluster_auth_preference
:
kind: cluster_auth_preference
version: v2
metadata:
name: cluster-auth-preference
spec:
type: local
second_factor: "on"
webauthn:
rp_id: example.com
connector_name: headless # headless by default
Update the configuration:
$ tctl create -f cap.yaml
# cluster auth preference has been updated
Alternative: disable Headless WebAuthn
Headless WebAuthn is enabled automatically when WebAuthn is configured. If you
want to forbid Headless WebAuthn in your cluster, add headless: false
to your
configuration.
Create a cap.yaml
file or get the existing configuration using
tctl get cluster_auth_preference
:
kind: cluster_auth_preference
version: v2
metadata:
name: cluster-auth-preference
spec:
type: local
second_factor: "on"
webauthn:
rp_id: example.com
headless: false # disable Headless WebAuthn
Update the configuration:
$ tctl create -f cap.yaml
# cluster auth preference has been updated
Step 2/3. Initiate Headless WebAuthn
First open a terminal on the remote machine and confirm the tsh
binary
is v12.2+ with tsh version
.
$ tsh version
Teleport v14.3.33 git: go1.21
Run a headless tsh
command with the --headless
flag. This will initiate
headless authentication, printing a URL and tsh
command.
$ tsh ls --headless --proxy=proxy.example.com --user=alice
# Complete headless authentication in your local web browser:
#
# https://proxy.example.com:3080/web/headless/86172f78-af7c-5935-a7c1-ed06b94f17dc
#
# or execute this command in your local terminal:
#
# tsh headless approve --user=alice --proxy=proxy.example.com 86172f78-af7c-5935-a7c1-ed06b94f17dc
Step 3/3. Approve Headless WebAuthn
To approve the headless authentication, click or copy+paste the URL printed by
tsh
in your local web browser. You will be prompted to approve the log in with
WebAuthn verification. Once approved, your initial tsh --headless <command>
should continue as if you had logged in locally.
Unlike a standard login session, headless sessions are only available for the
lifetime of a single tsh
request. This means that for each tsh --headless
command, you will need to go through the Headless WebAuthn flow:
Example: Listing SSH servers
$ tsh ls --headless --proxy=proxy.example.com --user=alice
# Complete headless authentication in your local web browser:
#
# https://proxy.example.com:3080/web/headless/86172f78-af7c-5935-a7c1-ed06b94f17dc
#
# or execute this command in your local terminal:
#
# tsh headless approve --user=alice --proxy=proxy.example.com 86172f78-af7c-5935-a7c1-ed06b94f17dc
# # User approves through link
# Node Name Address Labels
# --------- -------------- -----------
# server01 127.0.0.1:3022 arch=x86_64
Example: Initiating an SSH session
$ tsh ssh --headless --proxy=proxy.example.com --user=alice alice@server01
# Complete headless authentication in your local web browser:
#
# https://proxy.example.com:3080/web/headless/864cccd9-2425-46d9-a9f2-636387e66ebf
#
# or execute this command in your local terminal:
#
# tsh headless approve --user=alice --proxy=proxy.example.com 864cccd9-2425-46d9-a9f2-636387e66ebf
# # User approves through link and a ssh terminal starts
alice@server01 $
The Teleport user, --user
parameter, is the Teleport user requesting Headless WebAuthn activity.
If no --user
parameter or environment variables set the OS user in the machine terminal is used.
The login username, --login
parameter or login@hostname, for tsh ssh
commands is the user
to open a SSH session as. If no login username for the SSH session is set the OS terminal username is used.
A Teleport user must have access to that login user for that server or they will receive
an access denied message. The user could receive an access denied message after being approved
for their Headless WebAuthn activity since the same access rights are granted or denied as if running from
your local terminal.
Optional: Teleport Connect
Teleport Connect v13.3.1+ can also be used to approve Headless WebAuthn logins. Teleport Connect will automatically detect the Headless WebAuthn login attempt and allow you to approve or cancel the request.
You will be prompted to tap your MFA key to complete the approval process.
This also requires a v13.3.1+ Teleport Auth Service.
Troubleshooting
"WARN: Failed to lock system memory for headless login: ..."
When using Headless WebAuthn, tsh
does not write private key and certificate data
to disk(~/.tsh
). Instead, tsh
holds these secrets in memory for the duration of
the request. Additionally, it will try to lock the process memory to further protect
the secrets from being stolen by other users on a shared machine.
Below are some of the specific warning messages you may run into and how to fix them:
"operation not permitted" OR "cannot allocate memory"
In order to lock the process memory, your OS user must have permission to lock
the amount of memory needed. Use ulimit -l
to check your OS user's current limit.
The exact amount of memory needed may vary from system to system, so we recommend
updating your ulimit to unlimited, with either ulimit -l unlimited
or by adding
the line <os_username> hard memlock unlimited
to your /etc/security/limits.conf
.
"memory locking is not supported on non-linux operating systems"
The mlockall
syscall is only supported on Linux operating systems. This means
that on other operating systems, the memory lock attempt will always fail and
output the warning. We recommend only using Headless WebAuthn on Linux machines
for the best level of security on shared machines.
Disable mlock
If the above solutions are not feasible in your environment, you can also disable
the memory locking requirement by setting the --mlock
flag or TELEPORT_MLOCK_MODE
environment variable to off
or best_effort
. This is not recommended in production
environments on shared systems where a memory swap attack is possible.