# 🚀 Deployment Prerequisites Guide Complete guide for setting up MS Azure, MS Entra, Cloudflare, and all other services required for production deployment. ## 📋 Table of Contents 1. [Azure Setup](#azure-setup) 2. [MS Entra (Azure AD) Configuration](#ms-entra-azure-ad-configuration) 3. [Cloudflare Configuration](#cloudflare-configuration) 4. [Stripe Configuration](#stripe-configuration) 5. [Environment Variables](#environment-variables) 6. [Pre-Deployment Checklist](#pre-deployment-checklist) 7. [Post-Deployment Verification](#post-deployment-verification) --- ## 1. Azure Setup ### 1.1 Prerequisites - Azure subscription with Contributor or Owner role - Azure CLI installed and configured - Bicep CLI installed (optional, for local validation) - PowerShell 7+ (for deployment scripts) ### 1.2 Initial Azure Configuration #### Login to Azure ```bash # Login to Azure az login # Verify subscription az account show # Set default subscription (if multiple) az account set --subscription "Your Subscription ID" ``` #### Create Resource Group ```bash # Create resource group for production az group create \ --name rg-miraclesinmotion-prod \ --location eastus2 # Verify resource group az group show --name rg-miraclesinmotion-prod ``` ### 1.3 Required Azure Services The infrastructure deployment will create: - **Azure Static Web Apps** (Standard SKU) - Frontend hosting - **Azure Functions** (Premium EP1) - Backend API - **Azure Cosmos DB** - Database - **Azure Key Vault** - Secrets management - **Azure Application Insights** - Monitoring - **Log Analytics Workspace** - Logging - **Azure SignalR** - Real-time communications - **Storage Account** - Function app storage ### 1.4 Deploy Infrastructure ```bash # Navigate to infrastructure directory cd infrastructure # Deploy production infrastructure az deployment group create \ --resource-group rg-miraclesinmotion-prod \ --template-file main-production.bicep \ --parameters main-production.parameters.json \ --parameters stripePublicKey="pk_live_YOUR_KEY" \ --parameters customDomainName="miraclesinmotion.org" \ --parameters enableCustomDomain=true # Note: Replace pk_live_YOUR_KEY with your actual Stripe public key ``` ### 1.5 Get Deployment Outputs ```bash # Get deployment outputs az deployment group show \ --resource-group rg-miraclesinmotion-prod \ --name deployment-name \ --query properties.outputs ``` **Important Outputs:** - `staticWebAppName` - Static Web App resource name - `staticWebAppUrl` - Default URL for Static Web App - `functionAppName` - Function App resource name - `keyVaultName` - Key Vault resource name - `appInsightsName` - Application Insights resource name --- ## 2. MS Entra (Azure AD) Configuration ### 2.1 Create App Registration #### Using Azure Portal 1. Navigate to **Azure Portal** → **Microsoft Entra ID** → **App registrations** 2. Click **+ New registration** 3. Configure: - **Name**: `Miracles In Motion Web App` - **Supported account types**: `Accounts in any organizational directory and personal Microsoft accounts` - **Redirect URI**: - Type: `Single-page application (SPA)` - URI: `https://miraclesinmotion.org` (production) - URI: `https://YOUR_STATIC_WEB_APP.azurestaticapps.net` (staging) 4. Click **Register** #### Using Azure CLI ```bash # Create app registration az ad app create \ --display-name "Miracles In Motion Web App" \ --sign-in-audience "AzureADMultipleOrgs" \ --web-redirect-uris "https://miraclesinmotion.org" "https://www.miraclesinmotion.org" # Get app registration ID APP_ID=$(az ad app list --display-name "Miracles In Motion Web App" --query "[0].appId" -o tsv) echo "App ID: $APP_ID" ``` ### 2.2 Configure Authentication 1. In the app registration, go to **Authentication** 2. Enable **ID tokens** (used for implicit and hybrid flows) 3. Add redirect URIs: - `https://miraclesinmotion.org` - `https://www.miraclesinmotion.org` - `https://YOUR_STATIC_WEB_APP.azurestaticapps.net` 4. Under **Implicit grant and hybrid flows**, enable: - ✅ ID tokens 5. Save changes ### 2.3 Configure API Permissions 1. Go to **API permissions** 2. Click **+ Add a permission** 3. Select **Microsoft Graph** 4. Add the following **Delegated permissions**: - `User.Read` - Read user profile - `User.ReadBasic.All` - Read all users' basic profiles - `email` - View users' email address - `openid` - Sign users in - `profile` - View users' basic profile 5. Click **Add permissions** 6. Click **Grant admin consent** (if you have admin rights) ### 2.4 Create Client Secret (Optional - for server-side flows) ```bash # Create client secret (valid for 24 months) az ad app credential reset \ --id $APP_ID \ --display-name "Miracles In Motion Secret" \ --years 2 # Save the secret value immediately - it won't be shown again! ``` ### 2.5 Configure App Roles 1. Go to **App roles** → **+ Create app role** 2. Create roles: - **Display name**: `Admin` - **Allowed member types**: `Users/Groups` - **Value**: `Admin` - **Description**: `Administrator access to all features` - **Display name**: `Volunteer` - **Allowed member types**: `Users/Groups` - **Value**: `Volunteer` - **Description**: `Volunteer access to assigned tasks` - **Display name**: `Resource` - **Allowed member types**: `Users/Groups` - **Value**: `Resource` - **Description**: `Resource provider access` 3. Save each role ### 2.6 Assign Users to Roles ```bash # Get user object ID USER_ID=$(az ad user show --id "user@domain.com" --query "id" -o tsv) # Get app role ID (Admin role) ROLE_ID=$(az ad app show --id $APP_ID --query "appRoles[?value=='Admin'].id" -o tsv) # Assign user to role az ad app assignment create \ --app-id $APP_ID \ --principal-id $USER_ID \ --role-id $ROLE_ID ``` ### 2.7 Configure Static Web App Authentication 1. Navigate to **Static Web App** → **Authentication** 2. Click **Add identity provider** 3. Select **Microsoft** 4. Configure: - **App registration**: Select your app registration - **App ID**: Your app registration ID - **App secret setting name**: `MICROSOFT_CLIENT_SECRET` (optional) 5. Save #### Using Azure CLI ```bash # Get Static Web App resource ID SWA_ID=$(az staticwebapp show \ --name YOUR_STATIC_WEB_APP_NAME \ --resource-group rg-miraclesinmotion-prod \ --query "id" -o tsv) # Configure Microsoft identity provider az staticwebapp identity assign \ --name YOUR_STATIC_WEB_APP_NAME \ --resource-group rg-miraclesinmotion-prod # Note: Static Web Apps authentication is configured via Azure Portal # or through the staticwebapp.config.json file ``` ### 2.8 Update staticwebapp.config.json The `staticwebapp.config.json` file should include authentication configuration: ```json { "routes": [ { "route": "/api/*", "allowedRoles": ["anonymous", "authenticated"] }, { "route": "/admin/*", "allowedRoles": ["Admin"] }, { "route": "/volunteer/*", "allowedRoles": ["Volunteer", "Admin"] }, { "route": "/*", "rewrite": "/index.html" } ], "auth": { "identityProviders": { "azureActiveDirectory": { "registration": { "openIdIssuer": "https://login.microsoftonline.com/{tenantId}/v2.0", "clientIdSettingName": "AZURE_CLIENT_ID", "clientSecretSettingName": "AZURE_CLIENT_SECRET" } } } }, "navigationFallback": { "rewrite": "/index.html", "exclude": ["/api/*", "/admin/*"] } } ``` ### 2.9 Store Configuration in Key Vault ```bash # Store Azure AD configuration in Key Vault az keyvault secret set \ --vault-name YOUR_KEY_VAULT_NAME \ --name "azure-client-id" \ --value "$APP_ID" az keyvault secret set \ --vault-name YOUR_KEY_VAULT_NAME \ --name "azure-client-secret" \ --value "YOUR_CLIENT_SECRET" az keyvault secret set \ --vault-name YOUR_KEY_VAULT_NAME \ --name "azure-tenant-id" \ --value "$(az account show --query tenantId -o tsv)" ``` --- ## 3. Cloudflare Configuration ### 3.1 Prerequisites - Cloudflare account - Domain registered and added to Cloudflare - DNS management access ### 3.2 Add Domain to Cloudflare 1. Log in to **Cloudflare Dashboard** 2. Click **Add a site** 3. Enter your domain: `miraclesinmotion.org` 4. Select a plan (Free plan is sufficient for basic needs) 5. Cloudflare will scan your existing DNS records ### 3.3 Update Nameservers 1. Copy the nameservers provided by Cloudflare 2. Update your domain registrar with these nameservers 3. Wait for DNS propagation (24-48 hours) ### 3.4 Configure DNS Records #### Add CNAME Records 1. Go to **DNS** → **Records** 2. Add the following records: | Type | Name | Content | Proxy | TTL | |------|------|---------|-------|-----| | CNAME | www | YOUR_STATIC_WEB_APP.azurestaticapps.net | ✅ Proxied | Auto | | CNAME | @ | YOUR_STATIC_WEB_APP.azurestaticapps.net | ✅ Proxied | Auto | **Note**: Replace `YOUR_STATIC_WEB_APP` with your actual Static Web App name. #### Verify DNS Configuration ```bash # Check DNS records dig miraclesinmotion.org dig www.miraclesinmotion.org # Check Cloudflare proxy status curl -I https://miraclesinmotion.org # Look for "CF-Cache-Status" header ``` ### 3.5 Configure SSL/TLS 1. Go to **SSL/TLS** → **Overview** 2. Select **Full (strict)** encryption mode 3. Enable **Always Use HTTPS** 4. Enable **Automatic HTTPS Rewrites** ### 3.6 Configure Page Rules 1. Go to **Rules** → **Page Rules** 2. Create rules: **Rule 1: Force HTTPS** - URL: `*miraclesinmotion.org/*` - Settings: - Always Use HTTPS: ✅ On - SSL: Full (strict) **Rule 2: Cache Static Assets** - URL: `*miraclesinmotion.org/assets/*` - Settings: - Cache Level: Cache Everything - Edge Cache TTL: 1 month ### 3.7 Configure Security Settings 1. Go to **Security** → **Settings** 2. Configure: - **Security Level**: Medium - **Challenge Passage**: 30 minutes - **Browser Integrity Check**: On - **Privacy Pass Support**: On ### 3.8 Configure Firewall Rules 1. Go to **Security** → **WAF** → **Custom rules** 2. Create rules to block malicious traffic: **Rule: Block Bad Bots** - Expression: `(http.user_agent contains "bot" and not http.user_agent contains "Googlebot")` - Action: Block **Rule: Rate Limiting** - Expression: `(http.request.uri.path contains "/api/")` - Action: Challenge - Rate: 100 requests per minute ### 3.9 Configure Speed Optimization 1. Go to **Speed** → **Optimization** 2. Enable: - ✅ Auto Minify (JavaScript, CSS, HTML) - ✅ Brotli compression - ✅ Rocket Loader (optional) - ✅ Mirage (optional, for mobile) ### 3.10 Configure Analytics 1. Go to **Analytics** → **Web Analytics** 2. Enable **Web Analytics** for your domain 3. Add the tracking script to your application (optional) ### 3.11 Configure Custom Domain in Azure After DNS is configured: ```bash # Add custom domain to Static Web App az staticwebapp hostname set \ --name YOUR_STATIC_WEB_APP_NAME \ --resource-group rg-miraclesinmotion-prod \ --hostname "miraclesinmotion.org" az staticwebapp hostname set \ --name YOUR_STATIC_WEB_APP_NAME \ --resource-group rg-miraclesinmotion-prod \ --hostname "www.miraclesinmotion.org" ``` **Note**: Azure will automatically provision SSL certificates for custom domains. ### 3.12 Verify Cloudflare Configuration ```bash # Test DNS resolution nslookup miraclesinmotion.org nslookup www.miraclesinmotion.org # Test HTTPS curl -I https://miraclesinmotion.org # Test Cloudflare headers curl -I https://miraclesinmotion.org | grep -i "cf-" # Expected headers: # CF-Cache-Status: DYNAMIC # CF-Ray: [unique-id] # Server: cloudflare ``` --- ## 4. Stripe Configuration ### 4.1 Create Stripe Account 1. Go to [Stripe Dashboard](https://dashboard.stripe.com) 2. Create account or log in 3. Complete account verification ### 4.2 Get API Keys 1. Go to **Developers** → **API keys** 2. Copy: - **Publishable key** (starts with `pk_live_`) - **Secret key** (starts with `sk_live_`) - Keep this secret! ### 4.3 Configure Webhooks 1. Go to **Developers** → **Webhooks** 2. Click **+ Add endpoint** 3. Configure: - **Endpoint URL**: `https://miraclesinmotion.org/api/webhooks/stripe` - **Events to send**: Select relevant events: - `payment_intent.succeeded` - `payment_intent.payment_failed` - `charge.succeeded` - `charge.failed` 4. Copy the **Webhook signing secret** (starts with `whsec_`) ### 4.4 Store Stripe Secrets in Key Vault ```bash # Store Stripe keys in Key Vault az keyvault secret set \ --vault-name YOUR_KEY_VAULT_NAME \ --name "stripe-publishable-key" \ --value "pk_live_YOUR_KEY" az keyvault secret set \ --vault-name YOUR_KEY_VAULT_NAME \ --name "stripe-secret-key" \ --value "sk_live_YOUR_KEY" az keyvault secret set \ --vault-name YOUR_KEY_VAULT_NAME \ --name "stripe-webhook-secret" \ --value "whsec_YOUR_SECRET" ``` ### 4.5 Update Function App Settings ```bash # Get secrets from Key Vault STRIPE_SECRET=$(az keyvault secret show \ --vault-name YOUR_KEY_VAULT_NAME \ --name "stripe-secret-key" \ --query "value" -o tsv) # Update Function App settings az functionapp config appsettings set \ --name YOUR_FUNCTION_APP_NAME \ --resource-group rg-miraclesinmotion-prod \ --settings "STRIPE_SECRET_KEY=@Microsoft.KeyVault(SecretUri=https://YOUR_KEY_VAULT_NAME.vault.azure.net/secrets/stripe-secret-key/)" ``` --- ## 5. Environment Variables ### 5.1 Create Environment File Template Create `.env.production` file: ```bash # Azure Configuration AZURE_STATIC_WEB_APP_URL=https://miraclesinmotion.org AZURE_FUNCTION_APP_URL=https://YOUR_FUNCTION_APP.azurewebsites.net AZURE_CLIENT_ID=your-azure-client-id AZURE_TENANT_ID=your-azure-tenant-id # Stripe Configuration VITE_STRIPE_PUBLISHABLE_KEY=pk_live_YOUR_KEY STRIPE_SECRET_KEY=sk_live_YOUR_KEY STRIPE_WEBHOOK_SECRET=whsec_YOUR_SECRET # Cosmos DB Configuration COSMOS_DATABASE_NAME=MiraclesInMotion COSMOS_ENDPOINT=https://YOUR_COSMOS_ACCOUNT.documents.azure.com:443/ # Application Insights APPLICATIONINSIGHTS_CONNECTION_STRING=InstrumentationKey=YOUR_KEY # Key Vault KEY_VAULT_URL=https://YOUR_KEY_VAULT_NAME.vault.azure.net/ # SignalR SIGNALR_CONNECTION_STRING=Endpoint=https://YOUR_SIGNALR.service.signalr.net;AccessKey=YOUR_KEY; # Custom Domain CUSTOM_DOMAIN=miraclesinmotion.org ``` ### 5.2 Update Static Web App Configuration ```bash # Set environment variables for Static Web App az staticwebapp appsettings set \ --name YOUR_STATIC_WEB_APP_NAME \ --resource-group rg-miraclesinmotion-prod \ --setting-names "VITE_STRIPE_PUBLISHABLE_KEY=pk_live_YOUR_KEY" \ "AZURE_CLIENT_ID=your-azure-client-id" \ "AZURE_TENANT_ID=your-azure-tenant-id" ``` --- ## 6. Pre-Deployment Checklist ### 6.1 Azure Checklist - [ ] Azure subscription created and active - [ ] Resource group created - [ ] Infrastructure deployed via Bicep - [ ] All Azure resources created successfully - [ ] Key Vault configured with secrets - [ ] Application Insights configured - [ ] Static Web App created - [ ] Function App created and configured - [ ] Cosmos DB database and containers created - [ ] RBAC permissions configured ### 6.2 MS Entra Checklist - [ ] App registration created - [ ] Redirect URIs configured - [ ] API permissions granted - [ ] App roles created (Admin, Volunteer, Resource) - [ ] Users assigned to roles - [ ] Client ID and Tenant ID recorded - [ ] Client secret created (if needed) - [ ] Static Web App authentication configured ### 6.3 Cloudflare Checklist - [ ] Domain added to Cloudflare - [ ] Nameservers updated at registrar - [ ] DNS records configured (CNAME for www and @) - [ ] SSL/TLS set to Full (strict) - [ ] Always Use HTTPS enabled - [ ] Page rules configured - [ ] Firewall rules configured - [ ] Security settings configured - [ ] Speed optimization enabled - [ ] Custom domain added to Azure Static Web App ### 6.4 Stripe Checklist - [ ] Stripe account created and verified - [ ] API keys obtained (publishable and secret) - [ ] Webhook endpoint configured - [ ] Webhook signing secret obtained - [ ] Secrets stored in Key Vault - [ ] Function App configured with Stripe keys ### 6.5 Application Checklist - [ ] Environment variables configured - [ ] staticwebapp.config.json updated - [ ] Authentication flow tested - [ ] API endpoints tested - [ ] Stripe integration tested - [ ] Monitoring configured - [ ] Logging configured --- ## 7. Post-Deployment Verification ### 7.1 Verify Azure Resources ```bash # Check Static Web App status az staticwebapp show \ --name YOUR_STATIC_WEB_APP_NAME \ --resource-group rg-miraclesinmotion-prod # Check Function App status az functionapp show \ --name YOUR_FUNCTION_APP_NAME \ --resource-group rg-miraclesinmotion-prod # Check Cosmos DB status az cosmosdb show \ --name YOUR_COSMOS_ACCOUNT \ --resource-group rg-miraclesinmotion-prod ``` ### 7.2 Verify Authentication 1. Navigate to `https://miraclesinmotion.org` 2. Click "Sign In" 3. Verify Microsoft authentication flow 4. Verify user roles are assigned correctly 5. Test role-based access control ### 7.3 Verify Cloudflare ```bash # Test DNS resolution dig miraclesinmotion.org dig www.miraclesinmotion.org # Test HTTPS curl -I https://miraclesinmotion.org # Verify Cloudflare headers curl -I https://miraclesinmotion.org | grep -i "cf-" ``` ### 7.4 Verify Stripe Integration 1. Test donation flow on the website 2. Verify webhook events are received 3. Check Stripe dashboard for transactions 4. Verify payment processing ### 7.5 Verify Monitoring 1. Check Application Insights for telemetry 2. Verify logs are being collected 3. Set up alerts for critical issues 4. Test error tracking ### 7.6 Performance Testing ```bash # Test page load times curl -w "@curl-format.txt" -o /dev/null -s https://miraclesinmotion.org # Test API response times curl -w "@curl-format.txt" -o /dev/null -s https://miraclesinmotion.org/api/donations ``` --- ## 8. Troubleshooting ### 8.1 Common Issues #### Authentication Not Working - Verify app registration redirect URIs - Check Static Web App authentication configuration - Verify user roles are assigned - Check browser console for errors #### DNS Not Resolving - Verify nameservers are updated - Wait for DNS propagation (24-48 hours) - Check Cloudflare DNS records - Verify CNAME records point to correct Azure endpoint #### SSL Certificate Issues - Verify Cloudflare SSL mode is "Full (strict)" - Check Azure Static Web App custom domain configuration - Wait for SSL certificate provisioning (can take up to 24 hours) #### Stripe Webhook Not Working - Verify webhook endpoint URL is correct - Check webhook signing secret - Verify Function App is receiving webhook events - Check Function App logs for errors ### 8.2 Support Resources - **Azure Documentation**: https://docs.microsoft.com/azure - **MS Entra Documentation**: https://docs.microsoft.com/azure/active-directory - **Cloudflare Documentation**: https://developers.cloudflare.com - **Stripe Documentation**: https://stripe.com/docs --- ## 9. Next Steps After completing all prerequisites: 1. Deploy the application using the deployment script 2. Verify all functionality 3. Set up monitoring and alerts 4. Configure backup and disaster recovery 5. Set up CI/CD pipeline 6. Schedule regular security audits 7. Set up performance monitoring --- ## 10. Security Best Practices 1. **Never commit secrets to source control** 2. **Use Key Vault for all secrets** 3. **Enable MFA for all Azure accounts** 4. **Regularly rotate API keys and secrets** 5. **Monitor for suspicious activity** 6. **Keep dependencies updated** 7. **Use HTTPS everywhere** 8. **Implement rate limiting** 9. **Regular security audits** 10. **Follow principle of least privilege** --- **Last Updated**: January 2025 **Maintained by**: Miracles In Motion Development Team