feat: proxy mode (6.1.0-beta.1) - #20
Open
tomplex wants to merge 5 commits into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a "proxy mode" so consumers can talk to an in-pod Vault Agent's API-proxy listener instead of reading a token file at startup. Released as
6.1.0-beta.1— a new minor so the existing^6.0.0-beta.1ranges in downstreampackage.jsons don't silently absorb it; each consumer's upgrade is an explicit lockfile change.Why
In our k8s deployments, services that import
vault-envrace thevault2-agentsidecar at startup —vault-envreads/vault2/secrets/vault-tokenexactly once on import, and on a cold pod that file doesn't exist yet, so the process throwsExpected VAULT_TOKEN to be setand crash-loops until the agent wins. We've been eating 2–3 restarts per deploy because of this. The fix is to stop reading the file at all: pointVAULT_ADDRat the Vault Agent's local API-proxy listener (http://127.0.0.1:8201), which we configure withuse_auto_auth_token = "force"— the agent injects its auto-auth token on every request, so clients send noX-Vault-Tokenheader. As a bonus, that removes a separate class of bug where the file-read token would silently expire after its TTL.What this PR does
When
VAULT_TOKENis unset:VAULT_ADDRtohttp://127.0.0.1:8201(was:8200, which was never the agent port — it was always the wrong default)./vault2/secrets/vault-tokenfile read entirely (also drops the previous "retry 5 times" loop, which was a no-op anyway —setTimeoutdoesn't block, so thewhilespun to exhaustion synchronously).Expected VAULT_TOKEN to be set.X-Vault-Tokenheader on requests (build the headers object conditionally —undefinedwould otherwise throwERR_HTTP_INVALID_HEADER_VALUE).When
VAULT_TOKENis set, behavior is unchanged — the token is used,VAULT_ADDRdefaults to:8200as before, and the header is sent. So existing consumers passing tokens explicitly (CI tests, anything outside k8s) are unaffected.Plus: the initial synchronous secret fetch now retries with exponential backoff on connection errors and HTTP 5xx (≤ 6 attempts, 0/0.5/1/2/4/8s). 4xx fails fast as before —
RetryAuthFailure(403) remains a hard stop. Implemented viaAtomics.waiton a throwawaySharedArrayBuffer(the only clean way to block synchronously in Node without a busy-loop); neededlib: ["ES2017", "DOM", "ScriptHost"]intsconfig.jsonsincetarget: es5's default lib lacksAtomics/SharedArrayBuffer.Commits
test(vault-env): add proxy-mode test (no token, no header, no throw)feat(vault-env): proxy mode — no token => :8201, no X-Vault-Token, no throwtest(vault-env): cover initial-fetch retry on transient failurefeat(vault-env): retry the initial synchronous secret fetch on transient failureschore(vault-env): 6.1.0-beta.1Testing
All 16 tests pass (2 new + 14 existing),
tscclean,eslintclean (6 pre-existing.d.tswarnings, unrelated). The fake-server fixture (test/fakeVault.ts+test/fakeVaultWorker.ts) gained two options:acceptAnyToken— skip the token check and assertreq.headers["x-vault-token"] === undefined. Used by the proxy-mode test to prove no header is sent.failFirstRequests: N— reply 503 to the first N requests, then normal. Used by the retry test (failFirstRequests: 2⇒prepare()must retry through both before succeeding).Heads up — one thing to weigh in on
The
testscript inpackage.jsongotNODE_OPTIONS="--no-experimental-strip-types"prepended. On Node 25 (and 22.6+ with--experimental-strip-typesdefaulting on),mocha -r ts-node/registerhitsERR_UNSUPPORTED_TYPESCRIPT_SYNTAXonimport assert = require("assert")— Node's built-in TS handler intercepts beforets-nodedoes. The flag fixes it locally. But: that flag was only added in Node ~22.6; on older Node it errorsbad option, breakingnpm test. Options if that's a concern:"engines": { "node": ">=22.6" }.package.jsonand have devs/CI pass it inline when on Node ≥22.6.import x = require(...)syntax so Node's strip-types handler accepts it (a larger change).I lean toward (1) if no one's still running this on Node 14, but happy to do (2) if you'd rather not constrain.
Downstream
The matching consumer migration in
fdyis staged on a branch (tc/vault-token-startup-race); it bumpssojourner/zebra/kopeng/auth0/acceptance/magic/praxisto^6.1.0-beta.1and lands the matchingci-deploy-gcp+ agent-config changes. It's gated on this PR merging and6.1.0-beta.1being published to npm.