Hardening work for user-created ("bring your own bucket") data connections, ahead of granting create_data_connections more broadly.
Threat model and analysis are in a private security advisory: GHSA-2rjm-4mm8-gj29. Please read it before picking up an item — the ordering below is not arbitrary, and the first item gates the value of several others.
Spans three repos. Checkboxes note where each lands.
Federated-credential scoping
Connection validation
Defence in depth
Known residual
Even with the above, all products in a platform-managed bucket share one bucket-wide credential, so cross-account prefix confinement there remains application logic rather than IAM. Candidate follow-up: give the platform connection account scope plus a session policy on {base_prefix}{account}/* — cardinality becomes ~per-active-account instead of per-product. Prerequisite: confirm the platform connection's prefix_template leads with {{repository.account_id}}.
Hardening work for user-created ("bring your own bucket") data connections, ahead of granting
create_data_connectionsmore broadly.Threat model and analysis are in a private security advisory: GHSA-2rjm-4mm8-gj29. Please read it before picking up an item — the ordering below is not arbitrary, and the first item gates the value of several others.
Spans three repos. Checkboxes note where each lands.
Federated-credential scoping
Key the OIDC credential cache on
⚠️ The same design doc calls for single-flight around AssumeRole. Do not implement it as an isolate-shared async mutex — see fix(deps): bump multistore to 0.7.2 to stop federated reads hanging #197. Refresh-ahead is safe.
{role_arn}|{subject}rather than the role ARN alone —AwsBackendAuth::resolve_aws. (upstream:developmentseed/multistore)Include the ARN as well as the subject: a connection's
role_arncan change while its ID, and therefore its subject, stays fixed.|cannot occur in an ARN, so it is a safe delimiter. This restores the behaviourdocs/plans/2026-06-02-federated-backend-auth-design.mdstep 7 already specifies.Render the OIDC subject with scope derived from
owner(this repo)scv1:conn:{id}— cardinality 1, no change from todayscv1:conn:{id}:product:{account}/{product}No
subject_scopeschema field — the contract is already documented onownerinsource.coop/src/types/data-connection.ts. Uniform product-scope is explicitly ruled out by the design doc (line 180) on cache-cardinality grounds. Needsowneradded toDataConnectioninsrc/source_api/types.rs, and account/product threaded intoapply_backend_auth; both are already in scope atregistry.rs:66.Fix the documented-vs-emitted subject mismatch.
DataConnectionForm.tsx:196tells customers to pinscv1:conn:{id}:*, but the proxy emits barescv1:conn:{id}, which an IAMStringLikeofscv1:conn:{id}:*does not match. Implementing the item above makes the existing UI text correct; until then anyone who followed it has a role the proxy cannot assume. (this repo +source.coop)Condition the platform role's trust policy on subject structure —
deploy/lib/data-proxy-construct.ts. Trial against live IAM in staging before relying on it as a boundary. (source.coop)Connection validation
prefix_templateandbase_prefixfor owned connections. Both are barez.string()today. Force the canonical{{repository.account_id}}/{{repository.repository_id}}/(or at minimum require theaccount_idtoken), and normalizebase_prefix— reject leading/,.., and empty segments. (source.coop)isPlatformResource(details, authentication)predicate, called from bothcreateDataConnectionandupdateDataConnection. Fails loudly at create time rather than opaquely at request time. (source.coop)details.bucket,base_prefix, andauthenticationonce a connection is referenced by a product mirror (or force re-verification on change).listProductsByConnectionIdalready exists for the delete guard. Without this, creation-time validation is bypassable by editing after approval. (source.coop)Defence in depth
deploy/lib/data-proxy-construct.ts:58-59, which describes a per-request STS session policy that is not implemented. Worth doing immediately and independently — it currently misleads anyone reasoning about the blast radius. (source.coop)arn:aws:s3:::{bucket}/{resolved_prefix}*, moving prefix confinement from application logic to IAM. Needs aPolicyfield upstream. (upstream + this repo){base_prefix}.source-coop-verificationfor all providers; fors3_web_identity_role, require the customer's trust policy to pin their per-connection subject and verify by attempting the assume-role at creation (depends on the subject-rendering item). (source.coop)AssumeRoleWithWebIdentityagainst the platform role with an unexpectedsub. (source.coop)Known residual
Even with the above, all products in a platform-managed bucket share one bucket-wide credential, so cross-account prefix confinement there remains application logic rather than IAM. Candidate follow-up: give the platform connection
accountscope plus a session policy on{base_prefix}{account}/*— cardinality becomes ~per-active-account instead of per-product. Prerequisite: confirm the platform connection'sprefix_templateleads with{{repository.account_id}}.