diff --git a/docs/ms-app-proxy-deployment.md b/docs/ms-app-proxy-deployment.md new file mode 100644 index 0000000..1350edb --- /dev/null +++ b/docs/ms-app-proxy-deployment.md @@ -0,0 +1,269 @@ +# Microsoft Azure Application Proxy Deployment Guide + +This guide provides step-by-step instructions for deploying RDPGW behind Microsoft Azure Application Proxy with Conditional Access Policy enforcement. + +## Architecture Overview + +``` +Internet → Azure AD (Auth + CAP) → App Proxy → RDPGW (Internal) → RDP Hosts +``` + +**Authentication Flow:** +- **Web requests** (`/connect`): Full Azure AD authentication with headers +- **RDP protocol** (`/remoteDesktopGateway/`): Passthrough with token validation + +## Prerequisites + +- Azure AD Premium P1/P2 (for Conditional Access) +- Azure AD Application Proxy connector installed +- RDPGW deployed internally +- Network connectivity from connector to RDPGW + +## Step 1: Azure AD App Registration + +```powershell +# Create app registration +$app = New-AzADApplication -DisplayName "RDPGW-AppProxy" ` + -HomePage "https://rdpgw.yourdomain.com" ` + -IdentifierUris "https://rdpgw.yourdomain.com" + +# Note the Application ID +Write-Host "Application ID: $($app.ApplicationId)" +``` + +## Step 2: Configure Application Proxy + +### Portal Configuration + +1. **Navigate to**: Azure AD → Enterprise Applications → New Application +2. **Select**: On-premises application +3. **Configure**: + - **Name**: RDPGW + - **Internal URL**: `http://rdpgw-server:80` + - **External URL**: `https://rdpgw.yourdomain.com` + - **Pre-authentication**: Azure Active Directory + - **Connector Group**: Select appropriate connector + +### Advanced Configuration + +```json +{ + "application": { + "name": "RDPGW", + "internalUrl": "http://rdpgw-server", + "externalUrl": "https://rdpgw.yourdomain.com", + "preAuthentication": "aadPreAuthentication", + "externalAuthenticationType": "aadPreAuthentication", + "applicationProxyUrlSettings": { + "externalUrl": "https://rdpgw.yourdomain.com", + "internalUrl": "http://rdpgw-server", + "isTranslateHostHeaderEnabled": true, + "isTranslateLinksInBodyEnabled": false, + "isOnPremPublishingEnabled": true + } + } +} +``` + +## Step 3: Configure Passthrough for RDP Endpoint + +**Critical**: Configure App Proxy to bypass authentication for RDP connections: + +### PowerShell Configuration + +```powershell +# Get the application +$app = Get-AzADApplication -DisplayName "RDPGW-AppProxy" + +# Configure passthrough paths (if available via API) +# Note: This may need to be configured via Support ticket +$passthroughPaths = @("/remoteDesktopGateway/*") +``` + +### Support Request + +If passthrough configuration isn't available in portal: + +1. **Open Azure Support Ticket** +2. **Request**: Passthrough configuration for `/remoteDesktopGateway/*` path +3. **Provide**: Application ID and external URL +4. **Reason**: RDP client compatibility requirements + +## Step 4: RDPGW Configuration + +### Complete Configuration File + +```yaml +# rdpgw.yaml +Server: + Authentication: + - header + Tls: disable + GatewayAddress: https://rdpgw.yourdomain.com + Port: 80 + Hosts: + - server1.internal.domain:3389 + - server2.internal.domain:3389 + - "{{ preferred_username }}-desktop:3389" # Dynamic host mapping + +Header: + UserHeader: "X-MS-CLIENT-PRINCIPAL-NAME" + UserIdHeader: "X-MS-CLIENT-PRINCIPAL-ID" + EmailHeader: "X-MS-CLIENT-PRINCIPAL-EMAIL" + +Security: + VerifyClientIp: false + PAATokenSigningKey: "your-32-character-signing-key-here" + PAATokenEncryptionKey: "your-32-character-encryption-key" + +Caps: + TokenAuth: true + IdleTimeout: 60 + +Client: + UsernameTemplate: "{{ username }}\x1f{{ token }}" +``` + +### Docker Deployment + +```yaml +# docker-compose.yml +services: + rdpgw: + image: bolkedebruin/rdpgw:latest + ports: + - "80:443" + volumes: + - ./rdpgw.yaml:/app/rdpgw.yaml:ro + environment: + - RDPGW_SERVER__TLS=disable + - RDPGW_SERVER__PORT=443 + networks: + - internal + +networks: + internal: + driver: bridge +``` + +## Step 5: Conditional Access Policy + +### Create CAP for RDPGW + +```powershell +# PowerShell example (simplified) +$conditions = @{ + "applications" = @{ + "includeApplications" = @($app.ApplicationId) + } + "users" = @{ + "includeGroups" = @("rdp-users-group-id") + } + "locations" = @{ + "includeLocations" = @("AllTrusted") + } +} + +$grantControls = @{ + "operator" = "OR" + "builtInControls" = @("mfa", "compliantDevice") +} +``` + +### Portal Configuration + +1. **Navigate to**: Azure AD → Security → Conditional Access +2. **Create Policy**: + - **Name**: RDPGW Access Control + - **Users**: Select appropriate groups + - **Cloud apps**: Select RDPGW application + - **Conditions**: Configure as needed (device, location, etc.) + - **Grant**: Require MFA + Compliant Device + - **Session**: Configure session lifetime + +## Step 6: Testing + +### Test Web Authentication + +```bash +# Test /connect endpoint +curl -v https://rdpgw.yourdomain.com/connect +# Should redirect to Azure AD login +``` + +### Test RDP Connection + +1. **Access web interface**: `https://rdpgw.yourdomain.com/connect` +2. **Authenticate**: Complete Azure AD login + MFA +3. **Download RDP file**: Should contain token-based credentials +4. **Connect via RDP client**: Should work without additional authentication + +### Verify Headers + +Check that App Proxy forwards correct headers: + +```bash +# From internal network, test RDPGW directly +curl -H "X-MS-CLIENT-PRINCIPAL-NAME: user@domain.com" \ + http://rdpgw-server/connect +``` + +## Troubleshooting + +### Common Issues + +1. **RDP Client Won't Connect**: + - Verify passthrough configuration for `/remoteDesktopGateway/*` + - Check token generation in downloaded RDP file + - Ensure `TokenAuth: true` in configuration + +2. **Authentication Loop**: + - Verify header configuration matches App Proxy headers + - Check `VerifyClientIp: false` setting + - Validate App Proxy connector connectivity + +3. **CAP Not Enforced**: + - Verify policy targets correct application + - Check user/group assignments + - Review conditional access logs + +### Debug Commands + +```bash +# Check RDPGW logs +docker logs rdpgw-container + +# Test internal connectivity +curl -H "X-MS-CLIENT-PRINCIPAL-NAME: test@domain.com" \ + http://rdpgw-internal/connect + +# Verify token generation +curl -v https://rdpgw.yourdomain.com/connect +``` + +### Azure AD Logs + +Monitor these logs for authentication issues: + +- **Sign-ins**: User authentication events +- **Conditional Access**: Policy evaluation results +- **Application Proxy**: Connector and application events + +## Security Considerations + +- **Network Isolation**: Deploy RDPGW in private network +- **Connector Security**: Ensure App Proxy connector is secured +- **Token Validation**: Monitor for token replay attacks +- **Audit Logging**: Enable comprehensive logging for compliance +- **Certificate Management**: Ensure proper TLS certificate chain + +## Production Checklist + +- [ ] App Proxy connector deployed and healthy +- [ ] Application registration configured +- [ ] Passthrough paths configured for RDP endpoints +- [ ] Conditional Access policies tested +- [ ] RDPGW header authentication working +- [ ] RDP file download and connection successful +- [ ] Monitoring and alerting configured +- [ ] Backup and recovery procedures documented \ No newline at end of file