Files
PowderCoatingLogix/DEPLOYMENT_CONFIGURATION.md
2026-04-23 21:38:24 -04:00

487 lines
13 KiB
Markdown

# Deployment Configuration Guide
This guide explains how to configure the Powder Coating App for different environments (Development, Staging, Production).
## Overview
The application uses environment-specific configuration files and supports multiple secure configuration methods:
- **Development**: `appsettings.Development.json` (included in repo)
- **Production**: Environment variables, User Secrets, or Azure Key Vault
## Configuration Files
### Development Environment
**File**: `src/PowderCoating.Web/appsettings.Development.json`
- Contains actual development values
- Safe to commit to source control (dev-only credentials)
- Used automatically when `ASPNETCORE_ENVIRONMENT=Development`
**File**: `src/PowderCoating.Api/appsettings.Development.json`
- API-specific development settings
- Contains dev JWT secret and CORS origins
### Production Environment
**File**: `src/PowderCoating.Web/appsettings.json`
- Contains placeholders only (`USE_USER_SECRETS_OR_ENVIRONMENT_VARIABLE`)
- NEVER contains actual secrets
- Safe to commit to source control
**File**: `src/PowderCoating.Api/appsettings.json`
- Same approach - placeholders only
- Production secrets configured via environment variables or Key Vault
---
## Required Configuration Values
### 1. Database Connection String
**Development**:
```json
{
"ConnectionStrings": {
"DefaultConnection": "Server=.\\SQLEXPRESS;Database=PowderCoatingDb;Trusted_Connection=true;MultipleActiveResultSets=true;TrustServerCertificate=true"
}
}
```
**Production** (Windows Server with SQL Server):
```bash
# Environment Variable
set ConnectionStrings__DefaultConnection="Server=PROD_SERVER;Database=PowderCoatingDb;User Id=app_user;Password=SecurePassword123!;MultipleActiveResultSets=true;Encrypt=true"
```
**Production** (Linux/Docker):
```bash
export ConnectionStrings__DefaultConnection="Server=PROD_SERVER;Database=PowderCoatingDb;User Id=app_user;Password=SecurePassword123!;MultipleActiveResultSets=true;Encrypt=true"
```
**Production** (Azure Web App):
- Navigate to: Configuration > Connection strings
- Name: `DefaultConnection`
- Value: Your production connection string
- Type: `SQLServer`
---
### 2. JWT Settings (API Only)
**Development**:
```json
{
"JwtSettings": {
"SecretKey": "DEV-ONLY-SecretKey-MinimumLength32CharactersRequired!@#$",
"Issuer": "PowderCoatingAPI",
"Audience": "PowderCoatingMobileApp",
"ExpirationMinutes": 15,
"RefreshTokenExpirationDays": 7
}
}
```
**Production**:
Generate a strong secret key (minimum 32 characters):
```powershell
# PowerShell - Generate random secret
-join ((48..57) + (65..90) + (97..122) | Get-Random -Count 64 | ForEach-Object {[char]$_})
```
```bash
# Linux - Generate random secret
openssl rand -base64 64
```
Set as environment variable:
```bash
# Windows
set JwtSettings__SecretKey="YOUR_GENERATED_SECRET_HERE"
# Linux
export JwtSettings__SecretKey="YOUR_GENERATED_SECRET_HERE"
# Azure Web App - Application Settings
JwtSettings__SecretKey = YOUR_GENERATED_SECRET_HERE
```
---
### 3. CORS Origins (API Only)
**Development**:
```json
{
"CorsSettings": {
"AllowedOrigins": [
"http://localhost:3000",
"http://localhost:5173",
"http://localhost:58461",
"https://localhost:58461"
]
}
}
```
**Production**:
```json
{
"CorsSettings": {
"AllowedOrigins": [
"https://yourapp.com",
"https://www.yourapp.com",
"https://app.yourdomain.com"
]
}
}
```
⚠️ **NEVER use `*` (wildcard) in production!**
---
### 4. Allowed Hosts
**Development**:
```json
{
"AllowedHosts": "localhost;127.0.0.1"
}
```
**Production**:
```json
{
"AllowedHosts": "yourapp.com;www.yourapp.com;app.yourdomain.com"
}
```
---
### 5. Logging Configuration
**Development** (detailed logging):
```json
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"Microsoft.AspNetCore": "Information",
"Microsoft.EntityFrameworkCore": "Information"
}
}
}
```
**Production** (reduced logging):
```json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.EntityFrameworkCore": "Warning"
}
}
}
```
---
## Security Checklist
### ✅ Development Environment
- [x] Use `appsettings.Development.json` for local development
- [x] Development secrets can be simple (e.g., "Dev123!")
- [x] CORS can allow `localhost` origins
- [x] Detailed logging enabled for debugging
- [x] Database uses Trusted Connection (Windows Auth) or simple password
### ✅ Production Environment
- [ ] **CRITICAL**: Never use development secrets in production
- [ ] **CRITICAL**: Use strong, randomly generated secrets (64+ characters)
- [ ] **CRITICAL**: Store secrets in environment variables, User Secrets, or Azure Key Vault
- [ ] **CRITICAL**: Enable HTTPS with valid SSL certificate
- [ ] **CRITICAL**: Configure CORS with specific allowed origins (NO wildcards)
- [ ] Configure AllowedHosts with actual production domain(s)
- [ ] Use encrypted database connection with strong password
- [ ] Reduce logging verbosity (Warning/Error only)
- [ ] Set `ASPNETCORE_ENVIRONMENT=Production`
- [ ] Enable HSTS (Strict-Transport-Security headers)
- [ ] Configure rate limiting and DDoS protection
- [ ] Set up monitoring and alerting
- [ ] Regular security patches and updates
---
## Configuration Methods by Environment
### Method 1: Environment Variables (Recommended for Production)
**Advantages**:
- Secure (not stored in files)
- Easy to manage in cloud platforms
- Platform-agnostic
**Windows**:
```powershell
# Set for current session
$env:ConnectionStrings__DefaultConnection="Server=...;Database=...;User Id=...;Password=..."
$env:JwtSettings__SecretKey="YourSecretKey"
# Set permanently (System-wide)
[Environment]::SetEnvironmentVariable("ConnectionStrings__DefaultConnection", "Server=...;", "Machine")
```
**Linux**:
```bash
# Add to ~/.bashrc or /etc/environment
export ConnectionStrings__DefaultConnection="Server=...;Database=...;User Id=...;Password=..."
export JwtSettings__SecretKey="YourSecretKey"
```
**Docker**:
```yaml
# docker-compose.yml
services:
powdercoating-web:
environment:
- ConnectionStrings__DefaultConnection=Server=db;Database=PowderCoatingDb;User Id=sa;Password=YourPassword
- ASPNETCORE_ENVIRONMENT=Production
```
---
### Method 2: User Secrets (Development Only)
**Setup**:
```bash
cd src/PowderCoating.Web
dotnet user-secrets init
dotnet user-secrets set "ConnectionStrings:DefaultConnection" "Server=...;Database=...;"
dotnet user-secrets set "JwtSettings:SecretKey" "YourSecretKey"
```
**View secrets**:
```bash
dotnet user-secrets list
```
⚠️ **User Secrets are for development only** - they are stored locally on your machine and won't deploy to production.
---
### Method 3: Azure Key Vault (Production)
**Setup**:
1. Create Azure Key Vault
2. Add secrets to Key Vault:
- `ConnectionStrings--DefaultConnection`
- `JwtSettings--SecretKey`
3. Grant App Service Managed Identity access to Key Vault
**Code** (add to `Program.cs`):
```csharp
if (builder.Environment.IsProduction())
{
var keyVaultUri = new Uri($"https://{builder.Configuration["KeyVaultName"]}.vault.azure.net/");
builder.Configuration.AddAzureKeyVault(keyVaultUri, new DefaultAzureCredential());
}
```
---
## Deployment Steps
### Local Development
1. Clone repository
2. Ensure `ASPNETCORE_ENVIRONMENT=Development`
3. Verify `appsettings.Development.json` has correct local SQL Server connection
4. Run migrations:
```bash
cd src/PowderCoating.Web
dotnet ef database update --project ../PowderCoating.Infrastructure
```
5. Run application:
```bash
dotnet run
```
---
### Production Deployment (Windows Server/IIS)
1. **Publish Application**:
```bash
cd src/PowderCoating.Web
dotnet publish -c Release -o C:\Publish\PowderCoatingApp
```
2. **Configure Environment Variables** (IIS):
- Open IIS Manager
- Select Application Pool > Advanced Settings
- Under Environment Variables, add:
- `ASPNETCORE_ENVIRONMENT = Production`
- `ConnectionStrings__DefaultConnection = <your connection string>`
3. **Install SQL Server Database**:
```bash
# Run migrations on production database
dotnet ef database update --project ../PowderCoating.Infrastructure --configuration Release
```
4. **Configure IIS**:
- Enable HTTPS binding with valid SSL certificate
- Set Application Pool to "No Managed Code"
- Install ASP.NET Core Hosting Bundle
5. **Security Hardening**:
- Disable directory browsing
- Remove unnecessary HTTP headers
- Configure IP restrictions if needed
- Enable request filtering
---
### Production Deployment (Azure App Service)
1. **Create Azure Resources**:
- Azure SQL Database
- Azure App Service (Windows or Linux)
- Azure Key Vault (optional, but recommended)
2. **Configure App Service**:
- **Configuration > General Settings**:
- Stack: .NET 8
- Platform: 64-bit
- HTTPS Only: On
- **Configuration > Application Settings**:
```
ASPNETCORE_ENVIRONMENT = Production
JwtSettings__SecretKey = <your secret>
JwtSettings__ExpirationMinutes = 15
CorsSettings__AllowedOrigins__0 = https://yourapp.com
AllowedHosts = yourapp.com;www.yourapp.com
```
- **Configuration > Connection Strings**:
```
Name: DefaultConnection
Value: Server=tcp:yourserver.database.windows.net,1433;Database=PowderCoatingDb;User ID=sqladmin;Password=...;Encrypt=True;
Type: SQLServer
```
3. **Deploy Code**:
```bash
# Via Azure CLI
az webapp deployment source config-zip --resource-group YourRG --name YourAppName --src publish.zip
```
4. **Run Database Migrations**:
- Option 1: Use Azure Cloud Shell or local machine with connection to Azure SQL
- Option 2: Enable migrations on startup (NOT recommended for production)
---
## Password Requirements
**Development**: Minimum 8 characters
**Production** (enforced by application):
- Minimum 12 characters
- At least 1 uppercase letter
- At least 1 lowercase letter
- At least 1 digit
- At least 1 special character (!@#$%^&*)
- At least 4 unique characters
- Account lockout after 5 failed attempts (15-minute lockout)
---
## Security Headers (Automatically Applied)
The application automatically adds these security headers in production:
- `X-Frame-Options: DENY` - Prevent clickjacking
- `X-Content-Type-Options: nosniff` - Prevent MIME sniffing
- `X-XSS-Protection: 1; mode=block` - XSS protection
- `Strict-Transport-Security: max-age=31536000; includeSubDomains` - Force HTTPS
- `Content-Security-Policy` - Restrict resource loading
- `Referrer-Policy: strict-origin-when-cross-origin` - Control referrer info
- `Permissions-Policy` - Disable unnecessary browser features
---
## Troubleshooting
### Issue: "Connection string not found"
**Solution**: Ensure environment variable is set with double underscores (`__`):
```bash
ConnectionStrings__DefaultConnection # Correct
ConnectionStrings:DefaultConnection # Wrong (this is for User Secrets only)
```
### Issue: "JWT secret key is too short"
**Solution**: Generate a new secret with minimum 32 characters (64+ recommended)
### Issue: "CORS policy blocked"
**Solution**: Add your frontend domain to `CorsSettings:AllowedOrigins` array
### Issue: "Cookies not working"
**Solution**:
- Ensure HTTPS is enabled in production
- Check that `CookieSecurePolicy.Always` is compatible with your hosting
- For development over HTTP, set `SecurePolicy = CookieSecurePolicy.SameAsRequest`
---
## Monitoring and Logs
**Development**:
- Console output
- Files in `/logs/` directory
- `powdercoating-{date}.txt` - All logs
- `errors-{date}.txt` - Errors only
**Production**:
- Configure Azure Application Insights (recommended)
- Or use Serilog sinks (Seq, Elasticsearch, etc.)
- Set up alerts for errors and performance issues
---
## Summary
| Configuration | Development | Production |
|---------------|-------------|------------|
| **Secrets** | appsettings.Development.json | Environment Variables / Key Vault |
| **HTTPS** | Optional | **Required** |
| **CORS** | localhost:* | Specific domains only |
| **Logging** | Debug/Information | Warning/Error |
| **AllowedHosts** | localhost;127.0.0.1 | yourdomain.com |
| **JWT Expiration** | 15 minutes | 15 minutes |
| **Password Policy** | Strong (12 chars) | Strong (12 chars) |
| **Session Cookies** | Secure, HttpOnly, SameSite=Strict | Same + SecurePolicy=Always |
---
## Questions?
If you encounter any issues with deployment or configuration, check:
1. This guide
2. Application logs (Diagnostics > View Logs in the app)
3. Environment-specific appsettings files
4. Environment variables are correctly set
**Security Tip**: Regularly rotate secrets (JWT keys, database passwords) every 90 days in production.