feat(azure): update deployment files for Phase 3 auth variables

Replace DEMO_PASSWORD/SECRET_KEY with JWT_SECRET_KEY, ADMIN_EMAIL,
ADMIN_PASSWORD, and optional ACS (Azure Communication Services) vars
across config.sh.example, container-app.bicep, and 2-build-deploy.sh.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ubuntu 2026-05-16 09:32:25 +00:00
parent 2e0896e34d
commit 0d04dee670
3 changed files with 74 additions and 23 deletions

View File

@ -29,7 +29,8 @@ source "$CONFIG_FILE"
# ── Validar variables obligatòries ─────────────────────────────────────────── # ── Validar variables obligatòries ───────────────────────────────────────────
REQUIRED_VARS=( REQUIRED_VARS=(
AZURE_SUBSCRIPTION_ID RESOURCE_GROUP PROJECT_NAME AZURE_SUBSCRIPTION_ID RESOURCE_GROUP PROJECT_NAME
DEMO_PASSWORD SECRET_KEY LLM_API_KEY LLM_BASE_URL LLM_MODEL_NAME JWT_SECRET_KEY ADMIN_EMAIL ADMIN_PASSWORD
LLM_API_KEY LLM_BASE_URL LLM_MODEL_NAME
DATABASE_URL STORAGE_CONNECTION_STRING DATABASE_URL STORAGE_CONNECTION_STRING
) )
# Validate graph backend config # Validate graph backend config
@ -42,6 +43,9 @@ if [[ "$GRAPH_BACKEND" == "graphiti" && -z "${NEO4J_PASSWORD:-}" ]]; then
echo "ERROR: NEO4J_PASSWORD is required when GRAPH_BACKEND=graphiti" echo "ERROR: NEO4J_PASSWORD is required when GRAPH_BACKEND=graphiti"
exit 1 exit 1
fi fi
if [[ -z "${ACS_CONNECTION_STRING:-}" ]]; then
echo "AVÍS: ACS_CONNECTION_STRING no configurat — emails d'invitació es mostraran als logs"
fi
for var in "${REQUIRED_VARS[@]}"; do for var in "${REQUIRED_VARS[@]}"; do
if [[ -z "${!var:-}" ]]; then if [[ -z "${!var:-}" ]]; then
echo "ERROR: La variable $var no està configurada a config.sh" echo "ERROR: La variable $var no està configurada a config.sh"
@ -133,7 +137,15 @@ DEPLOY_OUTPUT=$(az deployment group create \
acrLoginServer="$ACR_LOGIN_SERVER" \ acrLoginServer="$ACR_LOGIN_SERVER" \
acrUsername="$ACR_USERNAME" \ acrUsername="$ACR_USERNAME" \
acrPassword="$ACR_PASSWORD" \ acrPassword="$ACR_PASSWORD" \
demoPassword="$DEMO_PASSWORD" \ jwtSecretKey="$JWT_SECRET_KEY" \
adminEmail="$ADMIN_EMAIL" \
adminPassword="$ADMIN_PASSWORD" \
acsConnectionString="${ACS_CONNECTION_STRING:-}" \
acsSenderAddress="${ACS_SENDER_ADDRESS:-}" \
acsInvitationTtlHours="${ACS_INVITATION_TTL_HOURS:-48}" \
acsResetPasswordTtlHours="${ACS_RESET_PASSWORD_TTL_HOURS:-1}" \
jwtAccessTokenExpires="${JWT_ACCESS_TOKEN_EXPIRES:-28800}" \
jwtRefreshTokenExpires="${JWT_REFRESH_TOKEN_EXPIRES:-604800}" \
llmApiKey="$LLM_API_KEY" \ llmApiKey="$LLM_API_KEY" \
llmBoostApiKey="${LLM_BOOST_API_KEY:-}" \ llmBoostApiKey="${LLM_BOOST_API_KEY:-}" \
llmProvider="${LLM_PROVIDER:-}" \ llmProvider="${LLM_PROVIDER:-}" \
@ -143,7 +155,6 @@ DEPLOY_OUTPUT=$(az deployment group create \
neo4jUser="${NEO4J_USER:-neo4j}" \ neo4jUser="${NEO4J_USER:-neo4j}" \
neo4jDatabase="${NEO4J_DATABASE:-neo4j}" \ neo4jDatabase="${NEO4J_DATABASE:-neo4j}" \
graphBackend="${GRAPH_BACKEND:-zep}" \ graphBackend="${GRAPH_BACKEND:-zep}" \
secretKey="$SECRET_KEY" \
llmBaseUrl="$LLM_BASE_URL" \ llmBaseUrl="$LLM_BASE_URL" \
llmModelName="$LLM_MODEL_NAME" \ llmModelName="$LLM_MODEL_NAME" \
llmBoostBaseUrl="${LLM_BOOST_BASE_URL:-}" \ llmBoostBaseUrl="${LLM_BOOST_BASE_URL:-}" \

View File

@ -22,12 +22,22 @@ PROJECT_NAME="mirofish" # prefix per a tots els recursos Azure
# ── Secrets de l'aplicació ──────────────────────────────────────────────────── # ── Secrets de l'aplicació ────────────────────────────────────────────────────
# Contrasenya de l'usuari "demo" per fer login a l'app # ── Auth JWT ──────────────────────────────────────────────────────────────────
DEMO_PASSWORD="<contrasenya-segura>" # Genera JWT_SECRET_KEY amb: python -c "import secrets; print(secrets.token_hex(32))"
JWT_SECRET_KEY="<clau-secreta-jwt>"
JWT_ACCESS_TOKEN_EXPIRES=28800 # 8h en segons
JWT_REFRESH_TOKEN_EXPIRES=604800 # 7d en segons
# Flask SECRET_KEY per signar tokens JWT # ── Admin inicial (per flask init-system) ─────────────────────────────────────
# Genera-la amb: python -c "import secrets; print(secrets.token_hex(32))" ADMIN_EMAIL="admin@example.com"
SECRET_KEY="<flask-secret-key>" ADMIN_PASSWORD="<contrasenya-segura>"
# ── Azure Communication Services (emails d'invitació i reset) ────────────────
# ACS és opcional en dev: els links apareixeran als logs si ACS_CONNECTION_STRING és buit
ACS_CONNECTION_STRING=""
ACS_SENDER_ADDRESS="donotreply@example.com"
ACS_INVITATION_TTL_HOURS=48
ACS_RESET_PASSWORD_TTL_HOURS=1
# ── LLM principal (OpenAI-compatible) ───────────────────────────────────────── # ── LLM principal (OpenAI-compatible) ─────────────────────────────────────────
LLM_API_KEY="<la-teva-llm-api-key>" LLM_API_KEY="<la-teva-llm-api-key>"

View File

@ -37,10 +37,6 @@ param acrUsername string
@secure() @secure()
param acrPassword string param acrPassword string
@description('Contrasenya de l\'usuari demo')
@secure()
param demoPassword string
@description('Clau de l\'API LLM principal (OpenAI-compatible)') @description('Clau de l\'API LLM principal (OpenAI-compatible)')
@secure() @secure()
param llmApiKey string param llmApiKey string
@ -57,9 +53,17 @@ param zepApiKey string = ''
@secure() @secure()
param neo4jPassword string = '' param neo4jPassword string = ''
@description('SECRET_KEY de Flask per a JWT (python -c "import secrets; print(secrets.token_hex(32))")') @description('JWT Secret Key per a flask-jwt-extended')
@secure() @secure()
param secretKey string param jwtSecretKey string
@description('Contrasenya de l\'admin inicial (per flask init-system)')
@secure()
param adminPassword string
@description('Connection string Azure Communication Services (opcional)')
@secure()
param acsConnectionString string = ''
@description('Connection string del Storage Account per a Azure Files (output d\'infra.bicep)') @description('Connection string del Storage Account per a Azure Files (output d\'infra.bicep)')
@secure() @secure()
@ -72,6 +76,24 @@ param databaseUrl string = ''
@description('Nom del Storage Account (output d\'infra.bicep)') @description('Nom del Storage Account (output d\'infra.bicep)')
param storageAccountName string = '' param storageAccountName string = ''
@description('Email de l\'admin inicial')
param adminEmail string = ''
@description('Adreça remitent ACS')
param acsSenderAddress string = ''
@description('TTL invitació en hores')
param acsInvitationTtlHours string = '48'
@description('TTL reset password en hores')
param acsResetPasswordTtlHours string = '1'
@description('Expiració access token JWT en segons')
param jwtAccessTokenExpires string = '28800'
@description('Expiració refresh token JWT en segons')
param jwtRefreshTokenExpires string = '604800'
// ─── Paràmetres LLM principal ───────────────────────────────────────────────── // ─── Paràmetres LLM principal ─────────────────────────────────────────────────
@description('URL base de l\'API LLM principal') @description('URL base de l\'API LLM principal')
@ -149,10 +171,10 @@ param reportAgentTemperature string = '0.5'
// ─── Secrets i env vars condicionals (Azure rebutja secrets amb valor buit) ─── // ─── Secrets i env vars condicionals (Azure rebutja secrets amb valor buit) ───
var mandatorySecrets = [ var mandatorySecrets = [
{ name: 'acr-password', value: acrPassword } { name: 'acr-password', value: acrPassword }
{ name: 'demo-password', value: demoPassword } { name: 'jwt-secret-key', value: jwtSecretKey }
{ name: 'llm-api-key', value: llmApiKey } { name: 'admin-password', value: adminPassword }
{ name: 'secret-key', value: secretKey } { name: 'llm-api-key', value: llmApiKey }
] ]
var optionalSecrets = concat( var optionalSecrets = concat(
empty(llmBoostApiKey) ? [] : [{ name: 'llm-boost-api-key', value: llmBoostApiKey }], empty(llmBoostApiKey) ? [] : [{ name: 'llm-boost-api-key', value: llmBoostApiKey }],
@ -161,14 +183,21 @@ var optionalSecrets = concat(
empty(zepApiKey) ? [] : [{ name: 'zep-api-key', value: zepApiKey }], empty(zepApiKey) ? [] : [{ name: 'zep-api-key', value: zepApiKey }],
empty(neo4jPassword) ? [] : [{ name: 'neo4j-password', value: neo4jPassword }], empty(neo4jPassword) ? [] : [{ name: 'neo4j-password', value: neo4jPassword }],
empty(storageConnectionString) ? [] : [{ name: 'storage-connection-string', value: storageConnectionString }], empty(storageConnectionString) ? [] : [{ name: 'storage-connection-string', value: storageConnectionString }],
empty(databaseUrl) ? [] : [{ name: 'database-url', value: databaseUrl }] empty(databaseUrl) ? [] : [{ name: 'database-url', value: databaseUrl }],
empty(acsConnectionString) ? [] : [{ name: 'acs-connection-string', value: acsConnectionString }]
) )
var allSecrets = concat(mandatorySecrets, optionalSecrets) var allSecrets = concat(mandatorySecrets, optionalSecrets)
var mandatoryEnv = [ var mandatoryEnv = [
{ name: 'DEMO_PASSWORD', secretRef: 'demo-password' } { name: 'JWT_SECRET_KEY', secretRef: 'jwt-secret-key' }
{ name: 'ADMIN_EMAIL', value: adminEmail }
{ name: 'ADMIN_PASSWORD', secretRef: 'admin-password' }
{ name: 'JWT_ACCESS_TOKEN_EXPIRES', value: jwtAccessTokenExpires }
{ name: 'JWT_REFRESH_TOKEN_EXPIRES', value: jwtRefreshTokenExpires }
{ name: 'ACS_SENDER_ADDRESS', value: acsSenderAddress }
{ name: 'ACS_INVITATION_TTL_HOURS', value: acsInvitationTtlHours }
{ name: 'ACS_RESET_PASSWORD_TTL_HOURS', value: acsResetPasswordTtlHours }
{ name: 'LLM_API_KEY', secretRef: 'llm-api-key' } { name: 'LLM_API_KEY', secretRef: 'llm-api-key' }
{ name: 'SECRET_KEY', secretRef: 'secret-key' }
{ name: 'LLM_BASE_URL', value: llmBaseUrl } { name: 'LLM_BASE_URL', value: llmBaseUrl }
{ name: 'LLM_MODEL_NAME', value: llmModelName } { name: 'LLM_MODEL_NAME', value: llmModelName }
{ name: 'LLM_PROVIDER', value: llmProvider } { name: 'LLM_PROVIDER', value: llmProvider }
@ -199,7 +228,8 @@ var optionalEnv = concat(
empty(zepApiKey) ? [] : [{ name: 'ZEP_API_KEY', secretRef: 'zep-api-key' }], empty(zepApiKey) ? [] : [{ name: 'ZEP_API_KEY', secretRef: 'zep-api-key' }],
empty(neo4jPassword) ? [] : [{ name: 'NEO4J_PASSWORD', secretRef: 'neo4j-password' }], empty(neo4jPassword) ? [] : [{ name: 'NEO4J_PASSWORD', secretRef: 'neo4j-password' }],
empty(storageConnectionString) ? [] : [{ name: 'AZURE_STORAGE_CONNECTION_STRING', secretRef: 'storage-connection-string' }], empty(storageConnectionString) ? [] : [{ name: 'AZURE_STORAGE_CONNECTION_STRING', secretRef: 'storage-connection-string' }],
empty(databaseUrl) ? [] : [{ name: 'DATABASE_URL', secretRef: 'database-url' }] empty(databaseUrl) ? [] : [{ name: 'DATABASE_URL', secretRef: 'database-url' }],
empty(acsConnectionString) ? [] : [{ name: 'ACS_CONNECTION_STRING', secretRef: 'acs-connection-string' }]
) )
var allEnv = concat(mandatoryEnv, optionalEnv) var allEnv = concat(mandatoryEnv, optionalEnv)
@ -266,7 +296,7 @@ resource containerApp 'Microsoft.App/containerApps@2023-05-01' = {
name: 'uploads' name: 'uploads'
storageType: 'AzureFile' storageType: 'AzureFile'
storageName: 'uploads' storageName: 'uploads'
mountOptions: 'nobrl,cache=strict,nosharesock,actimeo=30' mountOptions: 'nobrl,cache=strict,nosharesock'
} }
] ]