Skip to content

tbot: add scope support for application services - #69422

Closed
tscolari wants to merge 10 commits into
masterfrom
tscolari/57/scoped-app-access
Closed

tbot: add scope support for application services#69422
tscolari wants to merge 10 commits into
masterfrom
tscolari/57/scoped-app-access

Conversation

@tscolari

@tscolari tscolari commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

closes https://github.com/gravitational/core/issues/57

Changelog: Scoped bots can now issue application-routed certificates through tbot's
application, application-tunnel, and application-proxy services.

Request Flow Diagram scoped-app-access-flow

Extends tbot's application services (output, tunnel, proxy) to work in scoped mode by adding a UsageApp variant to the IssueScopedBotCerts RPC.

  • Adds UsageApp proto message to issuance/v1/service.proto
  • Introduces ScopedUsage type with UsageIdentity() and UsageApp(route) constructors in the tbot identity generator
  • Implements applyUsageApp in the issuance service: scope authorization, app lookup with exact scope match, app session creation, and cert annotation
  • Enables all three application services (output, tunnel, proxy) in scoped mode -- each calls GenerateScoped(..., UsageApp(route)) instead of the unscoped reissue path
  • E2E tests are gated behind TELEPORT_UNSTABLE_AGENT_SCOPE_PIN.

I've created #69429 as something I stumbled upon during this work.

Manual Test Plan

Test Environment

local

Test Cases

  • Application Output

    • Run tbot with scoped: true, oneshot:true and an application output targeting the scoped app
    • Verify tbot exits 0 and writes TLS cert to the destination
    • Inspect cert: OU=usage:apps (apps-only usage)
    • Inspect cert: scope pin present and matches bot's scope
    • Inspect cert: RouteToApp contains correct app name, public addr, cluster name
    • Inspect cert: DisallowReissue=true
    • Inspect cert: no roles or traits encoded
  • Application Tunnel:

    • Run tbot with scoped: true and an application-tunnel service pointing at the scoped app
    • Verify log shows "Listening for proxy connections"
    • Verify HTTP request with Host: is proxied to the correct backend
    • Verify request with Host: fails (not proxied)
  • Application Proxy:

    • Run tbot with scoped: true and an application-proxy service
    • Verify log shows "Listening for proxy connections"
    • Verify HTTP request with Host: is proxied to the correct backend
    • Verify request with Host: fails (not proxied)
  • Scope Enforcement

    • Target an unscoped app (registered by the main teleport process) — verify app "X" not found
    • Target a non-existent app name — verify app "X" not found

These guard the implementation of the feature ensuring the outcome is
as expected.
This allows GenerateScoped to have the usage set by the caller.
This also adds the UsageApp as a valid param, and makes sure all
previous calls to GenerateScoped and GenerateScopedFacade now set
UsageIdentity (previous hard coded value).
@tscolari
tscolari force-pushed the tscolari/57/scoped-app-access branch from a54a5e3 to 52dc6f4 Compare August 6, 2026 16:16
Implement the server-side handling for the UsageApp usage in
IssueScopedBotCerts. When a scoped bot requests app-routed certificates,
the service now:

- Validates the requested app scope against the caller's scope pin
- Resolves the app via RangeApplicationServersWithName, ensuring it
  exists in the exact scope claimed
- Rejects Identity Center account apps (not routable, no scoped role
  support for account assignments)
- Creates a scoped app session via CreateAppSessionFromReq
- Annotates the output certificate with app routing and session info
@tscolari
tscolari force-pushed the tscolari/57/scoped-app-access branch from 52dc6f4 to 5d2506d Compare August 6, 2026 16:19
@tscolari
tscolari force-pushed the tscolari/57/scoped-app-access branch from 5d2506d to ea96445 Compare August 6, 2026 16:27
@tscolari
tscolari marked this pull request as ready for review August 6, 2026 18:47
@tscolari tscolari added machine-id scopes Work related to scoped access (RFD 229). labels Aug 6, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ea9644520b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

databaseCAs, err := s.botAuthClient.GetCertAuthorities(ctx, types.DatabaseCA, false)
defer clt.Close()

routeToApp, _, err := getRouteToApp(ctx, s.getBotIdentity(), clt, s.cfg.AppName)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject ambiguous scoped application names

When a bot pinned to a parent scope can see two applications with the same app_name in different descendant scopes, this lookup returns both and getApp silently selects apps[0]; the service configuration has no scope field with which to disambiguate them. The generated credentials, tunnel, or proxy can therefore target whichever scoped application happens to be listed first, potentially forwarding production traffic to the wrong application. Require an explicit scope or reject multiple distinct matches before issuing the routed identity.

Useful? React with 👍 / 👎.

}

// Create a new session.
ws, err := s.authServer.CreateAppSessionFromReq(ctx, sessionreq.NewAppSessionRequest{

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Validate caller keys before persisting the app session

An authenticated scoped bot can supply a nonempty but malformed TLS or SSH public key and a long TTL: this call first creates and persists a valid app session, then the later outer GenerateUserCerts call fails while parsing the caller-controlled key. The RPC returns an error without deleting the newly stored session, so repeated invalid requests accumulate app-session records until expiry and can exhaust backend capacity. Parse the requested keys before creating the session, or delete the session whenever final certificate generation fails.

Useful? React with 👍 / 👎.

@public-teleport-github-review-bot

Copy link
Copy Markdown

@tscolari - this PR will require admin approval to merge due to its size. Consider breaking it up into a series smaller changes.

@tscolari

tscolari commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

@tscolari tscolari closed this Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport/branch/v18 machine-id scopes Work related to scoped access (RFD 229).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant