Merge branch 'ENG-8-Update-Terraform-on-github-to-reference-latest-Kasm-version-(1.12)' into 'develop'

Resolve ENG-8 "Update terraform on github to reference latest kasm version (1.12)"

Closes ENG-8

See merge request kasm-technologies/internal/terraform!10
This commit is contained in:
Justin Travis 2023-03-15 06:55:28 +00:00
commit faed31c30d
128 changed files with 5495 additions and 1660 deletions

7
.gitignore vendored
View file

@ -1,5 +1,6 @@
Local .terraform directories
# Local .terraform directories
**/.terraform/*
.terraform
# .tfstate files
*.tfstate
@ -8,12 +9,12 @@
# Crash log files
crash.log
# Exclude all .tfvars files, which are likely to contain sentitive data, such as
# Exclude secrets.tfvars files, which are likely to contain sentitive data, such as
# password, private keys, and other secrets. These should not be part of version
# control as they are data points which are potentially sensitive and subject
# to change depending on the environment.
#
*.tfvars
secrets.tfvars
# Ignore override files as they are usually used to override resources locally and so
# are not checked in

View file

@ -18,8 +18,6 @@ is deployed.
[Image_Diagram]: https://f.hubspotusercontent30.net/hubfs/5856039/terraform/diagrams/aws-multi-region-int-gw.png "Diagram"
# Pre-Configuration
Consider creating a special sub account for the Kasm deployment.
@ -27,12 +25,10 @@ Consider creating a special sub account for the Kasm deployment.
In your AWS account create a DNS Public zone that matches the desired domain name for the deployment. e.g `kasm.contoso.com`
### SSH Key Pair
In the desired AWS region create an aws Key pair. This will be configured as the SSH key for the deployed EC2 machines
In the each AWS region where you will deploy Kasm, create an aws Key pair with the same name. The key name will be value used in the `aws_key_pair` variable and it will be configured as the SSH key for the deployed EC2 machines.
### AWS API Keys
Create a user via the IAM console that will be used for the terraform deployment. Give the user **Programatic Access**
and attach the existing policy **AdministratorAccess**. Save the key and key secret
Create a user via the IAM console that will be used for the terraform deployment. Give the user **Programatic Access** and attach the existing policy **AdministratorAccess**. Save the key and key secret.
# Terraform Configuration
@ -41,22 +37,61 @@ and attach the existing policy **AdministratorAccess**. Save the key and key sec
terraform init
2. Open `variables.tf` and update the global variables. The variable definitions and descriptions
can be found in `<module-name>/variables.tf`
3. Open `deployment.tf` and update the module level variables as desired.
2. Open `settings.tfvars` and update the variable values. The variable definitions, descriptions, and validation expectations can be found in the `variables.tf` file.
4. Verify the configuration
> ***NOTE:*** This document assumes you are using a separate file named `secrets.tfvars` for the AWS credentials generated in the [AWS API Keys](#aws-api-keys) section above. The .gitignore file in this repository will ignore any files named `secrets.tfvars` since they are expected to have sensitive values in them. This will prevent you from accidentally committing them to source control.
terraform plan
3. If you are deploying more than 2 regions, you will need to modify the `provider.tf` and the `deployment.tf` files. There are commented sections in both files indicating how to deploy additional regions.
5. Deploy
3. Verify the configuration
terraform apply
terraform plan -var-file settings.tfvars -var-file secrets.tfvars
4. Deploy
terraform apply -var-file settings.tfvars -var-file secrets.tfvars
5. Login to the Deployment as an Admin via the domain defined e.g `https://kasm.contoso.com`
6. Navigate to the Agents tab, and enable each Agent after it checks in. (May take a few minutes)
6. Login to the Deployment as an Admin via the domain defined e.g `https://kasm.contoso.com`
# AWS Terraform Variable definitions
7. Navigate to the Agents tab, and enable each Agent after it checks in. (May take a few minutes)
| Variable | Description | Variable type | Example |
|:--------:|-------------|---------------|---------|
| `aws_access_key` | The AWS access key used for deployment. | String | `"AKIAJSIE27KKMHXI3BJQ"` |
| `aws_secret_key` | The AWS secret key used for deployment. | String | `"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"` |
| `aws_primary_region` | The AWS Region to deploy all Kasm Management resources. | String | `"us-east-1"` |
| `project_name` | The name of the deployment (e.g dev, staging). A short single word of up to 15 characters. | String | `"kasm"` |
| `aws_domain_name` | The Route53 Zone used for the dns entries. This must already exist in the AWS account. (e.g dev.kasm.contoso.com). The deployment will be accessed via this zone name via https. | String | `"kasm.contoso.com"` |
| `kasm_zone_name` | A name given to the kasm deployment Zone. | String | `"default"` |
| `primary_vpc_subnet_cidr` | The subnet CIDR to use for the Primary region's VPC. | String | `"10.0.0.0/16"` |
| `aws_key_pair` | The name of an aws keypair to use. | String | `"kasm_ssh_key"` |
| `primary_region_ec2_ami_id` | The AMI used for the EC2 nodes in the Primary (Management) region. Recommended Ubuntu 20.04 LTS. | String | `"ami-09cd747c78a9add63"` |
| `swap_size` | The amount of swap (in MB) to configure inside the Kasm servers. | Number | `2048` |
| `webapp_instance_type` | The instance type for the Kasm WebApps. | String | `"t3.small"` |
| `webapp_hdd_size_gb` | The HDD size for the WebApp EC2s in GB. | Number | `40` |
| `db_instance_type` | The instance type for the Kasm Database. | String | `"t3.medium"` |
| `db_hdd_size_gb` | The HDD size for the DB EC2 in GB. | Number | `40` |
| `agent_instance_type` | The instance type for the Kasm Agents in the Primary region. | String | `"t3.medium"` |
| `agent_hdd_size_gb` | The HDD size for the Agent EC2s in GB. | Number | `120` |
| `num_webapps` | The number of WebApp role servers to create in this deployment. Acceptable ranges from 1-3. | Number | `2` |
| `num_agents` | The number of static Kasm Agents to create in the primary region. Acceptable ranges from 0-100. | Number | `2` |
| `allow_ssh_cidrs` | A list of subnets in CIDR notation allowed to SSH into your kasm servers (use `["0.0.0.0/0]"` to allow SSH from any IP). | List(String) | `["1.1.1.1/32","172.217.22.14/32"]` |
| `web_access_cidrs` | A list of subnets in CIDR notation allowed Web access to your kasm servers (use `["0.0.0.0/0]"` to allow HTTP/HTTPS from any IP). | List(String) | `["0.0.0.0/0"]` |
| `secondary_regions_settings` | A map of AWS environment settings for secondary regions. The Primary region is considered "region1", thus all secondary regions should be labeled "region2", "region3", etc. Refer to the commented settings in the `secondary_regions_settings` variable in the `settings.tf` for an example. | Map(any) | <pre>{<br/>&nbsp;&nbsp;region2 = {<br/>&nbsp;&nbsp;&nbsp;&nbsp;agent_region = "eu-central-1"<br/>&nbsp;&nbsp;&nbsp;&nbsp;agent_ec2_ami_id = "ami-0e067cc8a2b58de59"<br/>&nbsp;&nbsp;&nbsp;&nbsp;agent_instance_type = "t3.medium"<br/>&nbsp;&nbsp;&nbsp;&nbsp;num_agents = 2<br/>&nbsp;&nbsp;&nbsp;&nbsp;agent_vpc_cidr = "10.1.0.0/16"<br/>&nbsp;&nbsp;}<br/>}</pre>
| `database_password` | The Kasm PostgreSQL database password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` |
| `redis_password` | The Kasm Redis password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` |
| `admin_password` | The Kasm Administrative user login password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` |
| `user_password` | A Kasm standard (non-administrator) user password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` |
| `manager_token` | The manager token value used by Kasm agents to authenticate to the Kasm WebApps. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` |
| `kasm_build` | The download URL for the desired Kasm Workspaces version. | String | `"https://kasm-static-content.s3.amazonaws.com/kasm_release_1.12.0.d4fd8a.tar.gz"` |
| `aws_default_tags` | A Map of all tags you wish to apply to all TF created resources in this deployment. | Map(Any) | <pre>{<br/>&nbsp;&nbsp;Service_name = "Kasm Workspaces"<br/>&nbsp;&nbsp;Kasm_version = "1.12"<br/>}</pre> |
# Detailed Terraform Deployment Diagram
![Detailed Diagram][Detailed_Diagram]
[Detailed_Diagram]: ./diagram/aws_multi_region.png "Detailed Diagram"

View file

@ -1,29 +1,25 @@
resource "aws_instance" "kasm-agent" {
count = "${var.num_agents}"
ami = "${var.ec2_ami}"
instance_type = "${var.agent_instance_type}"
vpc_security_group_ids = ["${aws_security_group.kasm-agent-sg.id}"]
subnet_id = "${aws_subnet.kasm-agent-subnet.id}"
key_name = "${var.aws_key_pair}"
count = var.num_agents
ami = var.ec2_ami
instance_type = var.agent_instance_type
vpc_security_group_ids = [data.aws_security_group.data-kasm_agent_sg.id]
subnet_id = data.aws_subnet.data-kasm_agent_subnet.id
key_name = var.aws_key_pair
root_block_device {
volume_size = "50"
volume_size = var.agent_hdd_size_gb
}
user_data = <<-EOF
#!/bin/bash
fallocate -l 4g /mnt/kasm.swap
chmod 600 /mnt/kasm.swap
mkswap /mnt/kasm.swap
swapon /mnt/kasm.swap
echo '/mnt/kasm.swap swap swap defaults 0 0' | tee -a /etc/fstab
cd /tmp
wget ${var.kasm_build}
tar xvf kasm_*.tar.gz
PUBLIC_DNS=(`curl -s http://169.254.169.254/latest/meta-data/public-ipv4`)
bash kasm_release/install.sh -S agent -e -p $PUBLIC_DNS -m ${var.zone_name}-lb.${var.aws_domain_name} -M ${var.manager_token}
EOF
user_data = templatefile("${path.module}/../userdata/agent_bootstrap.sh",
{
kasm_build_url = var.kasm_build
swap_size = var.swap_size
manager_address = var.aws_domain_name
manager_token = var.manager_token
}
)
tags = {
Name = "${var.project_name}-${var.zone_name}-kasm-agent"
}
}
}

View file

@ -0,0 +1,3 @@
data "aws_availability_zones" "available" {
state = "available"
}

View file

@ -1,8 +0,0 @@
provider "aws" {
region = "${var.aws_region}"
access_key = "${var.aws_access_key}"
secret_key = "${var.aws_secret_key}"
}
data "aws_availability_zones" "available" {
state = "available"
}

View file

@ -0,0 +1,8 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
#version = "4.56.0"
}
}
}

View file

@ -0,0 +1,21 @@
resource "aws_route_table" "internet_access" {
vpc_id = data.aws_vpc.data-kasm_agent_vpc.id
route {
cidr_block = var.anywhere
gateway_id = data.aws_internet_gateway.data-kasm_agent_default_ig.id
}
tags = {
Name = "${var.project_name}-kasm-agent-default-route"
}
}
data "aws_route_table" "data-agent_internet_gateway_route_table" {
route_table_id = aws_route_table.internet_access.id
}
resource "aws_route_table_association" "agent_table_association" {
subnet_id = data.aws_subnet.data-kasm_agent_subnet.id
route_table_id = data.aws_route_table.data-agent_internet_gateway_route_table.id
}

View file

@ -1,26 +1,30 @@
resource "aws_security_group" "kasm-agent-sg" {
name = "${var.project_name}-${var.zone_name}-kasm-agent-access"
description = "Allow access to agents"
vpc_id = "${aws_vpc.kasm-default-vpc.id}"
vpc_id = data.aws_vpc.data-kasm_agent_vpc.id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["${var.ssh_access_cidr}"]
cidr_blocks = var.ssh_access_cidrs
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
cidr_blocks = [var.anywhere]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
cidr_blocks = [var.anywhere]
}
}
}
data "aws_security_group" "data-kasm_agent_sg" {
id = aws_security_group.kasm-agent-sg.id
}

View file

@ -1,9 +1,19 @@
locals {
kasm_agent_vpc_subnet_cidr_mask = split("/", var.agent_vpc_cidr)[1]
kasm_agent_subnet_cidr_calculation = (8 - (local.kasm_agent_vpc_subnet_cidr_mask - 16))
kasm_agent_subnet_cidr_size = local.kasm_agent_subnet_cidr_calculation < 0 ? 0 : local.kasm_agent_subnet_cidr_calculation
}
resource "aws_subnet" "kasm-agent-subnet" {
vpc_id = "${aws_vpc.kasm-default-vpc.id}"
cidr_block = "10.0.40.0/24"
vpc_id = data.aws_vpc.data-kasm_agent_vpc.id
cidr_block = cidrsubnet(var.agent_vpc_cidr, local.kasm_agent_subnet_cidr_size, 0)
availability_zone = data.aws_availability_zones.available.names[0]
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-${var.zone_name}-kasm-agent-subnet"
}
}
}
data "aws_subnet" "data-kasm_agent_subnet" {
id = aws_subnet.kasm-agent-subnet.id
}

View file

@ -1,51 +1,76 @@
variable "aws_access_key" {
description = "The AWS access key used for deployment"
}
variable "aws_secret_key" {
description = "The AWS secret key used for deployment"
}
variable "project_name" {
description = "The name of the deployment (e.g dev, staging). A short single word"
type = string
}
variable "aws_domain_name" {
description = "The Route53 Zone used for the dns entries. This must already exist in the AWS account. (e.g dev.kasm.contoso.com). The deployment will be accessed via this zone name via https"
type = string
}
variable "agent_vpc_cidr" {
description = "Subnet CIDR range for Agent VPC"
type = string
}
variable "swap_size" {
description = "The amount of swap (in MB) to configure inside the compute instances"
type = number
}
variable "num_agents" {
description = "The number of Agent Role Servers to create in the deployment"
type = number
}
variable "agent_instance_type" {
description = "the instance type for the agents"
description = "The instance type for the agents"
type = string
}
variable "agent_hdd_size_gb" {
description = "The HDD size for agents"
type = number
}
variable "aws_region" {
description = "The AWS region for the deployment. (e.g us-east-1)"
type = string
}
variable "kasm_build" {
description = "The URL for the Kasm Workspaces build"
type = string
}
variable "zone_name" {
description = "A name given to the Kasm deployment Zone"
type = string
}
variable "aws_key_pair" {
description = "The name of an aws keypair to use."
type = string
}
variable "ec2_ami" {
description = "The AMI used for the EC2 nodes. Recommended Ubuntu 18.04 LTS."
description = "The AMI used for the EC2 nodes. Recommended Ubuntu 20.04 LTS."
type = string
}
variable "manager_token" {
description = "The password for the database. No special characters"
type = string
sensitive = true
}
variable "ssh_access_cidr" {
variable "ssh_access_cidrs" {
description = "CIDR notation of the bastion host allowed to SSH in to the machines"
type = list(string)
}
variable "anywhere" {
description = "Anywhere subnet for routing and load ingress from all IPs"
type = string
default = "0.0.0.0/0"
}

View file

@ -1,19 +1,23 @@
resource "aws_vpc" "kasm-default-vpc" {
cidr_block = "10.0.0.0/16"
resource "aws_vpc" "kasm-agent-vpc" {
cidr_block = var.agent_vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.project_name}-${var.zone_name}-kasm-vpc"
}
}
data "aws_vpc" "data-kasm_agent_vpc" {
id = aws_vpc.kasm-agent-vpc.id
}
resource "aws_internet_gateway" "kasm-default-ig" {
vpc_id = "${aws_vpc.kasm-default-vpc.id}"
vpc_id = data.aws_vpc.data-kasm_agent_vpc.id
tags = {
Name = "${var.project_name}-${var.zone_name}-kasm-ig"
}
}
resource "aws_route" "internet_access" {
route_table_id = "${aws_vpc.kasm-default-vpc.main_route_table_id}"
destination_cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.kasm-default-ig.id}"
}
data "aws_internet_gateway" "data-kasm_agent_default_ig" {
internet_gateway_id = aws_internet_gateway.kasm-default-ig.id
}

View file

@ -3,88 +3,175 @@
# This will house the Kasm Workspaces DB, and a set of
# agents/webapps that map to this region.
###########################################################
module "primary_region" {
source = "./primary"
aws_region = "us-east-1"
zone_name = "us-east-1"
ec2_ami = "ami-013f17f36f8b1fefb"
db_instance_type = "t3.small"
num_agents = 2
agent_instance_type = "t3.medium"
num_webapps = 2
webapp_instance_type = "t3.small"
aws_access_key = "${var.aws_access_key}"
aws_secret_key = "${var.aws_secret_key}"
project_name = "${var.project_name}"
kasm_build = "${var.kasm_build}"
database_password = "${var.database_password}"
redis_password = "${var.redis_password}"
user_password = "${var.user_password}"
admin_password = "${var.admin_password}"
manager_token = "${var.manager_token}"
aws_key_pair = "${var.aws_key_pair}"
aws_domain_name = "${var.aws_domain_name}"
ssh_access_cidr = "${var.ssh_access_cidr}"
source = "./primary"
aws_region = var.aws_primary_region
zone_name = var.aws_primary_region
vpc_subnet_cidr = var.primary_vpc_subnet_cidr
ec2_ami = var.primary_region_ec2_ami_id
db_instance_type = var.db_instance_type
num_webapps = var.num_webapps
project_name = var.project_name
kasm_build = var.kasm_build
db_hdd_size_gb = var.db_hdd_size_gb
swap_size = var.swap_size
database_password = var.database_password
redis_password = var.redis_password
user_password = var.user_password
admin_password = var.admin_password
manager_token = var.manager_token
service_registration_token = var.service_registration_token
aws_key_pair = var.aws_key_pair
aws_domain_name = var.aws_domain_name
ssh_access_cidrs = var.ssh_access_cidrs
web_access_cidrs = var.web_access_cidrs
}
###########################################################
# Add a pair of webapp and agent modules
# for each additional region desired.
###########################################################
module "us-west-1-webapps" {
source = "./webapps"
faux_aws_region = "us-west-1"
zone_name = "us-west-1"
num_webapps = 2
webapp_instance_type = "t3.small"
ec2_ami = "ami-013f17f36f8b1fefb"
primary_aws_region = "${module.primary_region.primary_aws_region}"
webapp_subnet_id_1 = "${module.primary_region.webapp_subnet_1_id}"
webapp_subnet_id_2 = "${module.primary_region.webapp_subnet_2_id}"
agent_subnet_id = "${module.primary_region.agent_subnet_id}"
aws_access_key = "${var.aws_access_key}"
aws_secret_key = "${var.aws_secret_key}"
aws_domain_name = "${var.aws_domain_name}"
project_name = "${var.project_name}"
kasm_build = "${var.kasm_build}"
database_password = "${var.database_password}"
redis_password = "${var.redis_password}"
manager_token = "${var.manager_token}"
aws_key_pair = "${var.aws_key_pair}"
kasm_db_ip = "${module.primary_region.kasm_db_ip}"
primary_vpc_id = "${module.primary_region.primary_vpc_id}"
certificate_arn = "${module.primary_region.certificate_arn}"
ssh_access_cidr = "${var.ssh_access_cidr}"
module "primary_region-webapps-and-agents" {
source = "./webapps"
faux_aws_region = var.aws_primary_region
zone_name = var.aws_primary_region
primary_aws_region = var.aws_primary_region
num_webapps = var.num_webapps
num_agents = var.num_agents
ec2_ami = var.primary_region_ec2_ami_id
swap_size = var.swap_size
webapp_subnet_ids = module.primary_region.webapp_subnet_ids
webapp_security_group_id = module.primary_region.webapp_security_group_id
agent_subnet_id = module.primary_region.agent_subnet_id
agent_security_group_id = module.primary_region.agent_security_group_id
load_balancer_security_group_id = module.primary_region.lb_security_group_id
webapp_instance_type = var.webapp_instance_type
webapp_hdd_size_gb = var.webapp_hdd_size_gb
agent_instance_type = var.agent_instance_type
agent_hdd_size_gb = var.agent_hdd_size_gb
aws_domain_name = var.aws_domain_name
project_name = var.project_name
kasm_build = var.kasm_build
database_password = var.database_password
redis_password = var.redis_password
manager_token = var.manager_token
aws_key_pair = var.aws_key_pair
kasm_db_ip = module.primary_region.kasm_db_ip
primary_vpc_id = module.primary_region.primary_vpc_id
certificate_arn = module.primary_region.certificate_arn
ssh_access_cidrs = var.ssh_access_cidrs
load_balancer_log_bucket = module.primary_region.lb_log_bucket
}
module "us-west-1-agents" {
source = "./agents"
aws_region = "us-west-1"
zone_name = "us-west-1"
num_agents = 2
agent_instance_type = "t3.medium"
ec2_ami = "ami-08d0eee5e00da8a9b"
aws_access_key = "${var.aws_access_key}"
aws_secret_key = "${var.aws_secret_key}"
aws_domain_name = "${var.aws_domain_name}"
project_name = "${var.project_name}"
kasm_build = "${var.kasm_build}"
manager_token = "${var.manager_token}"
aws_key_pair = "${var.aws_key_pair}"
ssh_access_cidr = "${var.ssh_access_cidr}"
#####################################################################
#
# Add a webapp and agent module for each additional region desired.
#
#####################################################################
module "region2-webapps" {
source = "./webapps"
faux_aws_region = var.secondary_regions_settings.region2.agent_region
zone_name = var.secondary_regions_settings.region2.agent_region
primary_aws_region = var.aws_primary_region
num_webapps = var.num_webapps
webapp_instance_type = var.webapp_instance_type
webapp_hdd_size_gb = var.webapp_hdd_size_gb
swap_size = var.swap_size
ec2_ami = var.primary_region_ec2_ami_id
webapp_subnet_ids = module.primary_region.webapp_subnet_ids
webapp_security_group_id = module.primary_region.webapp_security_group_id
load_balancer_security_group_id = module.primary_region.lb_security_group_id
aws_domain_name = var.aws_domain_name
project_name = var.project_name
kasm_build = var.kasm_build
database_password = var.database_password
redis_password = var.redis_password
manager_token = var.manager_token
aws_key_pair = var.aws_key_pair
kasm_db_ip = module.primary_region.kasm_db_ip
primary_vpc_id = module.primary_region.primary_vpc_id
certificate_arn = module.primary_region.certificate_arn
ssh_access_cidrs = var.ssh_access_cidrs
load_balancer_log_bucket = module.primary_region.lb_log_bucket
}
module "region2-agents" {
source = "./agents"
aws_region = var.secondary_regions_settings.region2.agent_region
zone_name = var.secondary_regions_settings.region2.agent_region
num_agents = var.secondary_regions_settings.region2.num_agents
agent_instance_type = var.secondary_regions_settings.region2.agent_instance_type
ec2_ami = var.secondary_regions_settings.region2.agent_ec2_ami_id
agent_vpc_cidr = var.secondary_regions_settings.region2.agent_vpc_cidr
agent_hdd_size_gb = var.secondary_regions_settings.region2.agent_hdd_size_gb
swap_size = var.swap_size
aws_domain_name = var.aws_domain_name
project_name = var.project_name
kasm_build = var.kasm_build
manager_token = var.manager_token
aws_key_pair = var.aws_key_pair
ssh_access_cidrs = var.ssh_access_cidrs
providers = {
aws = aws.region2
}
}
#########################################################################
#
# Uncomment the below section and update the provider and the settings
# in the secondary_regions_settings variable in the settings.tfvars
# file for your desired region.
#
#########################################################################
# module "region3-webapps" {
# source = "./webapps"
# ##### Update the values below to reference the appropriate region number
# faux_aws_region = var.secondary_regions_settings.region3.agent_region
# zone_name = var.secondary_regions_settings.region3.agent_region
#
# ##### The values below should not change
# primary_aws_region = var.aws_primary_region
# num_webapps = var.num_webapps
# webapp_instance_type = var.webapp_instance_type
# webapp_hdd_size_gb = var.webapp_hdd_size_gb
# swap_size = var.swap_size
# ec2_ami = var.primary_region_ec2_ami_id
# webapp_subnet_ids = module.primary_region.webapp_subnet_ids
# webapp_security_group_id = module.primary_region.webapp_security_group_id
# load_balancer_security_group_id = module.primary_region.lb_security_group_id
# aws_domain_name = var.aws_domain_name
# project_name = var.project_name
# kasm_build = var.kasm_build
# database_password = var.database_password
# redis_password = var.redis_password
# manager_token = var.manager_token
# aws_key_pair = var.aws_key_pair
# kasm_db_ip = module.primary_region.kasm_db_ip
# primary_vpc_id = module.primary_region.primary_vpc_id
# certificate_arn = module.primary_region.certificate_arn
# ssh_access_cidrs = var.ssh_access_cidrs
# load_balancer_log_bucket = module.primary_region.lb_log_bucket
# }
# module "region3-agents" {
# source = "./agents"
# ##### Update the values below to reference the appropriate region number
# aws_region = var.secondary_regions_settings.region3.agent_region
# zone_name = var.secondary_regions_settings.region3.agent_region
# num_agents = var.secondary_regions_settings.region3.num_agents
# agent_instance_type = var.secondary_regions_settings.region3.agent_instance_type
# ec2_ami = var.secondary_regions_settings.region3.agent_ec2_ami_id
# agent_vpc_cidr = var.secondary_regions_settings.region3.agent_vpc_cidr
# agent_hdd_size_gb = var.secondary_regions_settings.region3.agent_hdd_size_gb
# swap_size = var.swap_size
#
# ##### The values below should not change
# aws_domain_name = var.aws_domain_name
# project_name = var.project_name
# kasm_build = var.kasm_build
# manager_token = var.manager_token
# aws_key_pair = var.aws_key_pair
# ssh_access_cidrs = var.ssh_access_cidrs
#
# ##### Update the provider to reference the settings in the provder.tf file
# providers = {
# aws = aws.region3
# }
# }

View file

@ -0,0 +1,203 @@
<mxfile host="65bd71144e">
<diagram id="evBy-dt-jB8v2-nSfg1o" name="AWS Multi-Region">
<mxGraphModel dx="1551" dy="1272" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1100" pageHeight="850" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="15" value="WebApp Subnet 1&lt;br&gt;10.0.1.0/24" style="points=[[0,0],[0.25,0],[0.5,0],[0.75,0],[1,0],[1,0.25],[1,0.5],[1,0.75],[1,1],[0.75,1],[0.5,1],[0.25,1],[0,1],[0,0.75],[0,0.5],[0,0.25]];outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;container=1;pointerEvents=0;collapsible=0;recursiveResize=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_security_group;grStroke=0;strokeColor=#248814;fillColor=#E9F3E6;verticalAlign=top;align=left;spacingLeft=30;fontColor=#248814;dashed=0;" parent="1" vertex="1">
<mxGeometry x="460" y="189" width="130" height="261" as="geometry"/>
</mxCell>
<mxCell id="50" value="&lt;span style=&quot;color: rgb(0, 0, 0); font-size: 10px;&quot;&gt;US East&lt;br&gt;Webapp-1&lt;/span&gt;" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;" parent="15" vertex="1">
<mxGeometry x="45" y="61" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="70" value="&lt;span style=&quot;color: rgb(0, 0, 0); font-size: 10px;&quot;&gt;US West&lt;br&gt;Webapp-1&lt;/span&gt;" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;" parent="15" vertex="1">
<mxGeometry x="45" y="171" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="2" value="AWS Account" style="points=[[0,0],[0.25,0],[0.5,0],[0.75,0],[1,0],[1,0.25],[1,0.5],[1,0.75],[1,1],[0.75,1],[0.5,1],[0.25,1],[0,1],[0,0.75],[0,0.5],[0,0.25]];outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;container=1;pointerEvents=0;collapsible=0;recursiveResize=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_account;strokeColor=#CD2264;fillColor=none;verticalAlign=top;align=left;spacingLeft=30;fontColor=#CD2264;dashed=0;" parent="1" vertex="1">
<mxGeometry x="180" y="69" width="700" height="1101" as="geometry"/>
</mxCell>
<mxCell id="3" value="Mgmt VPC&lt;br&gt;10.0.0.0/16" style="sketch=0;outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_vpc;strokeColor=#879196;fillColor=none;verticalAlign=top;align=left;spacingLeft=30;fontColor=#879196;dashed=0;" parent="2" vertex="1">
<mxGeometry x="158" y="47" width="502" height="703" as="geometry"/>
</mxCell>
<mxCell id="20" value="Secondary Region - us-west-1" style="points=[[0,0],[0.25,0],[0.5,0],[0.75,0],[1,0],[1,0.25],[1,0.5],[1,0.75],[1,1],[0.75,1],[0.5,1],[0.25,1],[0,1],[0,0.75],[0,0.5],[0,0.25]];outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;container=1;pointerEvents=0;collapsible=0;recursiveResize=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_region;strokeColor=#147EBA;fillColor=none;verticalAlign=top;align=left;spacingLeft=30;fontColor=#147EBA;dashed=1;" parent="2" vertex="1">
<mxGeometry x="120" y="771" width="300" height="320" as="geometry"/>
</mxCell>
<mxCell id="22" value="AZ 1a" style="sketch=0;outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_availability_zone;strokeColor=#545B64;fillColor=none;verticalAlign=top;align=left;spacingLeft=30;fontColor=#545B64;dashed=1;" parent="20" vertex="1">
<mxGeometry x="80" y="101" width="180" height="200" as="geometry"/>
</mxCell>
<mxCell id="21" value="Agent VPC&lt;br&gt;10.1.0.0/16" style="sketch=0;outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_vpc;strokeColor=#879196;fillColor=none;verticalAlign=top;align=left;spacingLeft=30;fontColor=#879196;dashed=0;" parent="20" vertex="1">
<mxGeometry x="15" y="40" width="265" height="270" as="geometry"/>
</mxCell>
<mxCell id="79" value="Agent Security Group" style="fontStyle=0;verticalAlign=top;align=center;spacingTop=-2;fillColor=none;rounded=1;whiteSpace=wrap;html=1;strokeColor=#FF0000;strokeWidth=2;dashed=1;container=1;collapsible=0;expand=0;recursiveResize=0;labelBackgroundColor=none;fontSize=10;fontColor=#000000;arcSize=4;" parent="20" vertex="1">
<mxGeometry x="95" y="130" width="150" height="155" as="geometry"/>
</mxCell>
<mxCell id="23" value="Agent Subnet&lt;br&gt;10.1.0.0/24" style="points=[[0,0],[0.25,0],[0.5,0],[0.75,0],[1,0],[1,0.25],[1,0.5],[1,0.75],[1,1],[0.75,1],[0.5,1],[0.25,1],[0,1],[0,0.75],[0,0.5],[0,0.25]];outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;container=1;pointerEvents=0;collapsible=0;recursiveResize=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_security_group;grStroke=0;strokeColor=#248814;fillColor=#E9F3E6;verticalAlign=top;align=left;spacingLeft=30;fontColor=#248814;dashed=0;" parent="20" vertex="1">
<mxGeometry x="100" y="150" width="140" height="130" as="geometry"/>
</mxCell>
<mxCell id="26" value="Internet&lt;br&gt;Gateway" style="outlineConnect=0;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;shape=mxgraph.aws3.internet_gateway;fillColor=#F58536;gradientColor=none;fontSize=10;" parent="20" vertex="1">
<mxGeometry x="30" y="80" width="38.34" height="40" as="geometry"/>
</mxCell>
<mxCell id="38" value="" style="group" parent="20" vertex="1" connectable="0">
<mxGeometry x="130" y="200" width="70" height="90" as="geometry"/>
</mxCell>
<mxCell id="39" value="" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;" parent="38" vertex="1">
<mxGeometry x="5" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="40" value="" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;" parent="38" vertex="1">
<mxGeometry x="15" y="10" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="41" value="" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;" parent="38" vertex="1">
<mxGeometry x="25" y="20" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="42" value="Kasm Agents" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=10;" parent="38" vertex="1">
<mxGeometry y="60" width="70" height="30" as="geometry"/>
</mxCell>
<mxCell id="89" value="AZ 1a" style="sketch=0;outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_availability_zone;strokeColor=#545B64;fillColor=none;verticalAlign=top;align=left;spacingLeft=30;fontColor=#545B64;dashed=1;" parent="2" vertex="1">
<mxGeometry x="260" y="67" width="160" height="673" as="geometry"/>
</mxCell>
<mxCell id="14" value="AZ 1b" style="sketch=0;outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_availability_zone;strokeColor=#545B64;fillColor=none;verticalAlign=top;align=left;spacingLeft=30;fontColor=#545B64;dashed=1;" parent="2" vertex="1">
<mxGeometry x="450" y="67" width="160" height="333" as="geometry"/>
</mxCell>
<mxCell id="11" value="Primary Region - us-east-1" style="points=[[0,0],[0.25,0],[0.5,0],[0.75,0],[1,0],[1,0.25],[1,0.5],[1,0.75],[1,1],[0.75,1],[0.5,1],[0.25,1],[0,1],[0,0.75],[0,0.5],[0,0.25]];outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;container=0;pointerEvents=0;collapsible=0;recursiveResize=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_region;strokeColor=#147EBA;fillColor=none;verticalAlign=top;align=left;spacingLeft=30;fontColor=#147EBA;dashed=1;" parent="2" vertex="1">
<mxGeometry x="120" y="20" width="560" height="740" as="geometry"/>
</mxCell>
<mxCell id="9" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=1;exitY=0.75;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;fillColor=#ffe6cc;strokeColor=#994C00;strokeWidth=3;" parent="2" source="4" target="6" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="10" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=1;exitY=0.25;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;fillColor=#ffe6cc;strokeColor=#d79b00;strokeWidth=3;" parent="2" source="4" target="5" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="4" value="Route53 Latency&lt;br style=&quot;font-size: 10px;&quot;&gt;based DNS" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#945DF2;gradientDirection=north;fillColor=#5A30B5;strokeColor=#ffffff;dashed=0;verticalLabelPosition=top;verticalAlign=bottom;align=center;html=1;fontSize=10;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.route_53;labelPosition=center;" parent="2" vertex="1">
<mxGeometry x="29" y="240" width="50" height="50" as="geometry"/>
</mxCell>
<mxCell id="109" style="edgeStyle=orthogonalEdgeStyle;jumpStyle=arc;jumpSize=12;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeColor=#d6b656;strokeWidth=3;fontSize=10;fontColor=#000000;fillColor=#fff2cc;" parent="2" source="5" target="108" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="5" value="us-east-1&lt;br style=&quot;font-size: 10px;&quot;&gt;Load Balancer" style="outlineConnect=0;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;shape=mxgraph.aws3.application_load_balancer;fillColor=#F58534;gradientColor=none;fontSize=10;" parent="2" vertex="1">
<mxGeometry x="182" y="195" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="111" style="edgeStyle=orthogonalEdgeStyle;jumpStyle=arc;jumpSize=12;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeColor=#994C00;strokeWidth=3;fontSize=10;fontColor=#000000;" parent="2" source="6" target="110" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="6" value="us-west-1&lt;br&gt;Load Balancer" style="outlineConnect=0;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;shape=mxgraph.aws3.application_load_balancer;fillColor=#F58534;gradientColor=none;fontSize=10;" parent="2" vertex="1">
<mxGeometry x="182" y="307" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="76" value="Webapp Security&amp;nbsp; Group" style="fontStyle=0;verticalAlign=top;align=center;spacingTop=-2;fillColor=none;rounded=1;whiteSpace=wrap;html=1;strokeColor=#FF0000;strokeWidth=2;dashed=1;container=1;collapsible=0;expand=0;recursiveResize=0;labelBackgroundColor=none;fontSize=10;fontColor=#000000;arcSize=3;" parent="2" vertex="1">
<mxGeometry x="270" y="100" width="330" height="290" as="geometry"/>
</mxCell>
<mxCell id="16" value="WebApp Subnet 2&lt;br&gt;10.0.2.0/24" style="points=[[0,0],[0.25,0],[0.5,0],[0.75,0],[1,0],[1,0.25],[1,0.5],[1,0.75],[1,1],[0.75,1],[0.5,1],[0.25,1],[0,1],[0,0.75],[0,0.5],[0,0.25]];outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;container=1;pointerEvents=0;collapsible=0;recursiveResize=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_security_group;grStroke=0;strokeColor=#248814;fillColor=#E9F3E6;verticalAlign=top;align=left;spacingLeft=30;fontColor=#248814;dashed=0;" parent="76" vertex="1">
<mxGeometry x="190" y="20" width="130" height="260" as="geometry"/>
</mxCell>
<mxCell id="110" value="" style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fontSize=10;fillColor=none;strokeColor=#994C00;strokeWidth=2;dashed=1;arcSize=6;" parent="76" vertex="1">
<mxGeometry x="20" y="182" width="290" height="90" as="geometry"/>
</mxCell>
<mxCell id="72" value="&lt;span style=&quot;color: rgb(0, 0, 0); font-size: 10px;&quot;&gt;US West&lt;br&gt;Webapp-2&lt;/span&gt;" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;" parent="2" vertex="1">
<mxGeometry x="510" y="290" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="71" value="&lt;span style=&quot;color: rgb(0, 0, 0); font-size: 10px;&quot;&gt;US East&lt;br&gt;Webapp-2&lt;/span&gt;" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;" parent="2" vertex="1">
<mxGeometry x="510" y="180" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="121" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;fillColor=#e1d5e7;strokeColor=#9673a6;strokeWidth=3;" edge="1" parent="2" source="108" target="90">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="640" y="215"/>
<mxPoint x="640" y="478"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="108" value="" style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fontSize=10;fillColor=none;strokeColor=#d6b656;strokeWidth=2;dashed=1;arcSize=6;" parent="2" vertex="1">
<mxGeometry x="290" y="170" width="290" height="90" as="geometry"/>
</mxCell>
<mxCell id="98" value="DB Subnet 1&lt;br&gt;10.0.0.0/24" style="points=[[0,0],[0.25,0],[0.5,0],[0.75,0],[1,0],[1,0.25],[1,0.5],[1,0.75],[1,1],[0.75,1],[0.5,1],[0.25,1],[0,1],[0,0.75],[0,0.5],[0,0.25]];outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;container=1;pointerEvents=0;collapsible=0;recursiveResize=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_security_group;grStroke=0;strokeColor=#248814;fillColor=#E9F3E6;verticalAlign=top;align=left;spacingLeft=30;fontColor=#248814;dashed=0;" parent="2" vertex="1">
<mxGeometry x="267.5" y="418" width="145" height="135" as="geometry"/>
</mxCell>
<mxCell id="120" value="Kasm Database&lt;br&gt;Kasm Redis" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;" parent="98" vertex="1">
<mxGeometry x="50" y="49" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="123" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;strokeWidth=3;fillColor=#d5e8d4;strokeColor=#82b366;" edge="1" parent="2" source="91" target="4">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="128" value="Agent to Management&lt;br&gt;WebApp traffic" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="123">
<mxGeometry x="-0.7263" y="-2" relative="1" as="geometry">
<mxPoint x="-52" y="2" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="91" value="Agent Security Group" style="fontStyle=0;verticalAlign=top;align=center;spacingTop=-2;fillColor=none;rounded=1;whiteSpace=wrap;html=1;strokeColor=#FF0000;strokeWidth=2;dashed=1;container=1;collapsible=0;expand=0;recursiveResize=0;labelBackgroundColor=none;fontSize=10;fontColor=#000000;arcSize=2;" parent="2" vertex="1">
<mxGeometry x="265" y="567" width="150" height="152" as="geometry"/>
</mxCell>
<mxCell id="92" value="Agent Subnet 1&lt;br&gt;10.0.3.0/24" style="points=[[0,0],[0.25,0],[0.5,0],[0.75,0],[1,0],[1,0.25],[1,0.5],[1,0.75],[1,1],[0.75,1],[0.5,1],[0.25,1],[0,1],[0,0.75],[0,0.5],[0,0.25]];outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;container=1;pointerEvents=0;collapsible=0;recursiveResize=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_security_group;grStroke=0;strokeColor=#248814;fillColor=#E9F3E6;verticalAlign=top;align=left;spacingLeft=30;fontColor=#248814;dashed=0;" parent="2" vertex="1">
<mxGeometry x="270" y="586" width="140" height="130" as="geometry"/>
</mxCell>
<mxCell id="93" value="" style="group" parent="92" vertex="1" connectable="0">
<mxGeometry x="35" y="40" width="70" height="90" as="geometry"/>
</mxCell>
<mxCell id="94" value="" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;" parent="93" vertex="1">
<mxGeometry x="5" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="95" value="" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;" parent="93" vertex="1">
<mxGeometry x="15" y="10" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="96" value="" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;" parent="93" vertex="1">
<mxGeometry x="25" y="20" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="97" value="Kasm Agents" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=10;" parent="93" vertex="1">
<mxGeometry y="60" width="70" height="30" as="geometry"/>
</mxCell>
<mxCell id="25" value="Internet&lt;br&gt;Gateway" style="outlineConnect=0;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;shape=mxgraph.aws3.internet_gateway;fillColor=#F58536;gradientColor=none;fontSize=10;" parent="2" vertex="1">
<mxGeometry x="172" y="93" width="28.76" height="30" as="geometry"/>
</mxCell>
<mxCell id="90" value="Database Security Group" style="fontStyle=0;verticalAlign=top;align=center;spacingTop=-2;fillColor=none;rounded=1;whiteSpace=wrap;html=1;strokeColor=#FF0000;strokeWidth=2;dashed=1;container=1;collapsible=0;expand=0;recursiveResize=0;labelBackgroundColor=none;fontSize=10;fontColor=#000000;arcSize=4;" parent="2" vertex="1">
<mxGeometry x="265" y="400" width="150" height="155" as="geometry"/>
</mxCell>
<mxCell id="122" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=3;fillColor=#e1d5e7;strokeColor=#9673a6;" edge="1" parent="2" source="110" target="90">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="640" y="327"/>
<mxPoint x="640" y="478"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="124" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;entryPerimeter=0;strokeWidth=3;fillColor=#d5e8d4;strokeColor=#82b366;" edge="1" parent="2" source="79" target="4">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="129" value="Agent to Management&lt;br&gt;WebApp traffic" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="124">
<mxGeometry x="-0.7506" relative="1" as="geometry">
<mxPoint x="20" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="102" value="Load Balancer&lt;br style=&quot;font-size: 10px;&quot;&gt;Access Logs S3" style="sketch=0;outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#3F8624;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=10;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.bucket;labelBackgroundColor=none;" parent="2" vertex="1">
<mxGeometry x="595" y="674" width="32.68" height="34" as="geometry"/>
</mxCell>
<mxCell id="44" value="Management/User&lt;br&gt;Access Traffic" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=1;exitY=0.71;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;fontSize=10;strokeWidth=3;" parent="1" source="12" target="4" edge="1">
<mxGeometry x="-0.1867" y="17" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="81" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=0.67;exitY=1;exitDx=0;exitDy=0;exitPerimeter=0;fontSize=10;fontColor=#000000;fillColor=#dae8fc;strokeColor=#6c8ebf;strokeWidth=3;entryX=0;entryY=0.75;entryDx=0;entryDy=0;" parent="1" source="12" target="79" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="150" y="920" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="127" value="Kasm User&lt;br&gt;SessionTraffic" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="81">
<mxGeometry x="0.509" y="5" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="125" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=0.67;exitY=1;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;strokeWidth=3;fillColor=#dae8fc;strokeColor=#6c8ebf;jumpStyle=arc;jumpSize=12;" edge="1" parent="1" source="12" target="91">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="126" value="Kasm User&lt;br&gt;Session Traffic" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="125">
<mxGeometry x="0.2017" y="-5" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="12" value="&lt;font style=&quot;font-size: 10px;&quot;&gt;https://kasm.contoso.com&lt;/font&gt;" style="points=[[0.35,0,0],[0.98,0.51,0],[1,0.71,0],[0.67,1,0],[0,0.795,0],[0,0.65,0]];verticalLabelPosition=top;sketch=0;html=1;verticalAlign=bottom;aspect=fixed;align=center;pointerEvents=1;shape=mxgraph.cisco19.user;fillColor=#005073;strokeColor=none;fontColor=#005073;labelPosition=center;" parent="1" vertex="1">
<mxGeometry x="39" y="284" width="70" height="70" as="geometry"/>
</mxCell>
<mxCell id="119" value="&lt;u style=&quot;font-size: 16px;&quot;&gt;AWS Multi-Region Terraform Deployment&lt;/u&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;dashed=1;labelBackgroundColor=none;strokeWidth=2;fontSize=16;fontColor=#000000;" parent="1" vertex="1">
<mxGeometry x="390" y="20" width="320" height="30" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

View file

@ -0,0 +1,3 @@
data "aws_availability_zones" "available" {
state = "available"
}

View file

@ -1,12 +1,12 @@
data "aws_route53_zone" "kasm-route53-zone" {
name = "${var.aws_domain_name}"
name = var.aws_domain_name
private_zone = false
}
resource "aws_acm_certificate" "kasm-alb-cert" {
domain_name = "${var.aws_domain_name}"
domain_name = var.aws_domain_name
subject_alternative_names = ["*.${var.aws_domain_name}"]
validation_method = "DNS"
validation_method = "DNS"
lifecycle {
@ -15,8 +15,8 @@ resource "aws_acm_certificate" "kasm-alb-cert" {
}
resource "aws_route53_record" "kasm-route53-cert-validation-record" {
for_each = {
for dvo in aws_acm_certificate.kasm-alb-cert.domain_validation_options: dvo.domain_name => {
for_each = {
for dvo in aws_acm_certificate.kasm-alb-cert.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
@ -27,16 +27,12 @@ resource "aws_route53_record" "kasm-route53-cert-validation-record" {
records = [each.value.record]
zone_id = data.aws_route53_zone.kasm-route53-zone.id
ttl = 30
ttl = 30
allow_overwrite = true
}
resource "aws_acm_certificate_validation" "kasm-elb-certificate-validation" {
certificate_arn = aws_acm_certificate.kasm-alb-cert.arn
validation_record_fqdns = [for record in aws_route53_record.kasm-route53-cert-validation-record: record.fqdn]
validation_record_fqdns = [for record in aws_route53_record.kasm-route53-cert-validation-record : record.fqdn]
}
output "certificate_arn" {
value = "${aws_acm_certificate_validation.kasm-elb-certificate-validation.certificate_arn}"
}

View file

@ -1,33 +1,31 @@
resource "aws_instance" "kasm-db" {
ami = "${var.ec2_ami}"
instance_type = "${var.db_instance_type}"
vpc_security_group_ids = ["${aws_security_group.kasm-default-sg.id}"]
subnet_id = "${aws_subnet.kasm-database-subnet.id}"
key_name = "${var.aws_key_pair}"
ami = var.ec2_ami
instance_type = var.db_instance_type
vpc_security_group_ids = [data.aws_security_group.data-kasm_db_sg.id]
subnet_id = data.aws_subnet.data-kasm_db_subnet.id
key_name = var.aws_key_pair
root_block_device {
volume_size = "40"
volume_size = var.db_hdd_size_gb
}
user_data = <<-EOF
#!/bin/bash
fallocate -l 4g /mnt/kasm.swap
chmod 600 /mnt/kasmswap
mkswap /mnt/kasm.swap
swapon /mnt/kasm.swap
echo '/mnt/kasm.swap swap swap defaults 0 0' | tee -a /etc/fstab
cd /tmp
wget ${var.kasm_build}
tar xvf kasm_*.tar.gz
bash kasm_release/install.sh -S db -e -Q ${var.database_password} -R ${var.redis_password} -U ${var.user_password} -P ${var.admin_password} -M ${var.manager_token}
EOF
user_data = templatefile("${path.module}/../userdata/db_bootstrap.sh",
{
kasm_build_url = var.kasm_build
user_password = var.user_password
admin_password = var.admin_password
redis_password = var.redis_password
database_password = var.database_password
manager_token = var.manager_token
swap_size = var.swap_size
}
)
tags = {
Name = "${var.project_name}-kasm-db"
}
}
output "kasm_db_ip" {
value = "${aws_instance.kasm-db.private_ip}"
data "aws_instance" "data-kasm_db" {
instance_id = aws_instance.kasm-db.id
}

View file

@ -0,0 +1,56 @@
data "aws_elb_service_account" "main" {}
resource "aws_s3_bucket" "kasm_s3_logs" {
bucket_prefix = "${var.project_name}-${var.zone_name}-"
force_destroy = true
}
data "aws_s3_bucket" "data-kasm_s3_logs_bucket" {
bucket = aws_s3_bucket.kasm_s3_logs.bucket
}
resource "aws_s3_bucket_acl" "kasm_s3_acl" {
bucket = data.aws_s3_bucket.data-kasm_s3_logs_bucket.id
acl = "private"
}
resource "aws_s3_bucket_policy" "kasm_s3_logs_policy" {
bucket = data.aws_s3_bucket.data-kasm_s3_logs_bucket.id
policy = jsonencode({
Id = "Policy"
Version = "2012-10-17"
Statement = [
{
Action = [
"s3:PutObject"
]
Effect = "Allow"
Resource = "${aws_s3_bucket.kasm_s3_logs.arn}/AWSLogs/*"
Principal = {
AWS = [
data.aws_elb_service_account.main.arn
]
}
}
]
})
}
resource "aws_s3_bucket_server_side_encryption_configuration" "encrypt_elb_bucket" {
bucket = data.aws_s3_bucket.data-kasm_s3_logs_bucket.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
resource "aws_s3_bucket_public_access_block" "s3_log_public_access" {
bucket = data.aws_s3_bucket.data-kasm_s3_logs_bucket.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}

View file

@ -1,14 +0,0 @@
provider "aws" {
region = "${var.aws_region}"
access_key = "${var.aws_access_key}"
secret_key = "${var.aws_secret_key}"
}
data "aws_availability_zones" "available" {
state = "available"
}
output "primary_aws_region" {
value = "${var.aws_region}"
}

View file

@ -0,0 +1,35 @@
output "certificate_arn" {
value = aws_acm_certificate_validation.kasm-elb-certificate-validation.certificate_arn
}
output "webapp_subnet_ids" {
value = data.aws_subnet.data-kasm_webapp_subnets[*].id
}
output "agent_subnet_id" {
value = data.aws_subnet.data-kasm_agent_subnet.id
}
output "kasm_db_ip" {
value = data.aws_instance.data-kasm_db.private_ip
}
output "primary_vpc_id" {
value = data.aws_vpc.data-kasm-default-vpc.id
}
output "lb_log_bucket" {
value = data.aws_s3_bucket.data-kasm_s3_logs_bucket.bucket
}
output "lb_security_group_id" {
value = data.aws_security_group.data-kasm_default_elb_sg.id
}
output "webapp_security_group_id" {
value = data.aws_security_group.data-kasm_webapp_sg.id
}
output "agent_security_group_id" {
value = data.aws_security_group.data-kasm_agent_sg.id
}

View file

@ -0,0 +1,8 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
#version = "4.56.0"
}
}
}

View file

@ -0,0 +1,32 @@
resource "aws_route_table" "internet_access" {
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
route {
cidr_block = var.anywhere
gateway_id = data.aws_internet_gateway.data-kasm_default_ig.id
}
tags = {
Name = "${var.project_name}-kasm-default-route"
}
}
data "aws_route_table" "data-internet_gateway_route_table" {
route_table_id = aws_route_table.internet_access.id
}
resource "aws_route_table_association" "webapp_route_association" {
count = var.num_webapps
subnet_id = data.aws_subnet.data-kasm_webapp_subnets[count.index].id
route_table_id = data.aws_route_table.data-internet_gateway_route_table.id
}
resource "aws_route_table_association" "db_route_association" {
subnet_id = data.aws_subnet.data-kasm_db_subnet.id
route_table_id = data.aws_route_table.data-internet_gateway_route_table.id
}
resource "aws_route_table_association" "agent_table_association" {
subnet_id = data.aws_subnet.data-kasm_agent_subnet.id
route_table_id = data.aws_route_table.data-internet_gateway_route_table.id
}

View file

@ -1,37 +1,145 @@
resource "aws_security_group" "kasm-default-sg" {
name = "${var.project_name}-kasm-allow-db-access"
description = "Allow access to db"
vpc_id = "${aws_vpc.kasm-default-vpc.id}"
resource "aws_security_group" "kasm-default-elb-sg" {
name = "${var.project_name}-${var.zone_name}-kasm-allow-elb-access"
description = "Security Group for ELB"
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
ingress {
from_port = 22
to_port = 22
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["${var.ssh_access_cidr}"]
cidr_blocks = var.web_access_cidrs
}
ingress {
from_port = 5432
to_port = 5432
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = [aws_subnet.kasm-webapp-subnet-1.cidr_block, aws_subnet.kasm-webapp-subnet-2.cidr_block]
}
ingress {
from_port = 6379
to_port = 6379
protocol = "tcp"
cidr_blocks = [aws_subnet.kasm-webapp-subnet-1.cidr_block, aws_subnet.kasm-webapp-subnet-2.cidr_block]
cidr_blocks = var.web_access_cidrs
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
cidr_blocks = [var.anywhere]
}
tags = {
Name = "${var.project_name}-${var.zone_name}-kasm-allow-access"
}
}
data "aws_security_group" "data-kasm_default_elb_sg" {
id = aws_security_group.kasm-default-elb-sg.id
}
resource "aws_security_group" "kasm-db-sg" {
name = "${var.project_name}-kasm-allow-db-access"
description = "Allow access to db"
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = var.ssh_access_cidrs
}
ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
cidr_blocks = data.aws_subnet.data-kasm_webapp_subnets[*].id
}
ingress {
from_port = 6379
to_port = 6379
protocol = "tcp"
cidr_blocks = data.aws_subnet.data-kasm_webapp_subnets[*].id
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = [var.anywhere]
}
tags = {
Name = "${var.project_name}-kasm-allow-db-access"
}
}
data "aws_security_group" "data-kasm_db_sg" {
id = aws_security_group.kasm-db-sg.id
}
resource "aws_security_group" "kasm-webapp-sg" {
name = "${var.project_name}-${var.zone_name}-kasm-webapp-access"
description = "Allow access to webapps"
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = var.ssh_access_cidrs
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
security_groups = [data.aws_security_group.data-kasm_db_sg.id]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
security_groups = [data.aws_security_group.data-kasm_agent_sg.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = [var.anywhere]
}
}
data "aws_security_group" "data-kasm_webapp_sg" {
id = aws_security_group.kasm-webapp-sg.id
}
resource "aws_security_group" "kasm-agent-sg" {
name = "${var.project_name}-${var.zone_name}-kasm-agent-access"
description = "Allow access to agents"
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = var.ssh_access_cidrs
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = [var.anywhere]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = [var.anywhere]
}
}
data "aws_security_group" "data-kasm_agent_sg" {
id = aws_security_group.kasm-agent-sg.id
}

View file

@ -1,54 +1,51 @@
resource "aws_subnet" "kasm-database-subnet" {
vpc_id = "${aws_vpc.kasm-default-vpc.id}"
cidr_block = "10.0.0.0/24"
locals {
kasm_vpc_subnet_cidr_mask = split("/", var.vpc_subnet_cidr)[1]
kasm_server_subnet_cidr_calculation = (8 - (local.kasm_vpc_subnet_cidr_mask - 16))
kasm_server_subnet_cidr_size = local.kasm_server_subnet_cidr_calculation < 2 ? 2 : local.kasm_server_subnet_cidr_calculation
kasm_agent_subnet_id = (var.num_webapps + 1)
}
## Will create Agent subnet x.x.0.0/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/22)
resource "aws_subnet" "kasm-db-subnet" {
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, 0)
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-kasm-subnet"
Name = "${var.project_name}-kasm-db-subnet"
}
}
resource "aws_subnet" "kasm-webapp-subnet-1" {
vpc_id = "${aws_vpc.kasm-default-vpc.id}"
cidr_block = "10.0.20.0/24"
availability_zone = data.aws_availability_zones.available.names[2]
data "aws_subnet" "data-kasm_db_subnet" {
id = aws_subnet.kasm-db-subnet.id
}
## Will create WebApp subnets x.x.1.0/24 and x.x.2.0/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/22 and 2 webapps)
resource "aws_subnet" "kasm-webapp-subnets" {
count = var.num_webapps
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, (count.index + 1))
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-kasm-webapp-subnet-1"
Name = "${var.project_name}-kasm-webapp-subnet"
}
}
resource "aws_subnet" "kasm-webapp-subnet-2" {
vpc_id = "${aws_vpc.kasm-default-vpc.id}"
cidr_block = "10.0.30.0/24"
availability_zone = data.aws_availability_zones.available.names[1]
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-kasm-webapp-subnet-2"
}
data "aws_subnet" "data-kasm_webapp_subnets" {
count = var.num_webapps
id = aws_subnet.kasm-webapp-subnets[count.index].id
}
## Will create Agent subnet x.x.3.0/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/22)
resource "aws_subnet" "kasm-agent-subnet" {
vpc_id = "${aws_vpc.kasm-default-vpc.id}"
cidr_block = "10.0.40.0/24"
availability_zone = data.aws_availability_zones.available.names[1]
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, local.kasm_agent_subnet_id)
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-kasm-webapp-subnet-2"
Name = "${var.project_name}-agent-natgw-subnet"
}
}
output "webapp_subnet_1_id" {
value = "${aws_subnet.kasm-webapp-subnet-1.id}"
data "aws_subnet" "data-kasm_agent_subnet" {
id = aws_subnet.kasm-agent-subnet.id
}
output "webapp_subnet_2_id" {
value = "${aws_subnet.kasm-webapp-subnet-2.id}"
}
output "agent_subnet_id" {
value = "${aws_subnet.kasm-agent-subnet.id}"
}

View file

@ -1,82 +1,113 @@
variable "aws_region" {
description = "The AWS region for the deployment. (e.g us-east-1)"
type = string
}
variable "aws_access_key" {
description = "The AWS access key used for deployment"
}
variable "aws_secret_key" {
description = "The AWS secret key used for deployment"
}
variable "project_name" {
description = "The name of the deployment (e.g dev, staging). A short single word"
type = string
}
variable "vpc_subnet_cidr" {
description = "The subnet CIDR to use for the Primary VPC"
type = string
}
variable "aws_domain_name" {
description = "The Route53 Zone used for the dns entries. This must already exist in the AWS account. (e.g dev.kasm.contoso.com). The deployment will be accessed via this zone name via https"
type = string
}
variable "db_hdd_size_gb" {
description = "The HDD size in GB to configure for the Kasm Database instances"
type = number
}
variable "db_instance_type" {
description = "The instance type for the Database"
type = string
default = "t3.small"
}
variable "swap_size" {
description = "The amount of swap (in MB) to configure inside the compute instances"
type = number
}
variable "kasm_build" {
description = "The URL for the Kasm Workspaces build"
type = string
}
variable "database_password" {
description = "The password for the database. No special characters"
type = string
sensitive = true
}
variable "redis_password" {
description = "The password for the database. No special characters"
description = "The password for the Redis server. No special characters"
type = string
sensitive = true
}
variable "user_password" {
description = "The password for the database. No special characters"
description = "The standard (non administrator) user password. No special characters"
type = string
sensitive = true
}
variable "admin_password" {
description = "The password for the database. No special characters"
description = "The administrative user password. No special characters"
type = string
sensitive = true
}
variable "manager_token" {
description = "The password for the database. No special characters"
description = "The manager token value for Agents to authenticate to webapps. No special characters"
type = string
sensitive = true
}
variable "service_registration_token" {
description = "The guac token value for Guac RDP servers to authenticate to webapps. No special characters"
type = string
sensitive = true
}
variable "zone_name" {
default = "default"
description="A name given to the kasm deployment Zone"
description = "A name given to the kasm deployment Zone"
type = string
default = "default"
}
variable "aws_key_pair" {
description = "The name of an aws keypair to use."
}
variable "db_instance_type" {
default = "t3.small"
description = "The instance type for the Database"
type = string
}
variable "ec2_ami" {
description = "The AMI used for the EC2 nodes. Recommended Ubuntu 18.04 LTS."
description = "The AMI used for the EC2 nodes. Recommended Ubuntu 20.04 LTS."
type = string
}
variable "ssh_access_cidr" {
variable "ssh_access_cidrs" {
description = "CIDR notation of the bastion host allowed to SSH in to the machines"
type = list(string)
}
variable "num_agents" {
default = "2"
description = "The number of Agent Role Servers to create in the deployment"
variable "web_access_cidrs" {
description = "List of Networks in CIDR notation for IPs allowed to access the Kasm Web interface"
type = list(string)
}
variable "num_webapps" {
description = "The number of WebApp role servers to create in the deployment"
type = number
}
variable "agent_instance_type" {
default = "t3.medium"
}
variable "webapp_instance_type" {
default = "t3.small"
description = "The instance type for the webapps"
variable "anywhere" {
description = "Anywhere subnet for routing and load ingress from all IPs"
type = string
default = "0.0.0.0/0"
}

View file

@ -1,25 +1,23 @@
resource "aws_vpc" "kasm-default-vpc" {
cidr_block = "10.0.0.0/16"
cidr_block = var.vpc_subnet_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.project_name}-kasm-db-vpc"
}
}
data "aws_vpc" "data-kasm-default-vpc" {
id = aws_vpc.kasm-default-vpc.id
}
resource "aws_internet_gateway" "kasm-default-ig" {
vpc_id = "${aws_vpc.kasm-default-vpc.id}"
vpc_id = aws_vpc.kasm-default-vpc.id
tags = {
Name = "${var.project_name}-kasm-ig"
}
}
resource "aws_route" "internet_access" {
route_table_id = "${aws_vpc.kasm-default-vpc.main_route_table_id}"
destination_cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.kasm-default-ig.id}"
data "aws_internet_gateway" "data-kasm_default_ig" {
internet_gateway_id = aws_internet_gateway.kasm-default-ig.id
}
output "primary_vpc_id" {
value = "${aws_vpc.kasm-default-vpc.id}"
}

View file

@ -1,27 +0,0 @@
module "primary-webapps" {
source = "../webapps"
primary_aws_region = "${var.aws_region}"
faux_aws_region = "${var.aws_region}"
zone_name = "${var.zone_name}"
num_agents = "${var.num_agents}"
agent_instance_type = "${var.agent_instance_type}"
num_webapps = "${var.num_webapps}"
webapp_instance_type = "${var.webapp_instance_type}"
ec2_ami = "${var.ec2_ami}"
webapp_subnet_id_1 = "${aws_subnet.kasm-webapp-subnet-1.id}"
webapp_subnet_id_2 = "${aws_subnet.kasm-webapp-subnet-2.id}"
agent_subnet_id = "${aws_subnet.kasm-agent-subnet.id}"
aws_access_key = "${var.aws_access_key}"
aws_secret_key = "${var.aws_secret_key}"
aws_domain_name = "${var.aws_domain_name}"
project_name = "${var.project_name}"
kasm_build = "${var.kasm_build}"
database_password = "${var.database_password}"
redis_password = "${var.redis_password}"
manager_token = "${var.manager_token}"
aws_key_pair = "${var.aws_key_pair}"
kasm_db_ip = "${aws_instance.kasm-db.private_ip}"
primary_vpc_id = "${aws_vpc.kasm-default-vpc.id}"
certificate_arn = "${aws_acm_certificate_validation.kasm-elb-certificate-validation.certificate_arn}"
ssh_access_cidr = "${var.ssh_access_cidr}"
}

View file

@ -0,0 +1,49 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
#version = "4.56.0"
}
}
}
provider "aws" {
access_key = var.aws_access_key
secret_key = var.aws_secret_key
region = var.aws_primary_region
default_tags {
tags = var.aws_default_tags
}
}
provider "aws" {
access_key = var.aws_access_key
secret_key = var.aws_secret_key
region = var.secondary_regions_settings.region2.agent_region
alias = "region2"
default_tags {
tags = var.aws_default_tags
}
}
##############################################################################
###
### Uncomment the below provider section if you want to deploy a 3rd region.
###
### Copy/paste the provider below to deploy additional regions, then refer
### to the README.md, the deployment.tf file, and the settings.tfvars file for
### code blocks to copy/paste/configure to deploy the new regions.
###
##############################################################################
# provider "aws" {
# access_key = var.aws_access_key
# secret_key = var.aws_secret_key
# region = var.secondary_regions_settings.region3.agent_region
# alias = "region3"
# default_tags {
# tags = var.aws_default_tags
# }
# }

View file

@ -0,0 +1,62 @@
aws_domain_name = "kasm.contoso.com"
project_name = "contoso"
aws_key_pair = ""
aws_primary_region = "us-east-1"
primary_vpc_subnet_cidr = "10.0.0.0/16"
database_password = "changeme"
redis_password = "changeme"
user_password = "changeme"
admin_password = "changeme"
manager_token = "changeme"
kasm_build = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.12.0.d4fd8a.tar.gz"
ssh_access_cidrs = ["0.0.0.0/0"]
web_access_cidrs = ["0.0.0.0/0"]
swap_size = 2048
primary_region_ec2_ami_id = "ami-09cd747c78a9add63"
webapp_instance_type = "t3.small"
db_instance_type = "t3.small"
agent_instance_type = "t3.medium"
webapp_hdd_size_gb = 40
db_hdd_size_gb = 40
agent_hdd_size_gb = 40
## Settings for all additional Agent regions
secondary_regions_settings = {
region2 = {
agent_region = "us-west-1"
agent_ec2_ami_id = "ami-0d221cb540e0015f4"
agent_instance_type = "t3.medium"
agent_hdd_size_gb = 120
num_agents = 2
agent_vpc_cidr = "10.1.0.0/16"
}
#######################################################################
###
### Uncomment and update the settings below for an third region.
### Copy/paste the settings below (changing the region number) for any
### additional regions.
###
### Make sure to add a provider section for each additional region in
### the providers.tf file.
###
#######################################################################
# region3 = {
# agent_region = "eu-central-1"
# agent_ec2_ami_id = "ami-0e067cc8a2b58de59"
# agent_instance_type = "t3.medium"
# num_agents = 2
# agent_vpc_cidr = "10.2.0.0/16"
# }
}
## Default tags for all AWS resources
aws_default_tags = {
Deployed_by = "Terraform"
Deployment_type = "Multi-Region"
Service_name = "Kasm Workspaces"
Kasm_version = "1.12"
}

View file

@ -0,0 +1,29 @@
#!/bin/bash
set -ex
echo "Starting Kasm Workspaces Agent Install"
/bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=${swap_size}
/sbin/mkswap /var/swap.1
chmod 600 /var/swap.1
/sbin/swapon /var/swap.1
echo '/var/swap.1 swap swap defaults 0 0' | tee -a /etc/fstab
cd /tmp
PRIVATE_IP=(`hostname -I | cut -d' ' -f1 | tr -d '\\n'`)
wget ${kasm_build_url} -O kasm_workspaces.tar.gz
tar -xf kasm_workspaces.tar.gz
echo "Waiting for Kasm WebApp availability..."
while ! (curl -k https://${manager_address}/api/__healthcheck 2>/dev/null | grep -q true)
do
echo "Waiting for API server..."
sleep 5
done
echo "WebApp is alive"
bash kasm_release/install.sh -S agent -e -p $PRIVATE_IP -m ${manager_address} -M ${manager_token}
echo "Done"

View file

@ -0,0 +1,20 @@
#!/bin/bash
set -ex
echo "Starting Kasm Workspaces Install"
/bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=${swap_size}
/sbin/mkswap /var/swap.1
chmod 600 /var/swap.1
/sbin/swapon /var/swap.1
echo '/var/swap.1 swap swap defaults 0 0' | tee -a /etc/fstab
cd /tmp
PRIVATE_IP=(`hostname -I | cut -d ' ' -f1 | tr -d '\\n'`)
wget ${kasm_build_url} -O kasm_workspaces.tar.gz
tar -xf kasm_workspaces.tar.gz
bash kasm_release/install.sh -S db -e -Q ${database_password} -R ${redis_password} -U ${user_password} -P ${admin_password} -M ${manager_token}
echo "Done"

View file

@ -0,0 +1,36 @@
#!/bin/bash
set -ex
echo "Starting Kasm Workspaces Install"
/bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=${swap_size}
/sbin/mkswap /var/swap.1
chmod 600 /var/swap.1
/sbin/swapon /var/swap.1
echo '/var/swap.1 swap swap defaults 0 0' | tee -a /etc/fstab
cd /tmp
PRIVATE_IP=(`hostname -I | cut -d ' ' -f1 | tr -d '\\n'`)
wget ${kasm_build_url} -O kasm_workspaces.tar.gz
tar -xf kasm_workspaces.tar.gz
echo "Checking for Kasm DB and Redis..."
apt-get update && apt-get install -y netcat
while ! nc -w 1 -z ${db_ip} 5432; do
echo "Database not ready..."
sleep 5
done
echo "DB is alive"
while ! nc -w 1 -z ${db_ip} 6379; do
echo "Redis not ready..."
sleep 5
done
echo "Redis is alive"
bash kasm_release/install.sh -S app -e -z ${zone_name} -q "${db_ip}" -Q ${database_password} -R ${redis_password}
echo "Done"

View file

@ -1,47 +1,297 @@
variable "aws_domain_name" {
default = "kasm.contoso.com"
}
variable "project_name" {
default = "contoso"
}
variable "aws_key_pair" {
default = ""
}
variable "aws_access_key" {
default = ""
description = "The AWS access key used for deployment"
type = string
sensitive = true
validation {
condition = can(regex("^([A-Z0-9]{20})", var.aws_access_key))
error_message = "The aws_access_key variable must be a valid AWS Access Key (e.g. AKIAJSIE27KKMHXI3BJQ)."
}
}
variable "aws_secret_key" {
default = ""
description = "The AWS secret key used for deployment"
type = string
sensitive = true
validation {
condition = can(regex("^([a-zA-Z0-9+\\/-]{40})", var.aws_secret_key))
error_message = "The aws_secret_key variable must be a valid AWS Secret Key value (e.g. wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY)"
}
}
variable "aws_key_pair" {
description = "The name of an aws keypair to use."
type = string
validation {
condition = can(regex("^[a-zA-Z0-9-_]{4,15}", var.aws_key_pair))
error_message = "The aws_key_pair variable contains invalid characters. Allowed values are between 4-15 characters consisting of letters, numbers, and dashes (-)."
}
}
variable "project_name" {
description = "The name of the deployment (e.g dev, staging). A short single word"
type = string
validation {
condition = can(regex("^[a-z]{4,15}", var.project_name))
error_message = "The project_name variable can only be one word between 4 and 15 lower-case letters since it is a seed value in multiple object names."
}
}
variable "aws_domain_name" {
description = "The Route53 Zone used for the dns entries. This must already exist in the AWS account. (e.g dev.kasm.contoso.com). The deployment will be accessed via this zone name via https"
type = string
validation {
condition = can(regex("(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]", var.aws_domain_name))
error_message = "There are invalid characters in the aws_domain_name - it must be a valid domain name."
}
}
variable "primary_vpc_subnet_cidr" {
description = "The subnet CIDR to use for the VPC"
type = string
default = "10.0.0.0/16"
validation {
condition = can(cidrhost(var.primary_vpc_subnet_cidr, 0))
error_message = "The VPC subnet must be valid IPv4 CIDR."
}
}
variable "num_agents" {
description = "The number of Agent Role Servers to create in the deployment"
type = number
default = 2
validation {
condition = var.num_agents >= 0 && var.num_agents <= 100 && floor(var.num_agents) == var.num_agents
error_message = "Acceptable number of Kasm Agents range between 0-100."
}
}
variable "num_webapps" {
description = "The number of WebApp role servers to create in the deployment"
type = number
default = 2
validation {
condition = var.num_webapps >= 1 && var.num_webapps <= 3 && floor(var.num_webapps) == var.num_webapps
error_message = "Acceptable number of webapps range between 1-3."
}
}
variable "webapp_instance_type" {
description = "The instance type for the webapps"
type = string
default = "t3.small"
validation {
condition = can(regex("^(([a-z-]{1,3})(\\d{1,2})?(\\w{1,4})?)\\.(nano|micro|small|medium|metal|large|(2|3|4|6|8|9|10|12|16|18|24|32|48|56|112)?xlarge)", var.webapp_instance_type))
error_message = "Check the webapp_instance_type variable and ensure it is a valid AWS Instance type (https://aws.amazon.com/ec2/instance-types/)."
}
}
variable "db_instance_type" {
description = "The instance type for the Database"
type = string
default = "t3.small"
validation {
condition = can(regex("^(([a-z-]{1,3})(\\d{1,2})?(\\w{1,4})?)\\.(nano|micro|small|medium|metal|large|(2|3|4|6|8|9|10|12|16|18|24|32|48|56|112)?xlarge)", var.db_instance_type))
error_message = "Check the db_instance_type variable and ensure it is a valid AWS Instance type (https://aws.amazon.com/ec2/instance-types/)."
}
}
variable "agent_instance_type" {
description = "The instance type for the Agents"
type = string
default = "t3.medium"
validation {
condition = can(regex("^(([a-z-]{1,3})(\\d{1,2})?(\\w{1,4})?)\\.(nano|micro|small|medium|metal|large|(2|3|4|6|8|9|10|12|16|18|24|32|48|56|112)?xlarge)", var.agent_instance_type))
error_message = "Check the agent_instance_type variable and ensure it is a valid AWS Instance type (https://aws.amazon.com/ec2/instance-types/)."
}
}
variable "webapp_hdd_size_gb" {
description = "The HDD size in GB to configure for the Kasm WebApp instances"
type = number
validation {
condition = can(var.webapp_hdd_size_gb >= 40)
error_message = "Kasm Webapps should have at least a 40 GB HDD to ensure enough space for Kasm services."
}
}
variable "db_hdd_size_gb" {
description = "The HDD size in GB to configure for the Kasm Database instances"
type = number
validation {
condition = can(var.db_hdd_size_gb >= 40)
error_message = "Kasm Database should have at least a 40 GB HDD to ensure enough space for Kasm services."
}
}
variable "agent_hdd_size_gb" {
description = "The HDD size in GB to configure for the Kasm Agent instances"
type = number
validation {
condition = can(var.agent_hdd_size_gb >= 120)
error_message = "Kasm Agents should have at least a 120 GB HDD to ensure enough space for Kasm services."
}
}
variable "primary_region_ec2_ami_id" {
description = "AMI Id of Kasm EC2 image in the primary region. Recommended AMI OS Version is Ubuntu 20.04 LTS."
type = string
default = "ami-09cd747c78a9add63"
validation {
condition = can(regex("^(ami-[a-f0-9]{17})", var.primary_region_ec2_ami_id))
error_message = "Please verify that your AMI is in the correct format for AWS (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami.html)."
}
}
variable "secondary_regions_settings" {
description = "Map of Kasm settings for secondary regions"
type = map(any)
validation {
condition = can([for region in var.secondary_regions_settings : regex("^([a-z]{2}-[a-z]{4,}-[\\d]{1})$", region.agent_region)])
error_message = "Verify the regions in the secondary_regions_settings variable and ensure they are valid AWS regions in a valid format (e.g. us-east-1)."
}
validation {
condition = can([for ami_id in var.secondary_regions_settings : regex("^(ami-[a-f0-9]{17})", ami_id.agent_ec2_ami_id)])
error_message = "Please verify that all of your Region's AMI IDs are in the correct format for AWS (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami.html)."
}
validation {
condition = can([for instance_type in var.secondary_regions_settings : regex("^(([a-z-]{1,3})(\\d{1,2})?(\\w{1,4})?)\\.(nano|micro|small|medium|metal|large|(2|3|4|6|8|9|10|12|16|18|24|32|48|56|112)?xlarge)", instance_type.agent_instance_type)])
error_message = "Check the Instance types used in your secondary_regions_settings and ensure they are valid AWS Instance types (https://aws.amazon.com/ec2/instance-types/)."
}
validation {
condition = can([for number_of_agents in var.secondary_regions_settings : number_of_agents.num_agents >= 0 && number_of_agents.num_agents <= 100 && floor(number_of_agents.num_agents) == number_of_agents.num_agents])
error_message = "Check the number of agents in the secondary_regions_settings variable. Acceptable number of Kasm Agents range between 0-100."
}
validation {
condition = can([for subnet in var.secondary_regions_settings : cidrhost(subnet.agent_vpc_cidr, 0)])
error_message = "Verify the VPC subnet in your secondary_regions_settings. They must all be valid IPv4 CIDRs."
}
}
variable "aws_primary_region" {
description = "The AWS Region used for deployment"
type = string
default = "us-east-1"
validation {
condition = can(regex("^([a-z]{2}-[a-z]{4,}-[\\d]{1})$", var.aws_primary_region))
error_message = "The aws_primary_region must be a valid Amazon Web Services (AWS) Region name, e.g. us-east-1"
}
}
variable "swap_size" {
description = "The amount of swap (in MB) to configure inside the compute instances"
type = number
validation {
condition = var.swap_size >= 1024 && var.swap_size <= 8192 && floor(var.swap_size) == var.swap_size
error_message = "Swap size is the amount of disk space to use for Kasm in MB and must be an integer between 1024 and 8192."
}
}
variable "database_password" {
default = "changeme"
description = "The password for the database. No special characters"
type = string
sensitive = true
validation {
condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.database_password))
error_message = "The Database Password should be a string between 12 and 30 letters and numbers with no special characters."
}
}
variable "redis_password" {
default = "changeme"
description = "The password for the Redis server. No special characters"
type = string
sensitive = true
validation {
condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.redis_password))
error_message = "The Redis Password should be a string between 12 and 30 letters and numbers with no special characters."
}
}
variable "user_password" {
default = "changeme"
description = "The standard (non administrator) user password. No special characters"
type = string
sensitive = true
validation {
condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.user_password))
error_message = "The User Password should be a string between 12 and 30 letters and numbers with no special characters."
}
}
variable "admin_password" {
default = "changeme"
description = "The administrative user password. No special characters"
type = string
sensitive = true
validation {
condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.admin_password))
error_message = "The Admin password should be a string between 12 and 30 letters and numbers with no special characters."
}
}
variable "manager_token" {
default = "changeme"
description = "The manager token value for Agents to authenticate to webapps. No special characters"
type = string
sensitive = true
validation {
condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.manager_token))
error_message = "The Manager Token should be a string between 12 and 30 letters and numbers with no special characters."
}
}
variable "ssh_access_cidrs" {
description = "CIDR notation of the bastion host allowed to SSH in to the machines"
type = list(string)
default = ["0.0.0.0/0"]
validation {
condition = can([for subnet in var.ssh_access_cidrs : cidrhost(subnet, 0)])
error_message = "One of the subnets provided in the ssh_access_cidr variable is invalid."
}
}
variable "web_access_cidrs" {
description = "CIDR notation of the bastion host allowed to SSH in to the machines"
type = list(string)
default = ["0.0.0.0/0"]
validation {
condition = can([for subnet in var.web_access_cidrs : cidrhost(subnet, 0)])
error_message = "One of the subnets provided in the web_access_cidrs variable is invalid."
}
}
## Non-validated variables
variable "kasm_build" {
default = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.9.0.077388.tar.gz"
description = "Download URL for Kasm Workspaces"
type = string
}
variable "ssh_access_cidr" {
default = "0.0.0.0/0"
variable "aws_default_tags" {
description = "Default tags to apply to all AWS resources for this deployment"
type = map(any)
default = {
Service_name = "Kasm Workspaces"
Kasm_version = "1.12"
}
}

View file

@ -1,29 +1,25 @@
resource "aws_instance" "kasm-agent" {
count = "${var.num_agents}"
ami = "${var.ec2_ami}"
instance_type = "${var.agent_instance_type}"
vpc_security_group_ids = ["${aws_security_group.kasm-agent-sg.id}"]
subnet_id = "${var.webapp_subnet_id_1}"
key_name = "${var.aws_key_pair}"
count = var.num_agents
ami = var.ec2_ami
instance_type = var.agent_instance_type
vpc_security_group_ids = [var.agent_security_group_id]
subnet_id = var.agent_subnet_id
key_name = var.aws_key_pair
root_block_device {
volume_size = "50"
volume_size = var.agent_hdd_size_gb
}
user_data = <<-EOF
#!/bin/bash
fallocate -l 4g /mnt/kasm.swap
chmod 600 /mnt/kasm.swap
mkswap /mnt/kasm.swap
swapon /mnt/kasm.swap
echo '/mnt/kasm.swap swap swap defaults 0 0' | tee -a /etc/fstab
cd /tmp
wget ${var.kasm_build}
tar xvf kasm_*.tar.gz
PUBLIC_DNS=(`curl -s http://169.254.169.254/latest/meta-data/public-ipv4`)
bash kasm_release/install.sh -S agent -e -p $PUBLIC_DNS -m ${var.zone_name}-lb.${var.aws_domain_name} -M ${var.manager_token}
EOF
user_data = templatefile("${path.module}/../userdata/agent_bootstrap.sh",
{
kasm_build_url = var.kasm_build
swap_size = var.swap_size
manager_address = var.aws_domain_name
manager_token = var.manager_token
}
)
tags = {
Name = "${var.project_name}-${var.zone_name}-kasm-agent"
}
}
}

View file

@ -0,0 +1,3 @@
data "aws_availability_zones" "available" {
state = "available"
}

View file

@ -1,150 +1,103 @@
resource "aws_security_group" "kasm-default-elb-sg" {
name = "${var.project_name}-${var.zone_name}-kasm-allow-elb-access"
description = "Security Group for ELB"
vpc_id = "${var.primary_vpc_id}"
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.project_name}-${var.zone_name}-kasm-allow-access"
}
data "aws_route53_zone" "kasm-route53-zone" {
name = var.aws_domain_name
private_zone = false
}
resource "aws_s3_bucket" "kasm-s3-logs" {
bucket_prefix = "${var.project_name}-${var.zone_name}-"
acl = "private"
force_destroy = true
}
resource "aws_s3_bucket_policy" "kasm-s3-logs-policy" {
bucket = aws_s3_bucket.kasm-s3-logs.id
policy = <<POLICY
{
"Id": "Policy",
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:PutObject"
],
"Effect": "Allow",
"Resource": "${aws_s3_bucket.kasm-s3-logs.arn}/AWSLogs/*",
"Principal": {
"AWS": [
"${data.aws_elb_service_account.main.arn}"
]
}
}
]
}
POLICY
}
data "aws_elb_service_account" "main" {}
resource "aws_lb" "kasm-alb" {
name = "${var.project_name}-${var.zone_name}-kasm-lb"
name = "${var.project_name}-lb"
internal = false
load_balancer_type = "application"
security_groups = ["${aws_security_group.kasm-default-elb-sg.id}"]
subnets = ["${var.webapp_subnet_id_1}", "${var.webapp_subnet_id_2}"]
security_groups = [var.load_balancer_security_group_id]
subnets = var.webapp_subnet_ids
access_logs {
bucket = "${aws_s3_bucket.kasm-s3-logs.bucket}"
bucket = var.load_balancer_log_bucket
enabled = true
}
}
data "aws_lb" "data-kasm_alb" {
arn = aws_lb.kasm-alb.arn
}
resource "aws_lb_target_group" "kasm-target-group" {
name = "${var.project_name}-${var.zone_name}-tg"
name = "${var.project_name}-target-group"
port = 443
protocol = "HTTPS"
vpc_id = "${var.primary_vpc_id}"
vpc_id = var.primary_vpc_id
health_check {
path = "/api/__healthcheck"
matcher = 200
protocol = "HTTPS"
path = "/api/__healthcheck"
matcher = 200
protocol = "HTTPS"
}
}
data "aws_route53_zone" "kasm-route53-zone" {
name = "${var.aws_domain_name}"
private_zone = false
data "aws_lb_target_group" "data-kasm_target_group" {
arn = aws_lb_target_group.kasm-target-group.arn
}
resource "aws_lb_listener" "kasm-alb-listener" {
load_balancer_arn = aws_lb.kasm-alb.arn
load_balancer_arn = data.aws_lb.data-kasm_alb.arn
port = "443"
protocol = "HTTPS"
certificate_arn = "${var.certificate_arn}"
certificate_arn = var.certificate_arn
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.kasm-target-group.arn
target_group_arn = data.aws_lb_target_group.data-kasm_target_group.arn
}
}
resource "aws_lb_listener" "kasm_alb_listener_http" {
load_balancer_arn = data.aws_lb.data-kasm_alb.arn
port = "80"
protocol = "HTTP"
default_action {
type = "redirect"
redirect {
port = "443"
protocol = "HTTPS"
status_code = "HTTP_301"
}
}
}
resource "aws_lb_target_group_attachment" "kasm-target-group-attachment" {
count = "${var.num_webapps}"
target_group_arn = aws_lb_target_group.kasm-target-group.arn
target_id = aws_instance.kasm-web-app[count.index].id
count = var.num_webapps
target_group_arn = data.aws_lb_target_group.data-kasm_target_group.arn
target_id = data.aws_instance.data-kasm_web_apps[count.index].id
port = 443
}
resource "aws_route53_record" "kasm-route53-elb-record" {
zone_id = data.aws_route53_zone.kasm-route53-zone.zone_id
name = "${var.zone_name}-lb.${var.aws_domain_name}"
type = "A"
alias {
name = aws_lb.kasm-alb.dns_name
zone_id = aws_lb.kasm-alb.zone_id
name = data.aws_lb.data-kasm_alb.dns_name
zone_id = data.aws_lb.data-kasm_alb.zone_id
evaluate_target_health = true
}
}
resource "aws_route53_record" "kasm-app-url" {
zone_id = data.aws_route53_zone.kasm-route53-zone.zone_id
name = "${var.aws_domain_name}"
type = "A"
zone_id = data.aws_route53_zone.kasm-route53-zone.zone_id
name = var.aws_domain_name
type = "A"
set_identifier = "${var.project_name}-${var.zone_name}-set-id"
alias {
name = aws_lb.kasm-alb.dns_name
zone_id = aws_lb.kasm-alb.zone_id
name = data.aws_lb.data-kasm_alb.dns_name
zone_id = data.aws_lb.data-kasm_alb.zone_id
evaluate_target_health = true
}
latency_routing_policy {
region = "${var.faux_aws_region}"
region = var.faux_aws_region
}
}
@ -159,4 +112,4 @@ resource "aws_route53_health_check" "kasm-elb-hc" {
tags = {
Name = "hc-${var.zone_name}-lb.${var.aws_domain_name}"
}
}
}

View file

@ -1,9 +0,0 @@
provider "aws" {
region = "${var.primary_aws_region}"
access_key = "${var.aws_access_key}"
secret_key = "${var.aws_secret_key}"
}
data "aws_availability_zones" "available" {
state = "available"
}

View file

@ -0,0 +1,8 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
#version = "4.56.0"
}
}
}

View file

@ -1,63 +0,0 @@
resource "aws_security_group" "kasm-webapp-sg" {
name = "${var.project_name}-${var.zone_name}-kasm-webapp-access"
description = "Allow access to webapps"
vpc_id = "${var.primary_vpc_id}"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["${var.ssh_access_cidr}"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
security_groups = ["${aws_security_group.kasm-default-elb-sg.id}"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
security_groups = ["${aws_security_group.kasm-agent-sg.id}"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group" "kasm-agent-sg" {
name = "${var.project_name}-${var.zone_name}-kasm-agent-access"
description = "Allow access to agents"
vpc_id = "${var.primary_vpc_id}"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["${var.ssh_access_cidr}"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}

View file

@ -1,98 +1,149 @@
variable "aws_access_key" {
description = "The AWS access key used for deployment"
}
variable "aws_secret_key" {
description = "The AWS secret key used for deployment"
}
variable "project_name" {
description = "The name of the deployment (e.g dev, staging). A short single word"
type = string
}
variable "aws_domain_name" {
description = "The Route53 Zone used for the dns entries. This must already exist in the AWS account. (e.g dev.kasm.contoso.com). The deployment will be accessed via this zone name via https"
type = string
}
variable "webapp_hdd_size_gb" {
description = "The HDD size in GB to configure for the Kasm WebApp instances"
type = number
}
variable "agent_hdd_size_gb" {
description = "The HDD size in GB to configure for the Kasm Agent instances"
type = number
default = 0
}
variable "database_password" {
description = "The password for the database. No special characters"
type = string
sensitive = true
}
variable "redis_password" {
description = "The password for the database. No special characters"
type = string
sensitive = true
}
variable "manager_token" {
description = "The Manager Token used by Kasm Agents to authenticate. No special characters"
type = string
sensitive = true
}
variable "swap_size" {
description = "The amount of swap (in MB) to configure inside the compute instances"
type = number
}
variable "num_webapps" {
description = "The number of WebApp role servers to create in the deployment"
type = number
default = 2
}
variable "webapp_instance_type" {
default = "t3.small"
description = "The instance type for the webapps"
type = string
default = "t3.small"
}
variable "webapp_security_group_id" {
description = "WebApp security group ID"
type = string
}
variable "webapp_subnet_ids" {
description = "WebApp subnet IDs created to host webapps in the primary region"
type = list(string)
}
variable "num_agents" {
default = 0
description = "The number of Agent Role Servers to create in the deployment"
type = number
default = 0
}
variable "agent_instance_type" {
default = "t3.medium"
description = "the instance type for the agents"
}
variable "primary_aws_region" {
description = "The AWS region for primary region of the deployment. (e.g us-east-1)"
}
variable "faux_aws_region" {
description = "The AWS region for this region is supposed to represent even though it will be created in the primary region of the deployment. (e.g us-east-1)"
}
variable "kasm_build" {
description = "The URL for the Kasm Workspaces build"
}
variable "kasm_db_ip" {
description = "The IP/DINS name of the Kasm database"
}
variable "zone_name" {
description = "A name given to the Kasm deployment Zone"
}
variable "aws_key_pair" {
description = "The name of an aws keypair to use."
}
variable "ec2_ami" {
description = "The AMI used for the EC2 nodes. Recommended Ubuntu 18.04 LTS."
}
variable "manager_token" {
description = "The password for the database. No special characters"
}
variable "certificate_arn" {
description = "The certificate ARN created in the primary region for use with all load balancers in the deployment."
}
variable "ssh_access_cidr" {
description = "CIDR notation of the bastion host allowed to SSH in to the machines"
}
variable "webapp_subnet_id_1" {
description = "One of two subnet IDs created to host webapps in the primary region"
}
variable "webapp_subnet_id_2" {
description = "One of two subnet IDs created to host webapps in the primary region"
type = string
default = "t3.medium"
}
variable "agent_subnet_id" {
description = "Subnet ID created for agents"
type = string
default = ""
}
variable "agent_security_group_id" {
description = "Kasm Agent security group ID"
type = string
default = ""
}
variable "primary_aws_region" {
description = "The AWS region for primary region of the deployment. (e.g us-east-1)"
type = string
}
variable "faux_aws_region" {
description = "The AWS region this WebApp is supposed to represent even though it will be created in the primary region of the deployment. (e.g us-east-1)"
type = string
}
variable "kasm_build" {
description = "The URL for the Kasm Workspaces build"
type = string
}
variable "kasm_db_ip" {
description = "The IP/DNS name of the Kasm database"
type = string
}
variable "zone_name" {
description = "A name given to the Kasm deployment Zone"
type = string
}
variable "aws_key_pair" {
description = "The name of an aws keypair to use."
type = string
}
variable "ec2_ami" {
description = "The AMI used for the EC2 nodes. Recommended Ubuntu 20.04 LTS."
type = string
}
variable "certificate_arn" {
description = "The certificate ARN created in the primary region for use with all load balancers in the deployment."
type = string
}
variable "ssh_access_cidrs" {
description = "List of Networks in CIDR notation for IPs allowed to SSH in to the machines"
type = list(string)
}
variable "load_balancer_log_bucket" {
description = "S3 bucket name for load balancers to forward access logs to"
type = string
}
variable "primary_vpc_id" {
description = "The VPC ID of the primary region"
}
type = string
}
variable "load_balancer_security_group_id" {
description = "Security Group ID for the Primary region's load balancer"
type = string
}

View file

@ -1,36 +1,32 @@
resource "aws_instance" "kasm-web-app" {
count = "${var.num_webapps}"
ami = "${var.ec2_ami}"
instance_type = "${var.webapp_instance_type}"
vpc_security_group_ids = ["${aws_security_group.kasm-webapp-sg.id}"]
subnet_id = "${var.webapp_subnet_id_1}"
key_name = "${var.aws_key_pair}"
count = var.num_webapps
ami = var.ec2_ami
instance_type = var.webapp_instance_type
vpc_security_group_ids = [var.webapp_security_group_id]
subnet_id = var.webapp_subnet_ids[count.index]
key_name = var.aws_key_pair
root_block_device {
volume_size = "40"
volume_size = var.webapp_hdd_size_gb
}
user_data = <<-EOF
#!/bin/bash
set -x
fallocate -l 4g /mnt/kasm.swap
chmod 600 /mnt/kasm.swap
mkswap /mnt/kasm.swap
swapon /mnt/kasm.swap
echo '/mnt/kasm.swap swap swap defaults 0 0' | tee -a /etc/fstab
cd /tmp
wget ${var.kasm_build}
tar xvf kasm_*.tar.gz
echo "Checking for Kasm DB..."
while ! nc -w 1 -z ${var.kasm_db_ip} 5432; do
echo "Not Ready..."
sleep 5
done
echo "DB is alive"
user_data = templatefile("${path.module}/../userdata/webapp_bootstrap.sh",
{
kasm_build_url = var.kasm_build
db_ip = var.kasm_db_ip
database_password = var.database_password
redis_password = var.redis_password
swap_size = var.swap_size
zone_name = "default"
}
)
bash kasm_release/install.sh -S app -e -z ${var.zone_name} -q ${var.kasm_db_ip} -Q ${var.database_password} -R ${var.redis_password}
EOF
tags = {
Name = "${var.project_name}-${var.zone_name}-kasm-webapp"
}
}
}
data "aws_instance" "data-kasm_web_apps" {
count = var.num_webapps
instance_id = aws_instance.kasm-web-app[count.index].id
}

View file

@ -8,8 +8,6 @@ Each role is placed in a separate subnet and traffic from user sessions on the A
[Image_Diagram]: https://f.hubspotusercontent30.net/hubfs/5856039/terraform/diagrams/aws-multi-server-nat-gw.png "Diagram"
# Pre-Configuration
Consider creating a special sub account for the Kasm deployment.
@ -17,12 +15,10 @@ Consider creating a special sub account for the Kasm deployment.
In your AWS account create a DNS Public zone that matches the desired domain name for the deployment. e.g `kasm.contoso.com`
### SSH Key Pair
In the desired AWS region create an aws Key pair. This will be configured as the SSH key for the deployed EC2 machines
In the desired AWS region create an aws Key pair. The key name will be value used in the `aws_key_pair` variable and it will be configured as the SSH key for the deployed EC2 machines.
### AWS API Keys
Create a user via the IAM console that will be used for the terraform deployment. Give the user **Programatic Access**
and attach the existing policy **AdministratorAccess**. Save the key and key secret
Create a user via the IAM console that will be used for the terraform deployment. Give the user **Programatic Access** and attach the existing policy **AdministratorAccess**. Save the key and key secret
# Terraform Configuration
@ -31,21 +27,58 @@ and attach the existing policy **AdministratorAccess**. Save the key and key sec
terraform init
2. Open `deployment.tf` and update the variables. The variable definitions and descriptions
can be found in `module/variables.tf`
2. Open `settings.tfvars` and update the variable values. The variable definitions, descriptions, and validation expectations can be found in the `variables.tf` file.
> ***NOTE:*** This document assumes you are using a separate file named `secrets.tfvars` for the AWS credentials generated in the [AWS API Keys](#aws-api-keys) section above. The .gitignore file in this repository will ignore any files named `secrets.tfvars` since they are expected to have sensitive values in them. This will prevent you from accidentally committing them to source control.
3. Verify the configuration
terraform plan
terraform plan -var-file settings.tfvars -var-file secrets.tfvars
4. Deploy
terraform apply
terraform apply -var-file settings.tfvars -var-file secrets.tfvars
5. Login to the Deployment as an Admin via the domain defined e.g `https://kasm.contoso.com`
6. Navigate to the Agents tab, and enable each Agent after it checks in. (May take a few minutes)
# AWS Terraform Variable definitions
| Variable | Description | Variable type | Example |
|:--------:|-------------|---------------|---------|
| `aws_access_key` | The AWS access key used for deployment. | String | `"AKIAJSIE27KKMHXI3BJQ"` |
| `aws_secret_key` | The AWS secret key used for deployment. | String | `"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"` |
| `aws_region` | The AWS Region used for deployment. | String | `"us-east-1"` |
| `project_name` | The name of the deployment (e.g dev, staging). A short single word of up to 15 characters. | String | `"kasm"` |
| `aws_domain_name` | The Route53 Zone used for the dns entries. This must already exist in the AWS account. (e.g dev.kasm.contoso.com). The deployment will be accessed via this zone name via https. | String | `"kasm.contoso.com"` |
| `kasm_zone_name` | A name given to the kasm deployment Zone. | String | `"default"` |
| `vpc_subnet_cidr` | The subnet CIDR to use for the VPC | String | `"10.0.0.0/16"` |
| `aws_key_pair` | The name of an aws keypair to use. | String | `"kasm_ssh_key"` |
| `ec2_ami` | The AMI used for the EC2 nodes. Recommended Ubuntu 20.04 LTS. | String | `"ami-09cd747c78a9add63"` |
| `swap_size` | The amount of swap (in MB) to configure inside the Kasm servers. | Number | `2048` |
| `webapp_instance_type` | The instance type for the webapps. | String | `"t3.small"` |
| `db_instance_type` | The instance type for the webapps. | String | `"t3.medium"` |
| `agent_instance_type` | The instance type for the webapps. | String | `"t3.medium"` |
| `guac_instance_type` | The instance type for the webapps. | String | `"t3.medium"` |
| `num_webapps` | The number of WebApp role servers to create in this deployment. Acceptable ranges from 1-3. | Number | `2` |
| `num_agents` | The number of static Kasm Agents to create in this deploymenbt. Acceptable ranges from 0-100. | Number | `2` |
| `num_guac_rdp_nodes` | The number of Guacamole RDP access servers to create in this deployment. Acceptable ranges from 0-100. | Number | `1` |
| `allow_ssh_cidrs` | A list of subnets in CIDR notation allowed to SSH into your kasm servers | List(String) | `["10.0.0.0/16","172.217.22.14/32"]` |
| `web_access_cidrs` | A list of subnets in CIDR notation allowed Web access to your kasm servers | List(String) | `["0.0.0.0/0"]` |
| `database_password` | The Kasm PostgreSQL database password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` |
| `redis_password` | The Kasm Redis password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` |
| `admin_password` | The Kasm Administrative user login password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` |
| `user_password` | A Kasm standard (non-administrator) user password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` |
| `manager_token` | The manager token value used by Kasm agents to authenticate to the Kasm WebApps. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` |
| `service_registration_token` | The service registration token value used by Guac RDP servers to authenticate to the Kasm Webapps. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` |
| `kasm_build` | The download URL for the desired Kasm Workspaces version. | String | `"https://kasm-static-content.s3.amazonaws.com/kasm_release_1.12.0.d4fd8a.tar.gz"` |
| `aws_default_tags` | A Map of all tags you wish to apply to all TF created resources in this deployment. | Map(Any) | <pre align=left>{<br/>&nbsp;&nbsp;Service_name = "Kasm Workspaces"<br/>&nbsp;&nbsp;Kasm_version = "1.12"<br/>}</pre> |
# Detailed Terraform Deployment Diagram
![Detailed Diagram][Detailed_Diagram]
[Detailed_Diagram]: ./diagram/aws_multi_server.png "Detailed Diagram"

View file

@ -1,30 +1,30 @@
module "standard" {
source = "./module"
aws_access_key = ""
aws_secret_key = ""
aws_key_pair = ""
aws_region = "us-east-1"
aws_domain_name = "kasm.contoso.com"
project_name = "contoso"
num_agents = "2"
num_webapps = "2"
source = "./module"
aws_key_pair = var.aws_key_pair
aws_region = var.aws_region
aws_domain_name = var.aws_domain_name
project_name = var.project_name
num_agents = var.num_agents
num_webapps = var.num_webapps
num_guac_nodes = var.num_guac_nodes
vpc_subnet_cidr = var.vpc_subnet_cidr
## Kasm Server settings
agent_instance_type = var.agent_instance_type
guac_instance_type = var.guac_instance_type
webapp_instance_type = var.webapp_instance_type
db_instance_type = var.db_instance_type
ec2_ami = var.ec2_ami
swap_size = var.swap_size
agent_instance_type = "t3.medium"
webapp_instance_type = "t3.small"
db_instance_type = "t3.small"
ec2_ami = "ami-0747bdcabd34c712a"
ssh_access_cidr = "0.0.0.0/0"
database_password = "changeme"
redis_password = "changeme"
user_password = "changeme"
admin_password = "changeme"
manager_token = "changeme"
zone_name = "default"
kasm_build = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.9.0.077388.tar.gz"
ssh_access_cidrs = var.ssh_access_cidrs
web_access_cidrs = var.web_access_cidrs
database_password = var.database_password
redis_password = var.redis_password
user_password = var.user_password
admin_password = var.admin_password
manager_token = var.manager_token
service_registration_token = var.service_registration_token
kasm_zone_name = var.kasm_zone_name
kasm_build = var.kasm_build
}

View file

@ -0,0 +1,166 @@
<mxfile host="65bd71144e">
<diagram id="evBy-dt-jB8v2-nSfg1o" name="AWS Multi-Server">
<mxGraphModel dx="1395" dy="1340" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1100" pageHeight="850" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="15" value="WebApp Subnet 1&lt;br&gt;10.0.1.0/24" style="points=[[0,0],[0.25,0],[0.5,0],[0.75,0],[1,0],[1,0.25],[1,0.5],[1,0.75],[1,1],[0.75,1],[0.5,1],[0.25,1],[0,1],[0,0.75],[0,0.5],[0,0.25]];outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;container=1;pointerEvents=0;collapsible=0;recursiveResize=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_security_group;grStroke=0;strokeColor=#248814;fillColor=#E9F3E6;verticalAlign=top;align=left;spacingLeft=30;fontColor=#248814;dashed=0;" parent="1" vertex="1">
<mxGeometry x="531" y="189" width="130" height="141" as="geometry"/>
</mxCell>
<mxCell id="50" value="&lt;span style=&quot;color: rgb(0, 0, 0); font-size: 10px;&quot;&gt;US East&lt;br&gt;Webapp-1&lt;/span&gt;" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;" parent="15" vertex="1">
<mxGeometry x="45" y="51" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="2" value="AWS Account" style="points=[[0,0],[0.25,0],[0.5,0],[0.75,0],[1,0],[1,0.25],[1,0.5],[1,0.75],[1,1],[0.75,1],[0.5,1],[0.25,1],[0,1],[0,0.75],[0,0.5],[0,0.25]];outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;container=1;pointerEvents=0;collapsible=0;recursiveResize=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_account;strokeColor=#CD2264;fillColor=none;verticalAlign=top;align=left;spacingLeft=30;fontColor=#CD2264;dashed=0;" parent="1" vertex="1">
<mxGeometry x="239" y="69" width="681" height="831" as="geometry"/>
</mxCell>
<mxCell id="11" value="Primary Region - us-east-1" style="points=[[0,0],[0.25,0],[0.5,0],[0.75,0],[1,0],[1,0.25],[1,0.5],[1,0.75],[1,1],[0.75,1],[0.5,1],[0.25,1],[0,1],[0,0.75],[0,0.5],[0,0.25]];outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;container=0;pointerEvents=0;collapsible=0;recursiveResize=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_region;strokeColor=#147EBA;fillColor=none;verticalAlign=top;align=left;spacingLeft=30;fontColor=#147EBA;dashed=1;" parent="2" vertex="1">
<mxGeometry x="130" y="20" width="530" height="800" as="geometry"/>
</mxCell>
<mxCell id="3" value="Mgmt VPC&lt;br&gt;10.0.0.0/16" style="sketch=0;outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_vpc;strokeColor=#879196;fillColor=none;verticalAlign=top;align=left;spacingLeft=30;fontColor=#879196;dashed=0;" parent="2" vertex="1">
<mxGeometry x="171" y="49.75" width="471" height="760.25" as="geometry"/>
</mxCell>
<mxCell id="91" value="Agent Security Group" style="fontStyle=0;verticalAlign=top;align=center;spacingTop=-2;fillColor=none;rounded=1;whiteSpace=wrap;html=1;strokeColor=#FF0000;strokeWidth=2;dashed=1;container=1;collapsible=0;expand=0;recursiveResize=0;labelBackgroundColor=none;fontSize=10;fontColor=#000000;arcSize=2;" parent="2" vertex="1">
<mxGeometry x="286.5" y="461" width="150" height="156" as="geometry"/>
</mxCell>
<mxCell id="134" value="Guac Security Group" style="fontStyle=0;verticalAlign=top;align=center;spacingTop=-2;fillColor=none;rounded=1;whiteSpace=wrap;html=1;strokeColor=#FF0000;strokeWidth=2;dashed=1;container=1;collapsible=0;expand=0;recursiveResize=0;labelBackgroundColor=none;fontSize=10;fontColor=#000000;arcSize=2;" parent="2" vertex="1">
<mxGeometry x="284" y="641" width="150" height="156" as="geometry"/>
</mxCell>
<mxCell id="89" value="AZ 1a" style="sketch=0;outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_availability_zone;strokeColor=#545B64;fillColor=none;verticalAlign=top;align=left;spacingLeft=30;fontColor=#545B64;dashed=1;" parent="2" vertex="1">
<mxGeometry x="273" y="74.25" width="175" height="730.75" as="geometry"/>
</mxCell>
<mxCell id="76" value="Webapp Security&amp;nbsp; Group" style="fontStyle=0;verticalAlign=top;align=center;spacingTop=-2;fillColor=none;rounded=1;whiteSpace=wrap;html=1;strokeColor=#FF0000;strokeWidth=2;dashed=1;container=0;collapsible=0;expand=0;recursiveResize=0;labelBackgroundColor=none;fontSize=10;fontColor=#000000;arcSize=3;" parent="2" vertex="1">
<mxGeometry x="285" y="102" width="330" height="167" as="geometry"/>
</mxCell>
<mxCell id="10" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;fillColor=#fff2cc;strokeColor=#d6b656;strokeWidth=3;" parent="2" source="4" target="5" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="4" value="Route53 Latency&lt;br style=&quot;font-size: 10px;&quot;&gt;based DNS" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#945DF2;gradientDirection=north;fillColor=#5A30B5;strokeColor=#ffffff;dashed=0;verticalLabelPosition=top;verticalAlign=bottom;align=center;html=1;fontSize=10;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.route_53;labelPosition=center;" parent="2" vertex="1">
<mxGeometry x="39" y="183" width="50" height="50" as="geometry"/>
</mxCell>
<mxCell id="126" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#fff2cc;strokeColor=#d6b656;strokeWidth=3;" parent="2" source="5" target="108" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="5" value="Public&lt;br&gt;Web ALB" style="outlineConnect=0;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;shape=mxgraph.aws3.application_load_balancer;fillColor=#F58534;gradientColor=none;fontSize=10;" parent="2" vertex="1">
<mxGeometry x="192" y="188" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="92" value="Agent Subnet 1&lt;br&gt;10.0.3.0/24" style="points=[[0,0],[0.25,0],[0.5,0],[0.75,0],[1,0],[1,0.25],[1,0.5],[1,0.75],[1,1],[0.75,1],[0.5,1],[0.25,1],[0,1],[0,0.75],[0,0.5],[0,0.25]];outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;container=1;pointerEvents=0;collapsible=0;recursiveResize=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_security_group;grStroke=0;strokeColor=#248814;fillColor=#E9F3E6;verticalAlign=top;align=left;spacingLeft=30;fontColor=#248814;dashed=0;" parent="2" vertex="1">
<mxGeometry x="290" y="478" width="140" height="130" as="geometry"/>
</mxCell>
<mxCell id="93" value="" style="group" parent="92" vertex="1" connectable="0">
<mxGeometry x="35" y="40" width="70" height="90" as="geometry"/>
</mxCell>
<mxCell id="94" value="" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;" parent="93" vertex="1">
<mxGeometry x="5" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="95" value="" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;" parent="93" vertex="1">
<mxGeometry x="15" y="10" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="96" value="" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;" parent="93" vertex="1">
<mxGeometry x="25" y="20" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="97" value="Kasm Agents" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=10;" parent="93" vertex="1">
<mxGeometry y="60" width="70" height="30" as="geometry"/>
</mxCell>
<mxCell id="46" value="" style="edgeStyle=orthogonalEdgeStyle;html=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;entryPerimeter=0;fontSize=10;fillColor=#d5e8d4;strokeColor=#82b366;strokeWidth=3;labelBackgroundColor=default;" parent="2" source="91" target="127" edge="1">
<mxGeometry x="-0.4789" y="-6" relative="1" as="geometry">
<mxPoint x="-129" y="501" as="sourcePoint"/>
<Array as="points">
<mxPoint x="523" y="539"/>
</Array>
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="25" value="Internet&lt;br&gt;Gateway" style="outlineConnect=0;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;shape=mxgraph.aws3.internet_gateway;fillColor=#F58536;gradientColor=none;fontSize=10;" parent="2" vertex="1">
<mxGeometry x="185" y="92" width="28.76" height="30" as="geometry"/>
</mxCell>
<mxCell id="16" value="WebApp Subnet 2&lt;br&gt;10.0.2.0/24" style="points=[[0,0],[0.25,0],[0.5,0],[0.75,0],[1,0],[1,0.25],[1,0.5],[1,0.75],[1,1],[0.75,1],[0.5,1],[0.25,1],[0,1],[0,0.75],[0,0.5],[0,0.25]];outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;container=1;pointerEvents=0;collapsible=0;recursiveResize=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_security_group;grStroke=0;strokeColor=#248814;fillColor=#E9F3E6;verticalAlign=top;align=left;spacingLeft=30;fontColor=#248814;dashed=0;" parent="2" vertex="1">
<mxGeometry x="475" y="120" width="130" height="140" as="geometry"/>
</mxCell>
<mxCell id="71" value="&lt;span style=&quot;color: rgb(0, 0, 0); font-size: 10px;&quot;&gt;US East&lt;br&gt;Webapp-2&lt;/span&gt;" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;" parent="2" vertex="1">
<mxGeometry x="520" y="171" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="108" value="" style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fontSize=10;fillColor=none;strokeColor=#d6b656;strokeWidth=2;dashed=1;arcSize=6;" parent="2" vertex="1">
<mxGeometry x="305" y="163" width="290" height="90" as="geometry"/>
</mxCell>
<mxCell id="120" value="DB Subnet 1&lt;br&gt;10.0.0.0/24" style="points=[[0,0],[0.25,0],[0.5,0],[0.75,0],[1,0],[1,0.25],[1,0.5],[1,0.75],[1,1],[0.75,1],[0.5,1],[0.25,1],[0,1],[0,0.75],[0,0.5],[0,0.25]];outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;container=1;pointerEvents=0;collapsible=0;recursiveResize=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_security_group;grStroke=0;strokeColor=#248814;fillColor=#E9F3E6;verticalAlign=top;align=left;spacingLeft=30;fontColor=#248814;dashed=0;" parent="2" vertex="1">
<mxGeometry x="289" y="303" width="145" height="135" as="geometry"/>
</mxCell>
<mxCell id="124" value="Kasm Database&lt;br&gt;Kasm Redis" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;" parent="120" vertex="1">
<mxGeometry x="52.5" y="47.5" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="123" value="Database Security Group" style="fontStyle=0;verticalAlign=top;align=center;spacingTop=-2;fillColor=none;rounded=1;whiteSpace=wrap;html=1;strokeColor=#FF0000;strokeWidth=2;dashed=1;container=1;collapsible=0;expand=0;recursiveResize=0;labelBackgroundColor=none;fontSize=10;fontColor=#000000;arcSize=4;" parent="2" vertex="1">
<mxGeometry x="286.5" y="283" width="150" height="155" as="geometry"/>
</mxCell>
<mxCell id="14" value="AZ 1b" style="sketch=0;outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_availability_zone;strokeColor=#545B64;fillColor=none;verticalAlign=top;align=left;spacingLeft=30;fontColor=#545B64;dashed=1;" parent="2" vertex="1">
<mxGeometry x="462" y="73.25" width="164" height="205.75" as="geometry"/>
</mxCell>
<mxCell id="136" value="" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;exitPerimeter=0;labelBackgroundColor=default;strokeWidth=3;entryX=1;entryY=0.5;entryDx=0;entryDy=0;fillColor=#d5e8d4;strokeColor=#82b366;startArrow=classic;startFill=1;endArrow=none;endFill=0;" parent="2" source="127" target="128" edge="1">
<mxGeometry x="0.5668" y="8" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="137" value="&lt;span style=&quot;font-size: 10px;&quot;&gt;https://private-lb.kasm.contoso.com&lt;/span&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="136" vertex="1" connectable="0">
<mxGeometry x="-0.7987" relative="1" as="geometry">
<mxPoint y="-2" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="138" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;labelBackgroundColor=default;strokeWidth=3;startArrow=none;startFill=0;endArrow=classic;endFill=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="2" source="127" target="108" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="127" value="Private LB&lt;br&gt;Agent/Guac Mgmt" style="outlineConnect=0;dashed=0;verticalLabelPosition=middle;verticalAlign=middle;align=left;html=1;shape=mxgraph.aws3.application_load_balancer;fillColor=#F58534;gradientColor=none;fontSize=10;labelPosition=right;" parent="2" vertex="1">
<mxGeometry x="503" y="401" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="128" value="Guac Subnet&lt;br&gt;10.0.4.0/24" style="points=[[0,0],[0.25,0],[0.5,0],[0.75,0],[1,0],[1,0.25],[1,0.5],[1,0.75],[1,1],[0.75,1],[0.5,1],[0.25,1],[0,1],[0,0.75],[0,0.5],[0,0.25]];outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;container=1;pointerEvents=0;collapsible=0;recursiveResize=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_security_group;grStroke=0;strokeColor=#248814;fillColor=#E9F3E6;verticalAlign=top;align=left;spacingLeft=30;fontColor=#248814;dashed=0;" parent="2" vertex="1">
<mxGeometry x="287.5" y="658" width="140" height="130" as="geometry"/>
</mxCell>
<mxCell id="129" value="" style="group" parent="128" vertex="1" connectable="0">
<mxGeometry x="35" y="40" width="70" height="90" as="geometry"/>
</mxCell>
<mxCell id="130" value="" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;" parent="129" vertex="1">
<mxGeometry x="5" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="131" value="" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;" parent="129" vertex="1">
<mxGeometry x="15" y="10" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="132" value="" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;" parent="129" vertex="1">
<mxGeometry x="25" y="20" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="133" value="Kasm Guac RDP" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=10;" parent="129" vertex="1">
<mxGeometry y="60" width="70" height="30" as="geometry"/>
</mxCell>
<mxCell id="102" value="Load Balancer&lt;br style=&quot;font-size: 10px;&quot;&gt;Access Logs S3" style="sketch=0;outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#3F8624;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=10;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.bucket;labelBackgroundColor=none;" parent="2" vertex="1">
<mxGeometry x="588" y="748" width="28.85" height="30" as="geometry"/>
</mxCell>
<mxCell id="139" value="NAT GW" style="outlineConnect=0;dashed=0;verticalLabelPosition=middle;verticalAlign=middle;align=left;html=1;shape=mxgraph.aws3.vpc_nat_gateway;fillColor=#F58536;gradientColor=none;labelPosition=right;" vertex="1" parent="2">
<mxGeometry x="180" y="608" width="40" height="41.73" as="geometry"/>
</mxCell>
<mxCell id="144" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;strokeWidth=3;fillColor=#f8cecc;strokeColor=#b85450;" edge="1" parent="2" source="94" target="139">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="145" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;entryPerimeter=0;strokeWidth=3;fillColor=#f8cecc;strokeColor=#b85450;" edge="1" parent="2" source="130" target="139">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="44" value="Management/User&lt;br&gt;Access Traffic" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=1;exitY=0.71;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;fontSize=10;strokeWidth=3;" parent="1" source="12" target="4" edge="1">
<mxGeometry x="-0.2779" y="15" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="12" value="&lt;font style=&quot;font-size: 10px;&quot;&gt;https://kasm.contoso.com&lt;/font&gt;" style="points=[[0.35,0,0],[0.98,0.51,0],[1,0.71,0],[0.67,1,0],[0,0.795,0],[0,0.65,0]];verticalLabelPosition=top;sketch=0;html=1;verticalAlign=bottom;aspect=fixed;align=center;pointerEvents=1;shape=mxgraph.cisco19.user;fillColor=#005073;strokeColor=none;fontColor=#005073;labelPosition=center;" parent="1" vertex="1">
<mxGeometry x="100" y="227" width="70" height="70" as="geometry"/>
</mxCell>
<mxCell id="119" value="&lt;u style=&quot;font-size: 16px;&quot;&gt;AWS Multi-Server (Single Region with NAT Gateway) Terraform Deployment&lt;/u&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;dashed=1;labelBackgroundColor=none;strokeWidth=2;fontSize=16;fontColor=#000000;" parent="1" vertex="1">
<mxGeometry x="275" y="20" width="551" height="30" as="geometry"/>
</mxCell>
<mxCell id="141" value="" style="aspect=fixed;perimeter=ellipsePerimeter;html=1;align=center;shadow=0;dashed=0;spacingTop=3;image;image=img/lib/active_directory/internet_cloud.svg;" vertex="1" parent="1">
<mxGeometry x="86" y="658" width="126.98" height="80" as="geometry"/>
</mxCell>
<mxCell id="142" value="Kasm Workspace Internet" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="110" y="680" width="90" height="30" as="geometry"/>
</mxCell>
<mxCell id="143" style="edgeStyle=none;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=3;fillColor=#f8cecc;strokeColor=#b85450;" edge="1" parent="1" source="139" target="141">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

View file

@ -1,30 +1,26 @@
resource "aws_instance" "kasm-agent" {
count = "${var.num_agents}"
ami = "${var.ec2_ami}"
instance_type = "${var.agent_instance_type}"
vpc_security_group_ids = ["${aws_security_group.kasm-agent-sg.id}"]
subnet_id = "${aws_subnet.kasm-use-natgw-subnet.id}"
key_name = "${var.aws_key_pair}"
count = var.num_agents
ami = var.ec2_ami
instance_type = var.agent_instance_type
vpc_security_group_ids = [data.aws_security_group.data-kasm_agent_sg.id]
subnet_id = data.aws_subnet.data-kasm_agent_subnet.id
key_name = var.aws_key_pair
associate_public_ip_address = false
root_block_device {
volume_size = "50"
volume_size = 120
}
user_data = <<-EOF
#!/bin/bash
fallocate -l 5g /mnt/kasm.swap
chmod 600 /mnt/kasm.swap
mkswap /mnt/kasm.swap
swapon /mnt/kasm.swap
echo '/mnt/kasm.swap swap swap defaults 0 0' | tee -a /etc/fstab
cd /tmp
wget ${var.kasm_build}
tar xvf kasm_*.tar.gz
PRIVATE_IP=(`curl -s http://169.254.169.254/latest/meta-data/local-ipv4`)
bash kasm_release/install.sh -S agent -e -p $PRIVATE_IP -m ${var.zone_name}-lb.${var.aws_domain_name} -M ${var.manager_token}
EOF
user_data = templatefile("${path.module}/userdata/agent_bootstrap.sh",
{
kasm_build_url = var.kasm_build
swap_size = var.swap_size
manager_address = local.private_lb_hostname
manager_token = var.manager_token
}
)
tags = {
Name = "${var.project_name}-${var.zone_name}-kasm-agent"
Name = "${var.project_name}-${var.kasm_zone_name}-kasm-agent"
}
}

View file

@ -0,0 +1,60 @@
data "aws_route53_zone" "kasm-route53-zone" {
name = var.aws_domain_name
}
data "aws_elb_service_account" "main" {}
resource "aws_s3_bucket" "kasm_s3_logs" {
bucket_prefix = "${var.project_name}-${var.kasm_zone_name}-"
force_destroy = true
}
resource "aws_s3_bucket_acl" "kasm_s3_acl" {
bucket = aws_s3_bucket.kasm_s3_logs.id
acl = "private"
}
resource "aws_s3_bucket_policy" "kasm_s3_logs_policy" {
bucket = aws_s3_bucket.kasm_s3_logs.id
policy = jsonencode({
Id = "Policy"
Version = "2012-10-17"
Statement = [
{
Action = [
"s3:PutObject"
]
Effect = "Allow"
Resource = "${aws_s3_bucket.kasm_s3_logs.arn}/AWSLogs/*"
Principal = {
AWS = [
data.aws_elb_service_account.main.arn
]
}
}
]
})
}
resource "aws_s3_bucket_server_side_encryption_configuration" "encrypt_elb_bucket" {
bucket = aws_s3_bucket.kasm_s3_logs.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
data "aws_s3_bucket" "data-kasm_s3_logs_bucket" {
bucket = aws_s3_bucket.kasm_s3_logs.bucket
}
resource "aws_s3_bucket_public_access_block" "s3_log_public_access" {
bucket = aws_s3_bucket.kasm_s3_logs.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}

View file

@ -0,0 +1,3 @@
data "aws_availability_zones" "available" {
state = "available"
}

View file

@ -1,7 +1,7 @@
resource "aws_acm_certificate" "kasm-alb-cert" {
domain_name = "${var.aws_domain_name}"
domain_name = var.aws_domain_name
subject_alternative_names = ["*.${var.aws_domain_name}"]
validation_method = "DNS"
validation_method = "DNS"
lifecycle {
create_before_destroy = true
@ -10,7 +10,7 @@ resource "aws_acm_certificate" "kasm-alb-cert" {
resource "aws_route53_record" "kasm-route53-cert-validation-record" {
for_each = {
for dvo in aws_acm_certificate.kasm-alb-cert.domain_validation_options: dvo.domain_name => {
for dvo in aws_acm_certificate.kasm-alb-cert.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
@ -19,14 +19,13 @@ resource "aws_route53_record" "kasm-route53-cert-validation-record" {
name = each.value.name
type = each.value.type
records = [each.value.record]
zone_id = "${data.aws_route53_zone.kasm-route53-zone.id}"
zone_id = data.aws_route53_zone.kasm-route53-zone.id
ttl = 30
ttl = 30
allow_overwrite = true
}
resource "aws_acm_certificate_validation" "kasm-elb-certificate-validation" {
certificate_arn = aws_acm_certificate.kasm-alb-cert.arn
validation_record_fqdns = [for record in aws_route53_record.kasm-route53-cert-validation-record: record.fqdn]
validation_record_fqdns = [for record in aws_route53_record.kasm-route53-cert-validation-record : record.fqdn]
}

View file

@ -1,28 +1,32 @@
resource "aws_instance" "kasm-db" {
ami = "${var.ec2_ami}"
instance_type = "${var.db_instance_type}"
vpc_security_group_ids = ["${aws_security_group.kasm-db-sg.id}"]
subnet_id = "${aws_subnet.kasm-db-subnet.id}"
key_name = "${var.aws_key_pair}"
ami = var.ec2_ami
instance_type = var.db_instance_type
vpc_security_group_ids = [data.aws_security_group.data-kasm_db_sg.id]
subnet_id = data.aws_subnet.data-kasm_db_subnet.id
key_name = var.aws_key_pair
root_block_device {
volume_size = "40"
volume_type = "gp2"
volume_size = 40
}
user_data = <<-EOF
#!/bin/bash
fallocate -l 4g /mnt/kasm.swap
chmod 600 /mnt/kasm.swap
mkswap /mnt/kasm.swap
swapon /mnt/kasm.swap
echo '/mnt/kasm.swap swap swap defaults 0 0' | tee -a /etc/fstab
cd /tmp
wget ${var.kasm_build}
tar xvf kasm_*.tar.gz
bash kasm_release/install.sh -S db -e -Q ${var.database_password} -R ${var.redis_password} -U ${var.user_password} -P ${var.admin_password} -M ${var.manager_token}
EOF
user_data = templatefile("${path.module}/userdata/db_bootstrap.sh",
{
kasm_build_url = var.kasm_build
user_password = var.user_password
admin_password = var.admin_password
redis_password = var.redis_password
database_password = var.database_password
service_registration_token = var.service_registration_token
manager_token = var.manager_token
swap_size = var.swap_size
}
)
tags = {
Name = "${var.project_name}-kasm-db"
}
}
}
data "aws_instance" "data-kasm_db" {
instance_id = aws_instance.kasm-db.id
}

View file

@ -1,130 +0,0 @@
data "aws_route53_zone" "kasm-route53-zone" {
name = "${var.aws_domain_name}"
}
resource "aws_s3_bucket" "kasm-s3-logs" {
bucket_prefix = "${var.project_name}-${var.zone_name}-"
acl = "private"
force_destroy = true
}
resource "aws_s3_bucket_policy" "kasm-s3-logs-policy" {
bucket = aws_s3_bucket.kasm-s3-logs.id
policy = <<POLICY
{
"Id": "Policy",
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:PutObject"
],
"Effect": "Allow",
"Resource": "${aws_s3_bucket.kasm-s3-logs.arn}/AWSLogs/*",
"Principal": {
"AWS": [
"${data.aws_elb_service_account.main.arn}"
]
}
}
]
}
POLICY
}
data "aws_elb_service_account" "main" {}
resource "aws_lb" "kasm-alb" {
name = "${var.project_name}-lb"
internal = false
load_balancer_type = "application"
security_groups = ["${aws_security_group.kasm-default-elb-sg.id}"]
subnets = ["${aws_subnet.kasm-webapp-subnet.id}", "${aws_subnet.kasm-webapp-subnet-2.id}"]
access_logs {
bucket = "${aws_s3_bucket.kasm-s3-logs.bucket}"
enabled = true
}
}
resource "aws_lb_target_group" "kasm-target-group" {
name = "${var.project_name}-target-group"
port = 443
protocol = "HTTPS"
vpc_id = "${aws_vpc.kasm-default-vpc.id}"
health_check {
path = "/api/__healthcheck"
matcher = 200
protocol = "HTTPS"
}
}
resource "aws_lb_listener" "kasm-alb-listener" {
load_balancer_arn = aws_lb.kasm-alb.arn
port = "443"
protocol = "HTTPS"
certificate_arn = "${aws_acm_certificate_validation.kasm-elb-certificate-validation.certificate_arn}"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.kasm-target-group.arn
}
}
resource "aws_lb_target_group_attachment" "kasm-target-group-attachment" {
count = "${var.num_webapps}"
target_group_arn = aws_lb_target_group.kasm-target-group.arn
target_id = aws_instance.kasm-web-app[count.index].id
port = 443
}
resource "aws_route53_record" "kasm-route53-elb-record" {
zone_id = data.aws_route53_zone.kasm-route53-zone.zone_id
name = "${var.zone_name}-lb.${var.aws_domain_name}"
type = "A"
alias {
name = aws_lb.kasm-alb.dns_name
zone_id = aws_lb.kasm-alb.zone_id
evaluate_target_health = true
}
}
resource "aws_route53_record" "kasm-app-url" {
zone_id = data.aws_route53_zone.kasm-route53-zone.zone_id
name = "${var.aws_domain_name}"
type = "A"
set_identifier = "${var.project_name}-${var.zone_name}-set-id"
alias {
name = aws_lb.kasm-alb.dns_name
zone_id = aws_lb.kasm-alb.zone_id
evaluate_target_health = true
}
latency_routing_policy {
region = "${var.aws_region}"
}
}
resource "aws_route53_health_check" "kasm-elb-hc" {
fqdn = "${var.zone_name}-lb.${var.aws_domain_name}"
port = 443
type = "HTTPS"
resource_path = "/api/__healthcheck"
failure_threshold = "5"
request_interval = "30"
tags = {
Name = "hc-${var.zone_name}-lb.${var.aws_domain_name}"
}
}

View file

@ -0,0 +1,26 @@
resource "aws_instance" "kasm-guac" {
count = var.num_guac_nodes
ami = var.ec2_ami
instance_type = var.guac_instance_type
vpc_security_group_ids = [data.aws_security_group.data-kasm_guac_sg.id]
subnet_id = data.aws_subnet.data-kasm_guac_subnet.id
key_name = var.aws_key_pair
associate_public_ip_address = false
root_block_device {
volume_size = 120
}
user_data = templatefile("${path.module}/userdata/guac_bootstrap.sh",
{
kasm_build_url = var.kasm_build
swap_size = var.swap_size
manager_address = local.private_lb_hostname
service_registration_token = var.service_registration_token
}
)
tags = {
Name = "${var.project_name}-${var.kasm_zone_name}-kasm-guac"
}
}

View file

@ -1,8 +0,0 @@
provider "aws" {
region = "${var.aws_region}"
access_key = "${var.aws_access_key}"
secret_key = "${var.aws_secret_key}"
}
data "aws_availability_zones" "available" {
state = "available"
}

View file

@ -1,22 +1,14 @@
resource "aws_nat_gateway" "gw" {
allocation_id = "${aws_eip.nat_gateway_eip.id}"
subnet_id = "${aws_subnet.kasm-agent-subnet.id}"
}
resource "aws_eip" "nat_gateway_eip" {
vpc = true
}
resource "aws_route_table" "r" {
vpc_id = "${aws_vpc.kasm-default-vpc.id}"
resource "aws_nat_gateway" "agent_and_guac_natgw" {
allocation_id = aws_eip.nat_gateway_eip.id
subnet_id = data.aws_subnet.data-kasm_webapp_subnets[0].id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_nat_gateway.gw.id
}
depends_on = [data.aws_internet_gateway.data-kasm-default-ig]
}
resource "aws_route_table_association" "a" {
subnet_id = aws_subnet.kasm-use-natgw-subnet.id
route_table_id = aws_route_table.r.id
}
data "aws_nat_gateway" "data-agent_and_guac_natgw" {
id = aws_nat_gateway.agent_and_guac_natgw.id
}

View file

@ -0,0 +1,93 @@
locals {
private_lb_hostname = "${var.kasm_zone_name}-private-lb.${var.aws_domain_name}"
}
resource "aws_lb" "kasm-private-alb" {
name = "${var.project_name}-private-lb"
internal = true
load_balancer_type = "application"
security_groups = [data.aws_security_group.data-kasm_default_elb_sg.id]
subnets = data.aws_subnet.data-kasm_webapp_subnets[*].id
access_logs {
bucket = data.aws_s3_bucket.data-kasm_s3_logs_bucket.bucket
enabled = true
}
tags = {
Name = "${var.project_name}-kasm-private-lb"
}
}
data "aws_lb" "data-kasm_private_alb" {
arn = aws_lb.kasm-private-alb.arn
}
resource "aws_lb_target_group" "kasm-private-target-group" {
name = "${var.project_name}-private-target-group"
port = 443
protocol = "HTTPS"
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
health_check {
path = "/api/__healthcheck"
matcher = 200
protocol = "HTTPS"
}
tags = {
Name = "${var.project_name}-kasm-private-tg"
}
}
data "aws_lb_target_group" "data-kasm_private_target_group" {
arn = aws_lb_target_group.kasm-private-target-group.arn
}
resource "aws_lb_listener" "kasm-private-alb-listener" {
load_balancer_arn = data.aws_lb.data-kasm_private_alb.arn
port = "443"
protocol = "HTTPS"
certificate_arn = aws_acm_certificate_validation.kasm-elb-certificate-validation.certificate_arn
default_action {
type = "forward"
target_group_arn = data.aws_lb_target_group.data-kasm_private_target_group.arn
}
tags = {
Name = "${var.project_name}-kasm-private-https-listener"
}
}
resource "aws_lb_target_group_attachment" "kasm-private-target-group-attachment" {
count = var.num_webapps
target_group_arn = data.aws_lb_target_group.data-kasm_private_target_group.arn
target_id = data.aws_instance.data-kasm_web_app[count.index].id
port = 443
}
resource "aws_route53_record" "kasm-route53-private-elb-record" {
zone_id = data.aws_route53_zone.kasm-route53-zone.zone_id
name = local.private_lb_hostname
type = "A"
alias {
name = data.aws_lb.data-kasm_private_alb.dns_name
zone_id = data.aws_lb.data-kasm_private_alb.zone_id
evaluate_target_health = true
}
}
resource "aws_route53_health_check" "kasm-private-elb-hc" {
fqdn = local.private_lb_hostname
port = 443
type = "HTTPS"
resource_path = "/api/__healthcheck"
failure_threshold = "5"
request_interval = "30"
tags = {
Name = "hc-${var.kasm_zone_name}-private-lb.${var.aws_domain_name}"
}
}

View file

@ -0,0 +1,8 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
#version = "4.56.0"
}
}
}

View file

@ -0,0 +1,126 @@
resource "aws_lb" "kasm-alb" {
name = "${var.project_name}-lb"
internal = false
load_balancer_type = "application"
security_groups = [data.aws_security_group.data-kasm_default_elb_sg.id]
subnets = data.aws_subnet.data-kasm_webapp_subnets[*].id
access_logs {
bucket = data.aws_s3_bucket.data-kasm_s3_logs_bucket.bucket
enabled = true
}
tags = {
Name = "${var.project_name}-kasm-public-lb"
}
}
data "aws_lb" "data-kasm_alb" {
arn = aws_lb.kasm-alb.arn
}
resource "aws_lb_target_group" "kasm-target-group" {
name = "${var.project_name}-target-group"
port = 443
protocol = "HTTPS"
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
health_check {
path = "/api/__healthcheck"
matcher = 200
protocol = "HTTPS"
}
tags = {
Name = "${var.project_name}-kasm-public-tg"
}
}
data "aws_lb_target_group" "data-kasm_target_group" {
arn = aws_lb_target_group.kasm-target-group.arn
}
resource "aws_lb_listener" "kasm-alb-listener" {
load_balancer_arn = data.aws_lb.data-kasm_alb.arn
port = "443"
protocol = "HTTPS"
certificate_arn = aws_acm_certificate_validation.kasm-elb-certificate-validation.certificate_arn
default_action {
type = "forward"
target_group_arn = data.aws_lb_target_group.data-kasm_target_group.arn
}
tags = {
Name = "${var.project_name}-kasm-public-https-listener"
}
}
resource "aws_lb_listener" "kasm_alb_listener_http" {
load_balancer_arn = data.aws_lb.data-kasm_alb.arn
port = "80"
protocol = "HTTP"
default_action {
type = "redirect"
redirect {
port = "443"
protocol = "HTTPS"
status_code = "HTTP_301"
}
}
tags = {
Name = "${var.project_name}-kasm-public-http-listener"
}
}
resource "aws_lb_target_group_attachment" "kasm-target-group-attachment" {
count = var.num_webapps
target_group_arn = data.aws_lb_target_group.data-kasm_target_group.arn
target_id = data.aws_instance.data-kasm_web_app[count.index].id
port = 443
}
resource "aws_route53_record" "kasm-route53-elb-record" {
zone_id = data.aws_route53_zone.kasm-route53-zone.zone_id
name = "${var.kasm_zone_name}-lb.${var.aws_domain_name}"
type = "A"
alias {
name = aws_lb.kasm-alb.dns_name
zone_id = aws_lb.kasm-alb.zone_id
evaluate_target_health = true
}
}
resource "aws_route53_record" "kasm-app-url" {
zone_id = data.aws_route53_zone.kasm-route53-zone.zone_id
name = var.aws_domain_name
type = "A"
set_identifier = "${var.project_name}-${var.kasm_zone_name}-set-id"
alias {
name = data.aws_lb.data-kasm_alb.dns_name
zone_id = data.aws_lb.data-kasm_alb.zone_id
evaluate_target_health = true
}
latency_routing_policy {
region = var.aws_region
}
}
resource "aws_route53_health_check" "kasm-elb-hc" {
fqdn = "${var.kasm_zone_name}-lb.${var.aws_domain_name}"
port = 443
type = "HTTPS"
resource_path = "/api/__healthcheck"
failure_threshold = "5"
request_interval = "30"
tags = {
Name = "hc-${var.kasm_zone_name}-lb.${var.aws_domain_name}"
}
}

View file

@ -0,0 +1,54 @@
resource "aws_route_table" "internet_access" {
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
route {
cidr_block = var.anywhere
gateway_id = data.aws_internet_gateway.data-kasm-default-ig.id
}
tags = {
Name = "${var.project_name}-kasm-default-route"
}
}
data "aws_route_table" "data-internet_gateway_route_table" {
route_table_id = aws_route_table.internet_access.id
}
resource "aws_route_table_association" "webapp_route_association" {
count = var.num_webapps
subnet_id = data.aws_subnet.data-kasm_webapp_subnets[count.index].id
route_table_id = data.aws_route_table.data-internet_gateway_route_table.id
}
resource "aws_route_table_association" "db_route_association" {
subnet_id = data.aws_subnet.data-kasm_db_subnet.id
route_table_id = data.aws_route_table.data-internet_gateway_route_table.id
}
resource "aws_route_table" "nat_route_table" {
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
route {
cidr_block = var.anywhere
gateway_id = data.aws_nat_gateway.data-agent_and_guac_natgw.id
}
tags = {
Name = "${var.project_name}-kasm-natgw-route"
}
}
data "aws_route_table" "data-nat_route_table" {
route_table_id = aws_route_table.nat_route_table.id
}
resource "aws_route_table_association" "agent_nat_route_table_association" {
subnet_id = data.aws_subnet.data-kasm_agent_subnet.id
route_table_id = data.aws_route_table.data-nat_route_table.id
}
resource "aws_route_table_association" "guac_nat_route_table_association" {
subnet_id = data.aws_subnet.data-kasm_guac_subnet.id
route_table_id = data.aws_route_table.data-nat_route_table.id
}

View file

@ -1,20 +1,26 @@
resource "aws_security_group" "kasm-default-elb-sg" {
name = "${var.project_name}-kasm-allow-elb-access"
description = "Security Group for ELB"
vpc_id = "${aws_vpc.kasm-default-vpc.id}"
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
cidr_blocks = var.web_access_cidrs
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = var.web_access_cidrs
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
cidr_blocks = [var.anywhere]
}
tags = {
@ -22,107 +28,147 @@ resource "aws_security_group" "kasm-default-elb-sg" {
}
}
data "aws_security_group" "data-kasm_default_elb_sg" {
id = aws_security_group.kasm-default-elb-sg.id
}
resource "aws_security_group" "kasm-webapp-sg" {
name = "${var.project_name}-${var.zone_name}-kasm-webapp"
name = "${var.project_name}-${var.kasm_zone_name}-kasm-webapp"
description = "Allow access to webapps"
vpc_id = "${aws_vpc.kasm-default-vpc.id}"
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["${var.ssh_access_cidr}"]
cidr_blocks = var.ssh_access_cidrs
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
security_groups = ["${aws_security_group.kasm-default-elb-sg.id}"]
from_port = 443
to_port = 443
protocol = "tcp"
security_groups = [data.aws_security_group.data-kasm_default_elb_sg.id]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["${aws_subnet.kasm-agent-subnet.cidr_block}"]
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = [
data.aws_subnet.data-kasm_agent_subnet.cidr_block,
data.aws_subnet.data-kasm_guac_subnet.cidr_block
]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
cidr_blocks = [var.anywhere]
}
}
data "aws_security_group" "data-kasm_webapp_sg" {
id = aws_security_group.kasm-webapp-sg.id
}
resource "aws_security_group" "kasm-agent-sg" {
name = "${var.project_name}-${var.zone_name}-kasm-agent-access"
name = "${var.project_name}-${var.kasm_zone_name}-kasm-agent-access"
description = "Allow access to agents"
vpc_id = "${aws_vpc.kasm-default-vpc.id}"
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["${var.ssh_access_cidr}"]
cidr_blocks = var.ssh_access_cidrs
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["${aws_subnet.kasm-webapp-subnet.cidr_block}", "${aws_subnet.kasm-webapp-subnet-2.cidr_block}" ]
cidr_blocks = data.aws_subnet.data-kasm_webapp_subnets[*].cidr_block
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
cidr_blocks = [var.anywhere]
}
}
data "aws_security_group" "data-kasm_agent_sg" {
id = aws_security_group.kasm-agent-sg.id
}
resource "aws_security_group" "kasm-db-sg" {
name = "${var.project_name}-${var.zone_name}-kasm-db-access"
name = "${var.project_name}-${var.kasm_zone_name}-kasm-db-access"
description = "Allow access to webapps"
vpc_id = "${aws_vpc.kasm-default-vpc.id}"
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["${var.ssh_access_cidr}"]
cidr_blocks = var.ssh_access_cidrs
}
ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
cidr_blocks = ["${aws_subnet.kasm-webapp-subnet.cidr_block}"]
cidr_blocks = data.aws_subnet.data-kasm_webapp_subnets[*].cidr_block
}
ingress {
from_port = 6379
to_port = 6379
protocol = "tcp"
cidr_blocks = ["${aws_subnet.kasm-webapp-subnet.cidr_block}"]
cidr_blocks = data.aws_subnet.data-kasm_webapp_subnets[*].cidr_block
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
cidr_blocks = [var.anywhere]
}
}
data "aws_security_group" "data-kasm_db_sg" {
id = aws_security_group.kasm-db-sg.id
}
resource "aws_security_group" "kasm-guac-sg" {
name = "${var.project_name}-${var.kasm_zone_name}-kasm-guac-access"
description = "Allow access to guac RDP nodes"
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = var.ssh_access_cidrs
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = data.aws_subnet.data-kasm_webapp_subnets[*].cidr_block
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = [var.anywhere]
}
}
data "aws_security_group" "data-kasm_guac_sg" {
id = aws_security_group.kasm-guac-sg.id
}

View file

@ -1,49 +1,69 @@
locals {
kasm_vpc_subnet_cidr_mask = split("/", var.vpc_subnet_cidr)[1]
kasm_server_subnet_cidr_calculation = (8 - (local.kasm_vpc_subnet_cidr_mask - 16))
kasm_server_subnet_cidr_size = local.kasm_server_subnet_cidr_calculation < 3 ? 3 : local.kasm_server_subnet_cidr_calculation
kasm_agent_subnet_id = (var.num_webapps + 1)
}
## Will create Agent subnet x.x.0.x/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/21)
resource "aws_subnet" "kasm-db-subnet" {
vpc_id = "${aws_vpc.kasm-default-vpc.id}"
cidr_block = "10.${var.master_subnet_id}.10.0/24"
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, 0)
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-kasm-db-subnet"
}
}
resource "aws_subnet" "kasm-webapp-subnet" {
vpc_id = "${aws_vpc.kasm-default-vpc.id}"
cidr_block = "10.${var.master_subnet_id}.20.0/24"
availability_zone = data.aws_availability_zones.available.names[0]
data "aws_subnet" "data-kasm_db_subnet" {
id = aws_subnet.kasm-db-subnet.id
}
## Will create WebApp subnets x.x.1.x/24 and x.x.2.x/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/21)
resource "aws_subnet" "kasm-webapp-subnets" {
count = var.num_webapps
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, (count.index + 1))
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-kasm-webapp-subnet"
}
}
resource "aws_subnet" "kasm-webapp-subnet-2" {
vpc_id = "${aws_vpc.kasm-default-vpc.id}"
cidr_block = "10.${var.master_subnet_id}.30.0/24"
availability_zone = data.aws_availability_zones.available.names[1]
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-kasm-webapp-subnet"
}
data "aws_subnet" "data-kasm_webapp_subnets" {
count = var.num_webapps
id = aws_subnet.kasm-webapp-subnets[count.index].id
}
## Will create Agent subnet x.x.3.x/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/21)
resource "aws_subnet" "kasm-agent-subnet" {
vpc_id = "${aws_vpc.kasm-default-vpc.id}"
cidr_block = "10.${var.master_subnet_id}.40.0/24"
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, local.kasm_agent_subnet_id)
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-kasm-agent-subnet"
Name = "${var.project_name}-agent-natgw-subnet"
}
}
resource "aws_subnet" "kasm-use-natgw-subnet" {
vpc_id = "${aws_vpc.kasm-default-vpc.id}"
cidr_block = "10.${var.master_subnet_id}.50.0/24"
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-natgw-kasm-subnet"
}
data "aws_subnet" "data-kasm_agent_subnet" {
id = aws_subnet.kasm-agent-subnet.id
}
## Will create Guac subnet x.x.4.x/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/21)
resource "aws_subnet" "kasm-guac-subnet" {
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, (local.kasm_agent_subnet_id + 1))
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-guac-natgw-subnet"
}
}
data "aws_subnet" "data-kasm_guac_subnet" {
id = aws_subnet.kasm-guac-subnet.id
}

View file

@ -0,0 +1,29 @@
#!/bin/bash
set -ex
echo "Starting Kasm Workspaces Agent Install"
/bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=${swap_size}
/sbin/mkswap /var/swap.1
chmod 600 /var/swap.1
/sbin/swapon /var/swap.1
echo '/var/swap.1 swap swap defaults 0 0' | tee -a /etc/fstab
cd /tmp
PRIVATE_IP=(`hostname -I | cut -d' ' -f1 | tr -d '\\n'`)
wget ${kasm_build_url} -O kasm_workspaces.tar.gz
tar -xf kasm_workspaces.tar.gz
echo "Waiting for Kasm WebApp availability..."
while ! (curl -k https://${manager_address}/api/__healthcheck 2>/dev/null | grep -q true)
do
echo "Waiting for API server..."
sleep 5
done
echo "WebApp is alive"
bash kasm_release/install.sh -S agent -e -p $PRIVATE_IP -m ${manager_address} -M ${manager_token}
echo "Done"

View file

@ -0,0 +1,20 @@
#!/bin/bash
set -ex
echo "Starting Kasm Workspaces Install"
/bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=${swap_size}
/sbin/mkswap /var/swap.1
chmod 600 /var/swap.1
/sbin/swapon /var/swap.1
echo '/var/swap.1 swap swap defaults 0 0' | tee -a /etc/fstab
cd /tmp
PRIVATE_IP=(`hostname -I | cut -d ' ' -f1 | tr -d '\\n'`)
wget ${kasm_build_url} -O kasm_workspaces.tar.gz
tar -xf kasm_workspaces.tar.gz
bash kasm_release/install.sh -S db -e -Q ${database_password} -R ${redis_password} -U ${user_password} -P ${admin_password} -M ${manager_token} -k ${service_registration_token}
echo "Done"

View file

@ -0,0 +1,29 @@
#!/bin/bash
set -ex
echo "Starting Kasm Workspaces Agent Install"
/bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=${swap_size}
/sbin/mkswap /var/swap.1
chmod 600 /var/swap.1
/sbin/swapon /var/swap.1
echo '/var/swap.1 swap swap defaults 0 0' | tee -a /etc/fstab
cd /tmp
PRIVATE_IP=(`hostname -I | cut -d ' ' -f1 | tr -d '\\n'`)
wget ${kasm_build_url} -O kasm_workspaces.tar.gz
tar -xf kasm_workspaces.tar.gz
echo "Waiting for Kasm WebApp availability..."
while ! (curl -k https://${manager_address}/api/__healthcheck 2>/dev/null | grep -q true)
do
echo "Waiting for API server..."
sleep 5
done
echo "WebApp is alive"
bash kasm_release/install.sh -S guac -e -p $PRIVATE_IP -n ${manager_address} -k ${service_registration_token}
echo "Done"

View file

@ -0,0 +1,36 @@
#!/bin/bash
set -ex
echo "Starting Kasm Workspaces Install"
/bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=${swap_size}
/sbin/mkswap /var/swap.1
chmod 600 /var/swap.1
/sbin/swapon /var/swap.1
echo '/var/swap.1 swap swap defaults 0 0' | tee -a /etc/fstab
cd /tmp
PRIVATE_IP=(`hostname -I | cut -d ' ' -f1 | tr -d '\\n'`)
wget ${kasm_build_url} -O kasm_workspaces.tar.gz
tar -xf kasm_workspaces.tar.gz
echo "Checking for Kasm DB and Redis..."
apt-get update && apt-get install -y netcat
while ! nc -w 1 -z ${db_ip} 5432; do
echo "Database not ready..."
sleep 5
done
echo "DB is alive"
while ! nc -w 1 -z ${db_ip} 6379; do
echo "Redis not ready..."
sleep 5
done
echo "Redis is alive"
bash kasm_release/install.sh -S app -e -z ${zone_name} -q "${db_ip}" -Q ${database_password} -R ${redis_password}
echo "Done"

View file

@ -1,89 +1,147 @@
variable "project_name" {
description = "The name of the deployment (e.g dev, staging). A short single word"
type = string
}
variable "aws_domain_name" {
description = "The Route53 Zone used for the dns entries. This must already exist in the AWS account. (e.g dev.kasm.contoso.com). The deployment will be accessed via this zone name via https"
type = string
}
variable "aws_key_pair" {
description = "The name of an aws keypair to use."
type = string
}
variable "aws_access_key" {
description = "The AWS access key used for deployment"
variable "vpc_subnet_cidr" {
description = "The subnet CIDR to use for the VPC"
type = string
default = "10.0.0.0/16"
}
variable "aws_secret_key" {
description = "The AWS secret key used for deployment"
variable "num_webapps" {
description = "The number of WebApp role servers to create in the deployment"
type = number
default = 2
}
variable "num_agents" {
default = "2"
description = "The number of Agent Role Servers to create in the deployment"
type = number
default = 2
}
variable "agent_instance_type" {
default = "t3.medium"
description = "The instance type for the Agents"
}
variable "num_webapps" {
default = "2"
description = "The number of WebApp role servers to create in the deployment"
variable "num_guac_nodes" {
description = "The number of Agent Role Servers to create in the deployment"
type = number
default = 2
}
variable "webapp_instance_type" {
default = "t3.small"
description = "The instance type for the webapps"
type = string
default = "t3.small"
}
variable "db_instance_type" {
default = "t3.small"
description = "The instance type for the Database"
type = string
default = "t3.small"
}
variable "ssh_access_cidr" {
default = "0.0.0.0/0"
variable "agent_instance_type" {
description = "The instance type for the Agents"
type = string
default = "t3.medium"
}
variable "guac_instance_type" {
description = "The instance type for the Guacamole RDP nodes"
type = string
default = "t3.medium"
}
variable "ssh_access_cidrs" {
description = "CIDR notation of the bastion host allowed to SSH in to the machines"
type = list(string)
default = ["0.0.0.0/0"]
}
variable "web_access_cidrs" {
description = "CIDR notation of the bastion host allowed to SSH in to the machines"
type = list(string)
default = ["0.0.0.0/0"]
}
variable "aws_region" {
default = "us-east-1"
description = "The AWS region for the deployment. (e.g us-east-1)"
type = string
}
variable "ec2_ami" {
default = "ami-0747bdcabd34c712a"
description = "The AMI used for the EC2 nodes. Recommended Ubuntu 18.04 LTS."
description = "The AMI used for the EC2 nodes. Recommended Ubuntu 20.04 LTS."
type = string
}
variable "kasm_build" {
description = "The URL for the Kasm Workspaces build"
type = string
}
variable "master_subnet_id" {
default = "0"
description = "The 2nd octect of VPC subnet"
variable "swap_size" {
description = "The amount of swap (in MB) to configure inside the compute instances"
type = number
}
variable "database_password" {
description = "The password for the database. No special characters"
type = string
sensitive = true
}
variable "redis_password" {
description = "The password for the database. No special characters"
description = "The password for the Redis server. No special characters"
type = string
sensitive = true
}
variable "user_password" {
description = "The password for the database. No special characters"
description = "The standard (non administrator) user password. No special characters"
type = string
sensitive = true
}
variable "admin_password" {
description = "The password for the database. No special characters"
description = "The administrative user password. No special characters"
type = string
sensitive = true
}
variable "manager_token" {
description = "The password for the database. No special characters"
description = "The manager token value for Agents to authenticate to webapps. No special characters"
type = string
sensitive = true
}
variable "zone_name" {
default = "default"
description="A name given to the kasm deployment Zone"
variable "service_registration_token" {
description = "The service registration token value for Guac RDP servers to authenticate to webapps. No special characters"
type = string
sensitive = true
}
variable "kasm_zone_name" {
description = "A name given to the kasm deployment Zone"
type = string
default = "default"
}
variable "anywhere" {
description = "Anywhere route subnet"
type = string
default = "0.0.0.0/0"
validation {
condition = can(cidrhost(var.anywhere, 0))
error_message = "Anywhere variable must be valid IPv4 CIDR - usually 0.0.0.0/0 for all default routes and default Security Group access."
}
}

View file

@ -1,22 +1,23 @@
resource "aws_vpc" "kasm-default-vpc" {
cidr_block = "10.${var.master_subnet_id}.0.0/16"
cidr_block = var.vpc_subnet_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.project_name}-kasm-db-vpc"
}
}
data "aws_vpc" "data-kasm-default-vpc" {
id = aws_vpc.kasm-default-vpc.id
}
resource "aws_internet_gateway" "kasm-default-ig" {
vpc_id = "${aws_vpc.kasm-default-vpc.id}"
vpc_id = data.aws_vpc.data-kasm-default-vpc.id
tags = {
Name = "${var.project_name}-kasm-ig"
}
}
resource "aws_route" "internet_access" {
route_table_id = "${aws_vpc.kasm-default-vpc.main_route_table_id}"
destination_cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.kasm-default-ig.id}"
data "aws_internet_gateway" "data-kasm-default-ig" {
internet_gateway_id = aws_internet_gateway.kasm-default-ig.id
}

View file

@ -1,38 +1,33 @@
resource "aws_instance" "kasm-web-app" {
count = "${var.num_webapps}"
ami = "${var.ec2_ami}"
instance_type = "${var.webapp_instance_type}"
vpc_security_group_ids = ["${aws_security_group.kasm-webapp-sg.id}"]
subnet_id = "${aws_subnet.kasm-webapp-subnet.id}"
key_name = "${var.aws_key_pair}"
count = var.num_webapps
ami = var.ec2_ami
instance_type = var.webapp_instance_type
vpc_security_group_ids = [data.aws_security_group.data-kasm_webapp_sg.id]
subnet_id = data.aws_subnet.data-kasm_webapp_subnets[count.index].id
key_name = var.aws_key_pair
associate_public_ip_address = true
root_block_device {
volume_size = "40"
volume_size = 40
}
user_data = <<-EOF
#!/bin/bash
set -x
fallocate -l 4g /mnt/kasm.swap
chmod 600 /mnt/kasm.swap
mkswap /mnt/kasm.swap
swapon /mnt/kasm.swap
echo '/mnt/kasm.swap swap swap defaults 0 0' | tee -a /etc/fstab
cd /tmp
wget ${var.kasm_build}
tar xvf kasm_*.tar.gz
user_data = templatefile("${path.module}/userdata/webapp_bootstrap.sh",
{
kasm_build_url = var.kasm_build
db_ip = data.aws_instance.data-kasm_db.private_ip
database_password = var.database_password
redis_password = var.redis_password
swap_size = var.swap_size
zone_name = "default"
}
)
echo "Checking for Kasm DB..."
while ! nc -w 1 -z ${aws_instance.kasm-db.private_ip} 5432; do
echo "Not Ready..."
sleep 5
done
echo "DB is alive"
bash kasm_release/install.sh -S app -e -z ${var.zone_name} -q "${aws_instance.kasm-db.private_ip}" -Q ${var.database_password} -R ${var.redis_password}
EOF
tags = {
Name = "${var.project_name}-${var.zone_name}-kasm-webapp"
Name = "${var.project_name}-${var.kasm_zone_name}-kasm-webapp"
}
}
data "aws_instance" "data-kasm_web_app" {
count = var.num_webapps
instance_id = aws_instance.kasm-web-app[count.index].id
}

18
aws/standard/provider.tf Normal file
View file

@ -0,0 +1,18 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
#version = "4.56.0"
}
}
}
provider "aws" {
access_key = var.aws_access_key
secret_key = var.aws_secret_key
region = var.aws_region
default_tags {
tags = var.aws_default_tags
}
}

View file

@ -0,0 +1,43 @@
## AWS Environment settings
aws_key_pair = "troy-common-ssh"
aws_region = "us-east-1"
aws_domain_name = "bryan-test2.sandbox1.kasmweb.net"
vpc_subnet_cidr = "10.0.0.0/16"
## Kasm deployment settings
kasm_zone_name = "default"
project_name = "contoso"
num_agents = 2
num_webapps = 2
num_guac_nodes = 1
## Kasm Server settings
agent_instance_type = "t3.medium"
guac_instance_type = "t3.medium"
webapp_instance_type = "t3.small"
db_instance_type = "t3.small"
ec2_ami = "ami-09cd747c78a9add63"
swap_size = 2048
## VM Access subnets
ssh_access_cidrs = ["0.0.0.0/0"]
web_access_cidrs = ["0.0.0.0/0"]
## Kasm passwords
database_password = "changeme"
redis_password = "changeme"
user_password = "changeme"
admin_password = "changeme"
manager_token = "changeme"
service_registration_token = "changeme"
## Kasm download URL
kasm_build = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.12.0.d4fd8a.tar.gz"
## Default tags for all AWS resources
aws_default_tags = {
Deployed_by = "Terraform"
Deployment_type = "Multi-Server"
Service_name = "Kasm Workspaces"
Kasm_version = "1.12"
}

284
aws/standard/variables.tf Normal file
View file

@ -0,0 +1,284 @@
variable "aws_access_key" {
description = "The AWS access key used for deployment"
type = string
sensitive = true
validation {
condition = can(regex("^([A-Z0-9]{20})", var.aws_access_key))
error_message = "The aws_access_key variable must be a valid AWS Access Key (e.g. AKIAJSIE27KKMHXI3BJQ)."
}
}
variable "aws_secret_key" {
description = "The AWS secret key used for deployment"
type = string
sensitive = true
validation {
condition = can(regex("^([a-zA-Z0-9+\\/-]{40})", var.aws_secret_key))
error_message = "The aws_secret_key variable must be a valid AWS Secret Key value (e.g. wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY)"
}
}
variable "aws_region" {
description = "The AWS Region used for deployment"
type = string
default = "us-east-1"
validation {
condition = can(regex("^([a-z]{2}-[a-z]{4,}-[\\d]{1})$", var.aws_region))
error_message = "The aws_region must be a valid Amazon Web Services (AWS) Region name, e.g. us-east-1"
}
}
variable "project_name" {
description = "The name of the deployment (e.g dev, staging). A short single word"
type = string
validation {
condition = can(regex("^[a-z]{4,15}", var.project_name))
error_message = "The project_name variable can only be one word between 4 and 15 lower-case letters since it is a seed value in multiple object names."
}
}
variable "kasm_zone_name" {
description = "A name given to the kasm deployment Zone"
type = string
default = "default"
validation {
condition = can(regex("^[a-z0-9A-Z-_]{4,15}", var.kasm_zone_name))
error_message = "The kasm_zone_name variable can only be one word between 4 and 15 characters consisting of letters, numbers, dash (-), and underscore (_)."
}
}
variable "aws_domain_name" {
description = "The Route53 Zone used for the dns entries. This must already exist in the AWS account. (e.g dev.kasm.contoso.com). The deployment will be accessed via this zone name via https"
type = string
validation {
condition = can(regex("(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]", var.aws_domain_name))
error_message = "There are invalid characters in the aws_domain_name - it must be a valid domain name."
}
}
variable "aws_key_pair" {
description = "The name of an aws keypair to use."
type = string
validation {
condition = can(regex("^[a-zA-Z0-9-_]{4,15}", var.aws_key_pair))
error_message = "The aws_key_pair variable contains invalid characters. Allowed values are between 4-15 characters consisting of letters, numbers, and dashes (-)."
}
}
variable "vpc_subnet_cidr" {
description = "The subnet CIDR to use for the VPC"
type = string
default = "10.0.0.0/16"
validation {
condition = can(cidrhost(var.vpc_subnet_cidr, 0))
error_message = "The VPC subnet must be valid IPv4 CIDR."
}
}
variable "swap_size" {
description = "The amount of swap (in MB) to configure inside the compute instances"
type = number
validation {
condition = var.swap_size >= 1024 && var.swap_size <= 8192 && floor(var.swap_size) == var.swap_size
error_message = "Swap size is the amount of disk space to use for Kasm in MB and must be an integer between 1024 and 8192."
}
}
variable "webapp_instance_type" {
description = "The instance type for the webapps"
type = string
default = "t3.small"
validation {
condition = can(regex("^(([a-z-]{1,3})(\\d{1,2})?(\\w{1,4})?)\\.(nano|micro|small|medium|metal|large|(2|3|4|6|8|9|10|12|16|18|24|32|48|56|112)?xlarge)", var.webapp_instance_type))
error_message = "Check the webapp_instance_type variable and ensure it is a valid AWS Instance type (https://aws.amazon.com/ec2/instance-types/)."
}
}
variable "db_instance_type" {
description = "The instance type for the Database"
type = string
default = "t3.small"
validation {
condition = can(regex("^(([a-z-]{1,3})(\\d{1,2})?(\\w{1,4})?)\\.(nano|micro|small|medium|metal|large|(2|3|4|6|8|9|10|12|16|18|24|32|48|56|112)?xlarge)", var.db_instance_type))
error_message = "Check the db_instance_type variable and ensure it is a valid AWS Instance type (https://aws.amazon.com/ec2/instance-types/)."
}
}
variable "agent_instance_type" {
description = "The instance type for the Agents"
type = string
default = "t3.medium"
validation {
condition = can(regex("^(([a-z-]{1,3})(\\d{1,2})?(\\w{1,4})?)\\.(nano|micro|small|medium|metal|large|(2|3|4|6|8|9|10|12|16|18|24|32|48|56|112)?xlarge)", var.agent_instance_type))
error_message = "Check the agent_instance_type variable and ensure it is a valid AWS Instance type (https://aws.amazon.com/ec2/instance-types/)."
}
}
variable "guac_instance_type" {
description = "The instance type for the Guacamole RDP nodes"
type = string
default = "t3.medium"
validation {
condition = can(regex("^(([a-z-]{1,3})(\\d{1,2})?(\\w{1,4})?)\\.(nano|micro|small|medium|metal|large|(2|3|4|6|8|9|10|12|16|18|24|32|48|56|112)?xlarge)", var.guac_instance_type))
error_message = "Check the guac_instance_type variable and ensure it is a valid AWS Instance type (https://aws.amazon.com/ec2/instance-types/)."
}
}
variable "num_webapps" {
description = "The number of WebApp role servers to create in the deployment"
type = number
default = 2
validation {
condition = var.num_webapps >= 1 && var.num_webapps <= 3 && floor(var.num_webapps) == var.num_webapps
error_message = "Acceptable number of webapps range between 1-3."
}
}
variable "num_agents" {
description = "The number of Agent Role Servers to create in the deployment"
type = number
default = 2
validation {
condition = var.num_agents >= 0 && var.num_agents <= 100 && floor(var.num_agents) == var.num_agents
error_message = "Acceptable number of Kasm Agents range between 0-100."
}
}
variable "num_guac_nodes" {
description = "The number of Agent Role Servers to create in the deployment"
type = number
default = 1
validation {
condition = var.num_guac_nodes >= 0 && var.num_guac_nodes <= 100 && floor(var.num_guac_nodes) == var.num_guac_nodes
error_message = "Acceptable number of Kasm Agents range between 0-100."
}
}
variable "ssh_access_cidrs" {
description = "CIDR notation of the bastion host allowed to SSH in to the machines"
type = list(string)
default = ["0.0.0.0/0"]
validation {
condition = can([for subnet in var.ssh_access_cidrs : cidrhost(subnet, 0)])
error_message = "One of the subnets provided in the ssh_access_cidr variable is invalid."
}
}
variable "web_access_cidrs" {
description = "CIDR notation of the bastion host allowed to SSH in to the machines"
type = list(string)
default = ["0.0.0.0/0"]
validation {
condition = can([for subnet in var.web_access_cidrs : cidrhost(subnet, 0)])
error_message = "One of the subnets provided in the load_balancer_public_access variable is invalid."
}
}
variable "ec2_ami" {
description = "The AMI used for the EC2 nodes. Recommended Ubuntu 20.04 LTS."
type = string
validation {
condition = can(regex("^(ami-[a-f0-9]{17})", var.ec2_ami))
error_message = "Please verify that your AMI is in the correct format for AWS (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami.html)."
}
}
variable "database_password" {
description = "The password for the database. No special characters"
type = string
sensitive = true
validation {
condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.database_password))
error_message = "The Database Password should be a string between 12 and 30 letters or numbers with no special characters."
}
}
variable "redis_password" {
description = "The password for the Redis server. No special characters"
type = string
sensitive = true
validation {
condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.redis_password))
error_message = "The Redis Password should be a string between 12 and 30 letters or numbers with no special characters."
}
}
variable "user_password" {
description = "The standard (non administrator) user password. No special characters"
type = string
sensitive = true
validation {
condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.user_password))
error_message = "The User Password should be a string between 12 and 30 letters or numbers with no special characters."
}
}
variable "admin_password" {
description = "The administrative user password. No special characters"
type = string
sensitive = true
validation {
condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.admin_password))
error_message = "The Admin password should be a string between 12 and 30 letters or numbers with no special characters."
}
}
variable "manager_token" {
description = "The manager token value for Agents to authenticate to webapps. No special characters"
type = string
sensitive = true
validation {
condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.manager_token))
error_message = "The Manager Token should be a string between 12 and 30 letters or numbers with no special characters."
}
}
variable "service_registration_token" {
description = "The service registration token value for Guac RDP servers to authenticate to webapps. No special characters"
type = string
sensitive = true
validation {
condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.service_registration_token))
error_message = "The Service Registration Token should be a string between 12 and 30 letters or numbers with no special characters."
}
}
## Non-validated variables
variable "kasm_build" {
description = "The URL for the Kasm Workspaces build"
type = string
}
variable "aws_default_tags" {
description = "Default tags to apply to all AWS resources for this deployment"
type = map(any)
default = {
Service_name = "Kasm Workspaces"
Kasm_version = "1.12"
}
}

View file

@ -23,18 +23,40 @@ This project will launch a droplet and allow connections using the ssh keys defi
terraform init
2. Open `deployment.tf` and update the variables. The variable definitions and descriptions
can be found in `module/variables.tf`
2. Open `settings.tf` and update the variables. The variable definitions and descriptions can be found in `variables.tf`.
> ***NOTE:*** This document assumes you are using a separate file named `secrets.tfvars` for the DigitalOcean token credential. The .gitignore file in this repository will ignore any files named `secrets.tfvars` since they are expected to have sensitive values in them. This will prevent you from accidentally committing them to source control. Refer to the [Generating a DigitalOcean Access Token](https://docs.digitalocean.com/reference/api/create-personal-access-token/) document if you need help with this process.
3. Verify the configuration
terraform plan
terraform plan -var-file settings.tfvars -var-file secrets.tfvars
4. Deploy
terraform apply
terraform apply -var-file settings.tfvars -var-file secrets.tfvars
5. Login to the Deployment as an Admin via the domain defined e.g `https://kasm.contoso.com`. Single server installs
download all workspaces images during the install process so it may take ~15 minutes for the server to fully come online.
5. Login to the Deployment as an Admin via the domain defined e.g `https://kasm.contoso.com`. Single server installs download all workspaces images during the install process so it may take ~15 minutes for the server to fully come online.
# OCI Terraform Variable definitions
| Variable | Description | Variable type | Example |
|:--------:|-------------|---------------|---------|
| `digital_ocean_token` | The DigitalOcean authentication token. | String | `"dop_v1_EXAMPLEb8f85b081895f489921abbf26e64d7f3a0e581f8a1d8d532a5ba553"` |
| `digital_ocean_region` | The DigitalOcean region where you wish to deploy Kasm | String | `"nyc3"` |
| `do_domain_name` | The domain name that users will use to access kasm. | String | `"kasm.contoso.com"` |
| `ssh_key_fingerprints` | A list of DigitalOcean SSH fingerprints to use for SSH access to your Kasm server. | List(String) | `["66:e5:d1:85:cd:ba:ca:6a:d0:76:86:ef:1c:11:63:97"]` |
| `project_name` | The name of the deployment (e.g dev, staging). A short single word of up to 15 characters. | String | `"kasm"` |
| `oci_domain_name` | The public Zone used for the dns entries. This must already exist in the OCI account. (e.g kasm.contoso.com). The deployment will be accessed via this zone name using https. | String | `"kasm.contoso.com"` |
| `vpc_subnet_cidr` | The VPC Subnet CIDR where you wish to deploy Kasm | String | `"10.0.0.0/24"` |
| `digital_ocean_droplet_slug` | The Default Digital Ocean Droplet Slug: https://slugs.do-api.dev/ | String | `"s-2vcpu-4gb-intel"` |
| `digital_ocean_image` | Default Image for Ubuntu 20.04 LTS with Docker | String | `"docker-20-04"` |
| `kasm_build_url` | The download URL for the desired Kasm Workspaces version. | String | `"https://kasm-static-content.s3.amazonaws.com/kasm_release_1.12.0.d4fd8a.tar.gz"` |
| `admin_password` | The Kasm Administrative user login password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` |
| `user_password` | A Kasm standard (non-administrator) user password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` |
| `allow_ssh_cidrs` | A list of subnets in CIDR notation allowed to SSH into your kasm servers | List(String) | `["10.0.0.0/16","172.217.22.14/32"]` |
| `allow_web_cidrs` | A list of subnets in CIDR notation allowed Web access to your kasm servers | List(String) | `["0.0.0.0/0"]` |
| `swap_size` | The amount of swap (in MB) to configure inside the Kasm servers. | Number | `2048` |
| `instance_shape` | The OCI instance shape to use for Kasm deployment. Kasm recommends using a Flex instance type. | String | `"VM.Standard.E4.Flex"` |

View file

@ -1,19 +1,16 @@
module "kasm" {
source = "./module"
digital_ocean_token = ""
do_domain_name = "kasm.contoso.com"
project_name = "contoso"
digital_ocean_region = "nyc3"
digital_ocean_image = "docker-18-04"
digital_ocean_droplet_slug = "s-2vcpu-4gb-intel"
swap_size = 2048
kasm_build_url = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.9.0.077388.tar.gz"
user_password = "changeme"
admin_password = "changeme"
allow_ssh_cidrs = ["0.0.0.0/0"]
ssh_key_fingerprints = []
source = "./module"
project_name = var.project_name
do_domain_name = var.do_domain_name
vpc_subnet_cidr = var.vpc_subnet_cidr
digital_ocean_region = var.digital_ocean_region
digital_ocean_image = var.digital_ocean_image
digital_ocean_droplet_slug = var.digital_ocean_droplet_slug
swap_size = var.swap_size
kasm_build_url = var.kasm_build_url
user_password = var.user_password
admin_password = var.admin_password
allow_ssh_cidrs = var.allow_ssh_cidrs
allow_kasm_web_cidrs = var.allow_kasm_web_cidrs
ssh_key_fingerprints = var.ssh_key_fingerprints
}

View file

@ -1,5 +1,9 @@
resource "digitalocean_domain" "default" {
name = "${var.do_domain_name}"
name = var.do_domain_name
}
data "digitalocean_domain" "data-default" {
name = digitalocean_domain.default.name
}
resource "digitalocean_record" "static" {
@ -12,32 +16,13 @@ resource "digitalocean_record" "static" {
resource "digitalocean_certificate" "cert" {
name = "${var.project_name}-cert"
type = "lets_encrypt"
domains = ["${digitalocean_domain.default.id}"]
domains = [digitalocean_domain.default.id]
lifecycle {
create_before_destroy = true
}
}
resource "digitalocean_loadbalancer" "www-lb" {
name = "${var.project_name}-lb"
region = "${var.digital_ocean_region}"
forwarding_rule {
entry_port = 443
entry_protocol = "https"
target_port = 443
target_protocol = "https"
certificate_name = digitalocean_certificate.cert.name
}
healthcheck {
port = 443
protocol = "https"
path = "/"
}
droplet_ids = digitalocean_droplet.kasm-server.*.id
data "digitalocean_certificate" "data-cert" {
name = digitalocean_certificate.cert.name
}

View file

@ -4,31 +4,37 @@ resource "digitalocean_firewall" "workspaces-fw" {
tags = ["${digitalocean_tag.project.id}"]
inbound_rule {
protocol = "tcp"
port_range = "22"
source_addresses = "${var.allow_ssh_cidrs}"
protocol = "tcp"
port_range = "22"
source_addresses = var.allow_ssh_cidrs
}
inbound_rule {
protocol = "tcp"
port_range = "443"
source_addresses = ["0.0.0.0/0", "::/0"]
protocol = "tcp"
port_range = "443"
source_addresses = var.allow_kasm_web_cidrs
}
inbound_rule {
protocol = "tcp"
port_range = "80"
source_addresses = var.allow_kasm_web_cidrs
}
outbound_rule {
protocol = "tcp"
port_range = "1-65535"
destination_addresses = ["0.0.0.0/0", "::/0"]
protocol = "tcp"
port_range = "1-65535"
destination_addresses = var.anywhere
}
outbound_rule {
protocol = "udp"
port_range = "1-65535"
destination_addresses = ["0.0.0.0/0", "::/0"]
protocol = "udp"
port_range = "1-65535"
destination_addresses = var.anywhere
}
outbound_rule {
protocol = "icmp"
destination_addresses = ["0.0.0.0/0", "::/0"]
protocol = "icmp"
destination_addresses = var.anywhere
}
}

View file

@ -0,0 +1,24 @@
resource "digitalocean_loadbalancer" "www-lb" {
name = "${var.project_name}-lb"
region = var.digital_ocean_region
vpc_uuid = data.digitalocean_vpc.data-kasm_vpc.id
redirect_http_to_https = true
forwarding_rule {
entry_port = 443
entry_protocol = "https"
target_port = 443
target_protocol = "https"
certificate_name = data.digitalocean_certificate.data-cert.id
}
healthcheck {
port = 443
protocol = "https"
path = "/"
}
droplet_ids = [data.digitalocean_droplet.data-kasm_server.id]
}

View file

@ -0,0 +1,3 @@
output "kasm_server_ip" {
value = digitalocean_droplet.kasm-server.ipv4_address
}

View file

@ -1,10 +1,18 @@
resource "digitalocean_project" "project" {
name = "${var.project_name}"
name = var.project_name
description = "Deployment for ${var.project_name}"
purpose = "Kasm Workspaces"
purpose = "Kasm Workspaces"
environment = "Development"
resources = [
digitalocean_droplet.kasm-server.urn,
digitalocean_domain.default.urn
data.digitalocean_droplet.data-kasm_server.urn,
data.digitalocean_domain.data-default.urn
]
}
resource "digitalocean_tag" "project" {
name = var.project_name
}
data "digitalocean_tag" "data-project" {
name = digitalocean_tag.project.name
}

View file

@ -0,0 +1,8 @@
terraform {
required_providers {
digitalocean = {
source = "digitalocean/digitalocean"
version = "~> 2.0"
}
}
}

View file

@ -1,43 +1,23 @@
data "template_file" "user_data" {
template = "${file("${path.module}/files/kasm_server_init.sh")}"
vars = {
kasm_build_url = "${var.kasm_build_url}"
user_password = "${var.user_password}"
admin_password = "${var.admin_password}"
swap_size = "${var.swap_size}"
}
}
resource "digitalocean_droplet" "kasm-server" {
ssh_keys = "${var.ssh_key_fingerprints}"
image = "${var.digital_ocean_image}"
region = "${var.digital_ocean_region}"
size = "${var.digital_ocean_droplet_slug}"
private_networking = false
backups = false
ipv6 = false
name = "${var.project_name}-workspaces"
tags = ["${digitalocean_tag.project.id}"]
user_data = "${data.template_file.user_data.rendered}"
}
output "kasm_server_ip" {
value = "${digitalocean_droplet.kasm-server.ipv4_address}"
}
terraform {
required_providers {
digitalocean = {
source = "digitalocean/digitalocean"
version = "~> 2.0"
ssh_keys = var.ssh_key_fingerprints
image = var.digital_ocean_image
region = var.digital_ocean_region
size = var.digital_ocean_droplet_slug
vpc_uuid = data.digitalocean_vpc.data-kasm_vpc.id
backups = false
ipv6 = false
name = "${var.project_name}-workspaces"
tags = [data.digitalocean_tag.data-project.id]
user_data = templatefile("${path.module}/userdata/kasm_server_init.sh",
{
kasm_build_url = var.kasm_build_url
user_password = var.user_password
admin_password = var.admin_password
swap_size = var.swap_size
}
}
)
}
provider "digitalocean" {
token = "${var.digital_ocean_token}"
}
resource "digitalocean_tag" "project" {
name = "${var.project_name}"
data "digitalocean_droplet" "data-kasm_server" {
id = digitalocean_droplet.kasm-server.id
}

View file

@ -9,7 +9,7 @@ chmod 600 /var/swap.1
cd /tmp
PRIVATE_IP=(`hostname -I | cut -d ' ' -f1 | tr -d '\\n'`)
PRIVATE_IP=(`hostname -I | cut -d' ' -f1 | tr -d '\\n'`)
wget ${kasm_build_url} -O kasm_workspaces.tar.gz
tar -xf kasm_workspaces.tar.gz

View file

@ -1,45 +1,83 @@
variable "project_name" {
description = "The name of the project/deployment/company eg (acme). Lower case all one word as this will be used in a domain name"
type = string
}
variable "digital_ocean_token" {
description = "Authentication Token For Digital Ocean"
}
variable "digital_ocean_region" {
description = "The Default Digital Ocean Region Slug: https://docs.digitalocean.com/products/platform/availability-matrix/"
default = "nyc3"
type = string
}
variable "digital_ocean_droplet_slug" {
description = "The Default Digital Ocean Droplet Slug: https://slugs.do-api.dev/"
default = "s-2vcpu-4gb-intel"
type = string
}
variable "digital_ocean_image" {
description = "Default Image for Ubuntu LTS"
default = "docker-18-04"
type = string
}
variable "vpc_subnet_cidr" {
description = "VPC Subnet CIDR to deploy Kasm"
type = string
}
variable "kasm_build_url" {
description = "The Build file to install"
default = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.9.0.077388.tar.gz"
description = "The Kasm build file to install"
type = string
}
variable "user_password" {
default = "changeme"
description = "The default password to be used for the default user@kasm.local account. Only use alphanumeric characters"
type = string
sensitive = true
}
variable "admin_password" {
default = "changeme"
description = "The default password to be used for the default admin@kasm.local account. Only use alphanumeric characters"
type = string
sensitive = true
}
variable "allow_ssh_cidrs" {
description = "CIDR notation for hosts allowed to SSH"
description = "List of Subnets in CIDR notation for hosts allowed to SSH"
type = list(string)
}
variable "allow_kasm_web_cidrs" {
description = "CIDR notation of the bastion host allowed to SSH in to the machines"
type = list(string)
}
variable "do_domain_name" {
description = "The domain name that users will use to access kasm"
type = string
}
variable "ssh_key_fingerprints" {
# The ssh key fingerprints from uploaded keys can be obtained at https://cloud.digitalocean.com/account/security
description = "Keys used for sshing into kasm hosts"
type = list(string)
}
variable swap_size {
variable "swap_size" {
description = "The amount of swap (in MB) to configure inside the compute instances"
default = 2048
type = number
validation {
condition = var.swap_size >= 1024 && var.swap_size <= 8192 && floor(var.swap_size) == var.swap_size
error_message = "Swap size is the amount of disk space to use for Kasm in MB and must be an integer between 1024 and 8192."
}
}
variable "anywhere" {
description = "Anywhere route subnet"
type = list(string)
default = ["0.0.0.0/0", "::/0"]
validation {
condition = can([for subnet in var.anywhere : cidrhost(subnet, 0)])
error_message = "Anywhere variable must be valid IPv4 CIDR - usually 0.0.0.0/0 for all default routes and default Security Group access."
}
}

View file

@ -0,0 +1,10 @@
resource "digitalocean_vpc" "kasm_vpc" {
name = "${var.project_name}-vpc"
description = "Kasm deployment VPC for ${var.project_name}"
region = var.digital_ocean_region
ip_range = var.vpc_subnet_cidr
}
data "digitalocean_vpc" "data-kasm_vpc" {
name = digitalocean_vpc.kasm_vpc.name
}

View file

@ -0,0 +1,12 @@
terraform {
required_providers {
digitalocean = {
source = "digitalocean/digitalocean"
version = "~> 2.0"
}
}
}
provider "digitalocean" {
token = var.digital_ocean_token
}

View file

@ -0,0 +1,24 @@
## Kasm deployment settings
project_name = "contoso"
do_domain_name = "kasm.contoso.com"
digital_ocean_region = "nyc3"
vpc_subnet_cidr = "10.0.0.0/24"
## DO Authentication variables
ssh_key_fingerprints = ["c2:4c:f2:5d:0c:59:5a:3f:93:a2:9d:25:94:24:9a:b1"]
## VM Settings
digital_ocean_image = "docker-20-04"
digital_ocean_droplet_slug = "s-2vcpu-4gb-intel"
swap_size = 2048
## Kasm passwords
user_password = "changeme"
admin_password = "changeme"
## VM Access subnets
allow_ssh_cidrs = ["0.0.0.0/0"]
allow_kasm_web_cidrs = ["0.0.0.0/0"]
## Kasm download URL
kasm_build_url = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.12.0.d4fd8a.tar.gz"

View file

@ -0,0 +1,135 @@
variable "digital_ocean_token" {
description = "Authentication Token For Digital Ocean"
type = string
sensitive = true
validation {
condition = can(regex("^(dop_v1_[a-f0-9]{64})", var.digital_ocean_token))
error_message = "The digital_ocean_token must be a valid API Token (https://docs.digitalocean.com/reference/api/create-personal-access-token/)."
}
}
variable "digital_ocean_region" {
description = "The Digital Ocean region where you wish to deploy Kasm"
type = string
default = "nyc3"
validation {
condition = can(regex("^[a-zA-Z]{3}\\d", var.digital_ocean_region))
error_message = "The DigitalOcean region format is always 3 letters and a number (e.g. nyc3) - check out https://docs.digitalocean.com/products/platform/availability-matrix/ for available regions."
}
}
variable "do_domain_name" {
description = "The domain name that users will use to access Kasm"
type = string
validation {
condition = can(regex("^[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,6}", var.do_domain_name))
error_message = "There are invalid characters in the do_domain_name - it must be a valid domain name."
}
}
variable "ssh_key_fingerprints" {
# The ssh key fingerprints from uploaded keys can be obtained at https://cloud.digitalocean.com/account/security
description = "Keys used for sshing into kasm hosts"
type = list(string)
validation {
condition = can([for fingerprint in var.ssh_key_fingerprints : regex("^([a-f0-9]{2}:?){16}$", fingerprint)])
error_message = "One of the SSH Key fingerprints is incorrectly formatted. It should be 16 colon-delimited hex bytes (e.g. 12:34:56:78:90:ab:cd:ef:12:34:56:78:90:ab:cd:ef)."
}
}
variable "project_name" {
description = "The name of the project/deployment/company eg (acme)."
type = string
validation {
condition = can(regex("^[a-z]{1,15}", var.project_name))
error_message = "The project_name variable can only be one word between 1 and 15 lower-case letters since it is a seed value in multiple object names."
}
}
variable "vpc_subnet_cidr" {
description = "VPC Subnet CIDR where you wish to deploy Kasm"
type = string
default = "10.0.0.0/24"
validation {
condition = can(cidrhost(var.vpc_subnet_cidr, 0))
error_message = "The vpc_subnet_cidr must be a valid IPv4 Subnet in CIDR notation (e.g. 10.0.0.0/24)"
}
}
variable "digital_ocean_droplet_slug" {
description = "The Default Digital Ocean Droplet Slug: https://slugs.do-api.dev/"
type = string
default = "s-2vcpu-4gb-intel"
}
variable "digital_ocean_image" {
description = "Default Image for Ubuntu 20.04 LTS with Docker"
type = string
default = "docker-20-04"
}
variable "kasm_build_url" {
description = "The Kasm build file to install"
type = string
default = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.12.0.d4fd8a.tar.gz"
}
variable "user_password" {
description = "The default password to be used for the default user@kasm.local account. Only use alphanumeric characters"
type = string
default = "changeme"
validation {
condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.user_password))
error_message = "The User Password should be a string between 12 and 30 letters or numbers with no special characters."
}
}
variable "admin_password" {
description = "The default password to be used for the default admin@kasm.local account. Only use alphanumeric characters"
default = "changeme"
type = string
validation {
condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.admin_password))
error_message = "The Admin Password should be a string between 12 and 30 letters or numbers with no special characters."
}
}
variable "allow_ssh_cidrs" {
description = "CIDR notation of the bastion host allowed to SSH in to the machines"
type = list(string)
default = ["0.0.0.0/0"]
validation {
condition = can([for subnet in var.allow_ssh_cidrs : cidrhost(subnet, 0)])
error_message = "One of the subnets provided in the allow_ssh_cidrs list is invalid."
}
}
variable "allow_kasm_web_cidrs" {
description = "CIDR notation of the bastion host allowed to SSH in to the machines"
type = list(string)
default = ["0.0.0.0/0"]
validation {
condition = can([for subnet in var.allow_kasm_web_cidrs : cidrhost(subnet, 0)])
error_message = "One of the subnets provided in the allow_ssh_cidrs list is invalid."
}
}
variable "swap_size" {
description = "The amount of swap (in MB) to configure inside the compute instances"
default = 2048
validation {
condition = var.swap_size >= 1024 && var.swap_size <= 8192 && floor(var.swap_size) == var.swap_size
error_message = "Swap size is the amount of disk space to use for Kasm in MB and must be an integer between 1024 and 8192."
}
}

View file

@ -8,7 +8,6 @@ This project will deploy Kasm Workspaces in a single-server deployment in OCI.
# Pre-Configuration
Consider creating a new Compartment for the Kasm Workspaces deployment.
@ -16,40 +15,70 @@ Consider creating a new Compartment for the Kasm Workspaces deployment.
In OCI create a public DNS zone that matches the desired domain name for the deployment. e.g `kasm.contoso.com`.
### API Keys
Create an administative user in the OCI console that will be used for the terraform deployment. Add the user to the
**Administrators** Group. Generate an API Key for the user. The API Key Fingerprint will be used as a variable
in the deployment configuration. Save the private key to the local directory replacing `oci-private-key.pem`.
Create an administative user in the OCI console that will be used for the terraform deployment. Add the user to the **Administrators** Group. Generate an API Key for the user. The API Key Fingerprint will be used as a variable in the deployment configuration. Save the private key to the local directory replacing `oci-private-key.pem`.
### SSH Authorized Keys
The project will install an SSH key(s) inside the OCI compute instance(s). Update `authorized_keys` in this directory
with the desired SSH public keys.
### SSL Certificate
Create an SSL certificate that matches the desired domain for the deployment. e.g (kasm.contoso.com). Place the pem encoded
cert and key in this directory overwriting `kasm_ssl.crt` and `kasm_ssl.key`.
### SSL Certificate Options
#### Terraform-generated Let's Encrypt Certificate
To use Terraform to generate a Let's Encrypt certificate automatically, set the `letsencrypt_cert_support_email` to a valid email address and set the `letsencrypt_server_type` to either "staging" or "prod" and leave the `kasm_ssl_crt_path` and `kasm_ssl_key_path` variables empty.
***NOTE:***
- Staging generates certificates that a browser will not trust, but are formatted correctly and are designed for testing and validating the system configuraiton and deployment and has a limit of hundreds of certificates per domain per week.
- Prod generates valid Let's Encrypt certificates but is limited to 5 certificates per week per domain.
#### Bring Your Own Certificates
Create an SSL certificate that matches the desired domain for the deployment. e.g (kasm.contoso.com). Place the pem encoded cert and key in this directory overwriting `kasm_ssl.crt` and `kasm_ssl.key`.
# Terraform Configuration
1. Initialize the project
terraform init
2. Open `deployment.tf` and update the variables. The variable definitions and descriptions
can be found in `module/variables.tf`
2. Open `settings.tfvars` and update the variables. The variable definitions, descriptions, and validation requirements can be found in `variables.tf`, or in the [table](#oci-terraform-variable-definitions) below.
3. Verify the configuration
terraform plan
terraform plan -var-file settings.tfvars
4. Deploy
terraform apply
terraform apply -var-file settings.tfvars
5. Login to the Deployment as an Admin via the domain defined e.g `https://kasm.contoso.com`. Single server installs download all workspaces images during the install process so it may take ~15 minutes for the server to fully come online.
5. Login to the Deployment as an Admin via the domain defined e.g `https://kasm.contoso.com` . Single server installs
download all workspaces images during the install process so it may take ~15 minutes for the server to fully come online.
# OCI Terraform Variable definitions
| Variable | Description | Variable type | Example |
|:--------:|-------------|---------------|---------|
| `tenancy_ocid` | The OCI Tenancy OCID | String | `"ocid1.tenancy.oc1..aaaaaaaaai06vvcguozt39d4ilmwtpdovl998wsxpyn0hjkab2kuh7z16po7"` |
| `compartment_ocid` | The OCI Compartment OCID | String | `"ocid1.compartment.oc1..aaaaaaaauepg1z967huiazuiwjt80rtbszp64x9oxaidkoi7wz0pgr950bzb"` |
| `region` | The OCI Region name | String | `"us-ashburn-1"` |
| `user_ocid` | The OCI User OCID | String | `"ocid1.user.oc1..aaaaaaaau3me8nojmdjrbj2vzfxeouscc1i7cf9w0aoy0iyv9b38t2y0a1ba"` |
| `fingerprint` | The OCI User API Key fingerprint | String | `"66:e5:d1:85:cd:ba:ca:6a:d0:76:86:ef:1c:11:63:97"` |
| `private_key_path` | The path for the API Key PEM encoded Private Key for the OCI User. ***NOTE:*** *Ensure the API Key contents are a valid PEM encoded RSA key file. You can tell this by ensuring that the value `-----BEGIN RSA PRIVATE KEY-----` is the first line in the key file. Otherwise, you can validate the key file by running the `openssl rsa -in oci-private-key.pem -check` command.* | String | `"./oci-private-key.pem"` |
| `project_name` | The name of the deployment (e.g dev, staging). A short single word of up to 15 characters. | String | `"kasm"` |
| `oci_domain_name` | The public Zone used for the dns entries. This must already exist in the OCI account. (e.g kasm.contoso.com). The deployment will be accessed via this zone name using https. | String | `"kasm.contoso.com"` |
| `letsencrypt_cert_support_email` | Email address to use for Terraform-generated Let's Encrypt SSL certificates | String | `"support@contoso.com"` |
| `letsencrypt_server_type` | SSL Server type for certificate generation. Valid options are staging, prod, and empty string (""). Refer to [SSL Certificate Options](#ssl-certificate-options) section of this document for more information. | String | "prod" |
| `kasm_ssl_crt_path` | Bring Your own Certificate - The file path fo the PEM encoded SSL Certificate file generated outside of Terraform. Copy/paste the contents of your generated SSL Certificate to the file designated in this path variable. | String | `"./kasm_ssl.crt"` |
| `kasm_ssl_key_path` | Bring Your own Certificate - The file path to the PEM encoded SSL Private Key file generated outside of Terraform. Copy/paste the contents of your generated SSL Private Key to the file designated in this path variable. | String | `"./kasm_ssl.key"` |
| `vcn_subnet_cidr` | The OCI VCN Subnet CIDR of the VCN where you wish to deploy Kasm | String | `"10.0.0.0/16"` |
| `ssh_authorized_keys` | The SSH Public key to be installed on the Kasm servers for SSH access | String | `"ssh-rsa some_base64_encoded_ssh_public_key_data"` |
| `instance_image_ocid` | The OCI Image OCID value of the OS to use. Kasm recommends using lates Ubuntu 20.04 LTS-Minimal for speed and efficiency. | String | `"ocid1.image.oc1.iad.aaaaaaaahiz6xym3a76xhwkmwmhrz6luyiehho7dpxpkphxhsq5q6z4m3nlq"` |
| `allow_ssh_cidrs` | A list of subnets in CIDR notation allowed to SSH into your kasm servers | List(String) | `["10.0.0.0/16","172.217.22.14/32"]` |
| `allow_web_cidrs` | A list of subnets in CIDR notation allowed Web access to your kasm servers | List(String) | `["0.0.0.0/0"]` |
| `admin_password` | The Kasm Administrative user login password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` |
| `user_password` | A Kasm standard (non-administrator) user password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` |
| `kasm_build_url` | The download URL for the desired Kasm Workspaces version. | String | `"https://kasm-static-content.s3.amazonaws.com/kasm_release_1.12.0.d4fd8a.tar.gz"` |
| `swap_size` | The amount of swap (in MB) to configure inside the Kasm servers. | Number | `2048` |
| `instance_shape` | The OCI instance shape to use for Kasm deployment. Kasm recommends using a Flex instance type. | String | `"VM.Standard.E4.Flex"` |
| `kasm_server_cpus` | The number of CPUs, memory in GB, and HDD size to use for Kasm WebApps. | Number | `4` |
| `kasm_server_memory` | The number of CPUs, memory in GB, and HDD size to use for the Kasm Database server. | Number | `8` |
| `kasm_server_hdd_size` | The number of CPUs, memory in GB, and HDD size to use for the Kasm Agent server(s). | Number | `120` |
# Detailed Terraform Deployment Diagram
![Detailed Diagram][Detailed_Diagram]
[Detailed_Diagram]: ./diagram/oci_single_server.png "Detailed Diagram"

View file

@ -1 +0,0 @@
replaceme

View file

@ -1,30 +1,36 @@
module "kasm" {
source = "./module"
source = "./module"
oci_domain_name = var.oci_domain_name
project_name = var.project_name
kasm_build_url = var.kasm_build_url
vcn_subnet_cidr = var.vcn_subnet_cidr
oci_domain_name = "kasm.contoso.com"
project_name = "contoso"
## OCI Auth information
tenancy_ocid = var.tenancy_ocid
compartment_ocid = var.compartment_ocid
user_ocid = var.user_ocid
fingerprint = var.fingerprint
private_key_path = var.private_key_path
region = var.region
tenancy_ocid = ""
user_ocid = ""
compartment_ocid = ""
## SSL Certificate values
# Let TF generate Let's Encrypt SSL Certificates automatically
letsencrypt_cert_support_email = var.letsencrypt_cert_support_email
letsencrypt_server_type = var.letsencrypt_server_type
# Bring your own SSL Certificates
kasm_ssl_crt_path = var.kasm_ssl_crt_path
kasm_ssl_key_path = var.kasm_ssl_key_path
fingerprint = ""
private_key_path = "./oci-private-key.pem"
instance_image_ocid = var.instance_image_ocid
instance_shape = var.instance_shape
swap_size = var.swap_size
kasm_server_cpus = var.kasm_server_cpus
kasm_server_memory = var.kasm_server_memory
kasm_server_hdd_size = var.kasm_server_hdd_size
allow_ssh_cidrs = var.allow_ssh_cidrs
allow_web_cidrs = var.allow_web_cidrs
ssh_authorized_keys = var.ssh_authorized_keys
ssh_authorized_keys = "./authorized_keys"
kasm_ssl_crt_path = "./kasm_ssl.crt"
kasm_ssl_key_path = "./kasm_ssl.key"
region = "us-ashburn-1"
instance_image_ocid = "ocid1.image.oc1.iad.aaaaaaaafg6lg7dejwjebjqontwzyvutgf6qs5awyze6fgoiqepyj5qkvcuq"
instance_shape = "VM.Standard.E4.Flex"
instance_ocpus = 2
shape_memory_in_gb = 4
instance_boot_size_gb = 60
kasm_build_url = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.9.0.077388.tar.gz"
user_password = "changeme"
admin_password = "changeme"
allow_ssh_cidr = "0.0.0.0/0"
allow_web_cidr = "0.0.0.0/0"
}
admin_password = var.admin_password
user_password = var.user_password
}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

View file

@ -1,12 +1,17 @@
data "oci_dns_zones" "kasm_dns_zone" {
compartment_id = var.compartment_ocid
name = var.oci_domain_name
}
resource "oci_dns_rrset" "kasm_a_record" {
domain = var.oci_domain_name
rtype = "A"
zone_name_or_id = var.oci_domain_name
compartment_id = var.compartment_ocid
items {
domain = var.oci_domain_name
rtype = "A"
zone_name_or_id = var.oci_domain_name
compartment_id = var.compartment_ocid
items {
domain = var.oci_domain_name
rdata = oci_core_instance.kasm_instance.public_ip
rtype = "A"
ttl = 300
}
}
rdata = oci_core_instance.kasm_instance.public_ip
rtype = "A"
ttl = 300
}
}

View file

@ -1,15 +1,3 @@
data "template_file" "user_data" {
template = "${file("${path.module}/userdata/bootstrap.sh")}"
vars = {
kasm_build_url = "${var.kasm_build_url}"
user_password = "${var.user_password}"
admin_password = "${var.admin_password}"
swap_size = "${var.swap_size}"
nginx_cert_in = file("${var.kasm_ssl_crt_path}")
nginx_key_in = file("${var.kasm_ssl_key_path}")
}
}
resource "oci_core_instance" "kasm_instance" {
availability_domain = data.oci_identity_availability_domain.ad.name
compartment_id = var.compartment_ocid
@ -17,8 +5,8 @@ resource "oci_core_instance" "kasm_instance" {
shape = var.instance_shape
shape_config {
ocpus = var.instance_ocpus
memory_in_gbs = var.shape_memory_in_gb
ocpus = var.kasm_server_cpus
memory_in_gbs = var.kasm_server_memory
}
create_vnic_details {
@ -30,17 +18,24 @@ resource "oci_core_instance" "kasm_instance" {
}
source_details {
source_type = "image"
source_id = var.instance_image_ocid
boot_volume_size_in_gbs = var.instance_boot_size_gb
source_type = "image"
source_id = var.instance_image_ocid
boot_volume_size_in_gbs = var.kasm_server_hdd_size
}
metadata = {
ssh_authorized_keys = file("${var.ssh_authorized_keys}")
user_data = base64encode("${data.template_file.user_data.rendered}")
ssh_authorized_keys = var.ssh_authorized_keys
user_data = base64encode(templatefile("${path.module}/userdata/bootstrap.sh",
{
kasm_build_url = var.kasm_build_url
user_password = var.user_password
admin_password = var.admin_password
swap_size = var.swap_size
nginx_cert_in = var.letsencrypt_server_type == "" ? file(var.kasm_ssl_crt_path) : acme_certificate.certificate.certificate_pem
nginx_key_in = var.letsencrypt_server_type == "" ? file(var.kasm_ssl_key_path) : tls_private_key.certificate_private_key.private_key_pem
}
))
}
}

View file

@ -0,0 +1,48 @@
resource "tls_private_key" "registration_private_key" {
algorithm = "RSA"
}
resource "tls_private_key" "certificate_private_key" {
algorithm = "RSA"
}
resource "acme_registration" "registration" {
account_key_pem = tls_private_key.registration_private_key.private_key_pem
email_address = var.letsencrypt_cert_support_email
}
resource "tls_cert_request" "kasm_certificate_request" {
private_key_pem = tls_private_key.certificate_private_key.private_key_pem
dns_names = [data.oci_dns_zones.kasm_dns_zone.zones[0].name, "*.${data.oci_dns_zones.kasm_dns_zone.zones[0].name}"]
subject {
common_name = data.oci_dns_zones.kasm_dns_zone.zones[0].name
}
}
resource "acme_certificate" "certificate" {
account_key_pem = acme_registration.registration.account_key_pem
certificate_request_pem = tls_cert_request.kasm_certificate_request.cert_request_pem
recursive_nameservers = [
"8.8.8.8:53",
"4.4.2.2:53"
]
dns_challenge {
provider = "oraclecloud"
config = {
OCI_COMPARTMENT_OCID = var.compartment_ocid
OCI_PRIVKEY_FILE = var.private_key_path
OCI_TENANCY_OCID = var.tenancy_ocid
OCI_REGION = var.region
OCI_PUBKEY_FINGERPRINT = var.fingerprint
OCI_USER_OCID = var.user_ocid
OCI_PROPOGATION_TIMEOUT = 600
OCI_POLLING_INTERVAL = 60
OCI_TTL = 300
}
}
depends_on = [acme_registration.registration]
}

View file

@ -1,8 +0,0 @@
provider "oci" {
tenancy_ocid = var.tenancy_ocid
user_ocid = var.user_ocid
fingerprint = var.fingerprint
private_key_path = var.private_key_path
region = var.region
}

View file

@ -0,0 +1,16 @@
terraform {
required_providers {
oci = {
source = "oracle/oci"
version = ">= 4.0.0"
}
acme = {
source = "vancluever/acme"
version = ">= 2.0"
}
tls = {
source = "hashicorp/tls"
version = ">= 4.0.0"
}
}
}

View file

@ -1,42 +1,47 @@
resource "oci_core_security_list" "allow_web" {
compartment_id = var.compartment_ocid
vcn_id = oci_core_vcn.kasm_vcn.id
display_name = "allow_web"
compartment_id = var.compartment_ocid
vcn_id = oci_core_vcn.kasm_vcn.id
display_name = "allow_web"
egress_security_rules {
destination = "0.0.0.0/0"
protocol = "all"
stateless = "false"
}
egress_security_rules {
destination = var.anywhere
protocol = "all"
stateless = "false"
}
ingress_security_rules {
protocol = "6"
source = "${var.allow_web_cidr}"
tcp_options {
max = "443"
min = "443"
}
dynamic "ingress_security_rules" {
for_each = var.allow_web_cidrs
content {
protocol = "6"
source = ingress_security_rules.value
tcp_options {
max = "443"
min = "443"
}
}
}
}
resource "oci_core_security_list" "allow_ssh" {
compartment_id = var.compartment_ocid
vcn_id = oci_core_vcn.kasm_vcn.id
display_name = "allow_ssh"
compartment_id = var.compartment_ocid
vcn_id = oci_core_vcn.kasm_vcn.id
display_name = "allow_ssh"
egress_security_rules {
destination = "0.0.0.0/0"
protocol = "all"
stateless = "false"
}
egress_security_rules {
destination = var.anywhere
protocol = "all"
stateless = "false"
}
ingress_security_rules {
protocol = "6"
source = "${var.allow_ssh_cidr}"
tcp_options {
max = "22"
min = "22"
}
dynamic "ingress_security_rules" {
for_each = var.allow_ssh_cidrs
content {
protocol = "6"
source = ingress_security_rules.value
tcp_options {
max = "22"
min = "22"
}
}
}
}

View file

@ -9,17 +9,18 @@ chmod 600 /var/swap.1
cd /tmp
PRIVATE_IP=(`hostname -I | cut -d ' ' -f1 | tr -d '\\n'`)
PRIVATE_IP=(`hostname -I | cut -d ' ' -f1 | tr -d '\\n'`)
wget ${kasm_build_url} -O kasm_workspaces.tar.gz
tar -xf kasm_workspaces.tar.gz
bash kasm_release/install.sh -e -U ${user_password} -P ${admin_password} -p $PRIVATE_IP -m $PRIVATE_IP
echo -e "${nginx_cert_in}" > /opt/kasm/current/certs/kasm_nginx.crt
echo -e "${nginx_key_in}" > /opt/kasm/current/certs/kasm_nginx.key
docker exec kasm_proxy nginx -s reload
echo "Stopping and restarting Kasm services to apply certificates..."
/opt/kasm/bin/stop
docker rm $(docker ps -aq)
/opt/kasm/bin/start
echo "Done"

View file

@ -1,94 +1,139 @@
variable "project_name" {
description = "The name of the deployment (e.g dev, staging). A short single word"
type = string
}
variable "oci_domain_name" {
description = "The public Zone used for the dns entries. This must already exist in the OCI account. (e.g kasm.contoso.com). The deployment will be accessed via this zone name via https"
}
variable kasm_build_url {
description = "The URL for the Kasm Workspaces build"
}
variable swap_size {
description = "The amount of swap (in MB) to configure inside the compute instances"
default = 2048
type = string
}
variable "tenancy_ocid" {
description = "The Tenancy OCID."
}
variable "user_ocid" {
description = "The User OCID."
type = string
}
variable "compartment_ocid" {
description = "The Compartment OCID"
type = string
}
variable "region" {
description = "The OCI Region eg: (us-ashburn-1)"
type = string
}
variable "user_ocid" {
description = "The User OCID."
type = string
}
variable "fingerprint" {
description = "API Key Fingerprint"
type = string
}
variable "private_key_path" {
description = "The path to the API Key PEM encoded Private Key"
type = string
sensitive = true
}
variable "letsencrypt_cert_support_email" {
description = "Email address to use for Let's Encrypt SSL certificates for OCI Deployment"
type = string
}
variable "letsencrypt_server_type" {
description = "SSL Server type to generate. Valid options are staging, prod, and empty string. Prod certificates are limited to 5 per week per domain."
type = string
}
variable "vcn_subnet_cidr" {
description = "VPC Subnet CIDR where you wish to deploy Kasm"
type = string
}
variable "ssh_authorized_keys" {
description = "The file path to the authorized_keys file that contains SSH public keys to be installed on the OCI compute instance"
description = "The SSH Public Keys to be installed on the OCI compute instance"
type = string
}
variable "instance_image_ocid" {
description = "The OCID for the instance image , such as ubuntu 18.04, to use."
default = "ocid1.image.oc1.iad.aaaaaaaafg6lg7dejwjebjqontwzyvutgf6qs5awyze6fgoiqepyj5qkvcuq"
description = "The OCID for the instance image , such as ubuntu 20.04, to use."
type = string
}
variable "instance_boot_size_gb" {
description = "The size, in GB, of the instance drive"
default = 60
}
variable "instance_shape" {
description = "The instance shape to use. Should be a Flex type."
default = "VM.Standard.E3.Flex"
}
variable "instance_ocpus" {
description = "The number of CPUs to configure for the instance"
default = 2
}
variable "shape_memory_in_gb" {
description = "The amount of memory, in GB, to configure for the instance"
default = 4
}
variable "allow_ssh_cidr" {
variable "allow_ssh_cidrs" {
description = "The CIDR notation to allow SSH access to the systems."
default = "0.0.0.0/0"
type = list(string)
}
variable "allow_web_cidr" {
variable "allow_web_cidrs" {
description = "The CIDR notation to allow HTTPS access to the systems."
default = "0.0.0.0/0"
type = list(string)
}
variable "kasm_ssl_crt_path" {
description = "The file path to the PEM encoded SSL Certificate"
type = string
}
variable "kasm_ssl_key_path" {
description = "The file path to the PEM encoded SSL Certificate Key"
type = string
sensitive = true
}
variable "user_password" {
description = "The password for the database. No special characters"
description = "The standard (non administrator) user password. No special characters"
type = string
sensitive = true
}
variable "admin_password" {
description = "The password for the database. No special characters"
}
description = "The administrative user password. No special characters"
type = string
sensitive = true
}
variable "kasm_build_url" {
description = "The URL for the Kasm Workspaces build"
type = string
}
variable "swap_size" {
description = "The amount of swap (in MB) to configure inside the compute instances"
type = number
}
variable "instance_shape" {
description = "The instance shape to use. Should be a Flex type."
type = string
}
variable "kasm_server_cpus" {
description = "The number of CPUs to configure for the Kasm instance"
type = number
}
variable "kasm_server_memory" {
description = "The amount of memory to configure for the Kasm instance"
type = number
}
variable "kasm_server_hdd_size" {
description = "The size in GBs of the Kasm instance HDD"
type = number
}
## Pre-set values
variable "anywhere" {
description = "Anywhere route subnet"
type = string
default = "0.0.0.0/0"
validation {
condition = can(cidrhost(var.anywhere, 0))
error_message = "Anywhere variable must be valid IPv4 CIDR - usually 0.0.0.0/0 for all default routes and default Security Group access."
}
}

View file

@ -1,12 +1,16 @@
locals {
kasm_vcn_subnet_cidr_mask = split("/", var.vcn_subnet_cidr)[1]
kasm_server_subnet_cidr_calculation = (8 - (local.kasm_vcn_subnet_cidr_mask - 16))
kasm_server_subnet_cidr_size = local.kasm_server_subnet_cidr_calculation < 0 ? 0 : local.kasm_server_subnet_cidr_calculation
}
resource "oci_core_vcn" "kasm_vcn" {
cidr_block = "10.0.0.0/16"
cidr_block = var.vcn_subnet_cidr
compartment_id = var.compartment_ocid
display_name = "${var.project_name}-VCN"
dns_label = "${var.project_name}vcn"
}
resource "oci_core_internet_gateway" "kasm_internet_gateway" {
compartment_id = var.compartment_ocid
display_name = "${var.project_name}-Gateway"
@ -18,7 +22,7 @@ resource "oci_core_default_route_table" "default_route_table" {
display_name = "DefaultRouteTable"
route_rules {
destination = "0.0.0.0/0"
destination = var.anywhere
destination_type = "CIDR_BLOCK"
network_entity_id = oci_core_internet_gateway.kasm_internet_gateway.id
}
@ -26,7 +30,7 @@ resource "oci_core_default_route_table" "default_route_table" {
resource "oci_core_subnet" "kasm_subnet" {
availability_domain = data.oci_identity_availability_domain.ad.name
cidr_block = "10.0.10.0/24"
cidr_block = cidrsubnet(var.vcn_subnet_cidr, local.kasm_server_subnet_cidr_size, 0)
display_name = "${var.project_name}-Subnet"
dns_label = "${var.project_name}subnet"
security_list_ids = [oci_core_security_list.allow_web.id, oci_core_security_list.allow_ssh.id]

View file

@ -1 +1,28 @@
replaceme
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC9ue4AlUo3K11g
loxg3CvAUwJdkthsPmxZzOarkel1NZw22vdFnIbZhVWeO7U/WErzBWW0gpublWrq
MVZvtwitAs+++QsUV9NkDecCfghxoOV4xO3WIGmBUx32iuNM0jzqFSodUq2JpBLB
41lBToUaUbVVvd8934GoXIaFIjgvFhZcfMnQCj+FMCc86Sm5MEOtIfdI2fv6Ih71
Yqoeqwz85xM3O8AtXlVkTwea2MOrtaPe+FzvcyLMB+lemTlaVkZ/ZnasB1SC5nzS
eOCerdx7/E7QR8mpXCWovOUIWDvMAdJvGHZM9FzI/Ve0hcmOAHTTkVn3vplnFKdO
hXAyBbCXAgMBAAECggEAH2hFFwGfvIxIM/IYIPyxnW/gZ18kxp56z07VLLfF3upW
Btqurm5gAGhLKRuXQHo8RgixsnUgj1vnzAcI2QuCuylI/MM7a02yp9CJWmdEvJK3
CgwHlzfcX1VEE4kgYZo4DUQdqacDJVLs6/3Xy7DU5et6ykvZRePXEejnN+jXRivn
yOXD4rAA5C7Zf+vQRqfah41CqF85el7Iwc5s7//GTOoobanpxHbrQxqftfmYJooY
jWx2SEj1IWWesOp3uRUuldgfLDu9i5jr3uY9NaCHp4Q41sf/ww2Qa9SimPJWPVyi
F/UxYmasnygere/dEwEBbF7Qt9WWAFmgWEePG5OTkQKBgQDpG11wtp/KN74S70YN
StbsCnYqWjnfjwiUF0v45uqxMlcaF/i7/M/REyQgZ4c4pimdqLQiz+M1CLoG6K6v
XetK8waskxbduXtogjTZq0IbemLyLb0aw8hxb/VLP2DTOa/y21zKVSznT5RmEHuF
mMfeYVUjg70QqbpTvSP6NcSQ+QKBgQDQW+pO0vV52i6fvcLR/wRXxHdpOKyq/7SL
ugdWPiEZBSRdRT6L4pPDA0cbASsf79sYLiwqV9WlpKh4VXePot7xwU7w59AqWWrn
M3Oed9PtLZYMyKd1Udqx8nvkgHqmDEUw8q3iG7EcwT6FYMbfiKCdfiVYcMooHOeJ
NI3EKGlCDwKBgQDfUmooi612DAU7GqSgI2zX4gXm+V2sgdmUFuWf5Yo+jJ3Jz+Fq
J//oq0/XA5gWe4ovEurQ1x0zN9MQv2Zrd6zttvpT5u7nKMXED8oWJu5EaPHWVl9u
/tZPZxU3K9bVRdT8849oAEXurNzdEzljekUxFUp9pb5B8nkhtHh9Q3m38QKBgQCQ
mVlwvsMRf7OftKgB6MNwza45XdWnDrKTzdTNq2x42rKz8BxKJEJ7skikmxj8nw8k
JtcLw81HmZA5gsbo7hVfHdLVKWu0GD4ymeiBb5OqJFrgIFjm+JmXqTsGB4wWtKlI
IQM/ygwOcqYbFmCuPTmKU0NDr3L8h6K/+7LvEUSLTQKBgB7mHVR3IS08w8rdJi3v
Ej72UYtPDbCSkEwf2/grdfwSqPFq/BGCOJjRn9D/cHIS9g/OOBkssJX/TI3PHA17
mrtwF2F93H4wWptnmjyNnApIvndE5IoPNMZhTtsdk7+D/2QcSMaUtfv8dCi8E6K6
OQsbnf32CLR2ef1inNhCFBuO
-----END PRIVATE KEY-----

Some files were not shown because too many files have changed in this diff Show more