mirror of
https://github.com/cdr/code-server.git
synced 2025-12-07 17:02:27 +01:00
Add AWS Client VPN support for secure private access to code-server
This commit adds comprehensive VPN infrastructure to enable secure, certificate-based access to code-server deployments. VPN provides an additional security layer by requiring network-level authentication before accessing internal resources. Features: - AWS Client VPN endpoint with certificate-based authentication - Split tunnel support (route only VPC traffic through VPN) - CloudWatch logging for all VPN connections - Multi-platform client support (Windows, macOS, Linux, iOS, Android) - Automatic certificate generation and ACM upload - Client configuration export scripts - Integration with both EC2 and EKS deployments New Terraform Module: - modules/vpn: Complete AWS Client VPN infrastructure - VPN endpoint with configurable authentication - Network associations for HA across multiple AZs - Authorization rules for VPC access - Security groups for VPN traffic - CloudWatch log groups and streams - Support for SAML/federated authentication Scripts: - scripts/generate-vpn-certificates.sh: Generate and upload VPN certificates - Creates CA, server, and client certificates - Automatically uploads to AWS Certificate Manager - Outputs certificate ARNs for Terraform configuration - scripts/export-vpn-config.sh: Export client VPN configuration - Downloads VPN config from AWS - Embeds client certificates - Creates platform-ready .ovpn files Deployment Updates: - EC2 and EKS deployments now support optional VPN - New variables for VPN configuration - Updated outputs to include VPN endpoint information - Example configurations with VPN settings Documentation: - VPN-SETUP-GUIDE.md: Comprehensive VPN setup guide - Certificate generation process - Terraform configuration - Client setup for all major platforms - Testing and troubleshooting - Advanced configuration options - Cost considerations and optimization Configuration Options: - Certificate-based or SAML/SSO authentication - Split tunnel (recommended) or full tunnel - UDP (faster) or TCP (more reliable) transport - Configurable session timeout (8-24 hours) - Custom DNS servers - Client login banner - Multiple authorization rules Security Features: - X.509 certificate authentication - Private subnet associations - Network-level access control - Session logging and audit trail - Support for multi-factor (VPN cert + OAuth2/SAML) Cost: ~$216/month base + ~$0.40/user/day for active connections
This commit is contained in:
parent
b8094ac6a0
commit
369f459203
14 changed files with 1545 additions and 0 deletions
563
terraform/VPN-SETUP-GUIDE.md
Normal file
563
terraform/VPN-SETUP-GUIDE.md
Normal file
|
|
@ -0,0 +1,563 @@
|
|||
# AWS Client VPN Setup Guide for Code-Server
|
||||
|
||||
This guide explains how to set up AWS Client VPN to securely access your code-server deployment. With VPN enabled, users must connect to the VPN before accessing code-server, adding an extra layer of security.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Why Use VPN](#why-use-vpn)
|
||||
- [Architecture](#architecture)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Setup Steps](#setup-steps)
|
||||
- [1. Generate VPN Certificates](#1-generate-vpn-certificates)
|
||||
- [2. Configure Terraform](#2-configure-terraform)
|
||||
- [3. Deploy VPN](#3-deploy-vpn)
|
||||
- [4. Export Client Configuration](#4-export-client-configuration)
|
||||
- [5. Distribute to Users](#5-distribute-to-users)
|
||||
- [Client Setup](#client-setup)
|
||||
- [Testing VPN Connection](#testing-vpn-connection)
|
||||
- [Advanced Configuration](#advanced-configuration)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Cost Considerations](#cost-considerations)
|
||||
|
||||
## Overview
|
||||
|
||||
AWS Client VPN is a managed client-based VPN service that enables you to securely access your AWS resources from any location using an OpenVPN-based VPN client.
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Certificate-based Authentication**: Secure authentication using X.509 certificates
|
||||
- **Split Tunneling**: Only route VPC traffic through VPN (internet traffic goes direct)
|
||||
- **Session Logging**: CloudWatch logs for all VPN connections
|
||||
- **Multi-platform Support**: Works on Windows, macOS, Linux, iOS, and Android
|
||||
- **High Availability**: AWS managed service with automatic failover
|
||||
|
||||
## Why Use VPN
|
||||
|
||||
### Security Benefits
|
||||
|
||||
1. **Network-Level Access Control**: VPN required before accessing code-server
|
||||
2. **Hide Internal Infrastructure**: ALB and resources stay completely private
|
||||
3. **Additional Authentication Layer**: Certificates + OAuth2/SAML = multi-factor
|
||||
4. **Audit Trail**: All VPN connections logged in CloudWatch
|
||||
5. **IP Whitelisting Alternative**: No need to manage IP allowlists
|
||||
|
||||
### Use Cases
|
||||
|
||||
- **Fully Private Deployment**: No public endpoints at all
|
||||
- **Compliance Requirements**: Meet regulatory requirements for private access
|
||||
- **Remote Team Access**: Secure access for distributed teams
|
||||
- **Development Environments**: Keep dev/staging completely isolated
|
||||
|
||||
## Architecture
|
||||
|
||||
### With VPN Enabled
|
||||
|
||||
```
|
||||
User Device
|
||||
↓
|
||||
AWS Client VPN Endpoint (Certificate Auth)
|
||||
↓
|
||||
Private Subnets
|
||||
↓
|
||||
Internal ALB → OAuth2 Proxy → Code-Server
|
||||
↓
|
||||
Private EC2/EKS Resources
|
||||
```
|
||||
|
||||
### VPN Network Flow
|
||||
|
||||
1. User connects to VPN with client certificate
|
||||
2. VPN assigns IP from client CIDR (172.16.0.0/22 by default)
|
||||
3. VPN routes VPC traffic (10.0.0.0/16) through tunnel
|
||||
4. User accesses internal ALB at private IP
|
||||
5. OAuth2 Proxy provides SAML/OIDC authentication
|
||||
6. Code-Server accessible only via VPN
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- OpenSSL installed (for certificate generation)
|
||||
- AWS CLI configured with appropriate permissions
|
||||
- Terraform >= 1.0
|
||||
- IAM permissions to:
|
||||
- Create VPN endpoints
|
||||
- Import certificates to ACM
|
||||
- Create CloudWatch log groups
|
||||
- Modify security groups
|
||||
|
||||
## Setup Steps
|
||||
|
||||
### 1. Generate VPN Certificates
|
||||
|
||||
VPN requires server and client certificates for authentication.
|
||||
|
||||
```bash
|
||||
cd terraform/scripts
|
||||
|
||||
# Generate certificates (will upload to ACM automatically)
|
||||
./generate-vpn-certificates.sh [cert-dir] [region] [common-name]
|
||||
|
||||
# Example:
|
||||
./generate-vpn-certificates.sh ./vpn-certs us-east-1 code-server-vpn
|
||||
```
|
||||
|
||||
This script:
|
||||
1. Creates a Certificate Authority (CA)
|
||||
2. Generates server certificate
|
||||
3. Generates client certificate
|
||||
4. Uploads both to AWS Certificate Manager
|
||||
5. Outputs certificate ARNs for Terraform
|
||||
|
||||
**Output Files:**
|
||||
- `ca.key` - CA private key (keep secure!)
|
||||
- `ca.crt` - CA certificate
|
||||
- `server.key` - Server private key (keep secure!)
|
||||
- `server.crt` - Server certificate
|
||||
- `client.key` - Client private key (distribute to users)
|
||||
- `client.crt` - Client certificate (distribute to users)
|
||||
- `certificate-arns.txt` - ARNs for Terraform
|
||||
- `terraform-vars.txt` - Terraform configuration snippet
|
||||
|
||||
**Security Note:**
|
||||
- Store `ca.key` and `server.key` securely (never share these!)
|
||||
- Back up all certificates securely
|
||||
- Distribute `client.key` and `client.crt` to authorized users only
|
||||
|
||||
### 2. Configure Terraform
|
||||
|
||||
Edit your `terraform.tfvars` file:
|
||||
|
||||
```hcl
|
||||
# EC2 or EKS deployment
|
||||
|
||||
# Enable VPN
|
||||
enable_vpn = true
|
||||
|
||||
# Certificate ARNs from step 1
|
||||
vpn_server_certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/xxxxx"
|
||||
vpn_client_certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/yyyyy"
|
||||
|
||||
# VPN Configuration
|
||||
vpn_client_cidr_block = "172.16.0.0/22" # Must not overlap with VPC CIDR
|
||||
vpn_split_tunnel = true # Recommended
|
||||
vpn_transport_protocol = "udp" # udp (faster) or tcp
|
||||
vpn_port = 443 # 443 or 1194
|
||||
vpn_session_timeout_hours = 24 # 8-24 hours
|
||||
vpn_client_login_banner = "Welcome to Code-Server VPN. Authorized access only."
|
||||
|
||||
# Make ALB internal (required for VPN-only access)
|
||||
internal_alb = true
|
||||
```
|
||||
|
||||
### 3. Deploy VPN
|
||||
|
||||
Deploy the infrastructure with VPN enabled:
|
||||
|
||||
```bash
|
||||
# EC2 Deployment
|
||||
cd deployments/ec2
|
||||
terraform apply
|
||||
|
||||
# EKS Deployment
|
||||
cd deployments/eks
|
||||
terraform apply
|
||||
```
|
||||
|
||||
Terraform will create:
|
||||
- Client VPN Endpoint
|
||||
- VPN Network Associations (in private subnets)
|
||||
- Authorization Rules (allow access to VPC CIDR)
|
||||
- Security Group for VPN
|
||||
- CloudWatch Log Group for VPN connections
|
||||
|
||||
**Deployment Time:** ~5-10 minutes for VPN endpoint to become available
|
||||
|
||||
### 4. Export Client Configuration
|
||||
|
||||
After deployment completes, export the VPN client configuration:
|
||||
|
||||
```bash
|
||||
cd terraform/scripts
|
||||
|
||||
# Auto-detect VPN endpoint from Terraform state
|
||||
./export-vpn-config.sh
|
||||
|
||||
# Or specify manually
|
||||
./export-vpn-config.sh <vpn-endpoint-id> [region] [output-dir] [cert-dir]
|
||||
|
||||
# Example:
|
||||
./export-vpn-config.sh cvpn-endpoint-0123456789abcdef0 us-east-1 ./vpn-config ./vpn-certs
|
||||
```
|
||||
|
||||
This script:
|
||||
1. Downloads VPN configuration from AWS
|
||||
2. Embeds client certificate and key
|
||||
3. Creates platform-ready `.ovpn` file
|
||||
|
||||
**Output:** `code-server-vpn.ovpn` - ready to distribute to users
|
||||
|
||||
### 5. Distribute to Users
|
||||
|
||||
**Securely** distribute these files to authorized users:
|
||||
- `code-server-vpn.ovpn` - VPN configuration file
|
||||
|
||||
**Distribution Methods:**
|
||||
- Encrypted email
|
||||
- Secure file sharing (e.g., 1Password, encrypted USB)
|
||||
- MDM system for corporate devices
|
||||
- Secure internal portal
|
||||
|
||||
## Client Setup
|
||||
|
||||
### macOS
|
||||
|
||||
1. **Install Tunnelblick** (free, open-source)
|
||||
```bash
|
||||
brew install --cask tunnelblick
|
||||
# Or download from https://tunnelblick.net/
|
||||
```
|
||||
|
||||
2. **Import Configuration**
|
||||
- Double-click `code-server-vpn.ovpn`
|
||||
- Tunnelblick will import it automatically
|
||||
|
||||
3. **Connect**
|
||||
- Click Tunnelblick icon in menu bar
|
||||
- Select "Connect code-server-vpn"
|
||||
- VPN should connect within a few seconds
|
||||
|
||||
### Windows
|
||||
|
||||
1. **Install OpenVPN Connect**
|
||||
- Download from https://openvpn.net/client-connect-vpn-for-windows/
|
||||
- Install and launch
|
||||
|
||||
2. **Import Configuration**
|
||||
- File → Import Profile
|
||||
- Select `code-server-vpn.ovpn`
|
||||
|
||||
3. **Connect**
|
||||
- Click "Connect" on the profile
|
||||
- Wait for connection to establish
|
||||
|
||||
### Linux
|
||||
|
||||
1. **Install OpenVPN**
|
||||
```bash
|
||||
# Debian/Ubuntu
|
||||
sudo apt-get update
|
||||
sudo apt-get install openvpn
|
||||
|
||||
# RHEL/CentOS
|
||||
sudo yum install openvpn
|
||||
|
||||
# Arch
|
||||
sudo pacman -S openvpn
|
||||
```
|
||||
|
||||
2. **Connect**
|
||||
```bash
|
||||
sudo openvpn --config code-server-vpn.ovpn
|
||||
```
|
||||
|
||||
3. **Run as Service** (optional)
|
||||
```bash
|
||||
sudo cp code-server-vpn.ovpn /etc/openvpn/client/code-server.conf
|
||||
sudo systemctl start openvpn-client@code-server
|
||||
sudo systemctl enable openvpn-client@code-server
|
||||
```
|
||||
|
||||
### iOS
|
||||
|
||||
1. **Install OpenVPN Connect**
|
||||
- Download from App Store
|
||||
|
||||
2. **Transfer Configuration**
|
||||
- Email to yourself, or
|
||||
- Use AirDrop, or
|
||||
- Upload to iCloud/Dropbox
|
||||
|
||||
3. **Import and Connect**
|
||||
- Open `.ovpn` file
|
||||
- Import to OpenVPN Connect
|
||||
- Tap "Connect"
|
||||
|
||||
### Android
|
||||
|
||||
1. **Install OpenVPN for Android**
|
||||
- Download from Google Play Store
|
||||
|
||||
2. **Transfer Configuration**
|
||||
- Email to yourself, or
|
||||
- Upload to Google Drive/Dropbox
|
||||
|
||||
3. **Import and Connect**
|
||||
- Open `.ovpn` file
|
||||
- Import to OpenVPN
|
||||
- Tap "Connect"
|
||||
|
||||
## Testing VPN Connection
|
||||
|
||||
### 1. Connect to VPN
|
||||
|
||||
Connect using your platform's VPN client (see Client Setup above).
|
||||
|
||||
### 2. Verify VPN Connection
|
||||
|
||||
**macOS/Linux:**
|
||||
```bash
|
||||
# Check VPN interface
|
||||
ifconfig | grep tun
|
||||
|
||||
# Check VPN IP assignment
|
||||
ifconfig tun0 # or tun1, etc.
|
||||
|
||||
# Should show IP in 172.16.0.0/22 range
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```powershell
|
||||
# Check VPN adapter
|
||||
ipconfig | findstr "172.16"
|
||||
```
|
||||
|
||||
### 3. Test Access to Code-Server
|
||||
|
||||
Get the internal ALB DNS name:
|
||||
```bash
|
||||
# From Terraform output
|
||||
terraform output alb_dns_name # EC2
|
||||
# Or
|
||||
kubectl get ingress -n code-server # EKS
|
||||
```
|
||||
|
||||
Access code-server:
|
||||
```bash
|
||||
# EC2
|
||||
curl -I http://<alb-dns-name>
|
||||
|
||||
# EKS
|
||||
curl -I http://<alb-dns-name>
|
||||
```
|
||||
|
||||
**Expected Result:** You should get a redirect to OAuth2 login or code-server login page.
|
||||
|
||||
### 4. Check CloudWatch Logs
|
||||
|
||||
View VPN connection logs:
|
||||
```bash
|
||||
aws logs tail /aws/vpn/<prefix> --follow
|
||||
```
|
||||
|
||||
You should see connection events with your IP address.
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Multiple Client Certificates
|
||||
|
||||
To create additional client certificates for different users:
|
||||
|
||||
```bash
|
||||
# Generate new client cert
|
||||
openssl genrsa -out client2.key 2048
|
||||
openssl req -new -key client2.key -out client2.csr
|
||||
openssl x509 -req -days 3650 -in client2.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client2.crt
|
||||
|
||||
# Create user-specific .ovpn file
|
||||
./export-vpn-config.sh <vpn-endpoint-id> us-east-1 ./user2-config ./
|
||||
# Manually replace client cert/key in the .ovpn file
|
||||
```
|
||||
|
||||
### SAML/SSO Authentication
|
||||
|
||||
For enterprise deployments, use SAML-based authentication instead of certificates:
|
||||
|
||||
```hcl
|
||||
# terraform.tfvars
|
||||
vpn_authentication_type = "federated-authentication"
|
||||
enable_saml_authentication = true
|
||||
saml_provider_arn = "arn:aws:iam::123456789012:saml-provider/YourSAMLProvider"
|
||||
```
|
||||
|
||||
This combines VPN (network access) with SAML (user authentication).
|
||||
|
||||
### Split Tunnel Configuration
|
||||
|
||||
**Enabled (default - recommended):**
|
||||
```hcl
|
||||
vpn_split_tunnel = true
|
||||
```
|
||||
- Only VPC traffic (10.0.0.0/16) routed through VPN
|
||||
- Internet traffic goes directly
|
||||
- Better performance for users
|
||||
|
||||
**Disabled (full tunnel):**
|
||||
```hcl
|
||||
vpn_split_tunnel = false
|
||||
```
|
||||
- All traffic routed through VPN
|
||||
- More secure but slower
|
||||
- Required for some compliance scenarios
|
||||
|
||||
### Custom DNS Servers
|
||||
|
||||
Route DNS queries through VPN:
|
||||
|
||||
```hcl
|
||||
vpn_dns_servers = ["10.0.0.2"] # VPC DNS resolver
|
||||
```
|
||||
|
||||
### Session Timeout
|
||||
|
||||
Configure VPN session duration:
|
||||
|
||||
```hcl
|
||||
vpn_session_timeout_hours = 12 # 8-24 hours
|
||||
```
|
||||
|
||||
Users will be disconnected after this period and must reconnect.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Connection Fails
|
||||
|
||||
**Check Certificate Validity:**
|
||||
```bash
|
||||
openssl x509 -in client.crt -text -noout
|
||||
# Verify "Not After" date
|
||||
```
|
||||
|
||||
**Check VPN Endpoint Status:**
|
||||
```bash
|
||||
aws ec2 describe-client-vpn-endpoints \
|
||||
--client-vpn-endpoint-ids <endpoint-id>
|
||||
```
|
||||
|
||||
**Check CloudWatch Logs:**
|
||||
```bash
|
||||
aws logs tail /aws/vpn/<prefix> --follow
|
||||
```
|
||||
|
||||
### Cannot Access Code-Server After Connecting
|
||||
|
||||
**1. Verify VPN IP Assignment:**
|
||||
```bash
|
||||
ifconfig | grep 172.16 # macOS/Linux
|
||||
ipconfig | findstr "172.16" # Windows
|
||||
```
|
||||
|
||||
**2. Check Authorization Rules:**
|
||||
```bash
|
||||
aws ec2 describe-client-vpn-authorization-rules \
|
||||
--client-vpn-endpoint-id <endpoint-id>
|
||||
```
|
||||
|
||||
**3. Check Security Groups:**
|
||||
```bash
|
||||
# Verify VPN security group allows traffic to ALB
|
||||
aws ec2 describe-security-groups --group-ids <sg-id>
|
||||
```
|
||||
|
||||
**4. Test DNS Resolution:**
|
||||
```bash
|
||||
nslookup <alb-dns-name>
|
||||
dig <alb-dns-name>
|
||||
```
|
||||
|
||||
### Split Tunnel Not Working
|
||||
|
||||
Check routing table after VPN connection:
|
||||
|
||||
**macOS/Linux:**
|
||||
```bash
|
||||
netstat -rn | grep tun
|
||||
# Should only see VPC CIDR (10.0.0.0/16) routes
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```powershell
|
||||
route print | findstr "172.16"
|
||||
```
|
||||
|
||||
### Certificate Expired
|
||||
|
||||
Certificates are valid for 10 years by default. To renew:
|
||||
|
||||
1. Generate new certificates (see Step 1)
|
||||
2. Update certificate ARNs in Terraform
|
||||
3. Run `terraform apply`
|
||||
4. Export new client configuration
|
||||
5. Distribute to users
|
||||
|
||||
## Cost Considerations
|
||||
|
||||
### AWS Client VPN Pricing (as of 2024)
|
||||
|
||||
**Endpoint Association:**
|
||||
- $0.10 per hour per subnet association
|
||||
- For 3 subnets (multi-AZ): ~$216/month
|
||||
|
||||
**Connection Time:**
|
||||
- $0.05 per hour per connection
|
||||
- For 10 active users (8 hrs/day): ~$88/month
|
||||
|
||||
**Total Estimated Cost:**
|
||||
- Base: ~$216/month (always running)
|
||||
- Variable: ~$0.40 per user per day
|
||||
|
||||
**Cost Optimization:**
|
||||
|
||||
1. **Single Subnet Association** (not recommended for production):
|
||||
```hcl
|
||||
subnet_ids = [module.vpc.private_subnet_ids[0]] # Only one AZ
|
||||
```
|
||||
Saves: ~$140/month (but loses HA)
|
||||
|
||||
2. **Scheduled VPN** (for dev environments):
|
||||
- Use Lambda to disable VPN outside business hours
|
||||
- Potential savings: ~50-70%
|
||||
|
||||
3. **Alternative: Direct Connect or Site-to-Site VPN:**
|
||||
- For office connectivity: Site-to-Site VPN ($0.05/hr = ~$36/month)
|
||||
- For large teams: Direct Connect (higher setup, lower per-GB cost)
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Certificate Management:**
|
||||
- Store CA private key in HSM or secure vault
|
||||
- Rotate certificates annually
|
||||
- Revoke certificates for departed users
|
||||
|
||||
2. **Monitoring:**
|
||||
- Set up CloudWatch Alarms for unusual connection patterns
|
||||
- Review VPN logs regularly
|
||||
- Alert on failed authentication attempts
|
||||
|
||||
3. **Network Segmentation:**
|
||||
- Use separate subnets for VPN clients if needed
|
||||
- Apply additional security groups for VPN traffic
|
||||
- Implement network ACLs for defense in depth
|
||||
|
||||
4. **Multi-Factor Authentication:**
|
||||
- Combine VPN (certificate) + OAuth2/SAML for true MFA
|
||||
- Optionally add SAML to VPN itself for triple-factor
|
||||
|
||||
5. **Access Control:**
|
||||
- Use separate client certificates per user for audit trail
|
||||
- Implement IP-based restrictions if needed
|
||||
- Regular access reviews
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [AWS Client VPN Documentation](https://docs.aws.amazon.com/vpn/latest/clientvpn-admin/what-is.html)
|
||||
- [AWS Client VPN Pricing](https://aws.amazon.com/vpn/pricing/)
|
||||
- [OpenVPN Documentation](https://openvpn.net/community-resources/)
|
||||
- [Tunnelblick Documentation](https://tunnelblick.net/documents.html)
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions:
|
||||
- Check [Troubleshooting](#troubleshooting) section
|
||||
- Review CloudWatch Logs
|
||||
- Check AWS VPN endpoint status
|
||||
- Consult main [README.md](README.md)
|
||||
|
|
@ -115,3 +115,26 @@ module "code_server_ec2" {
|
|||
|
||||
tags = local.common_tags
|
||||
}
|
||||
|
||||
# VPN Module (Optional)
|
||||
module "vpn" {
|
||||
count = var.enable_vpn ? 1 : 0
|
||||
source = "../../modules/vpn"
|
||||
|
||||
name_prefix = local.name_prefix
|
||||
vpc_id = module.vpc.vpc_id
|
||||
vpc_cidr = module.vpc.vpc_cidr
|
||||
subnet_ids = module.vpc.private_subnet_ids
|
||||
server_certificate_arn = var.vpn_server_certificate_arn
|
||||
client_certificate_arn = var.vpn_client_certificate_arn
|
||||
client_cidr_block = var.vpn_client_cidr_block
|
||||
split_tunnel = var.vpn_split_tunnel
|
||||
authentication_type = var.vpn_authentication_type
|
||||
dns_servers = var.vpn_dns_servers
|
||||
transport_protocol = var.vpn_transport_protocol
|
||||
vpn_port = var.vpn_port
|
||||
session_timeout_hours = var.vpn_session_timeout_hours
|
||||
client_login_banner = var.vpn_client_login_banner
|
||||
|
||||
tags = local.common_tags
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,21 @@ output "kms_key_arn" {
|
|||
value = module.security.kms_key_arn
|
||||
}
|
||||
|
||||
output "vpn_endpoint_id" {
|
||||
description = "ID of the VPN endpoint (if enabled)"
|
||||
value = var.enable_vpn ? module.vpn[0].vpn_endpoint_id : null
|
||||
}
|
||||
|
||||
output "vpn_endpoint_dns_name" {
|
||||
description = "DNS name of the VPN endpoint (if enabled)"
|
||||
value = var.enable_vpn ? module.vpn[0].vpn_endpoint_dns_name : null
|
||||
}
|
||||
|
||||
output "vpn_client_cidr_block" {
|
||||
description = "CIDR block for VPN clients (if enabled)"
|
||||
value = var.enable_vpn ? var.vpn_client_cidr_block : null
|
||||
}
|
||||
|
||||
output "next_steps" {
|
||||
description = "Next steps to complete the setup"
|
||||
value = <<-EOT
|
||||
|
|
@ -73,5 +88,6 @@ output "next_steps" {
|
|||
- ALB is ${var.internal_alb ? "internal (private network only)" : "public"}
|
||||
- Data is encrypted at rest using KMS
|
||||
- VPC Flow Logs are enabled for monitoring
|
||||
${var.enable_vpn ? "\n VPN Configuration:\n - VPN Endpoint: ${module.vpn[0].vpn_endpoint_dns_name}\n - To export VPN configuration: ../../scripts/export-vpn-config.sh ${module.vpn[0].vpn_endpoint_id} ${var.aws_region}\n - VPN clients will receive IPs from: ${var.vpn_client_cidr_block}" : ""}
|
||||
EOT
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,3 +45,16 @@ oauth2_allowed_emails = [
|
|||
# "user1@example.com",
|
||||
# "user2@example.com"
|
||||
]
|
||||
|
||||
# VPN Configuration (Optional - for enhanced security)
|
||||
# First run: ../../scripts/generate-vpn-certificates.sh
|
||||
enable_vpn = false # Set to true to enable VPN
|
||||
vpn_server_certificate_arn = "" # ARN from generate-vpn-certificates.sh
|
||||
vpn_client_certificate_arn = "" # ARN from generate-vpn-certificates.sh
|
||||
vpn_client_cidr_block = "172.16.0.0/22" # Must not overlap with VPC
|
||||
vpn_split_tunnel = true # Only route VPC traffic through VPN
|
||||
vpn_authentication_type = "certificate-authentication"
|
||||
vpn_transport_protocol = "udp" # udp (faster) or tcp (more reliable)
|
||||
vpn_port = 443 # 443 or 1194
|
||||
vpn_session_timeout_hours = 24 # 8-24 hours
|
||||
vpn_client_login_banner = "Welcome to Code-Server VPN. Authorized access only."
|
||||
|
|
|
|||
|
|
@ -145,3 +145,70 @@ variable "oauth2_allowed_emails" {
|
|||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
# VPN Configuration
|
||||
variable "enable_vpn" {
|
||||
description = "Enable AWS Client VPN for secure access"
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "vpn_server_certificate_arn" {
|
||||
description = "ARN of server certificate in ACM for VPN"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "vpn_client_certificate_arn" {
|
||||
description = "ARN of client root certificate in ACM for VPN"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "vpn_client_cidr_block" {
|
||||
description = "CIDR block for VPN clients (must not overlap with VPC)"
|
||||
type = string
|
||||
default = "172.16.0.0/22"
|
||||
}
|
||||
|
||||
variable "vpn_split_tunnel" {
|
||||
description = "Enable split tunnel (only route VPC traffic through VPN)"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "vpn_authentication_type" {
|
||||
description = "VPN authentication type (certificate-authentication recommended)"
|
||||
type = string
|
||||
default = "certificate-authentication"
|
||||
}
|
||||
|
||||
variable "vpn_dns_servers" {
|
||||
description = "DNS servers for VPN clients (leave empty to use VPC DNS)"
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "vpn_transport_protocol" {
|
||||
description = "VPN transport protocol (udp recommended for better performance)"
|
||||
type = string
|
||||
default = "udp"
|
||||
}
|
||||
|
||||
variable "vpn_port" {
|
||||
description = "VPN port (443 or 1194)"
|
||||
type = number
|
||||
default = 443
|
||||
}
|
||||
|
||||
variable "vpn_session_timeout_hours" {
|
||||
description = "VPN session timeout in hours (8-24)"
|
||||
type = number
|
||||
default = 24
|
||||
}
|
||||
|
||||
variable "vpn_client_login_banner" {
|
||||
description = "Banner text to display on VPN client login"
|
||||
type = string
|
||||
default = "Welcome to Code-Server VPN. Authorized access only."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -243,3 +243,26 @@ resource "kubernetes_storage_class" "gp3" {
|
|||
|
||||
depends_on = [module.eks]
|
||||
}
|
||||
|
||||
# VPN Module (Optional)
|
||||
module "vpn" {
|
||||
count = var.enable_vpn ? 1 : 0
|
||||
source = "../../modules/vpn"
|
||||
|
||||
name_prefix = local.name_prefix
|
||||
vpc_id = module.vpc.vpc_id
|
||||
vpc_cidr = module.vpc.vpc_cidr
|
||||
subnet_ids = module.vpc.private_subnet_ids
|
||||
server_certificate_arn = var.vpn_server_certificate_arn
|
||||
client_certificate_arn = var.vpn_client_certificate_arn
|
||||
client_cidr_block = var.vpn_client_cidr_block
|
||||
split_tunnel = var.vpn_split_tunnel
|
||||
authentication_type = var.vpn_authentication_type
|
||||
dns_servers = var.vpn_dns_servers
|
||||
transport_protocol = var.vpn_transport_protocol
|
||||
vpn_port = var.vpn_port
|
||||
session_timeout_hours = var.vpn_session_timeout_hours
|
||||
client_login_banner = var.vpn_client_login_banner
|
||||
|
||||
tags = local.common_tags
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,21 @@ output "kms_key_arn" {
|
|||
value = module.security.kms_key_arn
|
||||
}
|
||||
|
||||
output "vpn_endpoint_id" {
|
||||
description = "ID of the VPN endpoint (if enabled)"
|
||||
value = var.enable_vpn ? module.vpn[0].vpn_endpoint_id : null
|
||||
}
|
||||
|
||||
output "vpn_endpoint_dns_name" {
|
||||
description = "DNS name of the VPN endpoint (if enabled)"
|
||||
value = var.enable_vpn ? module.vpn[0].vpn_endpoint_dns_name : null
|
||||
}
|
||||
|
||||
output "vpn_client_cidr_block" {
|
||||
description = "CIDR block for VPN clients (if enabled)"
|
||||
value = var.enable_vpn ? var.vpn_client_cidr_block : null
|
||||
}
|
||||
|
||||
output "configure_kubectl" {
|
||||
description = "Command to configure kubectl"
|
||||
value = "aws eks update-kubeconfig --region ${var.aws_region} --name ${module.eks.cluster_id}"
|
||||
|
|
@ -101,6 +116,7 @@ output "next_steps" {
|
|||
- Data is encrypted at rest using KMS
|
||||
- VPC Flow Logs are enabled for monitoring
|
||||
- IRSA (IAM Roles for Service Accounts) is enabled
|
||||
${var.enable_vpn ? "\n VPN Configuration:\n - VPN Endpoint: ${module.vpn[0].vpn_endpoint_dns_name}\n - To export VPN configuration: ../../scripts/export-vpn-config.sh ${module.vpn[0].vpn_endpoint_id} ${var.aws_region}\n - VPN clients will receive IPs from: ${var.vpn_client_cidr_block}" : ""}
|
||||
|
||||
Useful Commands:
|
||||
- Scale nodes: kubectl scale deployment code-server -n code-server --replicas=3
|
||||
|
|
|
|||
|
|
@ -36,3 +36,16 @@ oauth2_client_secret = "your-client-secret-from-idp"
|
|||
# Generate cookie secret with:
|
||||
# python -c 'import os,base64; print(base64.urlsafe_b64encode(os.urandom(32)).decode())'
|
||||
oauth2_cookie_secret = "generate-random-secret-here"
|
||||
|
||||
# VPN Configuration (Optional - for enhanced security)
|
||||
# First run: ../../scripts/generate-vpn-certificates.sh
|
||||
enable_vpn = false # Set to true to enable VPN
|
||||
vpn_server_certificate_arn = "" # ARN from generate-vpn-certificates.sh
|
||||
vpn_client_certificate_arn = "" # ARN from generate-vpn-certificates.sh
|
||||
vpn_client_cidr_block = "172.16.0.0/22" # Must not overlap with VPC
|
||||
vpn_split_tunnel = true # Only route VPC traffic through VPN
|
||||
vpn_authentication_type = "certificate-authentication"
|
||||
vpn_transport_protocol = "udp" # udp (faster) or tcp (more reliable)
|
||||
vpn_port = 443 # 443 or 1194
|
||||
vpn_session_timeout_hours = 24 # 8-24 hours
|
||||
vpn_client_login_banner = "Welcome to Code-Server VPN. Authorized access only."
|
||||
|
|
|
|||
|
|
@ -137,3 +137,70 @@ variable "oauth2_cookie_secret" {
|
|||
sensitive = true
|
||||
default = ""
|
||||
}
|
||||
|
||||
# VPN Configuration
|
||||
variable "enable_vpn" {
|
||||
description = "Enable AWS Client VPN for secure access"
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "vpn_server_certificate_arn" {
|
||||
description = "ARN of server certificate in ACM for VPN"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "vpn_client_certificate_arn" {
|
||||
description = "ARN of client root certificate in ACM for VPN"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "vpn_client_cidr_block" {
|
||||
description = "CIDR block for VPN clients (must not overlap with VPC)"
|
||||
type = string
|
||||
default = "172.16.0.0/22"
|
||||
}
|
||||
|
||||
variable "vpn_split_tunnel" {
|
||||
description = "Enable split tunnel (only route VPC traffic through VPN)"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "vpn_authentication_type" {
|
||||
description = "VPN authentication type (certificate-authentication recommended)"
|
||||
type = string
|
||||
default = "certificate-authentication"
|
||||
}
|
||||
|
||||
variable "vpn_dns_servers" {
|
||||
description = "DNS servers for VPN clients (leave empty to use VPC DNS)"
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "vpn_transport_protocol" {
|
||||
description = "VPN transport protocol (udp recommended for better performance)"
|
||||
type = string
|
||||
default = "udp"
|
||||
}
|
||||
|
||||
variable "vpn_port" {
|
||||
description = "VPN port (443 or 1194)"
|
||||
type = number
|
||||
default = 443
|
||||
}
|
||||
|
||||
variable "vpn_session_timeout_hours" {
|
||||
description = "VPN session timeout in hours (8-24)"
|
||||
type = number
|
||||
default = 24
|
||||
}
|
||||
|
||||
variable "vpn_client_login_banner" {
|
||||
description = "Banner text to display on VPN client login"
|
||||
type = string
|
||||
default = "Welcome to Code-Server VPN. Authorized access only."
|
||||
}
|
||||
|
|
|
|||
182
terraform/modules/vpn/main.tf
Normal file
182
terraform/modules/vpn/main.tf
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
# VPN Module for Code-Server
|
||||
# Creates AWS Client VPN endpoint for secure access to private resources
|
||||
|
||||
# CloudWatch Log Group for VPN connection logs
|
||||
resource "aws_cloudwatch_log_group" "vpn" {
|
||||
name = "/aws/vpn/${var.name_prefix}"
|
||||
retention_in_days = var.log_retention_days
|
||||
|
||||
tags = var.tags
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_log_stream" "vpn" {
|
||||
name = "vpn-connection-logs"
|
||||
log_group_name = aws_cloudwatch_log_group.vpn.name
|
||||
}
|
||||
|
||||
# Client VPN Endpoint
|
||||
resource "aws_ec2_client_vpn_endpoint" "main" {
|
||||
description = "Client VPN endpoint for ${var.name_prefix}"
|
||||
server_certificate_arn = var.server_certificate_arn
|
||||
client_cidr_block = var.client_cidr_block
|
||||
split_tunnel = var.split_tunnel
|
||||
vpc_id = var.vpc_id
|
||||
|
||||
# Authentication using certificate-based or Active Directory
|
||||
authentication_options {
|
||||
type = var.authentication_type
|
||||
root_certificate_chain_arn = var.authentication_type == "certificate-authentication" ? var.client_certificate_arn : null
|
||||
|
||||
# For Active Directory authentication
|
||||
active_directory_id = var.authentication_type == "directory-service-authentication" ? var.active_directory_id : null
|
||||
}
|
||||
|
||||
# Additional authentication option for MFA (optional)
|
||||
dynamic "authentication_options" {
|
||||
for_each = var.enable_saml_authentication ? [1] : []
|
||||
content {
|
||||
type = "federated-authentication"
|
||||
saml_provider_arn = var.saml_provider_arn
|
||||
self_service_saml_provider_arn = var.self_service_saml_provider_arn
|
||||
}
|
||||
}
|
||||
|
||||
# Connection logging
|
||||
connection_log_options {
|
||||
enabled = true
|
||||
cloudwatch_log_group = aws_cloudwatch_log_group.vpn.name
|
||||
cloudwatch_log_stream = aws_cloudwatch_log_stream.vpn.name
|
||||
}
|
||||
|
||||
# DNS servers to use
|
||||
dns_servers = var.dns_servers
|
||||
|
||||
# Transport protocol
|
||||
transport_protocol = var.transport_protocol
|
||||
|
||||
# VPN port
|
||||
vpn_port = var.vpn_port
|
||||
|
||||
# Session timeout
|
||||
session_timeout_hours = var.session_timeout_hours
|
||||
|
||||
# Client connect options (for custom authorization)
|
||||
dynamic "client_connect_options" {
|
||||
for_each = var.enable_client_connect_handler ? [1] : []
|
||||
content {
|
||||
enabled = true
|
||||
lambda_function_arn = var.client_connect_lambda_arn
|
||||
}
|
||||
}
|
||||
|
||||
# Client login banner
|
||||
dynamic "client_login_banner_options" {
|
||||
for_each = var.client_login_banner != "" ? [1] : []
|
||||
content {
|
||||
enabled = true
|
||||
banner_text = var.client_login_banner
|
||||
}
|
||||
}
|
||||
|
||||
tags = merge(
|
||||
var.tags,
|
||||
{
|
||||
Name = "${var.name_prefix}-vpn-endpoint"
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
# Associate VPN endpoint with subnets
|
||||
resource "aws_ec2_client_vpn_network_association" "main" {
|
||||
count = length(var.subnet_ids)
|
||||
client_vpn_endpoint_id = aws_ec2_client_vpn_endpoint.main.id
|
||||
subnet_id = var.subnet_ids[count.index]
|
||||
|
||||
lifecycle {
|
||||
# The issue why we are ignoring changes is that on the first resource creation, its terraform-aws-client-vpn-endpoint
|
||||
# This will change on AWS's next apply to the instance ID.
|
||||
ignore_changes = [subnet_id]
|
||||
}
|
||||
}
|
||||
|
||||
# Authorization rule to allow access to VPC CIDR
|
||||
resource "aws_ec2_client_vpn_authorization_rule" "vpc_access" {
|
||||
client_vpn_endpoint_id = aws_ec2_client_vpn_endpoint.main.id
|
||||
target_network_cidr = var.vpc_cidr
|
||||
authorize_all_groups = var.authorize_all_groups
|
||||
access_group_id = var.authorize_all_groups ? null : var.access_group_id
|
||||
description = "Allow access to VPC"
|
||||
}
|
||||
|
||||
# Additional authorization rules for specific CIDRs
|
||||
resource "aws_ec2_client_vpn_authorization_rule" "additional" {
|
||||
count = length(var.additional_authorization_rules)
|
||||
client_vpn_endpoint_id = aws_ec2_client_vpn_endpoint.main.id
|
||||
target_network_cidr = var.additional_authorization_rules[count.index].cidr
|
||||
authorize_all_groups = var.additional_authorization_rules[count.index].authorize_all_groups
|
||||
access_group_id = var.additional_authorization_rules[count.index].access_group_id
|
||||
description = var.additional_authorization_rules[count.index].description
|
||||
}
|
||||
|
||||
# Route to direct traffic to the VPC
|
||||
resource "aws_ec2_client_vpn_route" "vpc_route" {
|
||||
count = var.split_tunnel ? 1 : 0
|
||||
client_vpn_endpoint_id = aws_ec2_client_vpn_endpoint.main.id
|
||||
destination_cidr_block = var.vpc_cidr
|
||||
target_vpc_subnet_id = aws_ec2_client_vpn_network_association.main[0].subnet_id
|
||||
description = "Route to VPC"
|
||||
|
||||
depends_on = [aws_ec2_client_vpn_network_association.main]
|
||||
}
|
||||
|
||||
# Additional routes for specific networks
|
||||
resource "aws_ec2_client_vpn_route" "additional" {
|
||||
count = length(var.additional_routes)
|
||||
client_vpn_endpoint_id = aws_ec2_client_vpn_endpoint.main.id
|
||||
destination_cidr_block = var.additional_routes[count.index].cidr
|
||||
target_vpc_subnet_id = aws_ec2_client_vpn_network_association.main[0].subnet_id
|
||||
description = var.additional_routes[count.index].description
|
||||
|
||||
depends_on = [aws_ec2_client_vpn_network_association.main]
|
||||
}
|
||||
|
||||
# Security group for VPN endpoint
|
||||
resource "aws_security_group" "vpn" {
|
||||
name_prefix = "${var.name_prefix}-vpn-"
|
||||
description = "Security group for Client VPN endpoint"
|
||||
vpc_id = var.vpc_id
|
||||
|
||||
ingress {
|
||||
description = "VPN traffic"
|
||||
from_port = var.vpn_port
|
||||
to_port = var.vpn_port
|
||||
protocol = var.transport_protocol == "tcp" ? "tcp" : "udp"
|
||||
cidr_blocks = var.vpn_ingress_cidr_blocks
|
||||
}
|
||||
|
||||
egress {
|
||||
description = "Allow all outbound"
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "-1"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
}
|
||||
|
||||
tags = merge(
|
||||
var.tags,
|
||||
{
|
||||
Name = "${var.name_prefix}-vpn-sg"
|
||||
}
|
||||
)
|
||||
|
||||
lifecycle {
|
||||
create_before_destroy = true
|
||||
}
|
||||
}
|
||||
|
||||
# Apply security group to VPN endpoint
|
||||
resource "aws_ec2_client_vpn_endpoint_security_group_association" "main" {
|
||||
count = var.apply_security_group ? 1 : 0
|
||||
client_vpn_endpoint_id = aws_ec2_client_vpn_endpoint.main.id
|
||||
security_group_id = aws_security_group.vpn.id
|
||||
}
|
||||
36
terraform/modules/vpn/outputs.tf
Normal file
36
terraform/modules/vpn/outputs.tf
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# VPN Module Outputs
|
||||
|
||||
output "vpn_endpoint_id" {
|
||||
description = "ID of the Client VPN endpoint"
|
||||
value = aws_ec2_client_vpn_endpoint.main.id
|
||||
}
|
||||
|
||||
output "vpn_endpoint_arn" {
|
||||
description = "ARN of the Client VPN endpoint"
|
||||
value = aws_ec2_client_vpn_endpoint.main.arn
|
||||
}
|
||||
|
||||
output "vpn_endpoint_dns_name" {
|
||||
description = "DNS name of the Client VPN endpoint"
|
||||
value = aws_ec2_client_vpn_endpoint.main.dns_name
|
||||
}
|
||||
|
||||
output "vpn_security_group_id" {
|
||||
description = "ID of the VPN security group"
|
||||
value = aws_security_group.vpn.id
|
||||
}
|
||||
|
||||
output "client_cidr_block" {
|
||||
description = "CIDR block assigned to VPN clients"
|
||||
value = var.client_cidr_block
|
||||
}
|
||||
|
||||
output "vpn_endpoint_status" {
|
||||
description = "Status of the Client VPN endpoint"
|
||||
value = aws_ec2_client_vpn_endpoint.main.status
|
||||
}
|
||||
|
||||
output "cloudwatch_log_group" {
|
||||
description = "CloudWatch Log Group for VPN connections"
|
||||
value = aws_cloudwatch_log_group.vpn.name
|
||||
}
|
||||
192
terraform/modules/vpn/variables.tf
Normal file
192
terraform/modules/vpn/variables.tf
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
# VPN Module Variables
|
||||
|
||||
variable "name_prefix" {
|
||||
description = "Prefix for resource names"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "vpc_id" {
|
||||
description = "ID of the VPC"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "vpc_cidr" {
|
||||
description = "CIDR block of the VPC"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "subnet_ids" {
|
||||
description = "List of subnet IDs to associate with VPN endpoint"
|
||||
type = list(string)
|
||||
}
|
||||
|
||||
variable "server_certificate_arn" {
|
||||
description = "ARN of the server certificate in ACM"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "client_certificate_arn" {
|
||||
description = "ARN of the client root certificate in ACM (for certificate authentication)"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "client_cidr_block" {
|
||||
description = "CIDR block for VPN clients"
|
||||
type = string
|
||||
default = "172.16.0.0/22"
|
||||
}
|
||||
|
||||
variable "split_tunnel" {
|
||||
description = "Enable split tunnel (only route VPC traffic through VPN)"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "authentication_type" {
|
||||
description = "Authentication type (certificate-authentication, directory-service-authentication, or federated-authentication)"
|
||||
type = string
|
||||
default = "certificate-authentication"
|
||||
|
||||
validation {
|
||||
condition = contains(["certificate-authentication", "directory-service-authentication", "federated-authentication"], var.authentication_type)
|
||||
error_message = "Authentication type must be certificate-authentication, directory-service-authentication, or federated-authentication."
|
||||
}
|
||||
}
|
||||
|
||||
variable "active_directory_id" {
|
||||
description = "ID of Active Directory (for directory-service-authentication)"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "enable_saml_authentication" {
|
||||
description = "Enable SAML-based federated authentication as second factor"
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "saml_provider_arn" {
|
||||
description = "ARN of the SAML provider (for federated-authentication)"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "self_service_saml_provider_arn" {
|
||||
description = "ARN of the IAM SAML identity provider for self-service portal"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "dns_servers" {
|
||||
description = "DNS servers for VPN clients"
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "transport_protocol" {
|
||||
description = "Transport protocol (tcp or udp)"
|
||||
type = string
|
||||
default = "udp"
|
||||
|
||||
validation {
|
||||
condition = contains(["tcp", "udp"], var.transport_protocol)
|
||||
error_message = "Transport protocol must be tcp or udp."
|
||||
}
|
||||
}
|
||||
|
||||
variable "vpn_port" {
|
||||
description = "VPN port (443 or 1194)"
|
||||
type = number
|
||||
default = 443
|
||||
|
||||
validation {
|
||||
condition = contains([443, 1194], var.vpn_port)
|
||||
error_message = "VPN port must be 443 or 1194."
|
||||
}
|
||||
}
|
||||
|
||||
variable "session_timeout_hours" {
|
||||
description = "Maximum VPN session duration in hours (8-24)"
|
||||
type = number
|
||||
default = 24
|
||||
|
||||
validation {
|
||||
condition = var.session_timeout_hours >= 8 && var.session_timeout_hours <= 24
|
||||
error_message = "Session timeout must be between 8 and 24 hours."
|
||||
}
|
||||
}
|
||||
|
||||
variable "authorize_all_groups" {
|
||||
description = "Authorize all groups for VPC access"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "access_group_id" {
|
||||
description = "Access group ID for authorization (Active Directory group)"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "additional_authorization_rules" {
|
||||
description = "Additional authorization rules for specific CIDRs"
|
||||
type = list(object({
|
||||
cidr = string
|
||||
authorize_all_groups = bool
|
||||
access_group_id = string
|
||||
description = string
|
||||
}))
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "additional_routes" {
|
||||
description = "Additional routes for VPN clients"
|
||||
type = list(object({
|
||||
cidr = string
|
||||
description = string
|
||||
}))
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "log_retention_days" {
|
||||
description = "Number of days to retain VPN connection logs"
|
||||
type = number
|
||||
default = 30
|
||||
}
|
||||
|
||||
variable "enable_client_connect_handler" {
|
||||
description = "Enable client connect handler (Lambda function for custom authorization)"
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "client_connect_lambda_arn" {
|
||||
description = "ARN of Lambda function for client connect handler"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "client_login_banner" {
|
||||
description = "Text to display in client login banner"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "vpn_ingress_cidr_blocks" {
|
||||
description = "CIDR blocks allowed to connect to VPN"
|
||||
type = list(string)
|
||||
default = ["0.0.0.0/0"]
|
||||
}
|
||||
|
||||
variable "apply_security_group" {
|
||||
description = "Apply security group to VPN endpoint"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "tags" {
|
||||
description = "Tags to apply to resources"
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
157
terraform/scripts/export-vpn-config.sh
Executable file
157
terraform/scripts/export-vpn-config.sh
Executable file
|
|
@ -0,0 +1,157 @@
|
|||
#!/bin/bash
|
||||
# Export AWS Client VPN configuration
|
||||
# This script downloads the VPN client configuration file
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
echo_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
echo_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
echo_step() {
|
||||
echo -e "${BLUE}[STEP]${NC} $1"
|
||||
}
|
||||
|
||||
# Check prerequisites
|
||||
if ! command -v aws &> /dev/null; then
|
||||
echo_error "AWS CLI is not installed. Please install AWS CLI first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! aws sts get-caller-identity &> /dev/null; then
|
||||
echo_error "AWS credentials are not configured. Please configure AWS credentials first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get VPN endpoint ID from Terraform output or as parameter
|
||||
if [ -z "$1" ]; then
|
||||
echo_info "No VPN endpoint ID provided, attempting to get from Terraform..."
|
||||
|
||||
# Try to get from terraform output
|
||||
if [ -f "terraform.tfstate" ]; then
|
||||
VPN_ENDPOINT_ID=$(terraform output -raw vpn_endpoint_id 2>/dev/null || echo "")
|
||||
fi
|
||||
|
||||
if [ -z "$VPN_ENDPOINT_ID" ]; then
|
||||
echo_error "Could not find VPN endpoint ID."
|
||||
echo_error "Usage: $0 <vpn-endpoint-id> [region] [output-dir]"
|
||||
echo_error "Or run this script from the terraform deployment directory"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
VPN_ENDPOINT_ID="$1"
|
||||
fi
|
||||
|
||||
REGION="${2:-us-east-1}"
|
||||
OUTPUT_DIR="${3:-./vpn-config}"
|
||||
CERT_DIR="${4:-./vpn-certificates}"
|
||||
|
||||
echo_info "VPN Endpoint ID: ${VPN_ENDPOINT_ID}"
|
||||
echo_info "AWS Region: ${REGION}"
|
||||
echo_info "Output Directory: ${OUTPUT_DIR}"
|
||||
echo ""
|
||||
|
||||
# Create output directory
|
||||
mkdir -p "${OUTPUT_DIR}"
|
||||
|
||||
echo_step "Step 1: Export VPN client configuration"
|
||||
echo_info "Downloading VPN configuration from AWS..."
|
||||
|
||||
# Export the configuration
|
||||
aws ec2 export-client-vpn-client-configuration \
|
||||
--client-vpn-endpoint-id "${VPN_ENDPOINT_ID}" \
|
||||
--region "${REGION}" \
|
||||
--output text > "${OUTPUT_DIR}/client-config.ovpn"
|
||||
|
||||
echo_info "VPN configuration downloaded to: ${OUTPUT_DIR}/client-config.ovpn"
|
||||
echo ""
|
||||
|
||||
echo_step "Step 2: Add client certificate and key to configuration"
|
||||
|
||||
# Check if certificate files exist
|
||||
if [ ! -f "${CERT_DIR}/client.crt" ] || [ ! -f "${CERT_DIR}/client.key" ]; then
|
||||
echo_warn "Client certificates not found in ${CERT_DIR}"
|
||||
echo_warn "You'll need to manually add <cert> and <key> sections to the .ovpn file"
|
||||
echo_warn "Or specify the correct certificate directory as 4th parameter"
|
||||
else
|
||||
echo_info "Adding client certificate and key to configuration..."
|
||||
|
||||
# Append certificate and key to the configuration
|
||||
echo "" >> "${OUTPUT_DIR}/client-config.ovpn"
|
||||
echo "<cert>" >> "${OUTPUT_DIR}/client-config.ovpn"
|
||||
cat "${CERT_DIR}/client.crt" >> "${OUTPUT_DIR}/client-config.ovpn"
|
||||
echo "</cert>" >> "${OUTPUT_DIR}/client-config.ovpn"
|
||||
echo "" >> "${OUTPUT_DIR}/client-config.ovpn"
|
||||
echo "<key>" >> "${OUTPUT_DIR}/client-config.ovpn"
|
||||
cat "${CERT_DIR}/client.key" >> "${OUTPUT_DIR}/client-config.ovpn"
|
||||
echo "</key>" >> "${OUTPUT_DIR}/client-config.ovpn"
|
||||
|
||||
echo_info "Client certificate and key added to configuration"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
echo_step "Step 3: Create platform-specific configurations"
|
||||
|
||||
# Copy for different platforms
|
||||
cp "${OUTPUT_DIR}/client-config.ovpn" "${OUTPUT_DIR}/code-server-vpn.ovpn"
|
||||
|
||||
echo_info "Configuration files created:"
|
||||
echo " ${OUTPUT_DIR}/client-config.ovpn - Original configuration"
|
||||
echo " ${OUTPUT_DIR}/code-server-vpn.ovpn - Ready to import"
|
||||
echo ""
|
||||
|
||||
echo_step "Installation Instructions:"
|
||||
echo ""
|
||||
echo "📱 macOS:"
|
||||
echo " 1. Install Tunnelblick: https://tunnelblick.net/downloads.html"
|
||||
echo " 2. Double-click code-server-vpn.ovpn"
|
||||
echo " 3. Click 'Connect'"
|
||||
echo ""
|
||||
echo "🪟 Windows:"
|
||||
echo " 1. Install OpenVPN Connect: https://openvpn.net/client-connect-vpn-for-windows/"
|
||||
echo " 2. Import code-server-vpn.ovpn"
|
||||
echo " 3. Click 'Connect'"
|
||||
echo ""
|
||||
echo "🐧 Linux:"
|
||||
echo " 1. Install OpenVPN:"
|
||||
echo " sudo apt-get install openvpn # Debian/Ubuntu"
|
||||
echo " sudo yum install openvpn # RHEL/CentOS"
|
||||
echo " 2. Connect using:"
|
||||
echo " sudo openvpn --config ${OUTPUT_DIR}/code-server-vpn.ovpn"
|
||||
echo ""
|
||||
echo "📱 iOS:"
|
||||
echo " 1. Install OpenVPN Connect from App Store"
|
||||
echo " 2. Transfer code-server-vpn.ovpn to your device"
|
||||
echo " 3. Import and connect"
|
||||
echo ""
|
||||
echo "🤖 Android:"
|
||||
echo " 1. Install OpenVPN for Android from Play Store"
|
||||
echo " 2. Transfer code-server-vpn.ovpn to your device"
|
||||
echo " 3. Import and connect"
|
||||
echo ""
|
||||
|
||||
echo_info "✅ VPN configuration export complete!"
|
||||
echo_warn "🔒 Please distribute this configuration securely to authorized users only"
|
||||
echo ""
|
||||
|
||||
echo_info "To test the VPN connection:"
|
||||
echo " 1. Connect to VPN using the configuration file"
|
||||
echo " 2. Access code-server at the private ALB address"
|
||||
echo " 3. Check CloudWatch Logs for VPN connection logs:"
|
||||
echo " aws logs tail /aws/vpn/<prefix> --follow"
|
||||
177
terraform/scripts/generate-vpn-certificates.sh
Executable file
177
terraform/scripts/generate-vpn-certificates.sh
Executable file
|
|
@ -0,0 +1,177 @@
|
|||
#!/bin/bash
|
||||
# Generate certificates for AWS Client VPN
|
||||
# This script creates server and client certificates required for VPN authentication
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
echo_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
echo_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
echo_step() {
|
||||
echo -e "${BLUE}[STEP]${NC} $1"
|
||||
}
|
||||
|
||||
# Check prerequisites
|
||||
check_prerequisites() {
|
||||
echo_info "Checking prerequisites..."
|
||||
|
||||
if ! command -v openssl &> /dev/null; then
|
||||
echo_error "OpenSSL is not installed. Please install OpenSSL first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v aws &> /dev/null; then
|
||||
echo_error "AWS CLI is not installed. Please install AWS CLI first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! aws sts get-caller-identity &> /dev/null; then
|
||||
echo_error "AWS credentials are not configured. Please configure AWS credentials first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo_info "All prerequisites met!"
|
||||
}
|
||||
|
||||
# Configuration
|
||||
CERT_DIR="${1:-./vpn-certificates}"
|
||||
REGION="${2:-us-east-1}"
|
||||
COMMON_NAME="${3:-code-server-vpn}"
|
||||
|
||||
echo_info "Certificate Directory: ${CERT_DIR}"
|
||||
echo_info "AWS Region: ${REGION}"
|
||||
echo_info "Common Name: ${COMMON_NAME}"
|
||||
echo ""
|
||||
|
||||
# Create certificate directory
|
||||
mkdir -p "${CERT_DIR}"
|
||||
cd "${CERT_DIR}"
|
||||
|
||||
echo_step "Step 1: Generate CA private key and certificate"
|
||||
echo_info "Creating Certificate Authority (CA)..."
|
||||
|
||||
# Generate CA private key
|
||||
openssl genrsa -out ca.key 2048
|
||||
|
||||
# Generate CA certificate
|
||||
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt -subj "/C=US/ST=State/L=City/O=Organization/OU=IT/CN=${COMMON_NAME}-ca"
|
||||
|
||||
echo_info "CA certificate created: ca.crt"
|
||||
echo ""
|
||||
|
||||
echo_step "Step 2: Generate server private key and certificate"
|
||||
echo_info "Creating server certificate..."
|
||||
|
||||
# Generate server private key
|
||||
openssl genrsa -out server.key 2048
|
||||
|
||||
# Generate server certificate signing request (CSR)
|
||||
openssl req -new -key server.key -out server.csr -subj "/C=US/ST=State/L=City/O=Organization/OU=IT/CN=${COMMON_NAME}-server"
|
||||
|
||||
# Sign server certificate with CA
|
||||
openssl x509 -req -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt
|
||||
|
||||
echo_info "Server certificate created: server.crt"
|
||||
echo ""
|
||||
|
||||
echo_step "Step 3: Generate client private key and certificate"
|
||||
echo_info "Creating client certificate..."
|
||||
|
||||
# Generate client private key
|
||||
openssl genrsa -out client.key 2048
|
||||
|
||||
# Generate client certificate signing request (CSR)
|
||||
openssl req -new -key client.key -out client.csr -subj "/C=US/ST=State/L=City/O=Organization/OU=IT/CN=${COMMON_NAME}-client"
|
||||
|
||||
# Sign client certificate with CA
|
||||
openssl x509 -req -days 3650 -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt
|
||||
|
||||
echo_info "Client certificate created: client.crt"
|
||||
echo ""
|
||||
|
||||
echo_step "Step 4: Upload certificates to AWS Certificate Manager"
|
||||
echo_info "Uploading server certificate to ACM..."
|
||||
|
||||
# Upload server certificate
|
||||
SERVER_CERT_ARN=$(aws acm import-certificate \
|
||||
--certificate fileb://server.crt \
|
||||
--private-key fileb://server.key \
|
||||
--certificate-chain fileb://ca.crt \
|
||||
--region ${REGION} \
|
||||
--tags Key=Name,Value=${COMMON_NAME}-server Key=Purpose,Value=VPN-Server \
|
||||
--query CertificateArn \
|
||||
--output text)
|
||||
|
||||
echo_info "Server certificate uploaded: ${SERVER_CERT_ARN}"
|
||||
|
||||
# Upload client certificate (root CA)
|
||||
echo_info "Uploading client root certificate to ACM..."
|
||||
CLIENT_CERT_ARN=$(aws acm import-certificate \
|
||||
--certificate fileb://ca.crt \
|
||||
--private-key fileb://ca.key \
|
||||
--region ${REGION} \
|
||||
--tags Key=Name,Value=${COMMON_NAME}-client-root Key=Purpose,Value=VPN-Client-Root \
|
||||
--query CertificateArn \
|
||||
--output text)
|
||||
|
||||
echo_info "Client root certificate uploaded: ${CLIENT_CERT_ARN}"
|
||||
echo ""
|
||||
|
||||
echo_step "Step 5: Save certificate ARNs to file"
|
||||
|
||||
cat > certificate-arns.txt <<EOF
|
||||
Server Certificate ARN: ${SERVER_CERT_ARN}
|
||||
Client Root Certificate ARN: ${CLIENT_CERT_ARN}
|
||||
EOF
|
||||
|
||||
cat > terraform-vars.txt <<EOF
|
||||
# Add these to your terraform.tfvars file:
|
||||
enable_vpn = true
|
||||
vpn_server_certificate_arn = "${SERVER_CERT_ARN}"
|
||||
vpn_client_certificate_arn = "${CLIENT_CERT_ARN}"
|
||||
EOF
|
||||
|
||||
echo_info "Certificate ARNs saved to certificate-arns.txt"
|
||||
echo ""
|
||||
|
||||
echo_step "Summary of Generated Files:"
|
||||
echo " ca.key - CA private key (keep secure!)"
|
||||
echo " ca.crt - CA certificate"
|
||||
echo " server.key - Server private key (keep secure!)"
|
||||
echo " server.crt - Server certificate"
|
||||
echo " client.key - Client private key (distribute to VPN users)"
|
||||
echo " client.crt - Client certificate (distribute to VPN users)"
|
||||
echo ""
|
||||
|
||||
echo_step "Important Notes:"
|
||||
echo " 1. Store ca.key and server.key securely (never share these!)"
|
||||
echo " 2. Distribute client.key and client.crt to VPN users"
|
||||
echo " 3. Add the certificate ARNs to your terraform.tfvars:"
|
||||
cat terraform-vars.txt
|
||||
echo ""
|
||||
|
||||
echo_info "✅ Certificate generation complete!"
|
||||
echo_warn "🔒 Please backup the ${CERT_DIR} directory securely"
|
||||
echo ""
|
||||
|
||||
echo_info "Next steps:"
|
||||
echo " 1. Add the certificate ARNs to terraform.tfvars"
|
||||
echo " 2. Set enable_vpn = true in terraform.tfvars"
|
||||
echo " 3. Run terraform apply"
|
||||
echo " 4. Export VPN client configuration using export-vpn-config.sh"
|
||||
Loading…
Reference in a new issue