feat(major): new authentication layer between couch DB and app#2211
feat(major): new authentication layer between couch DB and app#2211PeterBaker0 wants to merge 40 commits into
Conversation
Co-authored-by: Peter Baker <PeterBaker0@users.noreply.github.com>
Co-authored-by: Peter Baker <PeterBaker0@users.noreply.github.com>
Co-authored-by: Peter Baker <PeterBaker0@users.noreply.github.com>
Co-authored-by: Peter Baker <PeterBaker0@users.noreply.github.com>
…rd name Signed-off-by: Peter Baker <peter.baker122@csiro.au>
Signed-off-by: Peter Baker <peter.baker122@csiro.au>
Signed-off-by: Peter Baker <peter.baker122@csiro.au>
Signed-off-by: Peter Baker <peter.baker122@csiro.au>
Signed-off-by: Peter Baker <peter.baker122@csiro.au>
Signed-off-by: Peter Baker <peter.baker122@csiro.au>
Close the Couch sync read gap for PROJECT_GUEST by stamping creator/parent on the clean write path, provisioning _design/acl with dbacl from the permission model, adding DATA v1→v2 backfill, and wiring compose so COUCHDB_PUBLIC_URL points at couch-auth-proxy while Conductor keeps the internal Couch URL. Co-authored-by: Peter Baker <PeterBaker0@users.noreply.github.com>
Preserve creator/parent through hydrated revision updates, stamp the legacy upsert/merge/attachment write paths, and fix migrationService tests that assumed DB_MIGRATIONS[0] was PEOPLE v1→v2. Co-authored-by: Peter Baker <PeterBaker0@users.noreply.github.com>
Keep creator/parent optional in Zod/legacy types so pre-migration fixtures still parse, while write paths continue to stamp. Wait for the proxy ACL follower before assertions, pin the compose image to the published sha tag, and exclude the integration suite from the default mocha glob. Co-authored-by: Peter Baker <PeterBaker0@users.noreply.github.com>
Bring feat/couch-auth-proxy-integration-413d onto feat/proxy-auth-integration as-is from main. Co-authored-by: Peter Baker <PeterBaker0@users.noreply.github.com>
Close remaining handover gaps: keep DATA defaultVersion at 1 so orphan data DBs still backfill, fail-closed orphan creator stamping, expand proxy integration scenarios, add dbacl repair script, and rebuild local client data DBs after ACL cutover. Co-authored-by: Peter Baker <PeterBaker0@users.noreply.github.com>
Capture a secure target topology (ALB → ECS proxy, Couch VPC-only), config/Conductor URL split, SG rules, and cutover order so the remaining infra follow-on from the proxy handover can be implemented safely. Co-authored-by: Peter Baker <PeterBaker0@users.noreply.github.com>
Remote Pouch handles expose a URL as db.name; Conductor now enqueues DATA
migrations under the logical data-{projectId} name, and performMigration
passes that name through so _design/acl ensure cannot be skipped.
Client ACL markers now bind to the advertised public base URL so a seal
against open Couch is invalidated when COUCHDB_PUBLIC_URL flips to the
proxy. Add operator cutover runbook and expand migration/deploy docs.
Co-authored-by: Peter Baker <PeterBaker0@users.noreply.github.com>
Resolve toctree conflict by keeping both Cutover and AwsCdk pages; cross-link the operator runbook with the CDK design brief on #20. Co-authored-by: Peter Baker <PeterBaker0@users.noreply.github.com>
Point production proxy follow-up at CouchAuthProxyAwsCdk.md. Co-authored-by: Peter Baker <PeterBaker0@users.noreply.github.com>
Add optional CouchAuthProxy ECS Fargate construct gated by couchAuthProxy.enabled. When enabled, public couch.* terminates on the proxy, Conductor gets distinct PUBLIC/INTERNAL Couch URLs, and Couch :5984 is limited to proxy + Conductor security groups. Legacy ALB→Couch behaviour is preserved when disabled for rollback. Do not enable in a live env until DATA v2 migration completes (see CouchAuthProxyCutover.md). Co-authored-by: Peter Baker <PeterBaker0@users.noreply.github.com>
Remove couchAuthProxy.enabled and attachToPublicAlb. The proxy is mandatory: ALB couch.* always terminates on ECS proxy, Couch is VPC-only, and Conductor always gets distinct PUBLIC/INTERNAL Couch URLs. Reject legacy enabled keys in config via Zod .strict(). Co-authored-by: Peter Baker <PeterBaker0@users.noreply.github.com>
Co-authored-by: Peter Baker <PeterBaker0@users.noreply.github.com>
Same-hostname AWS flips now bump COUCH_ACL_CLIENT_SCHEMA_VERSION so clients rebuild IndexedDB; fail-closed VDU requires creator/parent; restore and engine update paths re-stamp ACL; docs/tests aligned with always-on CDK. Co-authored-by: Peter Baker <PeterBaker0@users.noreply.github.com>
Remove openLocalDataDbWithAclCutover, the _local/faims-acl-schema marker, and dataDb.acl_client_schema_version / COUCH_ACL_CLIENT_SCHEMA_VERSION. Keep public-URL changeover: re-point remotes after listing when Conductor advertises a new couch URL. Accept that pre-proxy leftover local records may linger until refresh / re-activate. Co-authored-by: Peter Baker <PeterBaker0@users.noreply.github.com>
Co-authored-by: Peter Baker <PeterBaker0@users.noreply.github.com>
Signed-off-by: Peter Baker <peter.baker122@csiro.au>
Signed-off-by: Peter Baker <peter.baker122@csiro.au>
Signed-off-by: Peter Baker <peter.baker122@csiro.au>
…FAIMS3 into feat/proxy-auth-integration
…and other doc changes. Issue with auth proxy cold ACL cache on first sync resolved upstream v1.7 Signed-off-by: Peter Baker <peter.baker122@csiro.au>
…- all passing Signed-off-by: Peter Baker <peter.baker122@csiro.au>
Signed-off-by: Peter Baker <peter.baker122@csiro.au>
Signed-off-by: Peter Baker <peter.baker122@csiro.au>
stevecassidy
left a comment
There was a problem hiding this comment.
I've not done a full review but left a few comments. This is a big change. I wonder if we could break it into two parts:
- Document changes needed to support the fine-grained ACL model
- Support for the proxy
The first is likely to be relatively small and unproblematic. The proxy would ideally be optional and this split might make it easier to ensure that everything still works without it.
|
|
||
| # Live Couch + couch-auth-proxy ACL proof (guest isolation, VDU, dbacl). | ||
| # Fails hard if the proxy image/compose pin is unreachable (no skip in CI). | ||
| couch-auth-proxy: |
There was a problem hiding this comment.
Do we really want to deploy a proxy server during a build+lint check? Along with e2e tests this is becoming a very heavy process.
| @@ -0,0 +1,278 @@ | |||
| #!/usr/bin/env bash | |||
There was a problem hiding this comment.
Why is a CDK script here rather than in the AWS directory?
|
|
||
| /** | ||
| * Stamp missing couch-auth-proxy ACL fields on restored data docs. | ||
| * Backups taken before DATA v1→v2 (or from open Couch) may lack `creator` / |
There was a problem hiding this comment.
We would need to do a migration in general from the db version that was backed up to now.
| ); | ||
| } | ||
|
|
||
| // Proxy owns `_design/acl` map/VDU; warm it then patch FAIMS `dbacl`. |
There was a problem hiding this comment.
spell out VDU please, not a common acronym
| delete project._rev; | ||
| // add database connection details | ||
| if (project.dataDb) project.dataDb.base_url = config.couchdbPublicUrl; | ||
| if (project.dataDb) { |
There was a problem hiding this comment.
why braces now? This file has not changed.
| @@ -0,0 +1,189 @@ | |||
| /* eslint-disable n/no-process-exit */ | |||
There was a problem hiding this comment.
This looks useful but why is it here?
| @@ -0,0 +1,137 @@ | |||
| /* eslint-disable n/no-process-exit */ | |||
| /** | |||
| * Idempotent ops tool: warm couch-auth-proxy `_design/acl` on every project | |||
There was a problem hiding this comment.
I don't know what 'warm' means here and I can't work it out from the script. Do you mean it will be replaced by an updated version or something about it will be changed? You used 'warm' elsewhere too. Can you use a more descriptive term?
| @@ -0,0 +1,230 @@ | |||
| #!/usr/bin/env bash | |||
There was a problem hiding this comment.
Ah ok, you have these in each project - maybe one script in the AWS folder would be better.
Summary
Closes the long-standing per-document read gap on Pouch↔Couch sync by putting
couch-auth-proxyin front of project data DBs and aligning the FAIMS write path, migrations, and AWS topology with a single ACL model.Until now,
PROJECT_GUEST(and anyone with onlyREAD_MY_PROJECT_RECORDS) could replicate an entiredata-*database: Couch_securityis DB-wide, while API/UI already enforced my/all. This PR makes DB access match that policy without inventing a second permission language.The problem
READ_MY_*/READ_ALL_*)canReadRecordshouldDisplayRecord_design/permissionsVDU_security+ Pouch syncGuests must remain DB members to sync their own graph. Couch alone cannot answer “which docs?” — only “may talk to this DB?”.
What is couch-auth-proxy?
A reverse proxy (Docker/GHCR service, not an npm dep) in front of CouchDB that:
Authorization/ Cookie →GET /_session). FAIMS RSA JWT validation stays in Couch (jwt_keys); Conductor JWT issuance is unchanged._changes,_bulk_get,_all_docs, attachments, etc.) using doc fieldscreator/owners/acl/parent, plus a bucket overlay on_design/acl(dbacl.{_r,_w,_d}).1.7.0in compose/CDK) and only patch project-scopeddbacl.Role in FAIMS: the sync read boundary for apps. Conductor keeps admin Basic on
COUCHDB_INTERNAL_URLand bypasses the proxy.Auth / ACL model (FAIMS + proxy)
One policy source:
@faims3/data-modelRBAC.dbaclrole lists are derived fromnecessaryActionToCouchRoleListfor*_ALL_PROJECT_RECORDS— not hand-maintained role literals.Clean write path (always stamped; no “legacy mode” on hot path):
rec-*creator= record owner (alongside existingcreated_by)frev-*/avp-*/ attachmentscreator= writer;parent=rec-*id (inherit record ACL)Mapping:
READ_MY_PROJECT_RECORDScreator/parenton the record graphREAD_ALL_PROJECT_RECORDSdbacl._rcreator/dbacl+ existing_design/permissionsVDUDefense in depth stays: proxy (sync reads) + permissions VDU (writes) + API
canReadRecord+ UI filter. Layering is documented inAclValidationLayering.md.Unstamped docs remain member-readable (
r-*) by proxy semantics — which is why migrate/repair must follow deploy promptly.What’s in this PR
_design/faims_acl_shape, DATA migration v1→v2dbacl,repair-data-db-acl, integration suite:5985;COUCHDB_PUBLIC_URL→ proxycouch.*→ proxy; Couch VPC-only); Conductor public vs internal URL splitguest-record-isolation.e2e.ts+ sync probe harnessMigration / cutover path
Deploy-then-migrate (intentional, not multi-phase idle flip):
data-*DBs to version 2 (migrate-with-keys/ Conductor startup migrate).pnpm --filter=@faims3/api run repair-data-db-acl(warm_design/acl, patchdbacl, ensure FAIMS shape ddoc).test:couch-auth-proxy+ e2e).Until migrate stamps legacy docs, effective access matches today’s public Couch (not a new privacy regression). After migrate, guests lose other users’ graphs on the wire.
Known limitation: already-activated clients may retain pre-cutover local docs until refresh / re-activate / clear site data. Wire isolation is guaranteed; local wipe was deliberately not implemented.
Rollback: re-point public hostname /
COUCHDB_PUBLIC_URLat Couch → re-opens the old read gap. ACL fields and_design/aclcan remain harmlessly. There is noenabled: falseflag on AWS.Still open: DigitalOcean public→proxy / Couch-internal split (compose + AWS are the reference).
Risks vs rewards
r-*gapsACL_REQUIRE_CREATOR) + orphan stamp for missingcreated_byNet: this is the architectural fix for a real confidentiality hole in offline-first sync. The main operational bet is always-on proxy + immediate DATA v2 migrate, accepted as clearer and safer than a long dual-mode period.
Docs
CouchAuthProxyHandover.md— design briefCouchAuthProxyCutover.md— operator runbookAclValidationLayering.md— ownership / VDU splitCouchAuthProxyAwsCdk.md— AWS topology