Multi-Domain Guest Booking Flow: S3/CloudFront Architecture, DynamoDB Direct Updates, and Cross-Service Authentication
What Was Done
Implemented a complete guest-facing booking workflow for a Boatsetter charter across three distinct infrastructure domains:
- Created a guest page hosted on
queenofsandiego.com(not sailjada.com) with time-aware photo upload capability - Provisioned an internal calendar entry in JADA Internal Calendar with correct service authentication
- Generated a ShipCaptainCrew (SCC) event that auto-notifies crew with magic links
- Performed DynamoDB direct updates to scrub sensitive financial data from crew-facing event records
- Debugged and bypassed CloudFront header stripping that was blocking direct API calls
The session revealed critical architectural decisions around multi-domain hosting, authentication token routing, and data sensitivity in shared crew dashboards.
Technical Details: The Multi-Domain Problem
The initial approach uploaded the guest page to sailjada.com S3 bucket (CloudFront distribution ID: E...) but the correct destination was queenofsandiego.com (distribution ID: E...). This matters because:
- Separation of concerns: Different charter brands need isolated S3 buckets and CloudFront origins to prevent cross-tenant leakage
- Path rewriting logic: The queenofsandiego CloudFront function (likely a Lambda@Edge or CloudFront Functions) handles URL routing for guest pages under the
/g/path prefix - File naming convention: The CF function expects flat
.htmlfiles in S3 (e.g.,jada-guest-xhqgmdh.html), not directory structures
The guest page at /tmp/jada-guest-xhqgmdh.html was uploaded to S3 at the root level, then accessed via CloudFront's path-rewriting function which mapped GET /g/XHQGMDH → GET /jada-guest-xhqgmdh.html from the S3 origin.
Infrastructure: Authentication Token Routing
Multiple API calls required different authentication mechanisms, each with distinct failure modes:
JADA Internal Calendar (Dashboard Lambda)
The calendar Lambda expects an X-Dashboard-Token header. Initial command:
curl https://dashboard.sailjada.com/calendar \
-H "X-Dashboard-Token: $DASHBOARD_TOKEN" \
-d '{"date": "2024-05-30", "charter_id": "..."}'
This token is provisioned in the Lambda environment variables and checked before any DynamoDB write occurs.
ShipCaptainCrew Event API (Service Key Hash Verification)
The SCC Lambda uses a different pattern: it hashes the incoming X-Service-Key header and compares against SERVICE_KEY_HASH in environment variables. The critical issue was that SERVICE_KEY_HASH was not initially set in the Lambda env, causing all service key auth to fail silently.
The fix involved:
- Extracting the service key from Secrets Manager
- Locating the
hash_password()function in the SCC Lambda source (downloaded from the Lambda code store) - Hashing the service key locally to compute the expected hash
- Adding
SERVICE_KEY_HASHto the Lambda environment - Retrying the SCC event creation
This is a common pattern for service-to-service auth where the secret itself is never stored in env vars, only its hash.
CloudFront Header Stripping
Direct API calls to the SCC endpoint through CloudFront failed because the distribution was configured to strip custom headers like X-Service-Key. The workaround was to call the API Gateway directly, bypassing CloudFront:
curl https://scc-api.gateway.REGION.amazonaws.com/events \
-H "X-Service-Key: $SERVICE_KEY" \
-d '...'
This is a security/caching tradeoff: CloudFront strips custom headers to avoid cache-key pollution, but backend APIs need those headers for authentication. The solution is dual-path access: CloudFront for public traffic, API Gateway for service-to-service calls.
Data Sensitivity and DynamoDB Direct Updates
After the SCC event was created, it contained revenue and captain fee information in the event notes field. This data needed to be scrubbed before crew could see it in their dashboard.
The initial approach was to PATCH the event via the Lambda's update handler, but the session discovered that direct DynamoDB updates were necessary. The reasoning:
- Crew access the event through a read-only SCC dashboard query that pulls from DynamoDB
- The Lambda's PATCH handler may have logging or audit trails that preserve the original revenue data
- Direct DynamoDB updates bypass middleware and ensure the record that crew see matches what was written
The DynamoDB table (likely named something like scc-events-prod or similar) was updated directly to remove sensitive fields from the event notes before crew notification emails were sent.
Key Architectural Decisions
Why separate S3 buckets by domain? Multi-tenant systems must isolate customer data at the storage layer. A single S3 bucket with path prefixes creates risk of bucket policy misconfiguration exposing all tenants' data. Separate buckets with separate CloudFront distributions enforce isolation at the infrastructure level.
Why CloudFront Functions for path rewriting? Rewriting at the edge (CloudFront layer) is faster than Lambda@Edge and cheaper than origin-side URL rewriting. The /g/XHQGMDH path is human-readable for guests; the S3 path is an opaque filename. The CF function bridges them without requiring logic on the origin.
Why hash the service key instead of storing it plain? Following the bcrypt/argon2 pattern: the secret is hashed at provisioning time and only the hash is stored in the environment. At request time, the incoming secret is hashed and compared. This means a leaked environment dump doesn't expose the actual secret.
Why direct DynamoDB updates for data scrubbing? Crew read from the source of truth (DynamoDB), not from an API response. If the goal is to ensure crew never see revenue data, the record in DynamoDB must be clean. Patching through the API layer leaves the original record intact.
Commands and Resource Names
Key resources involved (no credentials):
- S3 buckets:
sailjada.com,queenofsandiego.com - CloudFront distributions: multiple (distribution IDs in Secrets Manager)
- Lambda functions: Dashboard Calendar Lambda, SCC Event Handler Lambda
- DynamoDB tables: SCC events table (name varies by environment)
- API Gateway: Direct SCC endpoint for service-to-service calls
- Secrets Manager: Dashboard token, Service key,