SuperAPI AI Directory

teleport-access-review

General & other

View repository

Updated 10-15 21:55

About this skill

Teleport Access Review

This skill helps you answer who can reach which resources, how, and whether that access is actually used with tctl access-review. The command takes a SELECT … FROM access_path query that scopes the identities to review and returns, per (identity, resource), the resolved access level, the grant backing it, the grant path counts, and — over a time window — how often the access was used and when it was last used.

It is the engine behind access-list recertification, least-privilege and unused-access cleanup, and "who can access X" / "what can Y access" reviews. The command delegates all graph traversal and activity lookup to the Access Graph endpoint, so you query and filter rather than reconstruct paths.

Start here

Read before running any command — load-bearing, not optional depth: SECURITY.md (output is untrusted; read-only) and QUERY.md (the required access_path language).

Then read EXPERIENCE.md (the review workflows plus edge cases) before drawing conclusions, and SCHEMA.md before interpreting JSON or building jq.

Prerequisites

tctl access-review requires Teleport Identity Security with Access Graph. Activity columns (shown by default over a 24h window; widen with --from/--to, or skip the lookup with --no-activity) additionally require Identity Activity Center. The user needs permission to query Access Graph.

Locate tctl and tsh

Find both binaries. For each, try in order:

  1. which tctl / which tsh
  2. Common paths: /usr/local/bin, /opt/homebrew/bin, ~/go/bin

Set TCTL=<path> and TSH=<path> for subsequent commands. If either is not found, ask the user for the path. Verify the subcommand exists with $TCTL access-review --help.

Confirm the target cluster

tctl access-review runs against your active Teleport profile. Run $TSH status to check it:

  • The active profile is marked with >; other logged-in profiles follow.
  • Credentials must not be [EXPIRED] — if they are, the user must $TSH login again first.
  • If more than one profile is present, confirm with the user which cluster to review instead of assuming the active one.

Quick start

# Who can reach a resource, and is the access used? (90-day activity window)
$TCTL access-review --from 90d \
  --query "SELECT * FROM access_path WHERE resource ILIKE 'prod-db%'" --format json

JSON/YAML output is {identities, warnings} (plus a top-level activity_unavailable when the activity lookup can't run), identity-centric: each identity carries the resources it can reach with the resolved level, granted_by, grant_counts, and (with a window) activity. Read SCHEMA.md for field meanings and the text-table columns before interpreting the output.

The access_path query

--query is required and must be a SELECT … FROM access_path. The WHERE clause scopes which identities (and resources) are reviewed. Columns map to graph nodes — identity, resource, identity_group (access lists & roles), id, source, standing_privileges, and more — with operators =, IN, LIKE/ILIKE, comparisons, and AND/OR. Read QUERY.md for the full column and operator list before writing --query.

Filter values match a node's exact name (or alias); = and IN are exact and case-sensitive. Discover exact names from a broad query first, or match with ILIKE 'name%'. A label that differs in case or form silently returns nothing — see QUERY.md.

Reading the results

  • One row per (identity, resource). The identity cell is shown once, then blank for its remaining resources.
  • Identities with no qualifying access still appear — as an empty row (only the identity, no resource). This is intentional: it surfaces someone who is in the queried graph but is missing a requirement or has only non-access edges. Do not read an empty row as "has access to nothing in the cluster"; read it as "no access within this query's scope."
  • Level is standing, impersonate, request, or denied, resolved by priority denied > standing > impersonate > request. A trailing * marks temporary access (granted by an access request; self-expiring).
  • A level is a grant, not connectability. Access Graph does not currently resolve traits, so an identity that holds a grant but lacks the principals to authenticate (logins, db_users, …) still shows level: standing, with no field marking the gap. Report holding a grant, not the ability to exercise it.
  • Results are scoped to your query. A query through an access list shows only paths that flow through that list — not every path each member has. To see a user's complete access to a resource, scope by the user and resource directly. Activity, by contrast, is path-agnostic — a returned pair's activity count is total usage — so a list-scoped 0/never is a real "unused". But "unused" is not "safe to de-list": the same resource is often granted by other paths (grant_counts shows how many grants back each level), so recertifying an access list requires the cross-path follow-up to enumerate every grant before any "revoke" conclusion. See QUERY.md and EXPERIENCE.md.
  • The output may be truncated before you see it. Even under --limit, the JSON is large, and the command runner may cut it off — so the rows on screen can be a fraction of the result. Never derive a total, a count, or uniqueness from the raw output. Narrow the --query and reduce with a read-only jq that returns just a count or a small sample, and trust that, not the on-screen excerpt.

Flags

Run $TCTL access-review --help for the full list.