Skip to main content

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 Support

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

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 v15.4.22 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 $
note

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.

Headless Confirmation

You will be prompted to tap your MFA key to complete the approval process.

Headless WebAuthn Approval

note

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.