security(encryptid): gate /api/internal/* against public reach
The /api/internal/* routes (user lookups, space invites, fund claims, agent mailbox creds) were publicly reachable via auth.rspace.online because Traefik forwards everything under the encryptid host rule. They were designed for service-to-service calls over the Docker network only. Add a Hono middleware that rejects /api/internal/* with 404 when the request arrives through the public edge (X-Forwarded-For / X-Real-IP set by Traefik) unless it carries a valid X-Internal-Key matching INTERNAL_API_KEY. Direct container-to-container fetches don't set forwarded headers so existing callers keep working untouched.
This commit is contained in:
parent
cfe060dc61
commit
0a896f5740
|
|
@ -245,6 +245,7 @@ services:
|
|||
- MAILCOW_API_URL=${MAILCOW_API_URL:-http://nginx-mailcow:8080}
|
||||
- MAILCOW_API_KEY=${MAILCOW_API_KEY:-}
|
||||
- ADMIN_DIDS=${ADMIN_DIDS}
|
||||
- INTERNAL_API_KEY=${INTERNAL_API_KEY}
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.encryptid.rule=Host(`auth.rspace.online`) || Host(`auth.ridentity.online`) || Host(`encryptid.jeffemmett.com`)"
|
||||
|
|
|
|||
|
|
@ -480,10 +480,25 @@ app.use('*', cors({
|
|||
return undefined;
|
||||
},
|
||||
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
||||
allowHeaders: ['Content-Type', 'Authorization'],
|
||||
allowHeaders: ['Content-Type', 'Authorization', 'X-Internal-Key'],
|
||||
credentials: true,
|
||||
}));
|
||||
|
||||
// /api/internal/* is for service-to-service calls over the Docker network only.
|
||||
// Traefik adds X-Forwarded-For for any request arriving through the public edge
|
||||
// (CF tunnel, direct HTTPS). Direct container-to-container fetches do not set it.
|
||||
// A shared INTERNAL_API_KEY also works for callers outside the Docker net.
|
||||
app.use('/api/internal/*', async (c, next) => {
|
||||
const forwarded = c.req.header('X-Forwarded-For') || c.req.header('X-Real-IP');
|
||||
const providedKey = c.req.header('X-Internal-Key');
|
||||
const expectedKey = process.env.INTERNAL_API_KEY;
|
||||
const hasValidKey = !!(expectedKey && providedKey && providedKey === expectedKey);
|
||||
if (forwarded && !hasValidKey) {
|
||||
return c.json({ error: 'Not found' }, 404);
|
||||
}
|
||||
return next();
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// STATIC FILES & WELL-KNOWN
|
||||
// ============================================================================
|
||||
|
|
|
|||
Loading…
Reference in New Issue