Enforce MFA for SSH Access Using Teleport Role-Based Access Control
Learn how to create a Teleport role that enforces MFA for SSH access, upload it with tctl, verify login prompts, and recover if users are locked out.
08 Dec 2025, 08:40 UTC

Desired outcome
After completing this guide, users can only establish SSH sessions to managed hosts when they present a valid Teleport certificate and> a second authentication factor (OTP or WebAuthn) enforced by a Teleport role. The Teleport Proxy Service will reject any login attempt that does not satisfy both factors.
Prerequisites
- Teleport Auth Service and Proxy Service running, version ≥12.x.
- An identity provider (OIDC, SAML, or GitHub) already configured and trusted by the Auth Service.
- SSH nodes joined to the Teleport cluster and reachable via the Proxy Service.
- Administrative access to the Teleport cluster (ability to run
tctlcommands against the Auth Service).
Procedure
- Create a role that requires MFA. Save the following YAML to a file, e.g.,
ssh-mfa-role.yaml. Replace{{IDP_GROUP}}with the group name from your IdP that should receive SSH access. - Upload the role to the Auth Service. Run:
This command must be executed on a host with access to the Auth Service's gRPC API (typically the same machine runningtctl create -f ssh-mfa-role.yamltctl). No special flags are needed; the command returns silently on success. - Verify the Proxy Service will enforce MFA. The
require_mfa: trueflag in the role tells the Proxy to prompt for a second factor after the IdP login succeeds. No additional Proxy configuration is required. - Reload the Auth Service to apply the new role. If you are using a self‑managed Teleport binary, send a SIGHUP or restart the service:
In a Kubernetes deployment, roll a restart of the Auth Service pod.systemctl reload teleport # or: teleport start --config=/etc/teleport.yaml - Instruct users to log in. Users should run:
Replacetsh login --proxy=proxy.example.com --auth=oidcproxy.example.comwith your Proxy Service address. After entering IdP credentials, Teleport will display a prompt for the second factor (OTP code or WebAuthn device).
kind: role
version: v5
metadata:
name: ssh-access-mfa
spec:
allow:
logins: ['{{USER}}'] # Teleport will substitute the authenticated username
node_labels:
'*': '*'
rules:
- resources: ['node']
verbs: ['list', 'read', 'ssh']
require_mfa: true
options:
max_session_ttl: 12h
# Map IdP groups to this role
traits:
- to: roles
add: ["ssh-access-mfa"]
match:
- key: "groups"
value: "{{IDP_GROUP}}"
Expected checks
- After a successful login, run
tsh status. The output should include a line similar to:
The presence ofLogged in as {{USER}} via oidc MFA: true Roles: ssh-access-mfaMFA: trueconfirms the second factor was satisfied. - Inspect the audit log for an MFA challenge event:
Look for an entry wheretctl get events --query='event:MFA_CHALLENGE' --format=jsonsuccess: truefollows a login. - Attempt to SSH directly to a node’s SSH port (bypassing Teleport). The connection should be refused or timed out, confirming that access is mediated by Teleport’s enforced gateway.
Recovery options (rollback)
Enabling require_mfa changes the state of the role; if users are locked out, administrators can:
- Temporarily disable MFA for the role:
After users regain access, repeat the edit to settctl get role/ssh-access-mfa > role.yaml # Edit role.yaml, set require_mfa: false tctl update -f role.yamlrequire_mfa: trueand update again. - Issue a one‑time bypass token via the Teleport Web UI or
tctl(requires admin rights) to allow a single login without MFA. - Reset a user’s MFA device in the IdP (e.g., regenerate OTP secret or re‑register WebAuthn) and then have the user repeat the login flow.
After recovery, verify that tsh status again shows MFA: true for normal logins.
Limitations and practical verification
This guide assumes the IdP supplies a groups claim that can be mapped to Teleport roles. If your IdP uses a different attribute, adjust the match block in the role YAML accordingly. Additionally, WebAuthn support requires the Teleport Proxy to be served over HTTPS with a valid certificate; self‑signed certificates will cause the WebAuthn registration to fail silently.
To confirm the configuration works in your environment, perform the expected checks with a test user that is not part of any production‑critical group. Capture the tsh status output and the audit log entry as evidence that both factors were required and satisfied.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.