mirror of
https://github.com/bolkedebruin/rdpgw.git
synced 2026-03-27 14:36:36 +00:00
259 lines
6.6 KiB
Markdown
259 lines
6.6 KiB
Markdown
# 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
|