优化
This commit is contained in:
@@ -60,6 +60,12 @@ services:
|
|||||||
AUTH_DB_URL: ${AUTH_DB_URL}
|
AUTH_DB_URL: ${AUTH_DB_URL}
|
||||||
AUTH_DB_USERNAME: ${AUTH_DB_USERNAME}
|
AUTH_DB_USERNAME: ${AUTH_DB_USERNAME}
|
||||||
AUTH_DB_PASSWORD: ${AUTH_DB_PASSWORD}
|
AUTH_DB_PASSWORD: ${AUTH_DB_PASSWORD}
|
||||||
|
OVERSEAS_JWT_ENABLED: ${OVERSEAS_JWT_ENABLED:-false}
|
||||||
|
OVERSEAS_JWT_ISSUER: ${OVERSEAS_JWT_ISSUER:-auth-service}
|
||||||
|
OVERSEAS_JWT_AUDIENCE: ${OVERSEAS_JWT_AUDIENCE:-lastleg-api}
|
||||||
|
OVERSEAS_JWT_RSA_JWK_SET: ${OVERSEAS_JWT_RSA_JWK_SET:-}
|
||||||
|
OVERSEAS_JWT_CURRENT_KID: ${OVERSEAS_JWT_CURRENT_KID:-}
|
||||||
|
OVERSEAS_ACCESS_TOKEN_TTL: ${OVERSEAS_ACCESS_TOKEN_TTL:-15m}
|
||||||
|
|
||||||
iam:
|
iam:
|
||||||
<<: *common
|
<<: *common
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { generateKeyPairSync, randomUUID } from 'node:crypto'
|
||||||
|
import { readFileSync, writeFileSync } from 'node:fs'
|
||||||
|
import { basename, dirname, resolve } from 'node:path'
|
||||||
|
|
||||||
|
const envPath = resolve(process.argv[2] || '')
|
||||||
|
if (!envPath || basename(dirname(envPath)) !== 'env' || !basename(envPath).startsWith('.env.')) {
|
||||||
|
throw new Error('用法: node scripts/generate-overseas-jwk.mjs deploy/env/.env.<environment>')
|
||||||
|
}
|
||||||
|
|
||||||
|
let source = readFileSync(envPath, 'utf8')
|
||||||
|
const existing = source.match(/^OVERSEAS_JWT_RSA_JWK_SET=(.*)$/m)?.[1]?.trim()
|
||||||
|
if (existing) throw new Error('目标环境已经配置 OVERSEAS_JWT_RSA_JWK_SET,拒绝覆盖')
|
||||||
|
|
||||||
|
const environment = basename(envPath).slice('.env.'.length).replace(/[^a-zA-Z0-9-]/g, '-')
|
||||||
|
const kid = `${environment}-overseas-${new Date().toISOString().slice(0, 10)}-${randomUUID().slice(0, 8)}`
|
||||||
|
const { privateKey } = generateKeyPairSync('rsa', { modulusLength: 3072 })
|
||||||
|
const privateJwk = privateKey.export({ format: 'jwk' })
|
||||||
|
const jwkSet = JSON.stringify({ keys: [{ ...privateJwk, use: 'sig', alg: 'RS256', kid }] })
|
||||||
|
|
||||||
|
const values = new Map([
|
||||||
|
['OVERSEAS_JWT_ENABLED', 'true'],
|
||||||
|
['OVERSEAS_JWT_ISSUER', 'auth-service'],
|
||||||
|
['OVERSEAS_JWT_AUDIENCE', 'lastleg-api'],
|
||||||
|
['OVERSEAS_JWT_RSA_JWK_SET', `'${jwkSet}'`],
|
||||||
|
['OVERSEAS_JWT_CURRENT_KID', kid],
|
||||||
|
['OVERSEAS_ACCESS_TOKEN_TTL', '15m'],
|
||||||
|
])
|
||||||
|
|
||||||
|
for (const [key, value] of values) {
|
||||||
|
const pattern = new RegExp(`^${key}=.*$`, 'm')
|
||||||
|
if (pattern.test(source)) source = source.replace(pattern, `${key}=${value}`)
|
||||||
|
else source += `${source.endsWith('\n') ? '' : '\n'}${key}=${value}\n`
|
||||||
|
}
|
||||||
|
|
||||||
|
writeFileSync(envPath, source, 'utf8')
|
||||||
|
process.stdout.write(`Configured development-only overseas JWK kid: ${kid}\n`)
|
||||||
@@ -67,3 +67,11 @@ test('CN and overseas event bridges have explicit opposite-region consumers', as
|
|||||||
'JWT_ISSUER', 'OVERSEAS_JWT_AUDIENCE', 'JWT_JWK_SET_URI'
|
'JWT_ISSUER', 'OVERSEAS_JWT_AUDIENCE', 'JWT_JWK_SET_URI'
|
||||||
]) assert.match(scripts, new RegExp(key))
|
]) assert.match(scripts, new RegExp(key))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('domestic Auth receives the overseas JWT signing configuration', async () => {
|
||||||
|
const compose = await read('deploy/docker-compose.yml')
|
||||||
|
for (const key of [
|
||||||
|
'OVERSEAS_JWT_ENABLED', 'OVERSEAS_JWT_ISSUER', 'OVERSEAS_JWT_AUDIENCE',
|
||||||
|
'OVERSEAS_JWT_RSA_JWK_SET', 'OVERSEAS_JWT_CURRENT_KID', 'OVERSEAS_ACCESS_TOKEN_TTL'
|
||||||
|
]) assert.match(compose, new RegExp(`${key}: \\$\\{${key}`))
|
||||||
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user