code-server/terraform/modules/ec2/main.tf
Claude b8094ac6a0
Add comprehensive Terraform infrastructure for code-server deployment on AWS
This commit adds complete Terraform infrastructure as code for deploying
code-server on both EC2 and EKS platforms with enterprise-grade security
and SAML/OIDC authentication.

Features:
- EC2 deployment with Auto Scaling Groups and Application Load Balancer
- EKS deployment with managed node groups and AWS Load Balancer Controller
- Private network setup with VPC, private subnets, and NAT gateways
- SAML/OIDC authentication using OAuth2 Proxy
- Security hardening:
  - KMS encryption for data at rest
  - TLS encryption in transit
  - IAM roles with least privilege
  - Security groups with minimal access
  - VPC Flow Logs
  - IMDSv2 enforcement
- Auto-scaling capabilities for both EC2 and EKS
- CloudWatch logging and monitoring
- Automated deployment scripts

Terraform Modules:
- modules/vpc: VPC with public/private subnets, NAT, and VPC endpoints
- modules/security: Security groups, IAM roles, and KMS keys
- modules/ec2: EC2 Auto Scaling deployment with ALB
- modules/eks: EKS cluster with managed node groups and addons

Deployments:
- deployments/ec2: EC2 deployment configuration
- deployments/eks: EKS deployment configuration with Kubernetes manifests

Documentation:
- README.md: Comprehensive deployment and operations guide
- QUICK-START.md: Quick reference for fast deployment
- SAML-SETUP-GUIDE.md: Step-by-step IdP configuration guide

Scripts:
- scripts/deploy-ec2.sh: Automated EC2 deployment
- scripts/deploy-eks.sh: Automated EKS deployment
- scripts/destroy-ec2.sh: EC2 cleanup
- scripts/destroy-eks.sh: EKS cleanup
2025-11-15 17:29:42 +00:00

346 lines
8.9 KiB
HCL

# EC2 Module for Code-Server Deployment
# Deploys code-server on EC2 instances with Auto Scaling, ALB, and OAuth2 Proxy
# Get latest Amazon Linux 2023 AMI
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-*-x86_64"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
# Generate random password for code-server if not provided
resource "random_password" "code_server" {
count = var.code_server_password == "" ? 1 : 0
length = 32
special = true
}
# Store password in AWS Secrets Manager
resource "aws_secretsmanager_secret" "code_server_password" {
name = "${var.name_prefix}-code-server-password"
description = "Code-Server password"
recovery_window_in_days = 7
tags = var.tags
}
resource "aws_secretsmanager_secret_version" "code_server_password" {
secret_id = aws_secretsmanager_secret.code_server_password.id
secret_string = var.code_server_password != "" ? var.code_server_password : random_password.code_server[0].result
}
# User data script for EC2 instances
locals {
user_data = templatefile("${path.module}/user-data.sh", {
code_server_version = var.code_server_version
region = var.aws_region
secret_name = aws_secretsmanager_secret.code_server_password.name
oauth2_client_id = var.oauth2_client_id
oauth2_client_secret = var.oauth2_client_secret
oauth2_issuer_url = var.oauth2_issuer_url
oauth2_redirect_url = var.oauth2_redirect_url
cookie_secret = var.oauth2_cookie_secret
allowed_emails = join(",", var.oauth2_allowed_emails)
})
}
# Launch Template
resource "aws_launch_template" "code_server" {
name_prefix = "${var.name_prefix}-code-server-"
image_id = var.ami_id != "" ? var.ami_id : data.aws_ami.amazon_linux.id
instance_type = var.instance_type
iam_instance_profile {
name = var.iam_instance_profile_name
}
vpc_security_group_ids = [var.security_group_id]
user_data = base64encode(local.user_data)
block_device_mappings {
device_name = "/dev/xvda"
ebs {
volume_size = var.ebs_volume_size
volume_type = var.ebs_volume_type
encrypted = true
kms_key_id = var.kms_key_arn
delete_on_termination = true
}
}
metadata_options {
http_endpoint = "enabled"
http_tokens = "required"
http_put_response_hop_limit = 1
instance_metadata_tags = "enabled"
}
monitoring {
enabled = true
}
tag_specifications {
resource_type = "instance"
tags = merge(
var.tags,
{
Name = "${var.name_prefix}-code-server"
}
)
}
tag_specifications {
resource_type = "volume"
tags = merge(
var.tags,
{
Name = "${var.name_prefix}-code-server-volume"
}
)
}
lifecycle {
create_before_destroy = true
}
tags = var.tags
}
# Auto Scaling Group
resource "aws_autoscaling_group" "code_server" {
name = "${var.name_prefix}-code-server-asg"
vpc_zone_identifier = var.subnet_ids
target_group_arns = [aws_lb_target_group.code_server.arn, aws_lb_target_group.oauth2_proxy.arn]
health_check_type = "ELB"
health_check_grace_period = 300
min_size = var.min_instances
max_size = var.max_instances
desired_capacity = var.desired_instances
launch_template {
id = aws_launch_template.code_server.id
version = "$Latest"
}
tag {
key = "Name"
value = "${var.name_prefix}-code-server"
propagate_at_launch = true
}
dynamic "tag" {
for_each = var.tags
content {
key = tag.key
value = tag.value
propagate_at_launch = true
}
}
lifecycle {
create_before_destroy = true
ignore_changes = [desired_capacity]
}
}
# Application Load Balancer
resource "aws_lb" "code_server" {
name = "${var.name_prefix}-code-server-alb"
internal = var.internal_alb
load_balancer_type = "application"
security_groups = [var.alb_security_group_id]
subnets = var.alb_subnet_ids
enable_deletion_protection = var.enable_deletion_protection
enable_http2 = true
enable_cross_zone_load_balancing = true
tags = merge(
var.tags,
{
Name = "${var.name_prefix}-code-server-alb"
}
)
}
# Target Group for OAuth2 Proxy
resource "aws_lb_target_group" "oauth2_proxy" {
name = "${var.name_prefix}-oauth2-tg"
port = 4180
protocol = "HTTP"
vpc_id = var.vpc_id
health_check {
enabled = true
healthy_threshold = 2
unhealthy_threshold = 2
timeout = 5
interval = 30
path = "/ping"
matcher = "200"
}
deregistration_delay = 30
tags = merge(
var.tags,
{
Name = "${var.name_prefix}-oauth2-tg"
}
)
}
# Target Group for Code-Server
resource "aws_lb_target_group" "code_server" {
name = "${var.name_prefix}-code-server-tg"
port = 8080
protocol = "HTTP"
vpc_id = var.vpc_id
health_check {
enabled = true
healthy_threshold = 2
unhealthy_threshold = 2
timeout = 5
interval = 30
path = "/healthz"
matcher = "200"
}
deregistration_delay = 30
stickiness {
type = "lb_cookie"
cookie_duration = 86400
enabled = true
}
tags = merge(
var.tags,
{
Name = "${var.name_prefix}-code-server-tg"
}
)
}
# HTTPS Listener (primary)
resource "aws_lb_listener" "https" {
count = var.certificate_arn != "" ? 1 : 0
load_balancer_arn = aws_lb.code_server.arn
port = "443"
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS-1-2-2017-01"
certificate_arn = var.certificate_arn
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.oauth2_proxy.arn
}
tags = var.tags
}
# HTTP Listener (redirect to HTTPS)
resource "aws_lb_listener" "http" {
load_balancer_arn = aws_lb.code_server.arn
port = "80"
protocol = "HTTP"
default_action {
type = var.certificate_arn != "" ? "redirect" : "forward"
dynamic "redirect" {
for_each = var.certificate_arn != "" ? [1] : []
content {
port = "443"
protocol = "HTTPS"
status_code = "HTTP_301"
}
}
target_group_arn = var.certificate_arn == "" ? aws_lb_target_group.oauth2_proxy.arn : null
}
tags = var.tags
}
# CloudWatch Log Group for Code-Server
resource "aws_cloudwatch_log_group" "code_server" {
name = "/aws/ec2/${var.name_prefix}-code-server"
retention_in_days = var.log_retention_days
tags = var.tags
}
# Auto Scaling Policies
resource "aws_autoscaling_policy" "scale_up" {
count = var.enable_autoscaling ? 1 : 0
name = "${var.name_prefix}-code-server-scale-up"
autoscaling_group_name = aws_autoscaling_group.code_server.name
adjustment_type = "ChangeInCapacity"
scaling_adjustment = 1
cooldown = 300
}
resource "aws_autoscaling_policy" "scale_down" {
count = var.enable_autoscaling ? 1 : 0
name = "${var.name_prefix}-code-server-scale-down"
autoscaling_group_name = aws_autoscaling_group.code_server.name
adjustment_type = "ChangeInCapacity"
scaling_adjustment = -1
cooldown = 300
}
# CloudWatch Alarms for Auto Scaling
resource "aws_cloudwatch_metric_alarm" "cpu_high" {
count = var.enable_autoscaling ? 1 : 0
alarm_name = "${var.name_prefix}-code-server-cpu-high"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = "2"
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = "300"
statistic = "Average"
threshold = "80"
dimensions = {
AutoScalingGroupName = aws_autoscaling_group.code_server.name
}
alarm_description = "This metric monitors ec2 cpu utilization"
alarm_actions = [aws_autoscaling_policy.scale_up[0].arn]
tags = var.tags
}
resource "aws_cloudwatch_metric_alarm" "cpu_low" {
count = var.enable_autoscaling ? 1 : 0
alarm_name = "${var.name_prefix}-code-server-cpu-low"
comparison_operator = "LessThanThreshold"
evaluation_periods = "2"
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = "300"
statistic = "Average"
threshold = "20"
dimensions = {
AutoScalingGroupName = aws_autoscaling_group.code_server.name
}
alarm_description = "This metric monitors ec2 cpu utilization"
alarm_actions = [aws_autoscaling_policy.scale_down[0].arn]
tags = var.tags
}