diff --git a/.gitignore b/.gitignore index e5c0d50..7e33b52 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ docker-compose/.env docker-compose/.volumes .idea +terraform/**/terraform.tfstate +terraform/**/terraform.tfstate.backup +terraform/**/.* +terraform/**/*.tfvars diff --git a/terraform/examples/basic/main.tf.example b/terraform/examples/basic/main.tf.example new file mode 100644 index 0000000..36e34e9 --- /dev/null +++ b/terraform/examples/basic/main.tf.example @@ -0,0 +1,566 @@ +locals { + ############################ AWS configuration ############################ + + # The AWS region where the Defguard infrastructure will be deployed. + region = "eu-north-1" + + ############################ Core configuration ########################### + + # The URL for the Defguard Core. This is the URL under which the Defguard Core should be accessible. + core_url = "https://defguard.example.com" + + # The gRPC port for the Defguard Core. This is the port that the core will use to communicate with Defguard Gateways. + core_grpc_port = 50055 + + # The HTTP port for the Defguard Core web UI. This is the port that the core will listen on for incoming HTTP requests. + core_http_port = 8000 + + # Whether to allow insecure cookies for the Defguard Core web UI. Set to true if you + # are using HTTP to access the Defguard Core web UI. + core_cookie_insecure = false + + # The initial password for the "admin" user. Use it to login to the Defguard Core web UI for the first time. + default_admin_password = "pass123" + + # The deb package version of the Defguard Core that will be installed on the instance. + # Must be a valid, released version of Defguard Core. + core_package_version = "1.3.2-alpha2" + + # The architecture of the Defguard Core server instance. + # Supported values: "x86_64", "aarch64" + core_arch = "x86_64" + + # The instance type for the Defguard Core server. + core_instance_type = "t3.micro" + + ########################### Proxy configuration ########################### + + # The URL for the Defguard Proxy. This is the URL under which the Defguard Proxy should be accessible. + proxy_url = "https://proxy.example.com" + + # The gRPC port for the Defguard Proxy. This is the port that the proxy will use to communicate with the Defguard Core. + proxy_grpc_port = 50051 + + # The HTTP port for the Defguard Proxy. This is the port that the proxy will listen on for incoming HTTP requests. + proxy_http_port = 8000 + + # The deb package version of the proxy that will be installed on the instance. + # Must be a valid, released version of Defguard Proxy. + proxy_package_version = "1.2.0" + + # The architecture of the Defguard Proxy server instance. + # Supported values: "x86_64", "aarch64" + proxy_arch = "x86_64" + + # The instance type for the Defguard Proxy server. + proxy_instance_type = "t3.micro" + + ###################### VPN and Gateway configuration ###################### + + # List of VPN networks to be created. A gateway will be created for each network. + vpn_networks = [ + { + # The ID of the VPN network. Must start with 1 and be incremented for each new network. + # Used for modifying the network configuration later. + id = 1 + # The name of the VPN network. Displayed to the users. + name = "vpn1" + # The CIDR address of the VPN network. Clients will be assigned IP addresses from this range. + address = "10.10.10.1/24" + # The UDP port for the WireGuard VPN. Gateways will listen on this port for incoming VPN connections. + port = 51820 + # Whether to enable NAT for the VPN network. If true, the gateway will perform NAT (masquerade) for the VPN clients. + # This is useful if you want the VPN clients to access the internet through the gateway or to access other resources in the VPC. + nat = true + } + ] + + # The gateway deb package version that will be installed on the instance. + # Must be a valid, released version of Defguard Gateway. + gateway_package_version = "1.3.0" + + # The architecture of the Defguard Gateway server instance. + # Supported values: "x86_64", "aarch64" + gateway_arch = "x86_64" + + # The instance type for the Defguard Gateway server. + gateway_instance_type = "t3.micro" + + ########################## Database configuration ######################### + + # The name of the database that will be created for the Defguard Core. + db_name = "defguard" + + # The username for the database that will be created for the Defguard Core. + db_username = "defguard" + + # The port on which the database will listen for incoming connections. + db_port = 5432 + + # The password for the database user. This will be used by the Defguard Core to connect to the database. + db_password = "defguard" + + # The amount of storage allocated for the database in GB. The minimum amount for this example required by AWS is 20 GB. + db_storage = 20 # GB + + # The instance class for the database. This defines the performance characteristics of the database instance. + db_instance_class = "db.t3.micro" + + ############################ VPC configuration ############################ + + # The name of the VPC that will be created for the Defguard infrastructure. + vpc_name = "defguard-vpc" + + # The CIDR block for the VPC. This defines the IP address range for the VPC and its subnets. + vpc_cidr = "10.0.0.0/16" + + # The tags to be applied to the Defguard VPC. + vpc_tags = { + Name = local.vpc_name + } + + # The private subnets for the VPC. These subnets are used for the database instance. + # Note: 2 subnets are required for high availability of the database instance. + vpc_private_subnets = ["10.0.2.0/24", "10.0.3.0/24"] + + # The subnets for the VPC that will be used for the Defguard Core, proxy, and gateways. + vpc_public_subnets = ["10.0.1.0/24"] + + # The availability zones for the VPC. This is used mainly for the database instance to ensure high availability. + azs = ["eu-north-1a", "eu-north-1b"] +} + +variable "aws_access_key" { + description = "AWS access key" + type = string +} + +variable "aws_secret_key" { + description = "AWS secret key" + type = string +} + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.0" + } + } +} + +data "aws_ami" "ubuntu" { + most_recent = true + owners = ["099720109477"] + + filter { + name = "name" + values = ["ubuntu/images/hvm-ssd-gp3/ubuntu-noble-24.04-amd64-server-*"] + } +} + +provider "aws" { + region = local.region + access_key = var.aws_access_key + secret_key = var.aws_secret_key +} + +resource "random_password" "gateway_secret" { + length = 64 + special = false +} + +module "defguard_core" { + # source = "../../modules/core" + source = "github.com/DefGuard/deployment//terraform/modules/core?ref=main" + instance_type = local.core_instance_type + package_version = local.core_package_version + arch = local.core_arch + ami = data.aws_ami.ubuntu.id + + core_url = local.core_url + proxy_grpc_port = local.proxy_grpc_port + proxy_url = local.proxy_url + grpc_port = local.core_grpc_port + http_port = local.core_http_port + cookie_insecure = local.core_cookie_insecure + vpn_networks = [for network in local.vpn_networks : { + id = network.id + name = network.name + address = network.address + port = network.port + endpoint = aws_eip.defguard_gateway_endpoint[network.id - 1].public_ip + }] + db_details = { + name = local.db_name + username = local.db_username + password = local.db_password + port = local.db_port + address = aws_db_instance.defguard_core_db.address + } + proxy_address = module.defguard_proxy.proxy_private_address + gateway_secret = random_password.gateway_secret.result + network_interface_id = aws_network_interface.defguard_core_network_interface.id + # log_level = "info" +} + +module "defguard_proxy" { + # source = "../../modules/proxy" + source = "github.com/DefGuard/deployment//terraform/modules/proxy?ref=main" + + instance_type = local.proxy_instance_type + package_version = local.proxy_package_version + arch = local.proxy_arch + grpc_port = local.proxy_grpc_port + http_port = local.proxy_http_port + proxy_url = local.proxy_url + # log_level = "info" + + ami = data.aws_ami.ubuntu.id + network_interface_id = aws_network_interface.defguard_proxy_network_interface.id +} + +module "defguard_gateway" { + count = length(local.vpn_networks) + # source = "../../modules/gateway" + source = "github.com/DefGuard/deployment//terraform/modules/gateway?ref=main" + + ami = data.aws_ami.ubuntu.id + instance_type = local.gateway_instance_type + package_version = local.gateway_package_version + arch = local.gateway_arch + + core_grpc_port = local.core_grpc_port + nat = local.vpn_networks[count.index].nat + network_id = local.vpn_networks[count.index].id + gateway_secret = random_password.gateway_secret.result + network_interface_id = aws_network_interface.defguard_gateway_network_interface[count.index].id + core_address = aws_network_interface.defguard_core_network_interface.private_ip + # log_level = "info" + + depends_on = [module.defguard_core] +} + +module "vpc" { + source = "terraform-aws-modules/vpc/aws" + + name = local.vpc_name + cidr = local.vpc_cidr + azs = local.azs + private_subnets = local.vpc_private_subnets + public_subnets = local.vpc_public_subnets + + enable_dns_hostnames = true + tags = local.vpc_tags +} + +########################################################################### +####################### Core database configuration ####################### +########################################################################### + +resource "aws_db_instance" "defguard_core_db" { + engine = "postgres" + instance_class = local.db_instance_class + username = local.db_username + password = local.db_password + db_name = local.db_name + port = local.db_port + skip_final_snapshot = true + allocated_storage = local.db_storage + db_subnet_group_name = aws_db_subnet_group.defguard.name + vpc_security_group_ids = [aws_security_group.defguard_db_sg.id] + parameter_group_name = aws_db_parameter_group.defguard_db_parameter_group.name +} + +resource "aws_db_parameter_group" "defguard_db_parameter_group" { + name = "defguard-db-parameter-group" + family = "postgres17" + + parameter { + name = "rds.force_ssl" + value = "0" + } +} + +resource "aws_db_subnet_group" "defguard" { + name = "defguard-db-subnet-group" + subnet_ids = module.vpc.private_subnets +} + +########################################################################### +######################## Core network configuration ####################### +########################################################################### + +# Public IP address for the Defguard Core instance +# Remove this if you want to use a private IP only +# or you are running Defguard behind a reverse proxy. +resource "aws_eip" "defguard_core_endpoint" { + domain = "vpc" +} + +resource "aws_eip_association" "defguard_core_endpoint_association" { + network_interface_id = aws_network_interface.defguard_core_network_interface.id + allocation_id = aws_eip.defguard_core_endpoint.id +} + +resource "aws_security_group" "defguard_core_sg" { + name = "defguard-core-sg" + description = "Core access" + vpc_id = module.vpc.vpc_id + + ########################### General access rules ########################## + + # (optional) SSH access to the Defguard Core server instance + # ingress { + # from_port = 22 + # to_port = 22 + # protocol = "tcp" + # cidr_blocks = ["0.0.0.0/0"] + # } + + # HTTP access to the Defguard Core web UI from connected VPN clients + # Remove this rule if you want to run core only behind a reverse proxy + # Note that the core access should be limited to the VPN clients and internal networks only. + ingress { + from_port = local.core_http_port + to_port = local.core_http_port + protocol = "tcp" + cidr_blocks = [ + for eip in aws_eip.defguard_gateway_endpoint : "${eip.public_ip}/32" + ] + } + + # Example access from a reverse proxy + # ingress { + # from_port = local.core_http_port + # to_port = local.core_http_port + # protocol = "tcp" + # security_groups = [ ] + # } + + ########## Security group rules essential for Defguard operation ########## + + # gRPC communication with Defguard Gateways + ingress { + from_port = local.core_grpc_port + to_port = local.core_grpc_port + protocol = "tcp" + security_groups = [ + for sg in aws_security_group.defguard_gateway_sg : sg.id + ] + } + + # General egress + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_network_interface" "defguard_core_network_interface" { + subnet_id = module.vpc.public_subnets[0] + security_groups = [aws_security_group.defguard_core_sg.id] + + tags = { + Name = "defguard-core-network-interface" + } +} + +########################################################################### +###################### Gateway network configuration ###################### +########################################################################### + +# Public IP addresses for the Defguard Gateway instances +# Gateways must be accessible externally to allow VPN clients to connect. + +resource "aws_eip" "defguard_gateway_endpoint" { + count = length(local.vpn_networks) + domain = "vpc" +} + +resource "aws_eip_association" "defguard_gateway_endpoint_association" { + count = length(local.vpn_networks) + network_interface_id = aws_network_interface.defguard_gateway_network_interface[count.index].id + allocation_id = aws_eip.defguard_gateway_endpoint[count.index].id +} + +resource "aws_security_group" "defguard_gateway_sg" { + count = length(local.vpn_networks) + name = "defguard-gateway-sg-${count.index}" + description = "Gateway access" + vpc_id = module.vpc.vpc_id + + ########################### General access rules ########################## + + # (optional) SSH access to the Defguard Gateway server instance + # ingress { + # from_port = 22 + # to_port = 22 + # protocol = "tcp" + # cidr_blocks = ["0.0.0.0/0"] + # } + + ########## Security group rules essential for Defguard operation ########## + + # VPN traffic coming from connected clients + ingress { + from_port = local.vpn_networks[count.index].port + to_port = local.vpn_networks[count.index].port + protocol = "udp" + cidr_blocks = ["0.0.0.0/0"] + } + + # General egress + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_network_interface" "defguard_gateway_network_interface" { + count = length(local.vpn_networks) + subnet_id = module.vpc.public_subnets[0] + security_groups = [aws_security_group.defguard_gateway_sg[count.index].id] + + tags = { + Name = "defguard-gateway-network-interface-${count.index}" + } +} + +########################################################################### +####################### Proxy network configuration ####################### +########################################################################### + +# Public IP address for the Defguard Proxy instance +# Remove this if you want to run proxy behind a reverse proxy +resource "aws_eip" "defguard_proxy_endpoint" { + domain = "vpc" +} + +resource "aws_eip_association" "defguard_proxy_endpoint_association" { + network_interface_id = aws_network_interface.defguard_proxy_network_interface.id + allocation_id = aws_eip.defguard_proxy_endpoint.id +} + +resource "aws_security_group" "defguard_proxy_sg" { + name = "defguard-proxy-sg" + description = "Proxy access" + vpc_id = module.vpc.vpc_id + + ########################### General access rules ########################## + + # (optional) SSH access to the Defguard Proxy server instance + # ingress { + # from_port = 22 + # to_port = 22 + # protocol = "tcp" + # cidr_blocks = ["0.0.0.0/0"] + # } + + # HTTP access to the Defguard Proxy web UI from anywhere + # Remove this rule if you want to run proxy behind a reverse proxy + # Note that the proxy should be accessible externally to allow Defguard clients + # to communicate through it and to allow the enrollment of new users. + ingress { + from_port = local.proxy_http_port + to_port = local.proxy_http_port + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + # Example access from a reverse proxy + # ingress { + # from_port = local.proxy_http_port + # to_port = local.proxy_http_port + # protocol = "tcp" + # security_groups = [ ] + # } + + ########## Security group rules essential for Defguard operation ########## + + # Internal communication with Defguard Core + ingress { + from_port = local.proxy_grpc_port + to_port = local.proxy_grpc_port + protocol = "tcp" + security_groups = [aws_security_group.defguard_core_sg.id] + } + + # General egress + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_network_interface" "defguard_proxy_network_interface" { + subnet_id = module.vpc.public_subnets[0] + security_groups = [aws_security_group.defguard_proxy_sg.id] + + tags = { + Name = "defguard-proxy-network-interface" + } +} + + +########################################################################### +###################### Database network configuration ##################### +########################################################################### + +resource "aws_security_group" "defguard_db_sg" { + name = "defguard-db-sg" + description = "Access to the database" + vpc_id = module.vpc.vpc_id + + # Allows access to the database from the Defguard Core instance + ingress { + from_port = local.db_port + to_port = local.db_port + protocol = "tcp" + security_groups = [aws_security_group.defguard_core_sg.id] + } + + tags = { + Name = "defguard-db-sg" + } +} + +########################################################################### +################################# Outputs ################################# +########################################################################### + +output "defguard_core_private_address" { + description = "The IP address of the Defguard Core instance in the internal network" + value = aws_network_interface.defguard_core_network_interface.private_ip +} + +output "defguard_core_public_address" { + description = "The public IP address of the Defguard Core instance" + value = aws_eip.defguard_core_endpoint.public_ip +} + +output "defguard_proxy_public_address" { + description = "The public IP address of the Defguard Proxy instance" + value = aws_eip.defguard_proxy_endpoint.public_ip +} + +output "defguard_proxy_private_address" { + description = "The private IP address of the Defguard Proxy instance" + value = aws_network_interface.defguard_proxy_network_interface.private_ip +} + +output "defguard_gateway_public_addresses" { + description = "The public IP addresses of the Defguard Gateway instances" + value = [for gw in aws_eip.defguard_gateway_endpoint : gw.public_ip] +} + +output "defguard_gateway_private_addresses" { + description = "The private IP addresses of the Defguard Gateway instances" + value = [for gw in aws_network_interface.defguard_gateway_network_interface : gw.private_ip] +} diff --git a/terraform/modules/core/main.tf b/terraform/modules/core/main.tf new file mode 100644 index 0000000..8ac6545 --- /dev/null +++ b/terraform/modules/core/main.tf @@ -0,0 +1,36 @@ +resource "aws_instance" "defguard_core" { + ami = var.ami + instance_type = var.instance_type + + user_data = templatefile("${path.module}/setup.sh", { + db_address = var.db_details.address + db_password = var.db_details.password + db_username = var.db_details.username + db_name = var.db_details.name + db_port = var.db_details.port + core_url = var.core_url + proxy_address = var.proxy_address + proxy_grpc_port = var.proxy_grpc_port + proxy_url = var.proxy_url + grpc_port = var.grpc_port + gateway_secret = var.gateway_secret + vpn_networks = var.vpn_networks + package_version = var.package_version + arch = var.arch + http_port = var.http_port + default_admin_password = var.default_admin_password + cookie_insecure = var.cookie_insecure + log_level = var.log_level + }) + user_data_replace_on_change = true + + network_interface { + network_interface_id = var.network_interface_id + device_index = 0 + } + + tags = { + Name = "defguard-core-instance" + } +} + diff --git a/terraform/modules/core/outputs.tf b/terraform/modules/core/outputs.tf new file mode 100644 index 0000000..e69de29 diff --git a/terraform/modules/core/setup.sh b/terraform/modules/core/setup.sh new file mode 100755 index 0000000..8496285 --- /dev/null +++ b/terraform/modules/core/setup.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +set -e + +LOG_FILE="/var/log/defguard.log" + +log() { + echo "$(date '+%Y-%m-%d %H:%M:%S') $1" +} + +generate_secret_inner() { + local length="$1" + openssl rand -base64 $${length} | tr -d "=+/" | tr -d '\n' | cut -c1-$${length-1} +} + +( +log "Updating apt repositories..." +apt update + +log "Installing curl..." +apt install -y curl + +log "Downloading defguard-core package..." +curl -fsSL -o /tmp/defguard-core.deb https://github.com/DefGuard/defguard/releases/download/v${package_version}/defguard-${package_version}-${arch}-unknown-linux-gnu.deb + +log "Installing defguard-core package..." +dpkg -i /tmp/defguard-core.deb + +log "Writing Core configuration to /etc/defguard/core.conf..." +tee /etc/defguard/core.conf <> "$LOG_FILE" 2>&1 +log "Created VPN location ${network.name} with address ${network.address} and endpoint ${network.endpoint} and port ${network.port}" +%{ endfor ~} + +log "Cleaning up after installing Defguard Core..." +rm -f /tmp/defguard-core.deb + +log "Setup completed." +) 2>&1 | tee -a "$LOG_FILE" diff --git a/terraform/modules/core/variables.tf b/terraform/modules/core/variables.tf new file mode 100644 index 0000000..bf2d46d --- /dev/null +++ b/terraform/modules/core/variables.tf @@ -0,0 +1,100 @@ +variable "ami" { + description = "AMI ID for the instance" + type = string +} + +variable "instance_type" { + description = "Instance type for the instance" + type = string + default = "t3.micro" +} + +variable "db_details" { + description = "Details of the database connection" + type = object({ + name = string + username = string + password = string + port = number + address = string + }) +} + +variable "core_url" { + description = "URL of the Defguard instance" + type = string +} + +variable "proxy_address" { + description = "The IP address of the Defguard Proxy instance" + type = string +} + +variable "proxy_grpc_port" { + description = "Port to be used to communicate with Defguard Proxy" + type = string +} + +variable "proxy_url" { + description = "The URL of the Defguard Proxy instance where enrollment is performed" + type = string +} + +variable "grpc_port" { + description = "Port to be used to communicate with Defguard Core" + type = number +} + +variable "http_port" { + description = "Port to be used to access Defguard Core via HTTP" + type = number + default = 8000 +} + +variable "gateway_secret" { + description = "Secret for the Defguard Gateway" + type = string +} + +variable "network_interface_id" { + description = "Network interface ID for the instance" + type = string +} + +variable "vpn_networks" { + description = "List of VPN networks" + type = list(object({ + name = string + address = string + port = number + endpoint = string + id = number + })) +} + +variable "package_version" { + description = "Version of the Defguard Core package to be installed" + type = string +} + +variable "arch" { + description = "Architecture of the Defguard Core package to be installed" + type = string +} + +variable "default_admin_password" { + description = "Default admin password for the Defguard Core" + type = string + default = "pass123" +} + +variable "cookie_insecure" { + description = "Whether to use insecure cookies for the Defguard Core" + type = bool +} + +variable "log_level" { + description = "Log level for Defguard Core. Possible values: trace, debug, info, warn, error" + type = string + default = "info" +} diff --git a/terraform/modules/gateway/main.tf b/terraform/modules/gateway/main.tf new file mode 100644 index 0000000..db4c233 --- /dev/null +++ b/terraform/modules/gateway/main.tf @@ -0,0 +1,27 @@ +resource "aws_instance" "defguard_gateway" { + ami = var.ami + instance_type = var.instance_type + + user_data = templatefile("${path.module}/setup.sh", { + gateway_port = var.gateway_port + gateway_secret = var.gateway_secret + network_id = var.network_id + core_address = var.core_address + core_grpc_port = var.core_grpc_port + package_version = var.package_version + nat = var.nat + gateway_name = "defguard-gateway-${var.network_id}" + arch = var.arch + log_level = var.log_level + }) + user_data_replace_on_change = true + + network_interface { + network_interface_id = var.network_interface_id + device_index = 0 + } + + tags = { + Name = "defguard-gateway-instance-${var.network_id}" + } +} diff --git a/terraform/modules/gateway/outputs.tf b/terraform/modules/gateway/outputs.tf new file mode 100644 index 0000000..e69de29 diff --git a/terraform/modules/gateway/setup.sh b/terraform/modules/gateway/setup.sh new file mode 100644 index 0000000..21529e3 --- /dev/null +++ b/terraform/modules/gateway/setup.sh @@ -0,0 +1,148 @@ +#!/usr/bin/env bash +set -e + +LOG_FILE="/var/log/defguard.log" + +log() { + echo "$(date '+%Y-%m-%d %H:%M:%S') $1" +} + +LOG_FILE="/var/log/defguard.log" + +log() { + echo "$(date '+%Y-%m-%d %H:%M:%S') $1" +} + +base64url_encode() { + echo -n "$1" | openssl base64 -e -A | tr '+/' '-_' | tr -d '=' +} + +( +log "Updating apt repositories..." +apt update + +log "Installing curl..." +apt install -y curl + +log "Downloading defguard-gateway package..." +curl -fsSL -o /tmp/defguard-gateway.deb https://github.com/DefGuard/gateway/releases/download/v${package_version}/defguard-gateway_${package_version}_${arch}-unknown-linux-gnu.deb + +log "Installing defguard-gateway package..." +dpkg -i /tmp/defguard-gateway.deb + +log "Generating gateway token..." +NETWORK_ID="${network_id}" +SECRET="${gateway_secret}" +ISSUER="DefGuard" + +HEADER='{"alg":"HS256","typ":"JWT"}' +NOW=$(date +%s) +EXPIRATION=$(($NOW + 315360000)) +PAYLOAD=$(cat <&1 | tee -a "$LOG_FILE" diff --git a/terraform/modules/gateway/variables.tf b/terraform/modules/gateway/variables.tf new file mode 100644 index 0000000..83c27df --- /dev/null +++ b/terraform/modules/gateway/variables.tf @@ -0,0 +1,63 @@ +variable "ami" { + description = "AMI ID for the instance" + type = string +} + +variable "instance_type" { + description = "Instance type for the instance" + type = string + default = "t3.micro" +} + +variable "gateway_port" { + description = "Port to be used by the VPN" + type = number + default = 50051 +} + +variable "gateway_secret" { + description = "Secret key for the Defguard Gateway" + type = string +} + +variable "network_id" { + description = "ID of the VPN network" + type = number +} + +variable "core_address" { + description = "Internal address of the Defguard instance" + type = string +} + +variable "core_grpc_port" { + description = "Port to be used to communicate with Defguard Core" + type = number +} + +variable "network_interface_id" { + description = "Network interface ID for the instance" + type = string +} + +variable "package_version" { + description = "Version of the Defguard Gateway package to be installed" + type = string +} + +variable "arch" { + description = "Architecture of the Defguard Gateway package to be installed" + type = string +} + +variable "nat" { + description = "Enable masquerading" + type = bool + default = true +} + +variable "log_level" { + description = "Log level for Defguard Gateway. Possible values: trace, debug, info, warn, error" + type = string + default = "info" +} diff --git a/terraform/modules/proxy/main.tf b/terraform/modules/proxy/main.tf new file mode 100644 index 0000000..15b0cba --- /dev/null +++ b/terraform/modules/proxy/main.tf @@ -0,0 +1,23 @@ +resource "aws_instance" "defguard_proxy" { + ami = var.ami + instance_type = var.instance_type + + user_data = templatefile("${path.module}/setup.sh", { + proxy_url = var.proxy_url + grpc_port = var.grpc_port + arch = var.arch + package_version = var.package_version + http_port = var.http_port + log_level = var.log_level + }) + user_data_replace_on_change = true + + network_interface { + network_interface_id = var.network_interface_id + device_index = 0 + } + + tags = { + Name = "defguard-proxy-instance" + } +} diff --git a/terraform/modules/proxy/outputs.tf b/terraform/modules/proxy/outputs.tf new file mode 100644 index 0000000..948469b --- /dev/null +++ b/terraform/modules/proxy/outputs.tf @@ -0,0 +1,4 @@ +output "proxy_private_address" { + description = "The private IP address of the Defguard Proxy instance" + value = aws_instance.defguard_proxy.private_ip +} diff --git a/terraform/modules/proxy/setup.sh b/terraform/modules/proxy/setup.sh new file mode 100644 index 0000000..b595ab6 --- /dev/null +++ b/terraform/modules/proxy/setup.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +set -e + +LOG_FILE="/var/log/defguard.log" + +log() { + echo "$(date '+%Y-%m-%d %H:%M:%S') $1" +} + +( +log "Updating apt repositories..." +apt update + +log "Installing curl..." +apt install -y curl + +log "Downloading defguard-proxy package..." +curl -fsSL -o /tmp/defguard-proxy.deb https://github.com/DefGuard/proxy/releases/download/v${package_version}/defguard-proxy-${package_version}-${arch}-unknown-linux-gnu.deb + +log "Installing defguard-proxy package..." +dpkg -i /tmp/defguard-proxy.deb + +log "Writing proxy configuration to /etc/defguard/proxy.toml..." +tee /etc/defguard/proxy.toml <&1 | tee -a "$LOG_FILE" + diff --git a/terraform/modules/proxy/variables.tf b/terraform/modules/proxy/variables.tf new file mode 100644 index 0000000..21a7eeb --- /dev/null +++ b/terraform/modules/proxy/variables.tf @@ -0,0 +1,47 @@ +variable "ami" { + description = "AMI ID for the instance" + type = string +} + +variable "instance_type" { + description = "Instance type for the instance" + type = string + default = "t3.micro" +} + +variable "proxy_url" { + description = "URL of the Proxy instance" + type = string +} + +variable "grpc_port" { + description = "Port to be used to communicate with Defguard Core" + type = string +} + +variable "network_interface_id" { + description = "Network interface ID for the instance" + type = string +} + +variable "arch" { + description = "Architecture of the Defguard Proxy package to be installed" + type = string +} + +variable "package_version" { + description = "Version of the Defguard Proxy package to be installed" + type = string +} + +variable "http_port" { + description = "Port to be used to access Defguard Proxy via HTTP" + type = number + default = 8080 +} + +variable "log_level" { + description = "Log level for Defguard Proxy. Possible values: trace, debug, info, warn, error" + type = string + default = "info" +}