494 lines
10 KiB
Markdown
494 lines
10 KiB
Markdown
# RDP Web Gateway
|
|
|
|
HTML5 WebSocket-based gateway for accessing RDP connections through a web browser. This service sits in front of RdpBroker and provides a modern web interface for remote desktop access.
|
|
|
|
## Features
|
|
|
|
- 🌐 **Browser-Based Access** - Connect to RDP sessions from any modern web browser
|
|
- 🔒 **Secure WebSocket** - Real-time bidirectional communication
|
|
- 🎨 **Modern UI** - Clean, responsive interface
|
|
- 🔑 **User-Specific Targets** - Each user sees only their authorized RDP servers
|
|
- 📊 **Service Health Monitoring** - Automatic RdpBroker availability checks
|
|
- 🎯 **Dynamic Target Loading** - Personalized targets from RdpBroker based on user permissions
|
|
- ⚡ **Low Latency** - Optimized for performance
|
|
- ☁️ **Kubernetes Native** - Console-only logging for cloud environments
|
|
- 🔐 **Samba AD Integration** - Authentication via RdpBroker with Samba Active Directory
|
|
|
|
## Architecture
|
|
|
|
```
|
|
User Browser (HTML5/WebSocket)
|
|
↓
|
|
RDP Web Gateway (Node.js)
|
|
↓ [WebSocket Protocol]
|
|
↓ 1. AUTH → receives user-specific targets
|
|
↓ 2. SELECT → connects to chosen target
|
|
↓
|
|
RdpBroker (C)
|
|
↓ [Samba AD Auth]
|
|
↓ [Target Authorization]
|
|
↓ [RDP Forwarding]
|
|
↓
|
|
Target RDP Servers
|
|
```
|
|
|
|
## Authentication Flow
|
|
|
|
1. **User Login** - User enters credentials in web interface
|
|
2. **Health Check** - Web-gateway verifies RdpBroker is available
|
|
3. **WebSocket Auth** - Credentials sent via WebSocket to RdpBroker
|
|
4. **LDAP Authentication** - RdpBroker authenticates against Samba AD
|
|
5. **Target Authorization** - RdpBroker determines user's authorized targets based on groups/permissions
|
|
6. **Targets Display** - User-specific target list sent back to web-gateway
|
|
7. **Target Selection** - User chooses from their authorized servers
|
|
8. **RDP Session** - RdpBroker establishes connection to selected target
|
|
|
|
## Prerequisites
|
|
|
|
- Node.js 18+
|
|
- RdpBroker service running
|
|
- Modern web browser with WebSocket support
|
|
|
|
## Installation
|
|
|
|
### Local Development
|
|
|
|
```bash
|
|
cd web-gateway
|
|
|
|
# Install dependencies
|
|
npm install
|
|
|
|
# Copy environment file
|
|
cp .env.example .env
|
|
|
|
# Edit configuration
|
|
nano .env
|
|
|
|
# Start development server
|
|
npm run dev
|
|
```
|
|
|
|
### Docker Build
|
|
|
|
```bash
|
|
docker build -t rdp-web-gateway:latest .
|
|
```
|
|
|
|
## Configuration
|
|
|
|
Edit `.env` file:
|
|
|
|
```env
|
|
PORT=8080
|
|
RDP_BROKER_HOST=rdpbroker
|
|
RDP_BROKER_PORT=3389
|
|
NODE_ENV=production
|
|
|
|
# Optional: Pre-configure RDP targets (JSON array)
|
|
# If not set, RdpBroker will provide targets dynamically
|
|
RDP_TARGETS=[{"name":"Server1","host":"srv1.example.com","port":3389,"description":"Production Server"}]
|
|
```
|
|
|
|
### Environment Variables
|
|
|
|
| Variable | Description | Default |
|
|
|----------|-------------|---------|
|
|
| `PORT` | Web server listening port | `8080` |
|
|
| `RDP_BROKER_HOST` | RdpBroker hostname | `rdpbroker` |
|
|
| `RDP_BROKER_PORT` | RdpBroker port | `3389` |
|
|
| `RDP_TARGETS` | JSON array of pre-configured targets | `null` |
|
|
| `NODE_ENV` | Environment mode | `development` |
|
|
|
|
## Usage
|
|
|
|
### Access the Web Interface
|
|
|
|
1. Open your browser to `http://localhost:8080`
|
|
2. Enter your credentials (validated against Samba AD via RdpBroker)
|
|
3. Select a target from the list
|
|
4. Connect and use the remote desktop
|
|
|
|
### API Endpoints
|
|
|
|
#### GET /health
|
|
Health check endpoint for monitoring the web gateway.
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"status": "healthy",
|
|
"version": "1.0.0",
|
|
"uptime": 12345
|
|
}
|
|
```
|
|
|
|
#### GET /api/broker-status
|
|
Check if RdpBroker service is available.
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"available": true,
|
|
"broker": "rdpbroker:3389",
|
|
"timestamp": "2025-12-04T10:30:00.000Z"
|
|
}
|
|
```
|
|
|
|
#### GET /api/targets
|
|
Fetch available RDP targets.
|
|
|
|
**Success Response (200):**
|
|
```json
|
|
{
|
|
"targets": [
|
|
{
|
|
"name": "Windows Server 2022",
|
|
"host": "ws2022.example.com",
|
|
"port": 3389,
|
|
"description": "Production Windows Server"
|
|
}
|
|
],
|
|
"timestamp": "2025-12-04T10:30:00.000Z"
|
|
}
|
|
```
|
|
|
|
**Service Unavailable (503):**
|
|
```json
|
|
{
|
|
"error": "RdpBroker service is unavailable. Please contact your administrator.",
|
|
"timestamp": "2025-12-04T10:30:00.000Z"
|
|
}
|
|
```
|
|
|
|
### WebSocket Protocol
|
|
|
|
Connect to `ws://localhost:8080/ws/rdp`
|
|
|
|
The protocol follows a two-phase approach:
|
|
1. **Authentication Phase**: User authenticates and receives personalized target list
|
|
2. **Connection Phase**: User selects target and establishes RDP session
|
|
|
|
#### Phase 1: Authentication
|
|
|
|
**Client → Server - Authenticate:**
|
|
```json
|
|
{
|
|
"type": "authenticate",
|
|
"username": "user@domain.com",
|
|
"password": "password123"
|
|
}
|
|
```
|
|
|
|
**Server → Client - Authentication Success with Targets:**
|
|
```json
|
|
{
|
|
"type": "targets",
|
|
"targets": [
|
|
{
|
|
"name": "Windows Server 2022",
|
|
"host": "ws2022.example.com",
|
|
"port": 3389,
|
|
"description": "Production Windows Server (user-specific)"
|
|
},
|
|
{
|
|
"name": "Development Server",
|
|
"host": "dev.example.com",
|
|
"port": 3389,
|
|
"description": "Development environment"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Server → Client - Authentication Failed:**
|
|
```json
|
|
{
|
|
"type": "error",
|
|
"error": "Invalid credentials"
|
|
}
|
|
```
|
|
|
|
#### Phase 2: Connection
|
|
|
|
**Client → Server - Connect to Target:**
|
|
```json
|
|
{
|
|
"type": "connect",
|
|
"target": {
|
|
"name": "Windows Server 2022",
|
|
"host": "ws2022.example.com",
|
|
"port": 3389
|
|
}
|
|
}
|
|
```
|
|
|
|
**Server → Client - RDP Session Ready:**
|
|
```json
|
|
{
|
|
"type": "connected",
|
|
"target": "Windows Server 2022"
|
|
}
|
|
```
|
|
|
|
#### Client → Server Messages
|
|
|
|
**Mouse event:**
|
|
```json
|
|
{
|
|
"type": "mouse",
|
|
"action": "move|down|up|wheel",
|
|
"x": 100,
|
|
"y": 200,
|
|
"button": 0,
|
|
"deltaY": 0
|
|
}
|
|
```
|
|
|
|
**Keyboard event:**
|
|
```json
|
|
{
|
|
"type": "keyboard",
|
|
"action": "down|up",
|
|
"key": "a",
|
|
"code": "KeyA",
|
|
"ctrlKey": false,
|
|
"altKey": false,
|
|
"shiftKey": false
|
|
}
|
|
```
|
|
|
|
**Special command:**
|
|
```json
|
|
{
|
|
"type": "special",
|
|
"action": "ctrl-alt-del"
|
|
}
|
|
```
|
|
|
|
#### Server → Client Messages
|
|
|
|
**Connected:**
|
|
```json
|
|
{
|
|
"type": "connected",
|
|
"target": "Server 01"
|
|
}
|
|
```
|
|
|
|
**Resize canvas:**
|
|
```json
|
|
{
|
|
"type": "resize",
|
|
"width": 1920,
|
|
"height": 1080
|
|
}
|
|
```
|
|
|
|
**Error:**
|
|
```json
|
|
{
|
|
"type": "error",
|
|
"error": "Error message"
|
|
}
|
|
```
|
|
|
|
## Deployment
|
|
|
|
### Kubernetes with Helm
|
|
|
|
#### Option 1: LoadBalancer (Default)
|
|
|
|
```bash
|
|
# Deploy with LoadBalancer service
|
|
helm install rdp-web-gateway ./chart/rdp-web-gateway \
|
|
--namespace rdpbroker \
|
|
--create-namespace \
|
|
--set service.type=LoadBalancer
|
|
```
|
|
|
|
#### Option 2: Traefik IngressRoute with Let's Encrypt
|
|
|
|
**Recommended for production with automatic HTTPS**
|
|
|
|
1. **Apply Traefik middlewares** (one time):
|
|
```bash
|
|
kubectl apply -f chart/rdp-web-gateway/examples/traefik-middlewares.yaml -n rdpbroker
|
|
```
|
|
|
|
2. **Deploy with Traefik IngressRoute**:
|
|
```bash
|
|
# Edit the host in examples/traefik-letsencrypt.yaml
|
|
# Then deploy:
|
|
helm install rdp-web-gateway ./chart/rdp-web-gateway \
|
|
--namespace rdpbroker \
|
|
--create-namespace \
|
|
-f chart/rdp-web-gateway/examples/traefik-letsencrypt.yaml
|
|
```
|
|
|
|
Or directly with values:
|
|
```bash
|
|
helm install rdp-web-gateway ./chart/rdp-web-gateway \
|
|
--namespace rdpbroker \
|
|
--create-namespace \
|
|
--set service.type=ClusterIP \
|
|
--set traefik.enabled=true \
|
|
--set traefik.host=rdp.yourdomain.com \
|
|
--set traefik.tls.enabled=true \
|
|
--set traefik.tls.certResolver=letsencrypt
|
|
```
|
|
|
|
3. **Verify deployment**:
|
|
```bash
|
|
# Check IngressRoute
|
|
kubectl get ingressroute -n rdpbroker
|
|
|
|
# Check certificate (after a few seconds)
|
|
kubectl get certificate -n rdpbroker
|
|
|
|
# Access your gateway
|
|
https://rdp.yourdomain.com
|
|
```
|
|
|
|
#### Option 3: Standard Ingress (nginx, etc.)
|
|
|
|
```bash
|
|
helm install rdp-web-gateway ./chart/rdp-web-gateway \
|
|
--namespace rdpbroker \
|
|
--create-namespace \
|
|
--set service.type=ClusterIP \
|
|
--set ingress.enabled=true \
|
|
--set ingress.className=nginx \
|
|
--set ingress.hosts[0].host=rdp.example.com \
|
|
--set ingress.hosts[0].paths[0].path=/ \
|
|
--set ingress.hosts[0].paths[0].pathType=Prefix
|
|
```
|
|
|
|
### Important Notes for Traefik
|
|
|
|
**WebSocket Support**: Traefik automatically handles WebSocket upgrades, no special configuration needed!
|
|
|
|
**Let's Encrypt Certificate Resolver**: Ensure your Traefik has a certResolver named `letsencrypt` configured. Example:
|
|
|
|
```yaml
|
|
# Traefik values.yaml or static config
|
|
certificatesResolvers:
|
|
letsencrypt:
|
|
acme:
|
|
email: admin@yourdomain.com
|
|
storage: /data/acme.json
|
|
httpChallenge:
|
|
entryPoint: web
|
|
```
|
|
|
|
**Middlewares**: Apply the recommended middlewares for security:
|
|
- `redirect-to-https` - Force HTTPS
|
|
- `security-headers` - Security headers including WebSocket support
|
|
- `rate-limit` - Prevent abuse
|
|
- `compression` - Reduce bandwidth
|
|
|
|
## Browser Support
|
|
|
|
- Chrome/Edge 90+
|
|
- Firefox 88+
|
|
- Safari 14+
|
|
- Opera 76+
|
|
## Security Considerations
|
|
|
|
- Use HTTPS/WSS in production
|
|
- Credentials are passed directly to RdpBroker (no storage in web-gateway)
|
|
- Implement rate limiting at ingress level
|
|
- Enable CORS restrictions
|
|
- Regular security audits
|
|
- All authentication handled by RdpBroker → Samba ADs
|
|
- Regular security audits
|
|
## Performance Tuning
|
|
|
|
- Configure WebSocket buffer sizes
|
|
- Use CDN for static assets in production
|
|
- Enable HTTP compression (already included)
|
|
- Adjust resource limits in Kubernetes
|
|
- Use CDN for static assets in production
|
|
|
|
## Troubleshooting
|
|
|
|
### Can't connect to RdpBroker
|
|
|
|
Check environment variables:
|
|
```bash
|
|
echo $RDP_BROKER_HOST
|
|
echo $RDP_BROKER_PORT
|
|
```
|
|
|
|
Test connectivity:
|
|
```bash
|
|
nc -zv rdpbroker 3389
|
|
```
|
|
|
|
### WebSocket connection fails
|
|
|
|
Ensure WebSocket upgrade is allowed through proxies/load balancers.
|
|
|
|
**For Traefik**: Already handled automatically! ✅
|
|
|
|
**For nginx**:
|
|
```nginx
|
|
location /ws/ {
|
|
proxy_pass http://backend;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection "upgrade";
|
|
}
|
|
```
|
|
|
|
**For Traefik middlewares**: Ensure security-headers middleware includes:
|
|
```yaml
|
|
customResponseHeaders:
|
|
Connection: "upgrade"
|
|
Upgrade: "$http_upgrade"
|
|
```
|
|
### High memory usage
|
|
|
|
Adjust resource limits in Kubernetes values.yaml
|
|
|
|
## Logging
|
|
|
|
All logs go to stdout/stderr for Kubernetes:
|
|
|
|
```bash
|
|
# View logs
|
|
kubectl logs -f deployment/rdp-web-gateway -n rdpbroker
|
|
|
|
# Follow logs for all pods
|
|
kubectl logs -f -l app=rdp-web-gateway -n rdpbroker
|
|
```
|
|
Reduce session timeout or implement session limits per user.
|
|
|
|
## Development
|
|
|
|
### Running Tests
|
|
```bash
|
|
npm test
|
|
```
|
|
|
|
### Code Style
|
|
```bash
|
|
npm run lint
|
|
```
|
|
|
|
## License
|
|
|
|
MIT License - see LICENSE file
|
|
|
|
## Support
|
|
|
|
For issues and questions, check the logs:
|
|
|
|
```bash
|
|
# View logs
|
|
kubectl logs -f deployment/rdp-web-gateway -n rdpbroker
|
|
|
|
# Check health
|
|
curl http://localhost:8080/health
|
|
```
|