Add 03-use-cases/keyless-agent-credentials.md (keyless AWS and tailnet access for off-cloud agents) - #3
Conversation
|
@jonatw thanks for this — the three-leg chain (X.509 → Roles Anywhere → STS outbound OIDC → Tailscale WIF) is exactly the kind of field-tested pattern the map wants, and the [Today]/[Proposed]/[Vision] tagging is great. We ran an independent review against the current octobroker source and AWS/Tailscale docs before merging, and there are five things we'd like to fix first. Proposed fixes below — tell us if you agree (or push back where we're wrong): 1. The 2. octobroker attribution. 3. Trust-anchor revocation is overstated. 4. The SSM section can't execute under its own reference policy. 5. Runbook + citations need a validation pass. Also one small convention nit: consolidate None of this touches your architecture — legs 1–3 and the pluggable-source table survive as-is. If you agree, push the edits and we'll merge; if you'd rather we handle it, say the word and we'll apply them on a branch with full attribution (the map now documents exactly that take-over convention 🙂). 你若覺得哪點不對,直接反駁沒問題! 🤖 Generated with Claude Code |
…ationale Addresses all five review points, plus three errors found while verifying. Review points: 1. "Keyless" scope now excludes the GitHub leg explicitly. That leg is rewritten from scratch: it records what is actually deployed (App private key in the agent runtime, self-minted installation tokens, installation-wide scope, one shared cache, static PAT fallback) rather than claiming a broker. 2. octobroker attribution corrected. It is a standalone community project, not an OpenAB component, and the reference deployment does not run it. Cross-linked to the MCP Facade as the composition point. 3. Trust-anchor revocation no longer overstated. Replaced with a layered model: anchor and CRL act at CreateSession only; aws:TokenIssueTime is the sole lever reaching already-issued sessions; static secrets are outside all of it. Notes that CRL import works with a self-managed CA. 4. SSM contradiction resolved. Tailscale client-id and audience are documented non-secrets and are plain String parameters; storing them as SecureString would be unreadable under the reference role's own deny. Real secrets are a separate class with a separate reader principal. 5. Citations re-verified. Tailscale KB link replaced (the old one redirects to an unrelated page). Condition-key claim carries its test date and region. Additional corrections found during verification: - The "condition keys absent from request context" note was a misdiagnosis and is withdrawn. Both keys exist and are enforced. Audience is multi-valued so it needs ForAllValues:StringEquals; DurationSeconds is optional so it needs NumericLessThanEqualsIfExists. A bare operator on either fails closed, which looks identical to the key being absent. - Runbook: get-web-identity-token requires --signing-algorithm; the token-exchange endpoint takes client_id + jwt, not RFC-8693 parameters; and Tailscale v1.94.0+ can skip the JWT entirely via --client-id + --audience. - Reference config gains the aws:SourceArn confused-deputy guard, wildcarded denies, and sts:AssumeRoot as its own entry. Also merges main so the MCP Facade cross-link resolves on this branch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ulary - Use OpenAB in prose to match every sibling page (the lowercase form was inherited from the source write-up). - Rewrite the sts:AssumeRoot note without the AssumeRo-ot hyphenation, which read like a literal action name inside backticks. State the prefix-expansion rule directly instead. - Component reference: Needs a broker -> Proposed (needs a broker), so every row uses the Today/Proposed/Vision vocabulary declared in the intro. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…e tailnet The old filename was residue from the source write-up's aviation/border metaphor, which this page deliberately dropped — "clearance" appears nowhere in the body, and the name matched neither of the directory's naming patterns. The title now names its own scope. "Keyless" is accurate and searchable for the AWS and tailnet legs, which is what this page delivers; stating those two in the title means a reader meets the GitHub boundary as a stated limit rather than discovering it mid-page. The scope note shortens accordingly — it no longer has to establish what the title already says, so it goes straight to why GitHub is excluded. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three of the six entries (governed community bot, deploy multiple agents, hook into the lifecycle) had no topical relation to credentials and no annotation. Sibling pages only carry lateral use-case links when they are related and explained, so those three are dropped. What is OpenAB is now bound to the 'thin broker' keyword in the intro rather than sitting in a list. The remaining two entries are also inline where they are relevant, and stay listed with the annotations the review asked for. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Thank you @shaun-agent — this was a genuinely careful review, and it deserves a straight answer first: all five points were right, and I should have caught most of them myself. The previous revision was assembled by pulling material out of our codebase and internal notes and stitching it into the use-case format. I checked that the architecture was right; I did not go back and re-verify the prose against the live environment or the current upstream docs. Several claims were true when first written and had quietly stopped being true. Please pass on my thanks to whoever (and whatever) did the independent pass — one of the things you flagged led me to withdraw a load-bearing claim that had been wrong for a while. Everything below is pushed. I re-verified each item against the live deployment or primary docs rather than against my own earlier text. 1. The
|
| Revoking | Lever | Reaches already-issued credentials? |
|---|---|---|
| Future identity issuance | Disable/delete trust anchor | No — new CreateSession only |
| One compromised leaf | rolesanywhere:ImportCrl |
No — checked at CreateSession |
| STS sessions already issued | aws:TokenIssueTime deny |
Yes |
| A static secret already read | Nothing in AWS — rotate at issuer | No |
Two things worth adding for anyone reading this page as a runbook:
- CRL import works with a self-managed CA. Paying for a managed private CA buys automated CRL generation, distribution, and OCSP — not the ability to revoke at all. And no CRL at any price reaches credentials already issued.
aws:TokenIssueTimeis the only instant lever, and it should be the first step in an incident, not trust-anchor deletion. Noted that AWS's own console sets the cutoff at roughly now + 30 seconds to absorb policy propagation.
4. The SSM section cannot execute under its own reference policy — agreed; reality picks your option (a)
Both halves of your fix turned out to be true simultaneously:
- (a) Tailscale documents the client-id and audience as non-secret ("These are not secrets and will be visible in the admin console"), and our live parameters for the paths in use are plain
String— read without--with-decryption, producing nokms:Decrypt. Storing them as SecureString would not just be unnecessary; the reference role's own deny would make them unreadable. - (b) The genuinely secret class is read by a different principal — the container's task role — never the read-only minting role. That is now stated explicitly, along with the limit of what a scoped vault buys: it controls who may retrieve a secret, never what happens to it afterwards.
5. Runbook and citations need a validation pass — agreed, and the condition-key note was flatly wrong
The Tailscale link is confirmed dead: /kb/1317/workload-identity-federation now 302s to /docs/integrations/google-sync, an unrelated page. Replaced with /docs/features/workload-identity-federation.
On the audience/duration note you asked me to date — I withdrew it instead. It was a misdiagnosis of our own operator error, and both keys are enforced in our deployed policy today (verified 2026-08-04, ap-northeast-1, by reading the live inline policy back from IAM). The root cause is visible in the API contract:
AudienceisAudience.member.N— an array of 1–10 strings, sosts:IdentityTokenAudienceis multi-valued. A bareStringEqualsagainst a multi-valued key fails closed, which presents exactly like "the key is absent from the request context." NeedsForAllValues:StringEquals.DurationSecondsis optional (60–3600, default 300) and is only injected when the caller passes it, so a bareNumericLessThanEqualsdenies every call that omits it. NeedsNumericLessThanEqualsIfExists.
You were right that the whole risk-bounding argument rested on that claim. It did, and the argument is now the opposite one: audience lock and duration cap are enforced, not procedural.
Three more the validation pass turned up
Re-running the runbook against primary docs found errors nobody had flagged:
aws sts get-web-identity-tokenrequires--signing-algorithm(RS256orES384). The published command omitted it and would fail outright.- The token-exchange call used RFC-8693 parameters (
grant_type/subject_token/subject_token_type). Tailscale's documented endpoint takes form-encodedclient_id+jwt. - Tailscale client v1.94.0+ can skip the JWT entirely —
--client-idplus--audience, auto-detecting AWS/GCP/GitHub Actions. That is the path our own containerised agents use, and the doc only showed the older manual flow. All three paths are now listed.
The reference config also gained things the deployed policy has and the page did not: the aws:SourceArn confused-deputy guard, wildcarded denies (an enumerated list had missed ssm:GetParameterHistory), and sts:AssumeRoot as its own entry — sts:AssumeRole* expands from the literal prefix AssumeRole and never reaches it.
Convention nit
Done — Related and Sources are consolidated into ## Further Reading, with the secrets-strategy cross-link drawing exactly the distinction you described: OpenAB-owned secrets resolved once at boot and never handed to an agent, versus the agent workload credentials this page covers.
While there I also pruned three lateral use-case links inherited from the old Related block — governed community bot, deploy multiple agents, hook into the lifecycle. They carried no annotation and no topical relation to credentials, which is not how the sibling pages use lateral links; yours explain why the reader should follow them. What is OpenAB moved inline onto the "thin broker" keyword rather than sitting in a list. Say the word if you would rather have the fuller list back.
One heads-up on your end
The mcp-facade.md link you pointed me at 404s from this branch — the branch was cut before that file landed on main, so the relative link resolved to nothing. Merged main in, and it resolves now. Worth knowing if other in-flight PRs are cross-linking recently-added pages.
Rename
The file is now 03-use-cases/keyless-agent-credentials.md, titled Keyless AWS and Tailnet Access for Off-Cloud Agents. The old name was residue from the source write-up's aviation metaphor, which this page deliberately dropped — "clearance" appeared nowhere in the body. Scoping the title means a reader meets the GitHub boundary as a stated limit rather than discovering it mid-page. Happy to revert either if it cuts against how you organise the map — that is your call, not mine.
Thanks again. 你們這輪抓得很準,尤其第 5 點逼我回頭實測,才發現那條 note 早就過期了 —— 這種錯自己是照不出來的。
|
@jonatw the revision is a big step up — 4 of the 5 original points are fully resolved (keyless scoping, octobroker attribution + facade cross-link, revocation semantics, conventions), and the dated condition-key evidence is exactly what we asked for. Three small items still block merge:
Two non-blocking nits while you're in there: octobroker#54 is now closed-completed (and the settled design split Same offer as before: push these three and we merge, or say the word and we'll apply them with attribution per the take-over convention. 🤖 Generated with Claude Code |
Adds a new
03-use-cases/page: Keyless Access for Off-Cloud Agents — how an openab agent running outside AWS obtains scoped, short-lived credentials for AWS, a Tailscale tailnet, and GitHub with no long-lived secret in the container (IAM Roles Anywhere → STS Outbound Identity Federation → Tailscale WIF).Source
Converted from an existing writeup —
keyless-clearance.md— and rewritten to fit openab-map's use-case conventions:03-use-casespages (schedule-agent-tasks,deploy-multi-agent) — no first-person or personal attribution.[Today]/[Proposed]/[Vision]maturity tags, a reference config, an adversarial risk section, and a component table.Relatedfooter links the sibling use-cases and the core "own the layers above" doc.Review ask
Please review for fit and accuracy — happy to adjust voice, depth, or placement.