diff --git a/backend/src/services/logger.ts b/backend/src/services/logger.ts index b8e4c79..2d2967c 100644 --- a/backend/src/services/logger.ts +++ b/backend/src/services/logger.ts @@ -1,5 +1,12 @@ import winston from 'winston'; import { config } from '../config/env.js'; +import * as fs from 'fs'; +import * as path from 'path'; +import { fileURLToPath } from 'url'; +import { dirname } from 'path'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); const { combine, timestamp, printf, colorize, errors } = winston.format; @@ -25,16 +32,45 @@ export const logger = winston.createLogger({ ], }); -if (config.isProduction) { - logger.add( - new winston.transports.File({ - filename: 'logs/error.log', - level: 'error', - }) - ); - logger.add( - new winston.transports.File({ - filename: 'logs/combined.log', - }) - ); +// Only add file logging if we're in production AND have write permissions +// In Azure App Service, console logging is automatically captured, so file logging is optional +if (config.isProduction && !process.env.AZURE_APP_SERVICE) { + // For non-Azure environments, try to use logs/ directory + const logDir = path.join(__dirname, '../../logs'); + + try { + // Ensure directory exists + if (!fs.existsSync(logDir)) { + fs.mkdirSync(logDir, { recursive: true }); + } + + // Test write permissions + const testFile = path.join(logDir, '.write-test'); + try { + fs.writeFileSync(testFile, 'test'); + fs.unlinkSync(testFile); + + // If we can write, add file transports + logger.add( + new winston.transports.File({ + filename: path.join(logDir, 'error.log'), + level: 'error', + }) + ); + logger.add( + new winston.transports.File({ + filename: path.join(logDir, 'combined.log'), + }) + ); + } catch (writeError) { + // Can't write to this directory, skip file logging + // Console logging will be used (which is fine for Azure App Service) + console.warn('File logging disabled: no write permissions. Using console logging only.'); + } + } catch (dirError) { + // Can't create directory, skip file logging + console.warn('File logging disabled: cannot create log directory. Using console logging only.'); + } } +// In Azure App Service, console logs are automatically captured by Azure Monitor +// No need for file logging diff --git a/docs/AZURE-APP-SERVICE-DEPLOYMENT.md b/docs/AZURE-APP-SERVICE-DEPLOYMENT.md index bcd1a29..d91c7ce 100644 --- a/docs/AZURE-APP-SERVICE-DEPLOYMENT.md +++ b/docs/AZURE-APP-SERVICE-DEPLOYMENT.md @@ -5,7 +5,7 @@ Complete deployment guide voor CMDB Insight naar Azure App Service. ## πŸ“‹ Prerequisites - Azure CLI geΓ―nstalleerd en geconfigureerd (`az login`) -- Docker images in ACR: `zdlas.azurecr.io/cmdb-insight/backend:latest` en `frontend:latest` +- Docker images in ACR: `zdlasacr.azurecr.io/cmdb-insight/backend:latest` en `frontend:latest` - Azure DevOps pipeline werkt (images worden automatisch gebouwd) --- @@ -16,7 +16,7 @@ Complete deployment guide voor CMDB Insight naar Azure App Service. ```bash az group create \ - --name rg-cmdb-gui-prod \ + --name zdl-cmdb-insight-prd-euwe-rg \ --location westeurope ``` @@ -24,8 +24,8 @@ az group create \ ```bash az appservice plan create \ - --name plan-cmdb-gui-prod \ - --resource-group rg-cmdb-gui-prod \ + --name zdl-cmdb-insight-prd-euwe-appsvc \ + --resource-group zdl-cmdb-insight-prd-euwe-rg \ --sku B1 \ --is-linux ``` @@ -35,32 +35,38 @@ az appservice plan create \ ```bash # Backend az webapp create \ - --name cmdb-backend-prod \ - --resource-group rg-cmdb-gui-prod \ - --plan plan-cmdb-gui-prod \ - --deployment-container-image-name zdlas.azurecr.io/cmdb-insight/backend:latest + --name zdl-cmdb-insight-prd-backend-webapp \ + --resource-group zdl-cmdb-insight-prd-euwe-rg \ + --plan zdl-cmdb-insight-prd-euwe-appsvc \ + --container-image-name zdlasacr.azurecr.io/cmdb-insight/backend:latest # Frontend az webapp create \ - --name cmdb-frontend-prod \ - --resource-group rg-cmdb-gui-prod \ - --plan plan-cmdb-gui-prod \ - --deployment-container-image-name zdlas.azurecr.io/cmdb-insight/frontend:latest + --name zdl-cmdb-insight-prd-frontend-webapp \ + --resource-group zdl-cmdb-insight-prd-euwe-rg \ + --plan zdl-cmdb-insight-prd-euwe-appsvc \ + --container-image-name zdlasacr.azurecr.io/cmdb-insight/frontend:latest ``` ### Stap 4: ACR Authentication ```bash # Enable Managed Identity -az webapp identity assign --name cmdb-backend-prod --resource-group rg-cmdb-gui-prod -az webapp identity assign --name cmdb-frontend-prod --resource-group rg-cmdb-gui-prod +az webapp identity assign --name zdl-cmdb-insight-prd-backend-webapp --resource-group zdl-cmdb-insight-prd-euwe-rg +az webapp identity assign --name zdl-cmdb-insight-prd-frontend-webapp --resource-group zdl-cmdb-insight-prd-euwe-rg # Get Principal IDs -BACKEND_PRINCIPAL_ID=$(az webapp identity show --name cmdb-backend-prod --resource-group rg-cmdb-gui-prod --query principalId -o tsv) -FRONTEND_PRINCIPAL_ID=$(az webapp identity show --name cmdb-frontend-prod --resource-group rg-cmdb-gui-prod --query principalId -o tsv) +BACKEND_PRINCIPAL_ID=$(az webapp identity show \ + --name zdl-cmdb-insight-prd-backend-webapp \ + --resource-group zdl-cmdb-insight-prd-euwe-rg \ + --query principalId -o tsv) +FRONTEND_PRINCIPAL_ID=$(az webapp identity show \ + --name zdl-cmdb-insight-prd-frontend-webapp \ + --resource-group zdl-cmdb-insight-prd-euwe-rg \ + --query principalId -o tsv) -# Get ACR Resource ID (vervang met jouw ACR resource group) -ACR_ID=$(az acr show --name zdlas --query id -o tsv) +# Get ACR Resource ID +ACR_ID=$(az acr show --name zdlasacr --query id -o tsv) # Grant AcrPull permissions az role assignment create --assignee $BACKEND_PRINCIPAL_ID --role AcrPull --scope $ACR_ID @@ -68,16 +74,14 @@ az role assignment create --assignee $FRONTEND_PRINCIPAL_ID --role AcrPull --sco # Configure container settings az webapp config container set \ - --name cmdb-backend-prod \ - --resource-group rg-cmdb-gui-prod \ - --docker-custom-image-name zdlas.azurecr.io/cmdb-insight/backend:latest \ - --docker-registry-server-url https://zdlas.azurecr.io + --name zdl-cmdb-insight-prd-backend-webapp \ + --resource-group zdl-cmdb-insight-prd-euwe-rg \ + --docker-registry-server-url https://zdlasacr.azurecr.io az webapp config container set \ - --name cmdb-frontend-prod \ - --resource-group rg-cmdb-gui-prod \ - --docker-custom-image-name zdlas.azurecr.io/cmdb-insight/frontend:latest \ - --docker-registry-server-url https://zdlas.azurecr.io + --name zdl-cmdb-insight-prd-frontend-webapp \ + --resource-group zdl-cmdb-insight-prd-euwe-rg \ + --docker-registry-server-url https://zdlasacr.azurecr.io ``` ### Stap 5: Environment Variabelen @@ -85,8 +89,8 @@ az webapp config container set \ ```bash # Backend (vervang met jouw waarden) az webapp config appsettings set \ - --name cmdb-backend-prod \ - --resource-group rg-cmdb-gui-prod \ + --name zdl-cmdb-insight-prd-backend-webapp \ + --resource-group zdl-cmdb-insight-prd-euwe-rg \ --settings \ NODE_ENV=production \ PORT=3001 \ @@ -94,37 +98,37 @@ az webapp config appsettings set \ JIRA_SCHEMA_ID=your-schema-id \ JIRA_PAT=your-pat-token \ SESSION_SECRET=$(openssl rand -hex 32) \ - FRONTEND_URL=https://cmdb-frontend-prod.azurewebsites.net + FRONTEND_URL=https://zdl-cmdb-insight-prd-frontend-webapp.azurewebsites.net # Frontend az webapp config appsettings set \ - --name cmdb-frontend-prod \ - --resource-group rg-cmdb-gui-prod \ + --name zdl-cmdb-insight-prd-frontend-webapp \ + --resource-group zdl-cmdb-insight-prd-euwe-rg \ --settings \ - VITE_API_URL=https://cmdb-backend-prod.azurewebsites.net/api + VITE_API_URL=https://zdl-cmdb-insight-prd-backend-webapp.azurewebsites.net/api ``` ### Stap 6: Start Apps ```bash -az webapp start --name cmdb-backend-prod --resource-group rg-cmdb-gui-prod -az webapp start --name cmdb-frontend-prod --resource-group rg-cmdb-gui-prod +az webapp start --name zdl-cmdb-insight-prd-backend-webapp --resource-group zdl-cmdb-insight-prd-euwe-rg +az webapp start --name zdl-cmdb-insight-prd-frontend-webapp --resource-group zdl-cmdb-insight-prd-euwe-rg ``` ### Stap 7: Test ```bash # Health check -curl https://cmdb-backend-prod.azurewebsites.net/api/health +curl https://zdl-cmdb-insight-prd-backend-webapp.azurewebsites.net/api/health # Frontend -curl https://cmdb-frontend-prod.azurewebsites.net +curl https://zdl-cmdb-insight-prd-frontend-webapp.azurewebsites.net ``` **πŸŽ‰ Je applicatie is nu live!** -- Frontend: `https://cmdb-frontend-prod.azurewebsites.net` -- Backend API: `https://cmdb-backend-prod.azurewebsites.net/api` +- Frontend: `https://zdl-cmdb-insight-prd-frontend-webapp.azurewebsites.net` +- Backend API: `https://zdl-cmdb-insight-prd-backend-webapp.azurewebsites.net/api` --- @@ -136,8 +140,8 @@ Voor productie: gebruik Azure Key Vault voor secrets. ```bash az keyvault create \ - --name kv-cmdb-gui-prod \ - --resource-group rg-cmdb-gui-prod \ + --name kv-cmdb-insight-prod \ + --resource-group zdl-cmdb-insight-prd-euwe-rg \ --location westeurope \ --sku standard ``` @@ -145,30 +149,53 @@ az keyvault create \ ### Stap 2: Secrets Toevoegen ```bash -az keyvault secret set --vault-name kv-cmdb-gui-prod --name JiraPat --value "your-token" -az keyvault secret set --vault-name kv-cmdb-gui-prod --name SessionSecret --value "$(openssl rand -hex 32)" -az keyvault secret set --vault-name kv-cmdb-gui-prod --name JiraSchemaId --value "your-schema-id" +az keyvault secret set --vault-name kv-cmdb-insight-prod --name JiraPat --value "your-token" +az keyvault secret set --vault-name kv-cmdb-insight-prod --name SessionSecret --value "$(openssl rand -hex 32)" +az keyvault secret set --vault-name kv-cmdb-insight-prod --name JiraSchemaId --value "your-schema-id" ``` ### Stap 3: Grant Access +**Voor Key Vault met RBAC authorization (aanbevolen):** + +```bash +# Get Key Vault Resource ID +KV_ID=$(az keyvault show --name zdl-cmdb-insight-prd-kv --query id -o tsv) + +# Grant Key Vault Secrets User role to backend +az role assignment create \ + --assignee $BACKEND_PRINCIPAL_ID \ + --role "Key Vault Secrets User" \ + --scope $KV_ID + +# Grant to frontend (if needed) +az role assignment create \ + --assignee $FRONTEND_PRINCIPAL_ID \ + --role "Key Vault Secrets User" \ + --scope $KV_ID +``` + +**Voor Key Vault met Access Policies (oude methode):** + ```bash az keyvault set-policy \ - --name kv-cmdb-gui-prod \ + --name zdl-cmdb-insight-prd-kv \ --object-id $BACKEND_PRINCIPAL_ID \ --secret-permissions get list ``` +**Let op:** Als je de fout krijgt "Cannot set policies to a vault with '--enable-rbac-authorization'", gebruik dan de RBAC methode hierboven. + ### Stap 4: Configure App Settings met Key Vault References ```bash az webapp config appsettings set \ - --name cmdb-backend-prod \ - --resource-group rg-cmdb-gui-prod \ + --name zdl-cmdb-insight-prd-backend-webapp \ + --resource-group zdl-cmdb-insight-prd-euwe-rg \ --settings \ - JIRA_PAT="@Microsoft.KeyVault(SecretUri=https://kv-cmdb-gui-prod.vault.azure.net/secrets/JiraPat/)" \ - SESSION_SECRET="@Microsoft.KeyVault(SecretUri=https://kv-cmdb-gui-prod.vault.azure.net/secrets/SessionSecret/)" \ - JIRA_SCHEMA_ID="@Microsoft.KeyVault(SecretUri=https://kv-cmdb-gui-prod.vault.azure.net/secrets/JiraSchemaId/)" + JIRA_PAT="@Microsoft.KeyVault(SecretUri=https://kv-cmdb-insight-prod.vault.azure.net/secrets/JiraPat/)" \ + SESSION_SECRET="@Microsoft.KeyVault(SecretUri=https://kv-cmdb-insight-prod.vault.azure.net/secrets/SessionSecret/)" \ + JIRA_SCHEMA_ID="@Microsoft.KeyVault(SecretUri=https://kv-cmdb-insight-prod.vault.azure.net/secrets/JiraSchemaId/)" ``` --- @@ -180,21 +207,21 @@ az webapp config appsettings set \ ```bash # Create Application Insights az monitor app-insights component create \ - --app cmdb-gui-prod \ + --app cmdb-insight-prod \ --location westeurope \ - --resource-group rg-cmdb-gui-prod \ + --resource-group zdl-cmdb-insight-prd-euwe-rg \ --application-type web # Get Instrumentation Key INSTRUMENTATION_KEY=$(az monitor app-insights component show \ - --app cmdb-gui-prod \ - --resource-group rg-cmdb-gui-prod \ + --app cmdb-insight-prod \ + --resource-group zdl-cmdb-insight-prd-euwe-rg \ --query instrumentationKey -o tsv) # Configure App Settings az webapp config appsettings set \ - --name cmdb-backend-prod \ - --resource-group rg-cmdb-gui-prod \ + --name zdl-cmdb-insight-prd-backend-webapp \ + --resource-group zdl-cmdb-insight-prd-euwe-rg \ --settings \ APPINSIGHTS_INSTRUMENTATIONKEY=$INSTRUMENTATION_KEY ``` @@ -207,8 +234,8 @@ az webapp config appsettings set \ ```bash # Restart Web Apps (pull nieuwe latest image) -az webapp restart --name cmdb-backend-prod --resource-group rg-cmdb-gui-prod -az webapp restart --name cmdb-frontend-prod --resource-group rg-cmdb-gui-prod +az webapp restart --name zdl-cmdb-insight-prd-backend-webapp --resource-group zdl-cmdb-insight-prd-euwe-rg +az webapp restart --name zdl-cmdb-insight-prd-frontend-webapp --resource-group zdl-cmdb-insight-prd-euwe-rg ``` ### Optie 2: Deployment Slots (Zero-Downtime) @@ -216,14 +243,14 @@ az webapp restart --name cmdb-frontend-prod --resource-group rg-cmdb-gui-prod ```bash # Create staging slot az webapp deployment slot create \ - --name cmdb-backend-prod \ - --resource-group rg-cmdb-gui-prod \ + --name zdl-cmdb-insight-prd-backend-webapp \ + --resource-group zdl-cmdb-insight-prd-euwe-rg \ --slot staging # Deploy to staging az webapp deployment slot swap \ - --name cmdb-backend-prod \ - --resource-group rg-cmdb-gui-prod \ + --name zdl-cmdb-insight-prd-backend-webapp \ + --resource-group zdl-cmdb-insight-prd-euwe-rg \ --slot staging \ --target-slot production ``` @@ -236,22 +263,22 @@ az webapp deployment slot swap \ ```bash # Live logs -az webapp log tail --name cmdb-backend-prod --resource-group rg-cmdb-gui-prod +az webapp log tail --name zdl-cmdb-insight-prd-backend-webapp --resource-group zdl-cmdb-insight-prd-euwe-rg # Download logs -az webapp log download --name cmdb-backend-prod --resource-group rg-cmdb-gui-prod --log-file logs.zip +az webapp log download --name zdl-cmdb-insight-prd-backend-webapp --resource-group zdl-cmdb-insight-prd-euwe-rg --log-file logs.zip ``` ### Check Status ```bash -az webapp show --name cmdb-backend-prod --resource-group rg-cmdb-gui-prod --query state +az webapp show --name zdl-cmdb-insight-prd-backend-webapp --resource-group zdl-cmdb-insight-prd-euwe-rg --query state ``` ### Restart App ```bash -az webapp restart --name cmdb-backend-prod --resource-group rg-cmdb-gui-prod +az webapp restart --name zdl-cmdb-insight-prd-backend-webapp --resource-group zdl-cmdb-insight-prd-euwe-rg ``` --- diff --git a/docs/KEY-VAULT-ACCESS-REQUEST.md b/docs/KEY-VAULT-ACCESS-REQUEST.md new file mode 100644 index 0000000..469fe95 --- /dev/null +++ b/docs/KEY-VAULT-ACCESS-REQUEST.md @@ -0,0 +1,101 @@ +# Key Vault Access Request - For Administrators + +## πŸ“‹ Request Information + +**Requested by:** adm_bhausmans@zuyderland.nl +**Date:** $(date +%Y-%m-%d) +**Purpose:** Grant App Services access to Key Vault for CMDB Insight deployment + +## πŸ” Key Vault Details + +- **Key Vault Name:** `zdl-cmdb-insight-prd-kv` +- **Resource Group:** `zdl-cmdb-insight-prd-euwe-rg` +- **Key Vault ID:** `/subscriptions/e9c3e35d-5eca-4bfb-aae5-2e2659d1b474/resourceGroups/zdl-cmdb-insight-prd-euwe-rg/providers/Microsoft.KeyVault/vaults/zdl-cmdb-insight-prd-kv` + +## 🎯 Required Access + +**Role:** `Key Vault Secrets User` +**Scope:** Key Vault resource +**Purpose:** Allow App Services to read secrets from Key Vault + +## πŸ“± App Service Principal IDs + +### Backend Web App +- **App Name:** `zdl-cmdb-insight-prd-backend-webapp` +- **Principal ID:** `6bd8373f-f734-4d21-84f2-776fd11b17ae` + +### Frontend Web App +- **App Name:** `zdl-cmdb-insight-prd-frontend-webapp` +- **Principal ID:** *(Get with command below)* + +## πŸš€ Commands for Administrator + +### Option 1: Use the Script (Recommended) + +```bash +cd /path/to/cmdb-insight +./scripts/grant-keyvault-access-admin.sh +``` + +### Option 2: Manual Commands + +```bash +# Get Key Vault Resource ID +KV_ID=$(az keyvault show \ + --name zdl-cmdb-insight-prd-kv \ + --query id -o tsv) + +# Get Frontend Principal ID (if needed) +FRONTEND_PRINCIPAL_ID=$(az webapp identity show \ + --name zdl-cmdb-insight-prd-frontend-webapp \ + --resource-group zdl-cmdb-insight-prd-euwe-rg \ + --query principalId -o tsv) + +# Grant access to Backend +az role assignment create \ + --assignee "6bd8373f-f734-4d21-84f2-776fd11b17ae" \ + --role "Key Vault Secrets User" \ + --scope $KV_ID + +# Grant access to Frontend (if needed) +az role assignment create \ + --assignee $FRONTEND_PRINCIPAL_ID \ + --role "Key Vault Secrets User" \ + --scope $KV_ID +``` + +### Option 3: Via Azure Portal + +1. Navigate to Key Vault: `zdl-cmdb-insight-prd-kv` +2. Go to **Access control (IAM)** +3. Click **Add** β†’ **Add role assignment** +4. Select role: **Key Vault Secrets User** +5. Assign access to: **Managed identity** +6. Select members: + - Backend: `zdl-cmdb-insight-prd-backend-webapp` + - Frontend: `zdl-cmdb-insight-prd-frontend-webapp` +7. Click **Review + assign** + +## βœ… Verification + +After granting access, verify with: + +```bash +# Check role assignments +az role assignment list \ + --scope "/subscriptions/e9c3e35d-5eca-4bfb-aae5-2e2659d1b474/resourceGroups/zdl-cmdb-insight-prd-euwe-rg/providers/Microsoft.KeyVault/vaults/zdl-cmdb-insight-prd-kv" \ + --query "[?principalId=='6bd8373f-f734-4d21-84f2-776fd11b17ae']" \ + --output table +``` + +## πŸ“ Notes + +- Key Vault uses **RBAC authorization** (not access policies) +- The role "Key Vault Secrets User" only allows reading secrets (not writing/deleting) +- This is the recommended approach for production deployments +- Access is granted via Managed Identity (no credentials stored) + +## πŸ”— Related Documentation + +- `docs/AZURE-APP-SERVICE-DEPLOYMENT.md` - Complete deployment guide +- `scripts/grant-keyvault-access-admin.sh` - Automated script for admins diff --git a/scripts/configure-acr-auth-admin.sh b/scripts/configure-acr-auth-admin.sh new file mode 100755 index 0000000..e4be0ab --- /dev/null +++ b/scripts/configure-acr-auth-admin.sh @@ -0,0 +1,63 @@ +#!/bin/bash +# Configure ACR Authentication using Admin Credentials +# Use this when you don't have permissions to create role assignments on shared ACR + +set -e + +# Configuration +RESOURCE_GROUP="zdl-cmdb-insight-prd-euwe-rg" +ACR_NAME="zdlasacr" +BACKEND_APP_NAME="zdl-cmdb-insight-prd-backend-webapp" +FRONTEND_APP_NAME="zdl-cmdb-insight-prd-frontend-webapp" + +echo "πŸ” Configuring ACR Authentication using Admin Credentials..." +echo "" + +# Step 1: Enable ACR admin (if not already enabled) +echo "πŸ“‹ Step 1: Enabling ACR admin..." +az acr update --name $ACR_NAME --admin-enabled true + +# Step 2: Get ACR credentials +echo "" +echo "πŸ”‘ Step 2: Getting ACR credentials..." +ACR_USERNAME=$(az acr credential show --name $ACR_NAME --query username -o tsv) +ACR_PASSWORD=$(az acr credential show --name $ACR_NAME --query passwords[0].value -o tsv) + +if [ -z "$ACR_USERNAME" ] || [ -z "$ACR_PASSWORD" ]; then + echo "❌ Failed to get ACR credentials" + exit 1 +fi + +echo "βœ… ACR credentials retrieved" +echo " Username: $ACR_USERNAME" +echo "" + +# Step 3: Configure backend web app +echo "🐳 Step 3: Configuring backend web app..." +az webapp config container set \ + --name $BACKEND_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --docker-registry-server-url https://${ACR_NAME}.azurecr.io \ + --docker-registry-server-user $ACR_USERNAME \ + --docker-registry-server-password $ACR_PASSWORD + +echo "βœ… Backend configured" + +# Step 4: Configure frontend web app +echo "" +echo "🐳 Step 4: Configuring frontend web app..." +az webapp config container set \ + --name $FRONTEND_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --docker-registry-server-url https://${ACR_NAME}.azurecr.io \ + --docker-registry-server-user $ACR_USERNAME \ + --docker-registry-server-password $ACR_PASSWORD + +echo "βœ… Frontend configured" + +echo "" +echo "βœ… ACR authentication configured successfully!" +echo "" +echo "⚠️ Note: Using admin credentials is simpler but less secure than Managed Identity." +echo " For production, consider asking an admin to grant AcrPull role via Managed Identity." +echo "" diff --git a/scripts/configure-app-settings-direct.sh b/scripts/configure-app-settings-direct.sh new file mode 100755 index 0000000..007875b --- /dev/null +++ b/scripts/configure-app-settings-direct.sh @@ -0,0 +1,87 @@ +#!/bin/bash +# Configure App Service App Settings Directly (Without Key Vault) +# This is a simpler alternative that works without Key Vault permissions + +set -e + +# Configuration +RESOURCE_GROUP="zdl-cmdb-insight-prd-euwe-rg" +BACKEND_APP_NAME="zdl-cmdb-insight-prd-backend-webapp" +FRONTEND_APP_NAME="zdl-cmdb-insight-prd-frontend-webapp" + +echo "βš™οΈ Configuring App Service App Settings (Direct - No Key Vault)..." +echo "" + +# Generate session secret +SESSION_SECRET=$(openssl rand -hex 32) +echo "βœ… Generated session secret" + +# Get app URLs +BACKEND_URL="https://${BACKEND_APP_NAME}.azurewebsites.net" +FRONTEND_URL="https://${FRONTEND_APP_NAME}.azurewebsites.net" + +echo "" +echo "πŸ“ Configure these values:" +echo " JIRA_SCHEMA_ID: (your Jira schema ID)" +echo " JIRA_PAT: (your Jira Personal Access Token)" +echo " Or JIRA_OAUTH_CLIENT_ID and JIRA_OAUTH_CLIENT_SECRET" +echo "" + +# Prompt for values (or set them as environment variables) +read -p "Enter JIRA_SCHEMA_ID (or press Enter to skip): " JIRA_SCHEMA_ID +read -p "Enter JIRA_PAT (or press Enter to skip): " JIRA_PAT +read -p "Enter JIRA_OAUTH_CLIENT_ID (or press Enter to skip): " JIRA_OAUTH_CLIENT_ID +read -p "Enter JIRA_OAUTH_CLIENT_SECRET (or press Enter to skip): " JIRA_OAUTH_CLIENT_SECRET + +echo "" +echo "πŸ”§ Configuring backend app settings..." + +# Build settings string +SETTINGS="NODE_ENV=production PORT=3001 JIRA_BASE_URL=https://jira.zuyderland.nl SESSION_SECRET=${SESSION_SECRET} FRONTEND_URL=${FRONTEND_URL}" + +if [ -n "$JIRA_SCHEMA_ID" ]; then + SETTINGS="${SETTINGS} JIRA_SCHEMA_ID=${JIRA_SCHEMA_ID}" +fi + +if [ -n "$JIRA_PAT" ]; then + SETTINGS="${SETTINGS} JIRA_PAT=${JIRA_PAT}" +fi + +if [ -n "$JIRA_OAUTH_CLIENT_ID" ]; then + SETTINGS="${SETTINGS} JIRA_OAUTH_CLIENT_ID=${JIRA_OAUTH_CLIENT_ID}" +fi + +if [ -n "$JIRA_OAUTH_CLIENT_SECRET" ]; then + SETTINGS="${SETTINGS} JIRA_OAUTH_CLIENT_SECRET=${JIRA_OAUTH_CLIENT_SECRET}" +fi + +# Configure backend +az webapp config appsettings set \ + --name $BACKEND_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --settings $SETTINGS \ + --output none + +echo "βœ… Backend configured" + +# Configure frontend +echo "" +echo "πŸ”§ Configuring frontend app settings..." +az webapp config appsettings set \ + --name $FRONTEND_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --settings "VITE_API_URL=${BACKEND_URL}/api" \ + --output none + +echo "βœ… Frontend configured" + +echo "" +echo "βœ… App settings configured successfully!" +echo "" +echo "⚠️ Note: Secrets are stored in App Service app settings (encrypted at rest)." +echo " For production, consider migrating to Key Vault later when permissions are available." +echo "" +echo "πŸ“‹ Configured URLs:" +echo " Backend: $BACKEND_URL" +echo " Frontend: $FRONTEND_URL" +echo "" diff --git a/scripts/deploy-app-service.sh b/scripts/deploy-app-service.sh new file mode 100755 index 0000000..d5ed321 --- /dev/null +++ b/scripts/deploy-app-service.sh @@ -0,0 +1,164 @@ +#!/bin/bash +# Azure App Service Deployment Script +# Deploys CMDB Insight backend and frontend to Azure App Service + +set -e # Exit on error + +# Configuration +RESOURCE_GROUP="zdl-cmdb-insight-prd-euwe-rg" +APP_SERVICE_PLAN="zdl-cmdb-insight-prd-euwe-appsvc" +ACR_NAME="zdlasacr" +BACKEND_APP_NAME="zdl-cmdb-insight-prd-backend-webapp" +FRONTEND_APP_NAME="zdl-cmdb-insight-prd-frontend-webapp" +REPOSITORY_NAME="cmdb-insight" +IMAGE_TAG="latest" + +echo "πŸš€ Starting Azure App Service Deployment..." +echo "Resource Group: $RESOURCE_GROUP" +echo "App Service Plan: $APP_SERVICE_PLAN" +echo "ACR: $ACR_NAME" +echo "" + +# Step 1: Create Backend Web App +echo "πŸ“¦ Step 1: Creating Backend Web App..." +az webapp create \ + --name $BACKEND_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --plan $APP_SERVICE_PLAN \ + --container-image-name ${ACR_NAME}.azurecr.io/${REPOSITORY_NAME}/backend:${IMAGE_TAG} + +if [ $? -eq 0 ]; then + echo "βœ… Backend web app created successfully" +else + echo "❌ Failed to create backend web app" + exit 1 +fi + +# Step 2: Create Frontend Web App +echo "" +echo "πŸ“¦ Step 2: Creating Frontend Web App..." +az webapp create \ + --name $FRONTEND_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --plan $APP_SERVICE_PLAN \ + --container-image-name ${ACR_NAME}.azurecr.io/${REPOSITORY_NAME}/frontend:${IMAGE_TAG} + +if [ $? -eq 0 ]; then + echo "βœ… Frontend web app created successfully" +else + echo "❌ Failed to create frontend web app" + exit 1 +fi + +# Step 3: Enable Managed Identity for both apps +echo "" +echo "πŸ” Step 3: Enabling Managed Identity..." +az webapp identity assign \ + --name $BACKEND_APP_NAME \ + --resource-group $RESOURCE_GROUP + +az webapp identity assign \ + --name $FRONTEND_APP_NAME \ + --resource-group $RESOURCE_GROUP + +echo "βœ… Managed Identity enabled for both apps" + +# Step 4: Get Principal IDs +echo "" +echo "πŸ”‘ Step 4: Getting Principal IDs..." +BACKEND_PRINCIPAL_ID=$(az webapp identity show \ + --name $BACKEND_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --query principalId -o tsv) + +FRONTEND_PRINCIPAL_ID=$(az webapp identity show \ + --name $FRONTEND_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --query principalId -o tsv) + +if [ -z "$BACKEND_PRINCIPAL_ID" ] || [ -z "$FRONTEND_PRINCIPAL_ID" ]; then + echo "⚠️ Warning: Could not retrieve Principal IDs. Managed Identity may not be fully enabled yet." + echo " Waiting 10 seconds and retrying..." + sleep 10 + + BACKEND_PRINCIPAL_ID=$(az webapp identity show \ + --name $BACKEND_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --query principalId -o tsv) + + FRONTEND_PRINCIPAL_ID=$(az webapp identity show \ + --name $FRONTEND_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --query principalId -o tsv) +fi + +echo "Backend Principal ID: $BACKEND_PRINCIPAL_ID" +echo "Frontend Principal ID: $FRONTEND_PRINCIPAL_ID" + +# Step 5: Get ACR Resource ID +echo "" +echo "πŸ“‹ Step 5: Getting ACR Resource ID..." +ACR_ID=$(az acr show --name $ACR_NAME --query id -o tsv) + +if [ -z "$ACR_ID" ]; then + echo "❌ Failed to get ACR Resource ID. Is the ACR name correct?" + exit 1 +fi + +echo "ACR Resource ID: $ACR_ID" + +# Step 6: Grant AcrPull permissions +echo "" +echo "πŸ”“ Step 6: Granting AcrPull permissions..." +az role assignment create \ + --assignee $BACKEND_PRINCIPAL_ID \ + --role AcrPull \ + --scope $ACR_ID \ + --output none + +az role assignment create \ + --assignee $FRONTEND_PRINCIPAL_ID \ + --role AcrPull \ + --scope $ACR_ID \ + --output none + +echo "βœ… AcrPull permissions granted" + +# Step 7: Configure container registry URL +echo "" +echo "🐳 Step 7: Configuring container registry settings..." +az webapp config container set \ + --name $BACKEND_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --docker-registry-server-url https://${ACR_NAME}.azurecr.io \ + --output none + +az webapp config container set \ + --name $FRONTEND_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --docker-registry-server-url https://${ACR_NAME}.azurecr.io \ + --output none + +echo "βœ… Container registry configured" + +# Step 8: Get web app URLs +echo "" +echo "🌐 Step 8: Getting web app URLs..." +BACKEND_URL="https://${BACKEND_APP_NAME}.azurewebsites.net" +FRONTEND_URL="https://${FRONTEND_APP_NAME}.azurewebsites.net" + +echo "" +echo "βœ… Deployment completed successfully!" +echo "" +echo "πŸ“‹ Summary:" +echo " Backend URL: $BACKEND_URL" +echo " Frontend URL: $FRONTEND_URL" +echo "" +echo "⚠️ Next Steps:" +echo " 1. Configure environment variables (see docs/AZURE-APP-SERVICE-DEPLOYMENT.md)" +echo " 2. Set up Azure Key Vault for secrets (recommended)" +echo " 3. Configure custom domain and SSL certificate" +echo " 4. Test the deployment:" +echo " curl $BACKEND_URL/api/health" +echo " curl $FRONTEND_URL" +echo "" diff --git a/scripts/grant-keyvault-access-admin.sh b/scripts/grant-keyvault-access-admin.sh new file mode 100755 index 0000000..024dc47 --- /dev/null +++ b/scripts/grant-keyvault-access-admin.sh @@ -0,0 +1,89 @@ +#!/bin/bash +# Grant Key Vault Access - For Admin to Run +# This script grants Key Vault access to App Service Managed Identities +# Run this script as a user with "User Access Administrator" or "Owner" role + +set -e + +# Configuration +KEY_VAULT_NAME="zdl-cmdb-insight-prd-kv" +RESOURCE_GROUP="zdl-cmdb-insight-prd-euwe-rg" +BACKEND_APP_NAME="zdl-cmdb-insight-prd-backend-webapp" +FRONTEND_APP_NAME="zdl-cmdb-insight-prd-frontend-webapp" + +echo "πŸ” Granting Key Vault Access to App Services..." +echo "" + +# Get Key Vault Resource ID +echo "πŸ“‹ Getting Key Vault Resource ID..." +KV_ID=$(az keyvault show --name $KEY_VAULT_NAME --query id -o tsv) +echo " Key Vault ID: $KV_ID" +echo "" + +# Get Backend Principal ID +echo "πŸ”‘ Getting Backend Principal ID..." +BACKEND_PRINCIPAL_ID=$(az webapp identity show \ + --name $BACKEND_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --query principalId -o tsv) + +if [ -z "$BACKEND_PRINCIPAL_ID" ]; then + echo "❌ Failed to get Backend Principal ID. Is Managed Identity enabled?" + exit 1 +fi + +echo " Backend Principal ID: $BACKEND_PRINCIPAL_ID" +echo "" + +# Get Frontend Principal ID +echo "πŸ”‘ Getting Frontend Principal ID..." +FRONTEND_PRINCIPAL_ID=$(az webapp identity show \ + --name $FRONTEND_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --query principalId -o tsv) + +if [ -z "$FRONTEND_PRINCIPAL_ID" ]; then + echo "⚠️ Warning: Could not get Frontend Principal ID. Skipping frontend." + FRONTEND_PRINCIPAL_ID="" +fi + +if [ -n "$FRONTEND_PRINCIPAL_ID" ]; then + echo " Frontend Principal ID: $FRONTEND_PRINCIPAL_ID" + echo "" +fi + +# Grant Key Vault Secrets User role to Backend +echo "πŸ”“ Granting 'Key Vault Secrets User' role to Backend..." +az role assignment create \ + --assignee $BACKEND_PRINCIPAL_ID \ + --role "Key Vault Secrets User" \ + --scope $KV_ID \ + --output none + +echo "βœ… Backend access granted" +echo "" + +# Grant Key Vault Secrets User role to Frontend (if available) +if [ -n "$FRONTEND_PRINCIPAL_ID" ]; then + echo "πŸ”“ Granting 'Key Vault Secrets User' role to Frontend..." + az role assignment create \ + --assignee $FRONTEND_PRINCIPAL_ID \ + --role "Key Vault Secrets User" \ + --scope $KV_ID \ + --output none + + echo "βœ… Frontend access granted" + echo "" +fi + +echo "βœ… Key Vault access configured successfully!" +echo "" +echo "πŸ“‹ Summary:" +echo " Key Vault: $KEY_VAULT_NAME" +echo " Backend App: $BACKEND_APP_NAME" +echo " Backend Principal ID: $BACKEND_PRINCIPAL_ID" +if [ -n "$FRONTEND_PRINCIPAL_ID" ]; then + echo " Frontend App: $FRONTEND_APP_NAME" + echo " Frontend Principal ID: $FRONTEND_PRINCIPAL_ID" +fi +echo ""