feat(resolver): per-host auth for remote template fetches#731
Merged
Conversation
Operators can now bind a different bearer token to each upstream host that templates are fetched from, configured through named entries: CATAPULTE_RESOLVER_TOKENS=github,gitlab CATAPULTE_RESOLVER_TOKEN_GITHUB_HOST=raw.githubusercontent.com CATAPULTE_RESOLVER_TOKEN_GITHUB_BEARER_TOKEN=... Each request only carries the token bound to its exact host, so a token is never sent to a different upstream. The host must also be in ALLOWED_DOMAINS to be fetched at all. Token values are marked sensitive and validated at build time; duplicate hosts and missing entry vars fail fast. Config parsing mirrors the SMTP multi-sender from_lookup idiom. Signed-off-by: Jeremie Drouet <jeremie.drouet@gmail.com>
ResolverAuthEntry gains a `headers: Vec<(String, String)>` field and `bearer_token` becomes `Option<String>`. The adapter builds one HeaderMap per host (bearer under Authorization if present, then each generic header via append so repeated names accumulate). Conflicts between a bearer_token and an explicit Authorization header are rejected at new(). resolve_remote() now attaches the full HeaderMap instead of a single Authorization value. Update existing tests to the new struct shape and add: - generic_header_attached_to_matching_host - new_with_bearer_and_explicit_authorization_header_conflicts - new_with_invalid_header_name_returns_err Signed-off-by: Jeremie Drouet <jeremie.drouet@gmail.com>
Bearer token is now optional when at least one header is configured. New env vars per auth entry: - _HEADERS: comma-separated list of header name fragments to attach to requests to the matching host (e.g. Accept,PRIVATE-TOKEN). - _HEADER_<FRAGMENT>_VALUE: value for the named header; FRAGMENT is the header name uppercased with hyphens replaced by underscores (e.g. ACCEPT, PRIVATE_TOKEN). Values are treated as secrets and never logged. Fragment collision guard rejects entries that map two different header names to the same fragment. Host-but-no-auth guard rejects entries that list a host but configure neither a bearer token nor any header. Signed-off-by: Jeremie Drouet <jeremie.drouet@gmail.com>
Add two new variables to the Template Resolver table: - TOKEN_<NAME>_HEADERS: comma-separated header names to attach per host. - TOKEN_<NAME>_HEADER_<FRAGMENT>_VALUE: value for a named header (FRAGMENT is the header name uppercased with hyphens replaced by underscores). Mark TOKEN_<NAME>_BEARER_TOKEN as optional now that headers are supported. Note the requirement that each entry must configure at least a bearer token or one header. Add worked examples: GitHub (bearer + Accept header) and GitLab (PRIVATE-TOKEN header, no bearer). Signed-off-by: Jeremie Drouet <jeremie.drouet@gmail.com>
List all failure modes: invalid header name or value, bearer token combined with explicit Authorization header, alongside the existing ones. Signed-off-by: Jeremie Drouet <jeremie.drouet@gmail.com>
Signed-off-by: Jeremie Drouet <jeremie.drouet@gmail.com>
2b7a869 to
0e46b17
Compare
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.
lets operators bind auth to specific upstream hosts when catapulte fetches remote mjml templates. each entry is pinned to an exact host, so a token never gets sent to the wrong upstream (and the host still has to be in
ALLOWED_DOMAINSto be fetched at all).started out as bearer-per-host:
but bearer isn't enough for everyone (#729): private github repos go through api.github.com and need
Accept: application/vnd.github.rawon top of the bearer, and gitlab doesn't use bearer at all, it's aPRIVATE-TOKENheader. so each entry can now carry arbitrary static headers too. bearer stays as sugar for a singleAuthorizationheader.github through the api:
gitlab (no bearer):
the value var fragment is just the header name uppercased with dashes turned into underscores (
PRIVATE-TOKEN->PRIVATE_TOKEN).header values and the bearer are marked sensitive so they stay out of logs. config fails fast on the obvious mistakes: duplicate hosts, a header listed with no value, two header names that collapse to the same fragment, a bearer plus an explicit authorization header, or an entry with a host but nothing to send.
closes #729
notes: