diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..0567e7c --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,63 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: mixed-line-ending + - id: trailing-whitespace + - repo: https://github.com/antonbabenko/pre-commit-terraform + rev: v1.81.0 + hooks: + - id: tfupdate + name: Autoupdate Terraform versions + args: + - --args=terraform + - --args=--version "~> 1.0" + - id: tfupdate + name: Autoupdate AWS version + args: + - --args=provider aws + - --args=--version "~> 5.0" + - id: tfupdate + name: Autoupdate OCI version + args: + - --args=provider oci + - --args=--version "~> 5.0" + - id: tfupdate + name: Autoupdate DigitalOcean version + args: + - --args=provider digitalocean + - --args=--version "~> 2.0" + - id: tfupdate + name: Autoupdate Acme version + args: + - --args=provider acme + - --args=--version "~> 2.0" + - id: tfupdate + name: Autoupdate TLS version + args: + - --args=provider tls + - --args=--version "~> 4.0" + - id: terraform_fmt + - id: terraform_tflint + args: + - '--args=--only=terraform_deprecated_interpolation' + - '--args=--only=terraform_deprecated_index' + - '--args=--only=terraform_unused_declarations' + - '--args=--only=terraform_comment_syntax' + - '--args=--only=terraform_documented_outputs' + - '--args=--only=terraform_documented_variables' + - '--args=--only=terraform_typed_variables' + - '--args=--only=terraform_module_pinned_source' + - '--args=--only=terraform_required_version' + - '--args=--only=terraform_required_providers' + - '--args=--minimum-failure-severity=error' + - --args=--fix + - id: terraform_validate + args: + - --tf-init-args=-upgrade + - --hook-config=--retry-once-with-cleanup=true + - id: terraform_docs + args: + - --hook-config=--path-to-file=README.md + - --hook-config=--add-to-existing-file=true + - --hook-config=--create-file-if-not-exist=true diff --git a/aws/multi_region/README.md b/aws/multi_region/README.md index 303e43e..3eddb16 100644 --- a/aws/multi_region/README.md +++ b/aws/multi_region/README.md @@ -12,11 +12,11 @@ It is expected that administrators will configure the traffic does not always traverse the **Primary Region** and instead flows directly to the Agent in whichever region it is deployed. - ![Diagram][Image_Diagram] -[Image_Diagram]: https://f.hubspotusercontent30.net/hubfs/5856039/terraform/diagrams/aws-multi-region-int-gw.png "Diagram" +[Image_Diagram]: https://5856039.fs1.hubspotusercontent-na1.net/hubfs/5856039/terraform/diagrams/aws-multi-region-new.jpg "Diagram" +> ***NOTE:*** This deployment has been tested and validated with both [Terraform](https://www.terraform.io/) and [OpenTofu](https://opentofu.org/) # Pre-Configuration Consider creating a special sub account for the Kasm deployment. @@ -35,60 +35,106 @@ Create a user via the IAM console that will be used for the terraform deployment 1. Initialize the project - terraform init + terraform init -2. Open `settings.tfvars` and update the variable values. The variable definitions, descriptions, and validation expectations can be found in the `variables.tf` file. +2. Open `terraform.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. +> ***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. If you would rather use Environment variables or some other AWS credential method in lieu of the `secrets.tfvars` file, check out the [AWS Terraform provider documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#environment-variables) for more information about configuring your environment. -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. +3. If you are deploying more than 2 regions, you will need to modify the `provider.tf`, `deployment.tf`, and `outputs.tf` files. There are commented sections in both files indicating how to deploy additional regions. 3. Verify the configuration - terraform plan -var-file settings.tfvars -var-file secrets.tfvars + terraform plan -var-file secrets.tfvars 4. Deploy - terraform apply -var-file settings.tfvars -var-file secrets.tfvars + terraform apply -var-file secrets.tfvars -5. Login to the Deployment as an Admin via the domain defined e.g `https://kasm.contoso.com` +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. Navigate to the `Infrastructure > Zones` section and update the following values according to output values from this deployment. + - Upstream Auth Address + - Proxy Hostname +7. Navigate to the `Infrastructure > Agents` section and enable each Agent after it checks in. (May take a few minutes) -# AWS Terraform Variable definitions +8. Now you are ready to add Workspaces via the registry and start using Kasm! -| 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) |
{
region2 = {
agent_region = "eu-central-1"
agent_ec2_ami_id = "ami-0e067cc8a2b58de59"
agent_instance_type = "t3.medium"
num_agents = 2
agent_vpc_cidr = "10.1.0.0/16"
}
}
-| `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.13.0.002947.tar.gz"` |
-| `aws_default_tags` | A Map of all tags you wish to apply to all TF created resources in this deployment. | Map(Any) | {
Service_name = "Kasm Workspaces"
Kasm_version = "1.12"
} |
+
+## Requirements
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0 |
+| [aws](#requirement\_aws) | ~> 5.0 |
+
+## Providers
+
+No providers.
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [primary\_region](#module\_primary\_region) | ./primary | n/a |
+| [primary\_region\_webapps\_and\_agents](#module\_primary\_region\_webapps\_and\_agents) | ./webapps | n/a |
+| [region2\_agents](#module\_region2\_agents) | ./agents | n/a |
+| [region2\_webapps](#module\_region2\_webapps) | ./webapps | n/a |
+
+## Resources
+
+No resources.
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [admin\_password](#input\_admin\_password) | The administrative user password. No special characters | `string` | n/a | yes |
+| [agent\_hdd\_size\_gb](#input\_agent\_hdd\_size\_gb) | The HDD size in GB to configure for the Kasm Agent instances | `number` | n/a | yes |
+| [agent\_instance\_type](#input\_agent\_instance\_type) | The instance type for the Agents | `string` | n/a | yes |
+| [aws\_access\_key](#input\_aws\_access\_key) | The AWS access key used for deployment | `string` | n/a | yes |
+| [aws\_default\_tags](#input\_aws\_default\_tags) | Default tags to apply to all AWS resources for this deployment | `map(any)` | {
"Kasm_version": "1.14",
"Service_name": "Kasm Workspaces"
} | no |
+| [aws\_domain\_name](#input\_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` | n/a | yes |
+| [aws\_key\_pair](#input\_aws\_key\_pair) | The name of an aws keypair to use. | `string` | n/a | yes |
+| [aws\_primary\_region](#input\_aws\_primary\_region) | The AWS Region used for deployment | `string` | `"us-east-1"` | no |
+| [aws\_secret\_key](#input\_aws\_secret\_key) | The AWS secret key used for deployment | `string` | n/a | yes |
+| [aws\_ssm\_iam\_role\_name](#input\_aws\_ssm\_iam\_role\_name) | The name of the SSM EC2 role to associate with Kasm VMs for SSH access | `string` | `""` | no |
+| [aws\_ssm\_instance\_profile\_name](#input\_aws\_ssm\_instance\_profile\_name) | The name of the SSM EC2 Instance Profile to associate with Kasm VMs for SSH access | `string` | `""` | no |
+| [cpx\_hdd\_size\_gb](#input\_cpx\_hdd\_size\_gb) | The HDD size in GB to configure for the Kasm Guac RDP instances | `number` | n/a | yes |
+| [cpx\_instance\_type](#input\_cpx\_instance\_type) | The instance type for the Guac RDP nodes | `string` | n/a | yes |
+| [create\_aws\_ssm\_iam\_role](#input\_create\_aws\_ssm\_iam\_role) | Create an AWS SSM IAM role to attach to VMs for SSH/console access to VMs. | `bool` | `false` | no |
+| [database\_password](#input\_database\_password) | The password for the database. No special characters | `string` | n/a | yes |
+| [db\_hdd\_size\_gb](#input\_db\_hdd\_size\_gb) | The HDD size in GB to configure for the Kasm Database instances | `number` | n/a | yes |
+| [db\_instance\_type](#input\_db\_instance\_type) | The instance type for the Database | `string` | n/a | yes |
+| [kasm\_build](#input\_kasm\_build) | Download URL for Kasm Workspaces | `string` | n/a | yes |
+| [manager\_token](#input\_manager\_token) | The manager token value for Agents to authenticate to webapps. No special characters | `string` | n/a | yes |
+| [num\_agents](#input\_num\_agents) | The number of Agent Role Servers to create in the deployment | `number` | `2` | no |
+| [num\_cpx\_nodes](#input\_num\_cpx\_nodes) | The number of RDP Conection Proxy Role Servers to create in the deployment. Set this to zero (0) and this Terraform will not deploy ANY Connection Proxy or Windows resoures like subnets, security groups, etc. | `number` | n/a | yes |
+| [num\_proxy\_nodes](#input\_num\_proxy\_nodes) | The number of Dedicated Proxy nodes to create in the deployment | `number` | n/a | yes |
+| [num\_webapps](#input\_num\_webapps) | The number of WebApp role servers to create in the deployment | `number` | `2` | no |
+| [primary\_region\_ec2\_ami\_id](#input\_primary\_region\_ec2\_ami\_id) | AMI Id of Kasm EC2 image in the primary region. Recommended AMI OS Version is Ubuntu 20.04 LTS. | `string` | n/a | yes |
+| [primary\_vpc\_subnet\_cidr](#input\_primary\_vpc\_subnet\_cidr) | The subnet CIDR to use for the VPC | `string` | `"10.0.0.0/16"` | no |
+| [project\_name](#input\_project\_name) | The name of the deployment (e.g dev, staging). A short single word | `string` | n/a | yes |
+| [proxy\_hdd\_size\_gb](#input\_proxy\_hdd\_size\_gb) | The HDD size in GB to configure for the Kasm dedicated proxy instances | `number` | n/a | yes |
+| [proxy\_instance\_type](#input\_proxy\_instance\_type) | The instance type for the dedicated proxy node | `string` | `""` | no |
+| [redis\_password](#input\_redis\_password) | The password for the Redis server. No special characters | `string` | n/a | yes |
+| [secondary\_regions\_settings](#input\_secondary\_regions\_settings) | Map of Kasm settings for secondary regions | map(object({
agent_region = string
agent_vpc_cidr = string
ec2_ami_id = string
})
) | n/a | yes |
+| [service\_registration\_token](#input\_service\_registration\_token) | The service registration token value for cpx RDP servers to authenticate to webapps. No special characters | `string` | n/a | yes |
+| [ssh\_access\_cidrs](#input\_ssh\_access\_cidrs) | CIDR notation of the bastion host allowed to SSH in to the machines | `list(string)` | [| no | +| [swap\_size](#input\_swap\_size) | The amount of swap (in MB) to configure inside the compute instances | `number` | n/a | yes | +| [user\_password](#input\_user\_password) | The standard (non administrator) user password. No special characters | `string` | n/a | yes | +| [web\_access\_cidrs](#input\_web\_access\_cidrs) | CIDR notation of the bastion host allowed to SSH in to the machines | `list(string)` |
"0.0.0.0/0"
]
[| no | +| [webapp\_hdd\_size\_gb](#input\_webapp\_hdd\_size\_gb) | The HDD size in GB to configure for the Kasm WebApp instances | `number` | n/a | yes | +| [webapp\_instance\_type](#input\_webapp\_instance\_type) | The instance type for the webapps | `string` | `""` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [region1\_zone\_settings](#output\_region1\_zone\_settings) | Upstream Auth and Proxy settings to apply to Kasm Primary Region Zone configuration | +| [region2\_zone\_settings](#output\_region2\_zone\_settings) | Upstream Auth and Proxy settings to apply to Kasm Agent Region 2 Zone configuration | + # Detailed Terraform Deployment Diagram diff --git a/aws/multi_region/agents/README.md b/aws/multi_region/agents/README.md new file mode 100644 index 0000000..43667c4 --- /dev/null +++ b/aws/multi_region/agents/README.md @@ -0,0 +1,109 @@ +# agents + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | ~> 1.0 | +| [aws](#requirement\_aws) | ~> 5.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | 5.36.0 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_acm_certificate.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate) | resource | +| [aws_acm_certificate_validation.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate_validation) | resource | +| [aws_eip.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip) | resource | +| [aws_instance.agent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource | +| [aws_instance.cpx](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource | +| [aws_instance.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource | +| [aws_internet_gateway.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/internet_gateway) | resource | +| [aws_lb.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb) | resource | +| [aws_lb_listener.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener) | resource | +| [aws_lb_target_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_target_group) | resource | +| [aws_lb_target_group_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_target_group_attachment) | resource | +| [aws_nat_gateway.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/nat_gateway) | resource | +| [aws_route53_record.alb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource | +| [aws_route53_record.certificate](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource | +| [aws_route_table.internet_gateway](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource | +| [aws_route_table.nat_gateway](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource | +| [aws_route_table_association.agent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource | +| [aws_route_table_association.alb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource | +| [aws_route_table_association.cpx](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource | +| [aws_route_table_association.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource | +| [aws_route_table_association.windows](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource | +| [aws_security_group.agent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | +| [aws_security_group.cpx](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | +| [aws_security_group.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | +| [aws_security_group.public_lb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | +| [aws_security_group.windows](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | +| [aws_security_group_rule.agent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | +| [aws_security_group_rule.agent_egress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | +| [aws_security_group_rule.cpx](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | +| [aws_security_group_rule.cpx_egress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | +| [aws_security_group_rule.proxy_agent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | +| [aws_security_group_rule.proxy_egress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | +| [aws_security_group_rule.proxy_public_lb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | +| [aws_security_group_rule.public_lb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | +| [aws_security_group_rule.public_lb_egress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | +| [aws_security_group_rule.windows_cpx](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | +| [aws_security_group_rule.windows_egress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | +| [aws_security_group_rule.windows_webapp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | +| [aws_subnet.agent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource | +| [aws_subnet.alb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource | +| [aws_subnet.cpx](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource | +| [aws_subnet.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource | +| [aws_subnet.windows](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource | +| [aws_vpc.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc) | resource | +| [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source | +| [aws_route53_zone.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route53_zone) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [agent\_hdd\_size\_gb](#input\_agent\_hdd\_size\_gb) | The HDD size for agents | `number` | n/a | yes | +| [agent\_instance\_type](#input\_agent\_instance\_type) | The instance type for the agents | `string` | n/a | yes | +| [agent\_security\_rules](#input\_agent\_security\_rules) | A map of objects of security rules to apply to the Kasm WebApp server |
"0.0.0.0/0"
]
map(object({
from_port = number
to_port = number
protocol = string
})) | {
"https": {
"from_port": 443,
"protocol": "tcp",
"to_port": 443
}
} | no |
+| [agent\_vpc\_cidr](#input\_agent\_vpc\_cidr) | Subnet CIDR range for Agent VPC | `string` | n/a | yes |
+| [anywhere](#input\_anywhere) | Anywhere subnet for routing and load ingress from all IPs | `string` | `"0.0.0.0/0"` | no |
+| [aws\_domain\_name](#input\_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` | n/a | yes |
+| [aws\_key\_pair](#input\_aws\_key\_pair) | The name of an aws keypair to use. | `string` | n/a | yes |
+| [aws\_region](#input\_aws\_region) | The AWS region for the deployment. (e.g us-east-1) | `string` | n/a | yes |
+| [aws\_ssm\_instance\_profile\_name](#input\_aws\_ssm\_instance\_profile\_name) | The name of the SSM EC2 Instance Profile to associate with Kasm VMs for SSH access | `string` | `""` | no |
+| [cpx\_hdd\_size\_gb](#input\_cpx\_hdd\_size\_gb) | The HDD size for Kasm Guac RDP nodes | `number` | n/a | yes |
+| [cpx\_instance\_type](#input\_cpx\_instance\_type) | The instance type for the cpx RDP nodes | `string` | n/a | yes |
+| [cpx\_security\_rules](#input\_cpx\_security\_rules) | A map of objects of security rules to apply to the Kasm Connection Proxy server | map(object({
from_port = number
to_port = number
protocol = string
})) | {
"https": {
"from_port": 443,
"protocol": "tcp",
"to_port": 443
}
} | no |
+| [default\_egress](#input\_default\_egress) | Default egress security rule for all security groups | map(object({
from_port = number
to_port = number
protocol = string
cidr_subnets = list(string)
})) | {
"all": {
"cidr_subnets": [
"0.0.0.0/0"
],
"from_port": 0,
"protocol": "-1",
"to_port": 0
}
} | no |
+| [ec2\_ami](#input\_ec2\_ami) | The AMI used for the EC2 nodes. Recommended Ubuntu 20.04 LTS. | `string` | n/a | yes |
+| [kasm\_build](#input\_kasm\_build) | The URL for the Kasm Workspaces build | `string` | n/a | yes |
+| [management\_region\_nat\_gateway](#input\_management\_region\_nat\_gateway) | A list Kasm management region NAT gateways to allow Webapps ingress on 4902 to Kasm Windows agent | `string` | n/a | yes |
+| [manager\_token](#input\_manager\_token) | The password for the database. No special characters | `string` | n/a | yes |
+| [num\_agents](#input\_num\_agents) | The number of Agent Role Servers to create in the deployment | `number` | n/a | yes |
+| [num\_cpx\_nodes](#input\_num\_cpx\_nodes) | The number of cpx Role Servers to create in the deployment | `number` | n/a | yes |
+| [num\_proxy\_nodes](#input\_num\_proxy\_nodes) | The number of Dedicated Proxy nodes to create in the deployment | `number` | `2` | no |
+| [project\_name](#input\_project\_name) | The name of the deployment (e.g dev, staging). A short single word | `string` | n/a | yes |
+| [proxy\_hdd\_size\_gb](#input\_proxy\_hdd\_size\_gb) | The HDD size for Dedicated Proxy nodes | `number` | n/a | yes |
+| [proxy\_instance\_type](#input\_proxy\_instance\_type) | The instance type for the dedicated proxy nodes | `string` | n/a | yes |
+| [proxy\_security\_rules](#input\_proxy\_security\_rules) | A map of objects of security rules to apply to the Kasm WebApp server | map(object({
from_port = number
to_port = number
protocol = string
})) | {
"https": {
"from_port": 443,
"protocol": "tcp",
"to_port": 443
}
} | no |
+| [public\_lb\_security\_rules](#input\_public\_lb\_security\_rules) | A map of objects of security rules to apply to the Public ALB | map(object({
from_port = number
to_port = number
protocol = string
})) | {
"http": {
"from_port": 80,
"protocol": "tcp",
"to_port": 80
},
"https": {
"from_port": 443,
"protocol": "tcp",
"to_port": 443
}
} | no |
+| [service\_registration\_token](#input\_service\_registration\_token) | The service registration token value for cpx RDP servers to authenticate to webapps. No special characters | `string` | n/a | yes |
+| [swap\_size](#input\_swap\_size) | The amount of swap (in MB) to configure inside the compute instances | `number` | n/a | yes |
+| [web\_access\_cidrs](#input\_web\_access\_cidrs) | List of Networks in CIDR notation for IPs allowed to access the Kasm Web interface | `list(string)` | [| no | +| [windows\_security\_rules](#input\_windows\_security\_rules) | A map of objects of security rules to apply to the Kasm Windows VMs |
"0.0.0.0/0"
]
map(object({
from_port = number
to_port = number
protocol = string
})) | {
"api": {
"from_port": 4902,
"protocol": "tcp",
"to_port": 4902
},
"rdp": {
"from_port": 3389,
"protocol": "tcp",
"to_port": 3389
}
} | no |
+
+## Outputs
+
+No outputs.
+
diff --git a/aws/multi_region/agents/agent.tf b/aws/multi_region/agents/agent.tf
index b32beb2..f709561 100644
--- a/aws/multi_region/agents/agent.tf
+++ b/aws/multi_region/agents/agent.tf
@@ -1,10 +1,12 @@
-resource "aws_instance" "kasm-agent" {
- 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
+resource "aws_instance" "agent" {
+ count = var.num_agents
+ ami = var.ec2_ami
+ instance_type = var.agent_instance_type
+ vpc_security_group_ids = [aws_security_group.agent.id]
+ subnet_id = aws_subnet.agent.id
+ key_name = var.aws_key_pair
+ associate_public_ip_address = true
+ iam_instance_profile = var.aws_ssm_instance_profile_name
root_block_device {
volume_size = var.agent_hdd_size_gb
@@ -19,7 +21,14 @@ resource "aws_instance" "kasm-agent" {
}
)
+ metadata_options {
+ http_endpoint = "enabled"
+ http_tokens = "required"
+ http_put_response_hop_limit = 1
+ instance_metadata_tags = null
+ }
+
tags = {
- Name = "${var.project_name}-${var.zone_name}-kasm-agent"
+ Name = "${var.project_name}-${var.aws_region}-kasm-agent-${count.index}"
}
}
diff --git a/aws/multi_region/agents/availability_zones.tf b/aws/multi_region/agents/availability_zones.tf
deleted file mode 100644
index 87d8f48..0000000
--- a/aws/multi_region/agents/availability_zones.tf
+++ /dev/null
@@ -1,3 +0,0 @@
-data "aws_availability_zones" "available" {
- state = "available"
-}
diff --git a/aws/multi_region/agents/cert.tf b/aws/multi_region/agents/cert.tf
new file mode 100644
index 0000000..6257cc9
--- /dev/null
+++ b/aws/multi_region/agents/cert.tf
@@ -0,0 +1,32 @@
+resource "aws_acm_certificate" "this" {
+ domain_name = var.aws_domain_name
+ subject_alternative_names = ["*.${var.aws_domain_name}"]
+ validation_method = "DNS"
+
+
+ lifecycle {
+ create_before_destroy = true
+ }
+}
+
+resource "aws_route53_record" "certificate" {
+ for_each = {
+ for dvo in aws_acm_certificate.this.domain_validation_options : dvo.domain_name => {
+ name = dvo.resource_record_name
+ record = dvo.resource_record_value
+ type = dvo.resource_record_type
+ }
+ }
+ name = each.value.name
+ type = each.value.type
+ records = [each.value.record]
+ zone_id = data.aws_route53_zone.this.id
+
+ ttl = 30
+ allow_overwrite = true
+}
+
+resource "aws_acm_certificate_validation" "this" {
+ certificate_arn = aws_acm_certificate.this.arn
+ validation_record_fqdns = [for record in aws_route53_record.certificate : record.fqdn]
+}
diff --git a/aws/multi_region/agents/cpx.tf b/aws/multi_region/agents/cpx.tf
new file mode 100644
index 0000000..7dc96fa
--- /dev/null
+++ b/aws/multi_region/agents/cpx.tf
@@ -0,0 +1,34 @@
+resource "aws_instance" "cpx" {
+ count = var.num_cpx_nodes
+
+ ami = var.ec2_ami
+ instance_type = var.cpx_instance_type
+ vpc_security_group_ids = aws_security_group.cpx[*].id
+ subnet_id = aws_subnet.cpx[0].id
+ key_name = var.aws_key_pair
+ iam_instance_profile = var.aws_ssm_instance_profile_name
+
+ root_block_device {
+ volume_size = var.cpx_hdd_size_gb
+ }
+
+ user_data = templatefile("${path.module}/../userdata/cpx_bootstrap.sh",
+ {
+ kasm_build_url = var.kasm_build
+ swap_size = var.swap_size
+ manager_address = var.aws_domain_name
+ service_registration_token = var.service_registration_token
+ }
+ )
+
+ metadata_options {
+ http_endpoint = "enabled"
+ http_tokens = "required"
+ http_put_response_hop_limit = 1
+ instance_metadata_tags = null
+ }
+
+ tags = {
+ Name = "${var.project_name}-${var.aws_region}-kasm-cpx-${count.index}"
+ }
+}
diff --git a/aws/multi_region/agents/dependencies.tf b/aws/multi_region/agents/dependencies.tf
new file mode 100644
index 0000000..e037b9d
--- /dev/null
+++ b/aws/multi_region/agents/dependencies.tf
@@ -0,0 +1,16 @@
+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 < 3 ? 3 : local.kasm_agent_subnet_cidr_calculation
+
+ region_short_name_for_lb = join("", slice(split("-", var.aws_region), 1, 3))
+}
+
+data "aws_route53_zone" "this" {
+ name = var.aws_domain_name
+ private_zone = false
+}
+
+data "aws_availability_zones" "available" {
+ state = "available"
+}
diff --git a/aws/multi_region/agents/elb.tf b/aws/multi_region/agents/elb.tf
new file mode 100644
index 0000000..402289a
--- /dev/null
+++ b/aws/multi_region/agents/elb.tf
@@ -0,0 +1,52 @@
+resource "aws_lb" "this" {
+ name = "${var.project_name}-${var.aws_region}-proxy-lb"
+ internal = false
+ load_balancer_type = "application"
+ security_groups = [aws_security_group.public_lb.id]
+ subnets = aws_subnet.alb[*].id
+}
+
+resource "aws_lb_listener" "this" {
+ load_balancer_arn = aws_lb.this.arn
+ port = "443"
+ protocol = "HTTPS"
+ certificate_arn = aws_acm_certificate.this.arn
+
+ default_action {
+ type = "forward"
+ target_group_arn = aws_lb_target_group.this.arn
+ }
+}
+
+resource "aws_lb_target_group" "this" {
+ name = "${var.project_name}-${local.region_short_name_for_lb}-tg"
+ port = 443
+ protocol = "HTTPS"
+ vpc_id = aws_vpc.this.id
+
+ health_check {
+ path = "/desktop"
+ matcher = 301
+ protocol = "HTTPS"
+ }
+}
+
+resource "aws_lb_target_group_attachment" "this" {
+ count = var.num_proxy_nodes
+
+ target_group_arn = aws_lb_target_group.this.arn
+ target_id = aws_instance.proxy[count.index].id
+ port = 443
+}
+
+resource "aws_route53_record" "alb" {
+ zone_id = data.aws_route53_zone.this.zone_id
+ name = "${local.region_short_name_for_lb}-proxy.${var.aws_domain_name}"
+ type = "A"
+
+ alias {
+ name = aws_lb.this.dns_name
+ zone_id = aws_lb.this.zone_id
+ evaluate_target_health = false
+ }
+}
diff --git a/aws/multi_region/agents/provider.tf b/aws/multi_region/agents/provider.tf
index ea82995..2039c6e 100644
--- a/aws/multi_region/agents/provider.tf
+++ b/aws/multi_region/agents/provider.tf
@@ -1,8 +1,10 @@
terraform {
+ required_version = "~> 1.0"
+
required_providers {
aws = {
- source = "hashicorp/aws"
- #version = "4.56.0"
+ source = "hashicorp/aws"
+ version = "~> 5.0"
}
}
}
\ No newline at end of file
diff --git a/aws/multi_region/agents/proxy.tf b/aws/multi_region/agents/proxy.tf
new file mode 100644
index 0000000..8341592
--- /dev/null
+++ b/aws/multi_region/agents/proxy.tf
@@ -0,0 +1,34 @@
+resource "aws_instance" "proxy" {
+ count = var.num_proxy_nodes
+
+ ami = var.ec2_ami
+ instance_type = var.proxy_instance_type
+ vpc_security_group_ids = [aws_security_group.proxy.id]
+ subnet_id = aws_subnet.proxy[(count.index)].id
+ key_name = var.aws_key_pair
+ iam_instance_profile = var.aws_ssm_instance_profile_name
+
+ root_block_device {
+ volume_size = var.proxy_hdd_size_gb
+ }
+
+ user_data = templatefile("${path.module}/../userdata/proxy_bootstrap.sh",
+ {
+ kasm_build_url = var.kasm_build
+ swap_size = var.swap_size
+ manager_address = var.aws_domain_name
+ proxy_alb_address = "${var.aws_region}-proxy.${var.aws_domain_name}"
+ }
+ )
+
+ metadata_options {
+ http_endpoint = "enabled"
+ http_tokens = "required"
+ http_put_response_hop_limit = 1
+ instance_metadata_tags = null
+ }
+
+ tags = {
+ Name = "${var.project_name}-${var.aws_region}-kasm-proxy-${count.index}"
+ }
+}
diff --git a/aws/multi_region/agents/routes.tf b/aws/multi_region/agents/routes.tf
index 3d48abb..39ee67f 100644
--- a/aws/multi_region/agents/routes.tf
+++ b/aws/multi_region/agents/routes.tf
@@ -1,21 +1,54 @@
-resource "aws_route_table" "internet_access" {
- vpc_id = data.aws_vpc.data-kasm_agent_vpc.id
+resource "aws_route_table" "internet_gateway" {
+ vpc_id = aws_vpc.this.id
route {
cidr_block = var.anywhere
- gateway_id = data.aws_internet_gateway.data-kasm_agent_default_ig.id
+ gateway_id = aws_internet_gateway.this.id
}
tags = {
- Name = "${var.project_name}-kasm-agent-default-route"
+ Name = "${var.project_name}-kasm-internet-gateway-route"
}
}
-data "aws_route_table" "data-agent_internet_gateway_route_table" {
- route_table_id = aws_route_table.internet_access.id
+resource "aws_route_table" "nat_gateway" {
+ vpc_id = aws_vpc.this.id
+
+ route {
+ cidr_block = var.anywhere
+ nat_gateway_id = aws_nat_gateway.this.id
+ }
+
+ tags = {
+ Name = "${var.project_name}-kasm-nat-gateway-route"
+ }
}
-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
+resource "aws_route_table_association" "alb" {
+ count = 2
+ subnet_id = aws_subnet.alb[(count.index)].id
+ route_table_id = aws_route_table.internet_gateway.id
+}
+
+resource "aws_route_table_association" "proxy" {
+ count = var.num_proxy_nodes
+ subnet_id = aws_subnet.proxy[(count.index)].id
+ route_table_id = aws_route_table.nat_gateway.id
+}
+
+resource "aws_route_table_association" "agent" {
+ subnet_id = aws_subnet.agent.id
+ route_table_id = aws_route_table.internet_gateway.id
+}
+
+resource "aws_route_table_association" "cpx" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+ subnet_id = aws_subnet.cpx[0].id
+ route_table_id = aws_route_table.nat_gateway.id
+}
+
+resource "aws_route_table_association" "windows" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+ subnet_id = aws_subnet.windows[0].id
+ route_table_id = aws_route_table.internet_gateway.id
}
diff --git a/aws/multi_region/agents/security_group.tf b/aws/multi_region/agents/security_group.tf
index 4fe5d53..c2896f2 100644
--- a/aws/multi_region/agents/security_group.tf
+++ b/aws/multi_region/agents/security_group.tf
@@ -1,30 +1,197 @@
-resource "aws_security_group" "kasm-agent-sg" {
- name = "${var.project_name}-${var.zone_name}-kasm-agent-access"
+resource "aws_security_group" "public_lb" {
+ name = "${var.project_name}-kasm-allow-public-lb-access"
+ description = "Security Group for ELB"
+ vpc_id = aws_vpc.this.id
+
+ tags = {
+ Name = "${var.project_name}-kasm-public-lb-access"
+ }
+}
+
+resource "aws_security_group_rule" "public_lb" {
+ for_each = var.public_lb_security_rules
+
+ description = "Allow Public LB ingress from ${join(",", var.web_access_cidrs)}"
+ security_group_id = aws_security_group.public_lb.id
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = var.web_access_cidrs
+}
+
+resource "aws_security_group_rule" "public_lb_egress" {
+ for_each = var.default_egress
+
+ description = "Allow Public LB egress"
+ security_group_id = aws_security_group.public_lb.id
+ type = "egress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = each.value.cidr_subnets
+}
+
+resource "aws_security_group" "proxy" {
+ name = "${var.project_name}-kasm-proxy"
+ description = "Allow access to proxy"
+ vpc_id = aws_vpc.this.id
+
+ tags = {
+ Name = "${var.project_name}-kasm-proxy-access"
+ }
+}
+
+resource "aws_security_group_rule" "proxy_public_lb" {
+ for_each = var.proxy_security_rules
+
+ security_group_id = aws_security_group.proxy.id
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ source_security_group_id = aws_security_group.public_lb.id
+}
+
+resource "aws_security_group_rule" "proxy_agent" {
+ for_each = var.proxy_security_rules
+
+ description = "Allow Proxy ingress from Public LB"
+ security_group_id = aws_security_group.proxy.id
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ source_security_group_id = aws_security_group.agent.id
+}
+
+resource "aws_security_group_rule" "proxy_egress" {
+ for_each = var.default_egress
+
+ description = "Allow Proxy Egress"
+ security_group_id = aws_security_group.proxy.id
+ type = "egress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = each.value.cidr_subnets
+}
+
+resource "aws_security_group" "agent" {
+ name = "${var.project_name}-kasm-agent-access"
description = "Allow access to agents"
- vpc_id = data.aws_vpc.data-kasm_agent_vpc.id
+ vpc_id = aws_vpc.this.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]
+ tags = {
+ Name = "${var.project_name}-kasm-agent-access"
}
}
-data "aws_security_group" "data-kasm_agent_sg" {
- id = aws_security_group.kasm-agent-sg.id
+resource "aws_security_group_rule" "agent" {
+ for_each = var.agent_security_rules
+
+ description = "Allow Kasm Agent ingress from Proxy"
+ security_group_id = aws_security_group.agent.id
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ source_security_group_id = aws_security_group.proxy.id
+}
+
+resource "aws_security_group_rule" "agent_egress" {
+ for_each = var.default_egress
+
+ description = "Allow Agents egress"
+ security_group_id = aws_security_group.agent.id
+ type = "egress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = each.value.cidr_subnets
+}
+
+
+resource "aws_security_group" "cpx" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+
+ name = "${var.project_name}-kasm-cpx-access"
+ description = "Allow access to cpx RDP nodes"
+ vpc_id = aws_vpc.this.id
+
+ tags = {
+ Name = "${var.project_name}-kasm-cpx-access"
+ }
+}
+
+resource "aws_security_group_rule" "cpx" {
+ for_each = var.num_cpx_nodes > 0 ? var.cpx_security_rules : {}
+
+ description = "Allow Kasm CPX ingress from Kasm Proxy"
+ security_group_id = one(aws_security_group.cpx[*].id)
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ source_security_group_id = aws_security_group.proxy.id
+}
+
+resource "aws_security_group_rule" "cpx_egress" {
+ for_each = var.num_cpx_nodes > 0 ? var.default_egress : {}
+
+ description = "Allow Kasm CPX egress"
+ security_group_id = one(aws_security_group.cpx[*].id)
+ type = "egress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = each.value.cidr_subnets
+}
+
+resource "aws_security_group" "windows" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+
+ name = "${var.project_name}-kasm-windows-access"
+ description = "Allow access to Windows servers"
+ vpc_id = aws_vpc.this.id
+
+ tags = {
+ Name = "${var.project_name}-kasm-windows-access"
+ }
+}
+
+resource "aws_security_group_rule" "windows_cpx" {
+ for_each = var.num_cpx_nodes > 0 ? var.windows_security_rules : {}
+
+ description = "Allow Windows ingress from Kasm CPX"
+ security_group_id = one(aws_security_group.windows[*].id)
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ source_security_group_id = one(aws_security_group.cpx[*].id)
+}
+
+resource "aws_security_group_rule" "windows_webapp" {
+ for_each = var.num_cpx_nodes > 0 ? { for key, value in var.windows_security_rules : key => value if can(regex("(?i:api)", key)) } : {}
+
+ description = "Allow Windows ingress from Kasm WebApp"
+ security_group_id = one(aws_security_group.windows[*].id)
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = [var.management_region_nat_gateway]
+}
+
+resource "aws_security_group_rule" "windows_egress" {
+ for_each = var.num_cpx_nodes > 0 ? var.default_egress : {}
+
+ description = "Allow Windows egress"
+ security_group_id = one(aws_security_group.windows[*].id)
+ type = "egress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = each.value.cidr_subnets
}
diff --git a/aws/multi_region/agents/subnet.tf b/aws/multi_region/agents/subnet.tf
index 598d6f8..df107d1 100644
--- a/aws/multi_region/agents/subnet.tf
+++ b/aws/multi_region/agents/subnet.tf
@@ -1,19 +1,59 @@
-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 = 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]
+resource "aws_subnet" "alb" {
+ count = 2
+ vpc_id = aws_vpc.this.id
+ cidr_block = cidrsubnet(var.agent_vpc_cidr, local.kasm_agent_subnet_cidr_size, count.index)
+ availability_zone = data.aws_availability_zones.available.names[(count.index)]
map_public_ip_on_launch = true
+
tags = {
- Name = "${var.project_name}-${var.zone_name}-kasm-agent-subnet"
+ Name = "${var.project_name}-${var.aws_region}-kasm-alb-subnet"
}
}
-data "aws_subnet" "data-kasm_agent_subnet" {
- id = aws_subnet.kasm-agent-subnet.id
+resource "aws_subnet" "proxy" {
+ count = var.num_proxy_nodes
+ vpc_id = aws_vpc.this.id
+ cidr_block = cidrsubnet(var.agent_vpc_cidr, local.kasm_agent_subnet_cidr_size, (count.index + 2))
+ availability_zone = data.aws_availability_zones.available.names[(count.index)]
+
+ tags = {
+ Name = "${var.project_name}-${var.aws_region}-kasm-proxy-subnet"
+ }
}
+
+resource "aws_subnet" "agent" {
+ vpc_id = aws_vpc.this.id
+ cidr_block = cidrsubnet(var.agent_vpc_cidr, local.kasm_agent_subnet_cidr_size, 4)
+ availability_zone = data.aws_availability_zones.available.names[0]
+ map_public_ip_on_launch = true
+
+ tags = {
+ Name = "${var.project_name}-${var.aws_region}-kasm-agent-subnet"
+ }
+}
+
+resource "aws_subnet" "cpx" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+
+ vpc_id = aws_vpc.this.id
+ cidr_block = cidrsubnet(var.agent_vpc_cidr, local.kasm_agent_subnet_cidr_size, 5)
+ availability_zone = data.aws_availability_zones.available.names[0]
+
+ tags = {
+ Name = "${var.project_name}-${var.aws_region}-kasm-cpx-subnet"
+ }
+}
+
+resource "aws_subnet" "windows" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+
+ vpc_id = aws_vpc.this.id
+ cidr_block = cidrsubnet(var.agent_vpc_cidr, local.kasm_agent_subnet_cidr_size, 6)
+ availability_zone = data.aws_availability_zones.available.names[0]
+ map_public_ip_on_launch = true
+
+ tags = {
+ Name = "${var.project_name}-${var.aws_region}-kasm-windows-subnet"
+ }
+}
+
diff --git a/aws/multi_region/agents/variables.tf b/aws/multi_region/agents/variables.tf
index 5d59afa..47a55a9 100644
--- a/aws/multi_region/agents/variables.tf
+++ b/aws/multi_region/agents/variables.tf
@@ -33,6 +33,43 @@ variable "agent_hdd_size_gb" {
type = number
}
+variable "num_cpx_nodes" {
+ description = "The number of cpx Role Servers to create in the deployment"
+ type = number
+}
+
+variable "cpx_instance_type" {
+ description = "The instance type for the cpx RDP nodes"
+ type = string
+}
+
+variable "cpx_hdd_size_gb" {
+ description = "The HDD size for Kasm Guac RDP nodes"
+ type = number
+}
+
+variable "aws_ssm_instance_profile_name" {
+ description = "The name of the SSM EC2 Instance Profile to associate with Kasm VMs for SSH access"
+ type = string
+ default = ""
+}
+
+variable "num_proxy_nodes" {
+ description = "The number of Dedicated Proxy nodes to create in the deployment"
+ type = number
+ default = 2
+}
+
+variable "proxy_instance_type" {
+ description = "The instance type for the dedicated proxy nodes"
+ type = string
+}
+
+variable "proxy_hdd_size_gb" {
+ description = "The HDD size for Dedicated Proxy nodes"
+ type = number
+}
+
variable "aws_region" {
description = "The AWS region for the deployment. (e.g us-east-1)"
type = string
@@ -43,11 +80,6 @@ variable "kasm_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
@@ -64,9 +96,15 @@ variable "manager_token" {
sensitive = true
}
-variable "ssh_access_cidrs" {
- description = "CIDR notation of the bastion host allowed to SSH in to the machines"
- type = list(string)
+variable "service_registration_token" {
+ description = "The service registration token value for cpx RDP servers to authenticate to webapps. No special characters"
+ type = string
+ sensitive = true
+}
+
+variable "management_region_nat_gateway" {
+ description = "A list Kasm management region NAT gateways to allow Webapps ingress on 4902 to Kasm Windows agent"
+ type = string
}
variable "anywhere" {
@@ -74,3 +112,123 @@ variable "anywhere" {
type = string
default = "0.0.0.0/0"
}
+
+variable "web_access_cidrs" {
+ description = "List of Networks in CIDR notation for IPs allowed to access the Kasm Web interface"
+ type = list(string)
+ default = ["0.0.0.0/0"]
+}
+
+variable "public_lb_security_rules" {
+ description = "A map of objects of security rules to apply to the Public ALB"
+ type = map(object({
+ from_port = number
+ to_port = number
+ protocol = string
+ }))
+
+ default = {
+ https = {
+ from_port = 443
+ to_port = 443
+ protocol = "tcp"
+ }
+ http = {
+ from_port = 80
+ to_port = 80
+ protocol = "tcp"
+ }
+ }
+}
+
+variable "proxy_security_rules" {
+ description = "A map of objects of security rules to apply to the Kasm WebApp server"
+ type = map(object({
+ from_port = number
+ to_port = number
+ protocol = string
+ }))
+
+ default = {
+ https = {
+ from_port = 443
+ to_port = 443
+ protocol = "tcp"
+ }
+ }
+}
+
+variable "cpx_security_rules" {
+ description = "A map of objects of security rules to apply to the Kasm Connection Proxy server"
+ type = map(object({
+ from_port = number
+ to_port = number
+ protocol = string
+ }))
+
+ default = {
+ https = {
+ from_port = 443
+ to_port = 443
+ protocol = "tcp"
+ }
+ }
+}
+
+variable "agent_security_rules" {
+ description = "A map of objects of security rules to apply to the Kasm WebApp server"
+ type = map(object({
+ from_port = number
+ to_port = number
+ protocol = string
+ }))
+
+ default = {
+ https = {
+ from_port = 443
+ to_port = 443
+ protocol = "tcp"
+ }
+ }
+}
+
+variable "windows_security_rules" {
+ description = "A map of objects of security rules to apply to the Kasm Windows VMs"
+ type = map(object({
+ from_port = number
+ to_port = number
+ protocol = string
+ }))
+
+ default = {
+ rdp = {
+ from_port = 3389
+ to_port = 3389
+ protocol = "tcp"
+ }
+ api = {
+ from_port = 4902
+ to_port = 4902
+ protocol = "tcp"
+ }
+ }
+}
+
+variable "default_egress" {
+ description = "Default egress security rule for all security groups"
+ type = map(object({
+ from_port = number
+ to_port = number
+ protocol = string
+ cidr_subnets = list(string)
+ }))
+
+ default = {
+ all = {
+ from_port = 0
+ to_port = 0
+ protocol = "-1"
+ cidr_subnets = ["0.0.0.0/0"]
+ }
+ }
+}
diff --git a/aws/multi_region/agents/vpc.tf b/aws/multi_region/agents/vpc.tf
index 4f5a78d..5935f27 100644
--- a/aws/multi_region/agents/vpc.tf
+++ b/aws/multi_region/agents/vpc.tf
@@ -1,23 +1,32 @@
-resource "aws_vpc" "kasm-agent-vpc" {
+resource "aws_vpc" "this" {
cidr_block = var.agent_vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
+
tags = {
- Name = "${var.project_name}-${var.zone_name}-kasm-vpc"
+ Name = "${var.project_name}-${var.aws_region}-kasm-vpc"
}
}
-data "aws_vpc" "data-kasm_agent_vpc" {
- id = aws_vpc.kasm-agent-vpc.id
-}
+resource "aws_internet_gateway" "this" {
+ vpc_id = aws_vpc.this.id
-resource "aws_internet_gateway" "kasm-default-ig" {
- vpc_id = data.aws_vpc.data-kasm_agent_vpc.id
tags = {
- Name = "${var.project_name}-${var.zone_name}-kasm-ig"
+ Name = "${var.project_name}-${var.aws_region}-kasm-ig"
}
}
-data "aws_internet_gateway" "data-kasm_agent_default_ig" {
- internet_gateway_id = aws_internet_gateway.kasm-default-ig.id
+resource "aws_eip" "this" {
+ domain = "vpc"
+}
+
+resource "aws_nat_gateway" "this" {
+ allocation_id = aws_eip.this.id
+ subnet_id = aws_subnet.alb[0].id
+
+ tags = {
+ Name = "${var.project_name}-${var.aws_region}-kasm-nat"
+ }
+
+ depends_on = [aws_internet_gateway.this]
}
diff --git a/aws/multi_region/deployment.tf b/aws/multi_region/deployment.tf
index 9d4b835..29c27f8 100644
--- a/aws/multi_region/deployment.tf
+++ b/aws/multi_region/deployment.tf
@@ -4,59 +4,69 @@
# agents/webapps that map to this region.
###########################################################
module "primary_region" {
- 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
+ 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
+ num_cpx_nodes = var.num_cpx_nodes
+ 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
+ web_access_cidrs = var.web_access_cidrs
+ create_aws_ssm_iam_role = var.create_aws_ssm_iam_role
+ aws_ssm_iam_role_name = var.aws_ssm_iam_role_name
+ aws_ssm_instance_profile_name = var.aws_ssm_instance_profile_name
}
-module "primary_region-webapps-and-agents" {
+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
+ load_balancer_subnet_ids = module.primary_region.lb_subnet_ids
num_webapps = var.num_webapps
num_agents = var.num_agents
+ num_cpx_nodes = var.num_cpx_nodes
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
+ cpx_subnet_id = module.primary_region.cpx_subnet_id
+ cpx_security_group_id = module.primary_region.cpx_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
+ cpx_instance_type = var.cpx_instance_type
+ cpx_hdd_size_gb = var.cpx_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
+ service_registration_token = var.service_registration_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
+ aws_ssm_instance_profile_name = var.aws_ssm_instance_profile_name
}
#####################################################################
@@ -64,11 +74,12 @@ module "primary_region-webapps-and-agents" {
# Add a webapp and agent module for each additional region desired.
#
#####################################################################
-module "region2-webapps" {
+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
+ load_balancer_subnet_ids = module.primary_region.lb_subnet_ids
num_webapps = var.num_webapps
webapp_instance_type = var.webapp_instance_type
webapp_hdd_size_gb = var.webapp_hdd_size_gb
@@ -87,26 +98,33 @@ module "region2-webapps" {
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
+ aws_ssm_instance_profile_name = var.aws_ssm_instance_profile_name
}
-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
+module "region2_agents" {
+ source = "./agents"
+ aws_region = var.secondary_regions_settings.region2.agent_region
+ ec2_ami = var.secondary_regions_settings.region2.ec2_ami_id
+ agent_vpc_cidr = var.secondary_regions_settings.region2.agent_vpc_cidr
+ management_region_nat_gateway = module.primary_region.nat_gateway_ip
+ proxy_instance_type = var.proxy_instance_type
+ proxy_hdd_size_gb = var.proxy_hdd_size_gb
+ num_agents = var.num_agents
+ agent_instance_type = var.agent_instance_type
+ agent_hdd_size_gb = var.agent_hdd_size_gb
+ num_cpx_nodes = var.num_cpx_nodes
+ cpx_instance_type = var.cpx_instance_type
+ cpx_hdd_size_gb = var.cpx_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
+ aws_key_pair = var.aws_key_pair
+ manager_token = var.manager_token
+ service_registration_token = var.service_registration_token
+ aws_ssm_instance_profile_name = var.aws_ssm_instance_profile_name
+ web_access_cidrs = var.web_access_cidrs
providers = {
aws = aws.region2
@@ -116,17 +134,15 @@ module "region2-agents" {
#########################################################################
#
# Uncomment the below section and update the provider and the settings
-# in the secondary_regions_settings variable in the settings.tfvars
+# in the secondary_regions_settings variable in the terraform.tfvars
# file for your desired region.
#
#########################################################################
-# module "region3-webapps" {
+# 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
+# load_balancer_subnet_ids = module.primary_region.lb_subnet_ids
# primary_aws_region = var.aws_primary_region
# num_webapps = var.num_webapps
# webapp_instance_type = var.webapp_instance_type
@@ -146,31 +162,35 @@ module "region2-agents" {
# 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
+# aws_ssm_instance_profile_name = var.aws_ssm_instance_profile_name
# }
-# 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
+# module "region3_agents" {
+# source = "./agents"
+# aws_region = var.secondary_regions_settings.region3.agent_region
+# ec2_ami = var.secondary_regions_settings.region3.ec2_ami_id
+# agent_vpc_cidr = var.secondary_regions_settings.region3.agent_vpc_cidr
+# load_balancer_log_bucket = module.primary_region.lb_log_bucket
+# management_region_nat_gateway = module.primary_region.nat_gateway_ip
+# proxy_instance_type = var.proxy_instance_type
+# proxy_hdd_size_gb = var.proxy_hdd_size_gb
+# num_agents = var.num_agents
+# agent_instance_type = var.agent_instance_type
+# agent_hdd_size_gb = var.agent_hdd_size_gb
+# num_cpx_nodes = var.num_cpx_nodes
+# cpx_instance_type = var.cpx_instance_type
+# cpx_hdd_size_gb = var.cpx_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
+# aws_key_pair = var.aws_key_pair
+# manager_token = var.manager_token
+# service_registration_token = var.service_registration_token
+# aws_ssm_instance_profile_name = var.aws_ssm_instance_profile_name
+# web_access_cidrs = var.web_access_cidrs
+
# providers = {
# aws = aws.region3
# }
diff --git a/aws/multi_region/diagram/aws_multi_region.drawio b/aws/multi_region/diagram/aws_multi_region.drawio
index 084fa9f..e80b08d 100644
--- a/aws/multi_region/diagram/aws_multi_region.drawio
+++ b/aws/multi_region/diagram/aws_multi_region.drawio
@@ -1,132 +1,92 @@
map(object({
from_port = number
to_port = number
protocol = string
})) | {
"https": {
"from_port": 443,
"protocol": "tcp",
"to_port": 443
}
} | no |
+| [anywhere](#input\_anywhere) | Anywhere subnet for routing and load ingress from all IPs | `string` | `"0.0.0.0/0"` | no |
+| [aws\_domain\_name](#input\_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` | n/a | yes |
+| [aws\_key\_pair](#input\_aws\_key\_pair) | The name of an aws keypair to use. | `string` | n/a | yes |
+| [aws\_region](#input\_aws\_region) | The AWS region for the deployment. (e.g us-east-1) | `string` | n/a | yes |
+| [aws\_ssm\_iam\_role\_name](#input\_aws\_ssm\_iam\_role\_name) | The name of the SSM EC2 role to associate with Kasm VMs for SSH access | `string` | `""` | no |
+| [aws\_ssm\_instance\_profile\_name](#input\_aws\_ssm\_instance\_profile\_name) | The name of the SSM EC2 Instance Profile to associate with Kasm VMs for SSH access | `string` | `""` | no |
+| [cpx\_security\_rules](#input\_cpx\_security\_rules) | A map of objects of security rules to apply to the Kasm Connection Proxy server | map(object({
from_port = number
to_port = number
protocol = string
})) | {
"https": {
"from_port": 443,
"protocol": "tcp",
"to_port": 443
}
} | no |
+| [create\_aws\_ssm\_iam\_role](#input\_create\_aws\_ssm\_iam\_role) | Create an AWS SSM IAM role to attach to VMs for SSH/console access to VMs. | `bool` | `false` | no |
+| [database\_password](#input\_database\_password) | The password for the database. No special characters | `string` | n/a | yes |
+| [db\_hdd\_size\_gb](#input\_db\_hdd\_size\_gb) | The HDD size in GB to configure for the Kasm Database instances | `number` | n/a | yes |
+| [db\_instance\_type](#input\_db\_instance\_type) | The instance type for the Database | `string` | n/a | yes |
+| [db\_security\_rules](#input\_db\_security\_rules) | A map of objects of security rules to apply to the Kasm DB | map(object({
from_port = number
to_port = number
protocol = string
})) | {
"postgres": {
"from_port": 5432,
"protocol": "tcp",
"to_port": 5432
},
"redis": {
"from_port": 6379,
"protocol": "tcp",
"to_port": 6379
}
} | no |
+| [default\_egress](#input\_default\_egress) | Default egress security rule for all security groups | map(object({
from_port = number
to_port = number
protocol = string
cidr_subnets = list(string)
})) | {
"all": {
"cidr_subnets": [
"0.0.0.0/0"
],
"from_port": 0,
"protocol": "-1",
"to_port": 0
}
} | no |
+| [ec2\_ami](#input\_ec2\_ami) | The AMI used for the EC2 nodes. Recommended Ubuntu 22.04 LTS. | `string` | n/a | yes |
+| [kasm\_build](#input\_kasm\_build) | The URL for the Kasm Workspaces build | `string` | n/a | yes |
+| [manager\_token](#input\_manager\_token) | The manager token value for Agents to authenticate to webapps. No special characters | `string` | n/a | yes |
+| [num\_cpx\_nodes](#input\_num\_cpx\_nodes) | The number of cpx RDP role servers to create in the deployment | `number` | n/a | yes |
+| [num\_webapps](#input\_num\_webapps) | The number of WebApp role servers to create in the deployment | `number` | n/a | yes |
+| [project\_name](#input\_project\_name) | The name of the deployment (e.g dev, staging). A short single word | `string` | n/a | yes |
+| [public\_lb\_security\_rules](#input\_public\_lb\_security\_rules) | A map of objects of security rules to apply to the Public ALB | map(object({
from_port = number
to_port = number
protocol = string
})) | {
"http": {
"from_port": 80,
"protocol": "tcp",
"to_port": 80
},
"https": {
"from_port": 443,
"protocol": "tcp",
"to_port": 443
}
} | no |
+| [redis\_password](#input\_redis\_password) | The password for the Redis server. No special characters | `string` | n/a | yes |
+| [service\_registration\_token](#input\_service\_registration\_token) | The service registration token value for cpx RDP servers to authenticate to webapps. No special characters | `string` | n/a | yes |
+| [swap\_size](#input\_swap\_size) | The amount of swap (in MB) to configure inside the compute instances | `number` | n/a | yes |
+| [user\_password](#input\_user\_password) | The standard (non administrator) user password. No special characters | `string` | n/a | yes |
+| [vpc\_subnet\_cidr](#input\_vpc\_subnet\_cidr) | The subnet CIDR to use for the Primary VPC | `string` | n/a | yes |
+| [web\_access\_cidrs](#input\_web\_access\_cidrs) | List of Networks in CIDR notation for IPs allowed to access the Kasm Web interface | `list(string)` | n/a | yes |
+| [webapp\_security\_rules](#input\_webapp\_security\_rules) | A map of objects of security rules to apply to the Kasm WebApp server | map(object({
from_port = number
to_port = number
protocol = string
})) | {
"https": {
"from_port": 443,
"protocol": "tcp",
"to_port": 443
}
} | no |
+| [windows\_security\_rules](#input\_windows\_security\_rules) | A map of objects of security rules to apply to the Kasm Windows VMs | map(object({
from_port = number
to_port = number
protocol = string
})) | {
"cpx_api": {
"from_port": 4902,
"protocol": "tcp",
"to_port": 4902
},
"cpx_rdp": {
"from_port": 3389,
"protocol": "tcp",
"to_port": 3389
},
"webapp_api": {
"from_port": 4902,
"protocol": "tcp",
"to_port": 4902
}
} | no |
+| [zone\_name](#input\_zone\_name) | A name given to the kasm deployment Zone | `string` | `"default"` | no |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [agent\_security\_group\_id](#output\_agent\_security\_group\_id) | Kasm Agent Primary region security group ID |
+| [agent\_subnet\_id](#output\_agent\_subnet\_id) | Kasm Agent Primary region subnet ID |
+| [certificate\_arn](#output\_certificate\_arn) | AWS Certificate manager certificate ARN |
+| [cpx\_security\_group\_id](#output\_cpx\_security\_group\_id) | Kasm Connection Proxy Primary region security group ID |
+| [cpx\_subnet\_id](#output\_cpx\_subnet\_id) | Kasm cpx RDP Primary region subnet ID |
+| [kasm\_db\_ip](#output\_kasm\_db\_ip) | Kasm Database server subnet ID |
+| [lb\_log\_bucket](#output\_lb\_log\_bucket) | Load balancer logging bucket name |
+| [lb\_security\_group\_id](#output\_lb\_security\_group\_id) | Kasm Load balancer security group ID |
+| [lb\_subnet\_ids](#output\_lb\_subnet\_ids) | A list of the Public LB subnet IDs |
+| [nat\_gateway\_ip](#output\_nat\_gateway\_ip) | The NAT Gateway IP returned in CIDR notation for use with Windows security group rules |
+| [primary\_vpc\_id](#output\_primary\_vpc\_id) | Kasm VPC ID |
+| [ssm\_iam\_profile](#output\_ssm\_iam\_profile) | The SSM IAM Instance Profile name |
+| [webapp\_security\_group\_id](#output\_webapp\_security\_group\_id) | Kasm Webapp security group ID |
+| [webapp\_subnet\_ids](#output\_webapp\_subnet\_ids) | A list of the Kasm Webapp subnet IDs |
+| [windows\_security\_group\_id](#output\_windows\_security\_group\_id) | Kasm Windows Primary region security group ID |
+| [windows\_subnet\_id](#output\_windows\_subnet\_id) | Kasm Windows Primary region subnet ID |
+
diff --git a/aws/multi_region/primary/availability_zones.tf b/aws/multi_region/primary/availability_zones.tf
deleted file mode 100644
index 87d8f48..0000000
--- a/aws/multi_region/primary/availability_zones.tf
+++ /dev/null
@@ -1,3 +0,0 @@
-data "aws_availability_zones" "available" {
- state = "available"
-}
diff --git a/aws/multi_region/primary/cert.tf b/aws/multi_region/primary/cert.tf
index 9881f83..2284fb4 100644
--- a/aws/multi_region/primary/cert.tf
+++ b/aws/multi_region/primary/cert.tf
@@ -1,9 +1,4 @@
-data "aws_route53_zone" "kasm-route53-zone" {
- name = var.aws_domain_name
- private_zone = false
-}
-
-resource "aws_acm_certificate" "kasm-alb-cert" {
+resource "aws_acm_certificate" "this" {
domain_name = var.aws_domain_name
subject_alternative_names = ["*.${var.aws_domain_name}"]
validation_method = "DNS"
@@ -14,9 +9,9 @@ resource "aws_acm_certificate" "kasm-alb-cert" {
}
}
-resource "aws_route53_record" "kasm-route53-cert-validation-record" {
+resource "aws_route53_record" "certificate" {
for_each = {
- for dvo in aws_acm_certificate.kasm-alb-cert.domain_validation_options : dvo.domain_name => {
+ for dvo in aws_acm_certificate.this.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
@@ -25,14 +20,14 @@ 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.this.id
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]
+resource "aws_acm_certificate_validation" "this" {
+ certificate_arn = aws_acm_certificate.this.arn
+ validation_record_fqdns = [for record in aws_route53_record.certificate : record.fqdn]
}
diff --git a/aws/multi_region/primary/db.tf b/aws/multi_region/primary/db.tf
index 6f7b8e4..252e455 100644
--- a/aws/multi_region/primary/db.tf
+++ b/aws/multi_region/primary/db.tf
@@ -1,9 +1,10 @@
-resource "aws_instance" "kasm-db" {
+resource "aws_instance" "db" {
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
+ vpc_security_group_ids = [aws_security_group.db.id]
+ subnet_id = aws_subnet.db.id
key_name = var.aws_key_pair
+ iam_instance_profile = var.create_aws_ssm_iam_role ? aws_iam_instance_profile.this[0].name : var.aws_ssm_instance_profile_name
root_block_device {
volume_size = var.db_hdd_size_gb
@@ -11,21 +12,25 @@ resource "aws_instance" "kasm-db" {
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
+ 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
+ service_registration_token = var.service_registration_token
+ swap_size = var.swap_size
}
)
+ metadata_options {
+ http_endpoint = "enabled"
+ http_tokens = "required"
+ http_put_response_hop_limit = 1
+ instance_metadata_tags = null
+ }
+
tags = {
Name = "${var.project_name}-kasm-db"
}
}
-
-data "aws_instance" "data-kasm_db" {
- instance_id = aws_instance.kasm-db.id
-}
diff --git a/aws/multi_region/primary/dependencies.tf b/aws/multi_region/primary/dependencies.tf
new file mode 100644
index 0000000..18145ba
--- /dev/null
+++ b/aws/multi_region/primary/dependencies.tf
@@ -0,0 +1,10 @@
+data "aws_availability_zones" "available" {
+ state = "available"
+}
+
+data "aws_elb_service_account" "main" {}
+
+data "aws_route53_zone" "this" {
+ name = var.aws_domain_name
+ private_zone = false
+}
diff --git a/aws/multi_region/primary/lb_s3_log_bucket.tf b/aws/multi_region/primary/lb_s3_log_bucket.tf
index b43677f..74269a1 100644
--- a/aws/multi_region/primary/lb_s3_log_bucket.tf
+++ b/aws/multi_region/primary/lb_s3_log_bucket.tf
@@ -1,21 +1,10 @@
-data "aws_elb_service_account" "main" {}
-
-resource "aws_s3_bucket" "kasm_s3_logs" {
+resource "aws_s3_bucket" "this" {
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
+resource "aws_s3_bucket_policy" "this" {
+ bucket = aws_s3_bucket.this.id
policy = jsonencode({
Id = "Policy"
@@ -26,7 +15,7 @@ resource "aws_s3_bucket_policy" "kasm_s3_logs_policy" {
"s3:PutObject"
]
Effect = "Allow"
- Resource = "${aws_s3_bucket.kasm_s3_logs.arn}/AWSLogs/*"
+ Resource = "${aws_s3_bucket.this.arn}/AWSLogs/*"
Principal = {
AWS = [
data.aws_elb_service_account.main.arn
@@ -37,8 +26,8 @@ resource "aws_s3_bucket_policy" "kasm_s3_logs_policy" {
})
}
-resource "aws_s3_bucket_server_side_encryption_configuration" "encrypt_elb_bucket" {
- bucket = data.aws_s3_bucket.data-kasm_s3_logs_bucket.id
+resource "aws_s3_bucket_server_side_encryption_configuration" "this" {
+ bucket = aws_s3_bucket.this.id
rule {
apply_server_side_encryption_by_default {
@@ -47,8 +36,8 @@ resource "aws_s3_bucket_server_side_encryption_configuration" "encrypt_elb_bucke
}
}
-resource "aws_s3_bucket_public_access_block" "s3_log_public_access" {
- bucket = data.aws_s3_bucket.data-kasm_s3_logs_bucket.id
+resource "aws_s3_bucket_public_access_block" "this" {
+ bucket = aws_s3_bucket.this.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
diff --git a/aws/multi_region/primary/output.tf b/aws/multi_region/primary/output.tf
index f735419..fc10d44 100644
--- a/aws/multi_region/primary/output.tf
+++ b/aws/multi_region/primary/output.tf
@@ -1,35 +1,79 @@
output "certificate_arn" {
- value = aws_acm_certificate_validation.kasm-elb-certificate-validation.certificate_arn
+ description = "AWS Certificate manager certificate ARN"
+ value = aws_acm_certificate_validation.this.certificate_arn
+}
+
+output "lb_subnet_ids" {
+ description = "A list of the Public LB subnet IDs"
+ value = aws_subnet.alb[*].id
}
output "webapp_subnet_ids" {
- value = data.aws_subnet.data-kasm_webapp_subnets[*].id
+ description = "A list of the Kasm Webapp subnet IDs"
+ value = aws_subnet.webapp[*].id
}
output "agent_subnet_id" {
- value = data.aws_subnet.data-kasm_agent_subnet.id
+ description = "Kasm Agent Primary region subnet ID"
+ value = aws_subnet.agent.id
+}
+
+output "cpx_subnet_id" {
+ description = "Kasm cpx RDP Primary region subnet ID"
+ value = one(aws_subnet.cpx[*].id)
+}
+
+output "windows_subnet_id" {
+ description = "Kasm Windows Primary region subnet ID"
+ value = one(aws_subnet.windows[*].id)
}
output "kasm_db_ip" {
- value = data.aws_instance.data-kasm_db.private_ip
+ description = "Kasm Database server subnet ID"
+ value = aws_instance.db.private_ip
}
output "primary_vpc_id" {
- value = data.aws_vpc.data-kasm-default-vpc.id
+ description = "Kasm VPC ID"
+ value = aws_vpc.this.id
}
output "lb_log_bucket" {
- value = data.aws_s3_bucket.data-kasm_s3_logs_bucket.bucket
+ description = "Load balancer logging bucket name"
+ value = aws_s3_bucket.this.bucket
}
output "lb_security_group_id" {
- value = data.aws_security_group.data-kasm_default_elb_sg.id
+ description = "Kasm Load balancer security group ID"
+ value = aws_security_group.public_lb.id
}
output "webapp_security_group_id" {
- value = data.aws_security_group.data-kasm_webapp_sg.id
+ description = "Kasm Webapp security group ID"
+ value = aws_security_group.webapp.id
}
output "agent_security_group_id" {
- value = data.aws_security_group.data-kasm_agent_sg.id
+ description = "Kasm Agent Primary region security group ID"
+ value = aws_security_group.agent.id
+}
+
+output "cpx_security_group_id" {
+ description = "Kasm Connection Proxy Primary region security group ID"
+ value = one(aws_security_group.cpx[*].id)
+}
+
+output "windows_security_group_id" {
+ description = "Kasm Windows Primary region security group ID"
+ value = one(aws_security_group.windows[*].id)
+}
+
+output "ssm_iam_profile" {
+ description = "The SSM IAM Instance Profile name"
+ value = var.aws_ssm_iam_role_name == "" ? aws_iam_instance_profile.this[0].name : var.aws_ssm_iam_role_name
+}
+
+output "nat_gateway_ip" {
+ description = "The NAT Gateway IP returned in CIDR notation for use with Windows security group rules"
+ value = "${aws_nat_gateway.this.public_ip}/32"
}
diff --git a/aws/multi_region/primary/provider.tf b/aws/multi_region/primary/provider.tf
index ea82995..2039c6e 100644
--- a/aws/multi_region/primary/provider.tf
+++ b/aws/multi_region/primary/provider.tf
@@ -1,8 +1,10 @@
terraform {
+ required_version = "~> 1.0"
+
required_providers {
aws = {
- source = "hashicorp/aws"
- #version = "4.56.0"
+ source = "hashicorp/aws"
+ version = "~> 5.0"
}
}
}
\ No newline at end of file
diff --git a/aws/multi_region/primary/routes.tf b/aws/multi_region/primary/routes.tf
index 50c62e8..8d6e2ad 100644
--- a/aws/multi_region/primary/routes.tf
+++ b/aws/multi_region/primary/routes.tf
@@ -1,9 +1,9 @@
-resource "aws_route_table" "internet_access" {
- vpc_id = data.aws_vpc.data-kasm-default-vpc.id
+resource "aws_route_table" "internet_gateway" {
+ vpc_id = aws_vpc.this.id
route {
cidr_block = var.anywhere
- gateway_id = data.aws_internet_gateway.data-kasm_default_ig.id
+ gateway_id = aws_internet_gateway.this.id
}
tags = {
@@ -11,22 +11,51 @@ resource "aws_route_table" "internet_access" {
}
}
-data "aws_route_table" "data-internet_gateway_route_table" {
- route_table_id = aws_route_table.internet_access.id
+resource "aws_route_table" "nat_gateway" {
+ vpc_id = aws_vpc.this.id
+
+ route {
+ cidr_block = var.anywhere
+ nat_gateway_id = aws_nat_gateway.this.id
+ }
+
+ tags = {
+ Name = "${var.project_name}-kasm-nat-gateway-route"
+ }
}
-resource "aws_route_table_association" "webapp_route_association" {
+resource "aws_route_table_association" "alb" {
+ count = 2
+ subnet_id = aws_subnet.alb[count.index].id
+ route_table_id = aws_route_table.internet_gateway.id
+}
+
+resource "aws_route_table_association" "webapp" {
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
+ subnet_id = aws_subnet.webapp[count.index].id
+ route_table_id = aws_route_table.nat_gateway.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" "db" {
+ subnet_id = aws_subnet.db.id
+ route_table_id = aws_route_table.nat_gateway.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
+resource "aws_route_table_association" "cpx" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+
+ subnet_id = one(aws_subnet.cpx[*].id)
+ route_table_id = aws_route_table.nat_gateway.id
+}
+
+resource "aws_route_table_association" "agent" {
+ subnet_id = aws_subnet.agent.id
+ route_table_id = aws_route_table.internet_gateway.id
+}
+
+resource "aws_route_table_association" "windows" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+
+ subnet_id = one(aws_subnet.windows[*].id)
+ route_table_id = aws_route_table.internet_gateway.id
}
diff --git a/aws/multi_region/primary/security_group.tf b/aws/multi_region/primary/security_group.tf
index fe1cc95..21c87ef 100644
--- a/aws/multi_region/primary/security_group.tf
+++ b/aws/multi_region/primary/security_group.tf
@@ -1,145 +1,243 @@
-resource "aws_security_group" "kasm-default-elb-sg" {
- name = "${var.project_name}-${var.zone_name}-kasm-allow-elb-access"
+resource "aws_security_group" "public_lb" {
+ name = "${var.project_name}-kasm-allow-public-lb-access"
description = "Security Group for ELB"
- vpc_id = data.aws_vpc.data-kasm-default-vpc.id
-
- ingress {
- from_port = 443
- to_port = 443
- protocol = "tcp"
- 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 = [var.anywhere]
- }
+ vpc_id = aws_vpc.this.id
tags = {
- Name = "${var.project_name}-${var.zone_name}-kasm-allow-access"
+ Name = "${var.project_name}-kasm-public-lb-access"
}
}
-data "aws_security_group" "data-kasm_default_elb_sg" {
- id = aws_security_group.kasm-default-elb-sg.id
+resource "aws_security_group_rule" "public_lb" {
+ for_each = var.public_lb_security_rules
+
+ description = "Allow Public LB ingress from ${join(",", var.web_access_cidrs)}"
+ security_group_id = aws_security_group.public_lb.id
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = var.web_access_cidrs
}
-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
+resource "aws_security_group_rule" "public_lb_egress" {
+ for_each = var.default_egress
- 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"
- }
+ description = "Allow Public LB egress"
+ security_group_id = aws_security_group.public_lb.id
+ type = "egress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = each.value.cidr_subnets
}
-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"
+resource "aws_security_group" "webapp" {
+ name = "${var.project_name}-kasm-webapp"
description = "Allow access to webapps"
- vpc_id = data.aws_vpc.data-kasm-default-vpc.id
+ vpc_id = aws_vpc.this.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]
+ tags = {
+ Name = "${var.project_name}-kasm-webapp-access"
}
}
-data "aws_security_group" "data-kasm_webapp_sg" {
- id = aws_security_group.kasm-webapp-sg.id
+resource "aws_security_group_rule" "webapp_public_lb" {
+ for_each = var.webapp_security_rules
+
+ description = "Allow Webapp ingress from Public LB"
+ security_group_id = aws_security_group.webapp.id
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ source_security_group_id = aws_security_group.public_lb.id
}
-resource "aws_security_group" "kasm-agent-sg" {
- name = "${var.project_name}-${var.zone_name}-kasm-agent-access"
+resource "aws_security_group_rule" "webapp_agent" {
+ for_each = var.webapp_security_rules
+
+ description = "Allow Webapp ingress from Kasm Agent"
+ security_group_id = aws_security_group.webapp.id
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ source_security_group_id = aws_security_group.agent.id
+}
+
+resource "aws_security_group_rule" "webapp_egress" {
+ for_each = var.default_egress
+
+ description = "Allow Webapp egress"
+ security_group_id = aws_security_group.webapp.id
+ type = "egress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = each.value.cidr_subnets
+}
+
+resource "aws_security_group" "agent" {
+ name = "${var.project_name}-kasm-agent-access"
description = "Allow access to agents"
- vpc_id = data.aws_vpc.data-kasm-default-vpc.id
+ vpc_id = aws_vpc.this.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]
+ tags = {
+ Name = "${var.project_name}-kasm-agent-access"
}
}
-data "aws_security_group" "data-kasm_agent_sg" {
- id = aws_security_group.kasm-agent-sg.id
+resource "aws_security_group_rule" "agent" {
+ for_each = var.agent_security_rules
+
+ description = "Allow Kasm Agent ingress from WebApps"
+ security_group_id = aws_security_group.agent.id
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ source_security_group_id = aws_security_group.webapp.id
+}
+
+resource "aws_security_group_rule" "agent_egress" {
+ for_each = var.default_egress
+
+ description = "Allow Agents egress"
+ security_group_id = aws_security_group.agent.id
+ type = "egress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = each.value.cidr_subnets
+}
+
+resource "aws_security_group" "db" {
+ name = "${var.project_name}-kasm-db-access"
+ description = "Allow access to webapps"
+ vpc_id = aws_vpc.this.id
+
+ tags = {
+ Name = "${var.project_name}-kasm-db-access"
+ }
+}
+
+resource "aws_security_group_rule" "db" {
+ for_each = var.db_security_rules
+
+ description = "Allow Kasm DB ingress from Kasm Webapp"
+ security_group_id = aws_security_group.db.id
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ source_security_group_id = aws_security_group.webapp.id
+}
+
+resource "aws_security_group_rule" "db_egress" {
+ for_each = var.default_egress
+
+ description = "Allow Kasm Db egress"
+ security_group_id = aws_security_group.db.id
+ type = "egress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = each.value.cidr_subnets
+}
+
+resource "aws_security_group" "cpx" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+
+ name = "${var.project_name}-kasm-cpx-access"
+ description = "Allow access to cpx RDP nodes"
+ vpc_id = aws_vpc.this.id
+
+ tags = {
+ Name = "${var.project_name}-kasm-cpx-access"
+ }
+}
+
+resource "aws_security_group_rule" "cpx" {
+ for_each = var.num_cpx_nodes > 0 ? var.cpx_security_rules : {}
+
+ description = "Allow Kasm CPX ingress from Kasm Webapp"
+ security_group_id = one(aws_security_group.cpx[*].id)
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ source_security_group_id = aws_security_group.webapp.id
+}
+
+resource "aws_security_group_rule" "cpx_egress" {
+ for_each = var.num_cpx_nodes > 0 ? var.default_egress : {}
+
+ description = "Allow Kasm CPX egress"
+ security_group_id = one(aws_security_group.cpx[*].id)
+ type = "egress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = each.value.cidr_subnets
+}
+
+resource "aws_security_group_rule" "webapp_cpx" {
+ for_each = var.num_cpx_nodes > 0 ? var.webapp_security_rules : {}
+
+ description = "Allow Webapp ingress from Kasm CPX"
+ security_group_id = aws_security_group.webapp.id
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ source_security_group_id = one(aws_security_group.cpx[*].id)
+}
+
+resource "aws_security_group" "windows" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+
+ name = "${var.project_name}-kasm-windows-access"
+ description = "Allow access to Windows servers"
+ vpc_id = aws_vpc.this.id
+
+ tags = {
+ Name = "${var.project_name}-kasm-windows-access"
+ }
+}
+
+resource "aws_security_group_rule" "windows" {
+ for_each = var.num_cpx_nodes > 0 ? var.windows_security_rules : {}
+
+ description = "Allow Windows ingress from Kasm CPX and WebApp"
+ security_group_id = one(aws_security_group.windows[*].id)
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ source_security_group_id = can(regex("(?i:cpx)", each.key)) ? one(aws_security_group.cpx[*].id) : aws_security_group.webapp.id
+}
+
+resource "aws_security_group_rule" "windows_egress" {
+ for_each = var.num_cpx_nodes > 0 ? var.default_egress : {}
+
+ description = "Allow Windows egress"
+ security_group_id = one(aws_security_group.windows[*].id)
+ type = "egress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = each.value.cidr_subnets
+}
+
+resource "aws_security_group_rule" "webapp_windows" {
+ for_each = var.num_cpx_nodes > 0 ? var.webapp_security_rules : {}
+
+ description = "Allow Windows ingress from Kasm WebApp"
+ security_group_id = aws_security_group.webapp.id
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ source_security_group_id = one(aws_security_group.windows[*].id)
}
diff --git a/aws/multi_region/primary/ssm.tf b/aws/multi_region/primary/ssm.tf
new file mode 100644
index 0000000..98b6dd3
--- /dev/null
+++ b/aws/multi_region/primary/ssm.tf
@@ -0,0 +1,35 @@
+data "aws_iam_policy_document" "this" {
+ statement {
+ effect = "Allow"
+
+ principals {
+ type = "Service"
+ identifiers = [
+ "ec2.amazonaws.com"
+ ]
+ }
+
+ actions = ["sts:AssumeRole"]
+ }
+}
+
+resource "aws_iam_role" "this" {
+ count = var.create_aws_ssm_iam_role ? 1 : 0
+
+ name = var.aws_ssm_iam_role_name != "" ? var.aws_ssm_iam_role_name : "Kasm_SSM_IAM_Instance_Role"
+ assume_role_policy = data.aws_iam_policy_document.this.json
+}
+
+resource "aws_iam_role_policy_attachment" "this" {
+ count = var.create_aws_ssm_iam_role ? 1 : 0
+
+ policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
+ role = one(aws_iam_role.this[*].name)
+}
+
+resource "aws_iam_instance_profile" "this" {
+ count = var.create_aws_ssm_iam_role ? 1 : 0
+
+ name = var.aws_ssm_instance_profile_name != "" ? var.aws_ssm_instance_profile_name : "Kasm_SSM_Instance_Profile"
+ role = one(aws_iam_role.this[*].name)
+}
diff --git a/aws/multi_region/primary/subnet.tf b/aws/multi_region/primary/subnet.tf
index a626318..c461f7a 100644
--- a/aws/multi_region/primary/subnet.tf
+++ b/aws/multi_region/primary/subnet.tf
@@ -1,51 +1,77 @@
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)
+ kasm_server_subnet_cidr_size = local.kasm_server_subnet_cidr_calculation < 3 ? 3 : local.kasm_server_subnet_cidr_calculation
}
-## 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
+## Will create Agent subnet x.x.0.0/24 and x.x.1.0/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/21)
+resource "aws_subnet" "alb" {
+ count = 2
+
+ vpc_id = aws_vpc.this.id
+ cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, count.index)
+ availability_zone = data.aws_availability_zones.available.names[count.index]
+
tags = {
- Name = "${var.project_name}-kasm-db-subnet"
+ Name = "${var.project_name}-kasm_alb_subnet"
}
}
-data "aws_subnet" "data-kasm_db_subnet" {
- id = aws_subnet.kasm-db-subnet.id
-}
+## Will create WebApp subnets x.x.2.0/24 and x.x.3.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" "webapp" {
+ count = var.num_webapps
+
+ vpc_id = aws_vpc.this.id
+ cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, (count.index + 2))
+ availability_zone = data.aws_availability_zones.available.names[count.index]
-## 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"
}
}
-data "aws_subnet" "data-kasm_webapp_subnets" {
- count = var.num_webapps
- id = aws_subnet.kasm-webapp-subnets[count.index].id
-}
+## Will create DB subnet x.x.4.0/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/22)
+resource "aws_subnet" "db" {
+ vpc_id = aws_vpc.this.id
+ cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, 4)
+ availability_zone = data.aws_availability_zones.available.names[0]
-## 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 = 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}-agent-natgw-subnet"
+ Name = "${var.project_name}-kasm_db_subnet"
}
}
-data "aws_subnet" "data-kasm_agent_subnet" {
- id = aws_subnet.kasm-agent-subnet.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" "agent" {
+ vpc_id = aws_vpc.this.id
+ cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, 5)
+ availability_zone = data.aws_availability_zones.available.names[1]
+
+ tags = {
+ Name = "${var.project_name}-agent-subnet"
+ }
+}
+
+## Will create Agent subnet x.x.4.0/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/22)
+resource "aws_subnet" "cpx" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+ vpc_id = aws_vpc.this.id
+ cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, 6)
+ availability_zone = data.aws_availability_zones.available.names[0]
+
+ tags = {
+ Name = "${var.project_name}-cpx-subnet"
+ }
+}
+
+## Will create Agent subnet x.x.5.0/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/22)
+resource "aws_subnet" "windows" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+ vpc_id = aws_vpc.this.id
+ cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, 7)
+ availability_zone = data.aws_availability_zones.available.names[1]
+
+ tags = {
+ Name = "${var.project_name}-windows-subnet"
+ }
}
diff --git a/aws/multi_region/primary/variables.tf b/aws/multi_region/primary/variables.tf
index dca6b3b..243ebfc 100644
--- a/aws/multi_region/primary/variables.tf
+++ b/aws/multi_region/primary/variables.tf
@@ -26,7 +26,6 @@ variable "db_hdd_size_gb" {
variable "db_instance_type" {
description = "The instance type for the Database"
type = string
- default = "t3.small"
}
variable "swap_size" {
@@ -70,7 +69,7 @@ variable "manager_token" {
}
variable "service_registration_token" {
- description = "The guac token value for Guac RDP servers to authenticate to webapps. No special characters"
+ description = "The service registration token value for cpx RDP servers to authenticate to webapps. No special characters"
type = string
sensitive = true
}
@@ -87,15 +86,10 @@ variable "aws_key_pair" {
}
variable "ec2_ami" {
- description = "The AMI used for the EC2 nodes. Recommended Ubuntu 20.04 LTS."
+ description = "The AMI used for the EC2 nodes. Recommended Ubuntu 22.04 LTS."
type = string
}
-variable "ssh_access_cidrs" {
- description = "CIDR notation of the bastion host allowed to SSH in to the machines"
- type = list(string)
-}
-
variable "web_access_cidrs" {
description = "List of Networks in CIDR notation for IPs allowed to access the Kasm Web interface"
type = list(string)
@@ -106,8 +100,172 @@ variable "num_webapps" {
type = number
}
+variable "num_cpx_nodes" {
+ description = "The number of cpx RDP role servers to create in the deployment"
+ type = number
+}
+
+variable "create_aws_ssm_iam_role" {
+ description = "Create an AWS SSM IAM role to attach to VMs for SSH/console access to VMs."
+ type = bool
+ default = false
+}
+
+variable "aws_ssm_iam_role_name" {
+ description = "The name of the SSM EC2 role to associate with Kasm VMs for SSH access"
+ type = string
+ default = ""
+}
+
+variable "aws_ssm_instance_profile_name" {
+ description = "The name of the SSM EC2 Instance Profile to associate with Kasm VMs for SSH access"
+ type = string
+ default = ""
+}
+
variable "anywhere" {
description = "Anywhere subnet for routing and load ingress from all IPs"
type = string
default = "0.0.0.0/0"
}
+
+variable "public_lb_security_rules" {
+ description = "A map of objects of security rules to apply to the Public ALB"
+ type = map(object({
+ from_port = number
+ to_port = number
+ protocol = string
+ }))
+
+ default = {
+ https = {
+ from_port = 443
+ to_port = 443
+ protocol = "tcp"
+ }
+ http = {
+ from_port = 80
+ to_port = 80
+ protocol = "tcp"
+ }
+ }
+}
+
+variable "webapp_security_rules" {
+ description = "A map of objects of security rules to apply to the Kasm WebApp server"
+ type = map(object({
+ from_port = number
+ to_port = number
+ protocol = string
+ }))
+
+ default = {
+ https = {
+ from_port = 443
+ to_port = 443
+ protocol = "tcp"
+ }
+ }
+}
+
+variable "db_security_rules" {
+ description = "A map of objects of security rules to apply to the Kasm DB"
+ type = map(object({
+ from_port = number
+ to_port = number
+ protocol = string
+ }))
+
+ default = {
+ postgres = {
+ from_port = 5432
+ to_port = 5432
+ protocol = "tcp"
+ }
+ redis = {
+ from_port = 6379
+ to_port = 6379
+ protocol = "tcp"
+ }
+ }
+}
+
+variable "cpx_security_rules" {
+ description = "A map of objects of security rules to apply to the Kasm Connection Proxy server"
+ type = map(object({
+ from_port = number
+ to_port = number
+ protocol = string
+ }))
+
+ default = {
+ https = {
+ from_port = 443
+ to_port = 443
+ protocol = "tcp"
+ }
+ }
+}
+
+variable "agent_security_rules" {
+ description = "A map of objects of security rules to apply to the Kasm WebApp server"
+ type = map(object({
+ from_port = number
+ to_port = number
+ protocol = string
+ }))
+
+ default = {
+ https = {
+ from_port = 443
+ to_port = 443
+ protocol = "tcp"
+ }
+ }
+}
+
+variable "windows_security_rules" {
+ description = "A map of objects of security rules to apply to the Kasm Windows VMs"
+ type = map(object({
+ from_port = number
+ to_port = number
+ protocol = string
+ }))
+
+ default = {
+ cpx_rdp = {
+ from_port = 3389
+ to_port = 3389
+ protocol = "tcp"
+ }
+ cpx_api = {
+ from_port = 4902
+ to_port = 4902
+ protocol = "tcp"
+ }
+ webapp_api = {
+ from_port = 4902
+ to_port = 4902
+ protocol = "tcp"
+ }
+ }
+}
+
+variable "default_egress" {
+ description = "Default egress security rule for all security groups"
+ type = map(object({
+ from_port = number
+ to_port = number
+ protocol = string
+ cidr_subnets = list(string)
+ }))
+
+ default = {
+ all = {
+ from_port = 0
+ to_port = 0
+ protocol = "-1"
+ cidr_subnets = ["0.0.0.0/0"]
+ }
+ }
+}
diff --git a/aws/multi_region/primary/vpc.tf b/aws/multi_region/primary/vpc.tf
index 133c952..a881f43 100644
--- a/aws/multi_region/primary/vpc.tf
+++ b/aws/multi_region/primary/vpc.tf
@@ -1,4 +1,4 @@
-resource "aws_vpc" "kasm-default-vpc" {
+resource "aws_vpc" "this" {
cidr_block = var.vpc_subnet_cidr
enable_dns_hostnames = true
enable_dns_support = true
@@ -7,17 +7,24 @@ resource "aws_vpc" "kasm-default-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
+resource "aws_internet_gateway" "this" {
+ vpc_id = aws_vpc.this.id
tags = {
Name = "${var.project_name}-kasm-ig"
}
}
-data "aws_internet_gateway" "data-kasm_default_ig" {
- internet_gateway_id = aws_internet_gateway.kasm-default-ig.id
+resource "aws_eip" "this" {
+ domain = "vpc"
+}
+
+resource "aws_nat_gateway" "this" {
+ allocation_id = aws_eip.this.id
+ subnet_id = aws_subnet.alb[0].id
+
+ tags = {
+ Name = "${var.project_name}-${var.aws_region}-kasm-nat"
+ }
+
+ depends_on = [aws_internet_gateway.this]
}
diff --git a/aws/multi_region/provider.tf b/aws/multi_region/provider.tf
index 041dd35..30e67fa 100644
--- a/aws/multi_region/provider.tf
+++ b/aws/multi_region/provider.tf
@@ -1,8 +1,10 @@
terraform {
+ required_version = "~> 1.0"
+
required_providers {
aws = {
- source = "hashicorp/aws"
- #version = "4.56.0"
+ source = "hashicorp/aws"
+ version = "~> 5.0"
}
}
}
@@ -31,7 +33,7 @@ provider "aws" {
##############################################################################
###
### 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.
diff --git a/aws/multi_region/secrets.tfvars.example b/aws/multi_region/secrets.tfvars.example
new file mode 100644
index 0000000..8cae349
--- /dev/null
+++ b/aws/multi_region/secrets.tfvars.example
@@ -0,0 +1,2 @@
+aws_access_key = ""
+aws_secret_key = ""
\ No newline at end of file
diff --git a/aws/multi_region/settings.tfvars b/aws/multi_region/settings.tfvars
deleted file mode 100644
index 03502de..0000000
--- a/aws/multi_region/settings.tfvars
+++ /dev/null
@@ -1,62 +0,0 @@
-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.13.0.002947.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"
-}
diff --git a/aws/multi_region/terraform.tfvars b/aws/multi_region/terraform.tfvars
new file mode 100644
index 0000000..caff6a7
--- /dev/null
+++ b/aws/multi_region/terraform.tfvars
@@ -0,0 +1,88 @@
+## AWS Environment settings
+aws_key_pair = ""
+aws_primary_region = ""
+aws_domain_name = "contoso.kasm.com"
+primary_vpc_subnet_cidr = "10.0.0.0/16"
+
+## Kasm deployment project
+project_name = ""
+
+## 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.14.0.3a7abb.tar.gz"
+
+## VM Public Access subnets
+web_access_cidrs = ["0.0.0.0/0"]
+
+## AWS SSM setup for console/SSH access to VMs behind NAT gateway
+create_aws_ssm_iam_role = true
+aws_ssm_iam_role_name = ""
+aws_ssm_instance_profile_name = ""
+
+## Kasm Server Settings
+swap_size = 2048
+primary_region_ec2_ami_id = ""
+
+## Kasm Webapp Instance Settings
+num_webapps = 2
+webapp_instance_type = "t3.small"
+webapp_hdd_size_gb = 50
+
+## Kasm DB Instance Settings
+db_instance_type = "t3.medium"
+db_hdd_size_gb = 80
+
+## Kasm Agent Instance Settings
+num_agents = 2
+agent_instance_type = "t3.medium"
+agent_hdd_size_gb = 150
+
+## Kasm CPX Instance Settings
+num_cpx_nodes = 1
+cpx_instance_type = "t3.small"
+cpx_hdd_size_gb = 50
+
+## Kasm Dedicated Proxy Instance Settings
+num_proxy_nodes = 2
+proxy_hdd_size_gb = 40
+proxy_instance_type = "t3.micro"
+
+## Settings for all additional Agent regions
+secondary_regions_settings = {
+ region2 = {
+ agent_region = ""
+ ec2_ami_id = ""
+ 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 = ""
+ # ec2_ami_id = ""
+ # 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.14"
+}
diff --git a/aws/multi_region/userdata/agent_bootstrap.sh b/aws/multi_region/userdata/agent_bootstrap.sh
index ca26186..7dc4430 100644
--- a/aws/multi_region/userdata/agent_bootstrap.sh
+++ b/aws/multi_region/userdata/agent_bootstrap.sh
@@ -2,7 +2,7 @@
set -ex
echo "Starting Kasm Workspaces Agent Install"
-/bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=${swap_size}
+/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
@@ -24,6 +24,6 @@ do
done
echo "WebApp is alive"
-bash kasm_release/install.sh -S agent -e -p $PRIVATE_IP -m ${manager_address} -M ${manager_token}
+bash kasm_release/install.sh -S agent -e -p $PRIVATE_IP -m "${manager_address}" -M "${manager_token}"
echo "Done"
diff --git a/aws/multi_region/userdata/cpx_bootstrap.sh b/aws/multi_region/userdata/cpx_bootstrap.sh
new file mode 100644
index 0000000..7159ca8
--- /dev/null
+++ b/aws/multi_region/userdata/cpx_bootstrap.sh
@@ -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"
diff --git a/aws/multi_region/userdata/db_bootstrap.sh b/aws/multi_region/userdata/db_bootstrap.sh
index ac7b403..b4e74a5 100644
--- a/aws/multi_region/userdata/db_bootstrap.sh
+++ b/aws/multi_region/userdata/db_bootstrap.sh
@@ -2,7 +2,7 @@
set -ex
echo "Starting Kasm Workspaces Install"
-/bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=${swap_size}
+/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
@@ -11,10 +11,8 @@ 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
+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}
+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"
diff --git a/aws/multi_region/userdata/proxy_bootstrap.sh b/aws/multi_region/userdata/proxy_bootstrap.sh
new file mode 100644
index 0000000..4de9f6f
--- /dev/null
+++ b/aws/multi_region/userdata/proxy_bootstrap.sh
@@ -0,0 +1,27 @@
+#!/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
+
+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 proxy -e -H -p "${proxy_alb_address}" -n "${manager_address}"
+
+echo "Done"
diff --git a/aws/multi_region/userdata/webapp_bootstrap.sh b/aws/multi_region/userdata/webapp_bootstrap.sh
index 5f781f5..9bdb0b0 100644
--- a/aws/multi_region/userdata/webapp_bootstrap.sh
+++ b/aws/multi_region/userdata/webapp_bootstrap.sh
@@ -2,7 +2,7 @@
set -ex
echo "Starting Kasm Workspaces Install"
-/bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=${swap_size}
+/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
@@ -11,26 +11,24 @@ 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
+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
+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
+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}
+bash kasm_release/install.sh -S app -e -z "${zone_name}" -q "${db_ip}" -Q "${database_password}" -R "${redis_password}"
echo "Done"
diff --git a/aws/multi_region/variables.tf b/aws/multi_region/variables.tf
index aca2488..beedfc5 100644
--- a/aws/multi_region/variables.tf
+++ b/aws/multi_region/variables.tf
@@ -30,6 +30,39 @@ variable "aws_key_pair" {
}
}
+variable "create_aws_ssm_iam_role" {
+ description = "Create an AWS SSM IAM role to attach to VMs for SSH/console access to VMs."
+ type = bool
+ default = false
+
+ validation {
+ condition = can(tobool(var.create_aws_ssm_iam_role))
+ error_message = "The create_aws_ssm_iam_role is a boolean value and can only be either true or false."
+ }
+}
+
+variable "aws_ssm_iam_role_name" {
+ description = "The name of the SSM EC2 role to associate with Kasm VMs for SSH access"
+ type = string
+ default = ""
+
+ validation {
+ condition = can(regex("[a-zA-Z0-9+=,.@-]{1,64}", var.aws_ssm_iam_role_name))
+ error_message = "The aws_ssm_iam_role_name must be unique across the account and can only consisit of between 1 and 64 characters consisting of letters, numbers, underscores (_), plus (+), equals (=), comman (,), period (.), at symbol (@), or dash (-)."
+ }
+}
+
+variable "aws_ssm_instance_profile_name" {
+ description = "The name of the SSM EC2 Instance Profile to associate with Kasm VMs for SSH access"
+ type = string
+ default = ""
+
+ validation {
+ condition = var.aws_ssm_instance_profile_name == "" ? true : can(regex("[a-zA-Z0-9+=,.@-]{1,64}", var.aws_ssm_instance_profile_name))
+ error_message = "The aws_ssm_instance_profile_name must be unique across the account and can only consisit of between 1 and 64 characters consisting of letters, numbers, underscores (_), plus (+), equals (=), comman (,), period (.), at symbol (@), or dash (-)."
+ }
+}
+
variable "project_name" {
description = "The name of the deployment (e.g dev, staging). A short single word"
type = string
@@ -83,10 +116,30 @@ variable "num_webapps" {
}
}
+variable "num_cpx_nodes" {
+ description = "The number of RDP Conection Proxy Role Servers to create in the deployment. Set this to zero (0) and this Terraform will not deploy ANY Connection Proxy or Windows resoures like subnets, security groups, etc."
+ type = number
+
+ validation {
+ condition = var.num_cpx_nodes == 0 ? true : var.num_cpx_nodes >= 0 && var.num_cpx_nodes <= 100 && floor(var.num_cpx_nodes) == var.num_cpx_nodes
+ error_message = "If num_cpx_nodes is set to 0, this Terraform will not deploy the Connection Proxy node. Acceptable number ranges between 0-100."
+ }
+}
+
+variable "num_proxy_nodes" {
+ description = "The number of Dedicated Proxy nodes to create in the deployment"
+ type = number
+
+ validation {
+ condition = var.num_proxy_nodes == 1 ? true : var.num_proxy_nodes >= 1 && var.num_proxy_nodes <= 100 && floor(var.num_proxy_nodes) == var.num_proxy_nodes
+ error_message = "The number of Dedicated Proxy nodes to deploy in remote regions. Acceptable number ranges between 1-100."
+ }
+}
+
variable "webapp_instance_type" {
description = "The instance type for the webapps"
type = string
- default = "t3.small"
+ default = ""
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))
@@ -97,7 +150,6 @@ variable "webapp_instance_type" {
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))
@@ -108,7 +160,6 @@ variable "db_instance_type" {
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))
@@ -116,6 +167,27 @@ variable "agent_instance_type" {
}
}
+variable "cpx_instance_type" {
+ description = "The instance type for the Guac RDP nodes"
+ type = string
+
+ 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.cpx_instance_type))
+ error_message = "Check the cpx_instance_type variable and ensure it is a valid AWS Instance type (https://aws.amazon.com/ec2/instance-types/)."
+ }
+}
+
+variable "proxy_instance_type" {
+ description = "The instance type for the dedicated proxy node"
+ type = string
+ default = ""
+
+ 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.proxy_instance_type))
+ error_message = "Check the proxy_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
@@ -146,10 +218,29 @@ variable "agent_hdd_size_gb" {
}
}
+variable "cpx_hdd_size_gb" {
+ description = "The HDD size in GB to configure for the Kasm Guac RDP instances"
+ type = number
+
+ validation {
+ condition = can(var.cpx_hdd_size_gb >= 40)
+ error_message = "Kasm Guac RDP nodes should have at least a 40 GB HDD to ensure enough space for Kasm services."
+ }
+}
+
+variable "proxy_hdd_size_gb" {
+ description = "The HDD size in GB to configure for the Kasm dedicated proxy instances"
+ type = number
+
+ validation {
+ condition = can(var.proxy_hdd_size_gb >= 40)
+ error_message = "Kasm dedicated proxy nodes should have at least a 40 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))
@@ -159,24 +250,21 @@ variable "primary_region_ec2_ami_id" {
variable "secondary_regions_settings" {
description = "Map of Kasm settings for secondary regions"
- type = map(any)
+ type = map(object({
+ agent_region = string
+ agent_vpc_cidr = string
+ ec2_ami_id = string
+ })
+ )
validation {
condition = alltrue([for region in var.secondary_regions_settings : can(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 = alltrue([for ami_id in var.secondary_regions_settings : can(regex("^(ami-[a-f0-9]{17})", ami_id.agent_ec2_ami_id))])
+ condition = alltrue([for ami_id in var.secondary_regions_settings : can(regex("^(ami-[a-f0-9]{17})", ami_id.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 = alltrue([for instance_type in var.secondary_regions_settings : 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)", 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 = alltrue([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 = alltrue([for subnet in var.secondary_regions_settings : can(cidrhost(subnet.agent_vpc_cidr, 0))])
error_message = "Verify the VPC subnet in your secondary_regions_settings. They must all be valid IPv4 CIDRs."
@@ -259,6 +347,17 @@ variable "manager_token" {
}
}
+variable "service_registration_token" {
+ description = "The service registration token value for cpx 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."
+ }
+}
+
variable "ssh_access_cidrs" {
description = "CIDR notation of the bastion host allowed to SSH in to the machines"
type = list(string)
@@ -292,6 +391,6 @@ variable "aws_default_tags" {
type = map(any)
default = {
Service_name = "Kasm Workspaces"
- Kasm_version = "1.12"
+ Kasm_version = "1.14"
}
}
diff --git a/aws/multi_region/webapps/README.md b/aws/multi_region/webapps/README.md
new file mode 100644
index 0000000..571b71e
--- /dev/null
+++ b/aws/multi_region/webapps/README.md
@@ -0,0 +1,84 @@
+# webapps
+
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0 |
+| [aws](#requirement\_aws) | ~> 5.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | 5.36.0 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_instance.agent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource |
+| [aws_instance.cpx](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource |
+| [aws_instance.webapp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource |
+| [aws_lb.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb) | resource |
+| [aws_lb_listener.http](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener) | resource |
+| [aws_lb_listener.https](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener) | resource |
+| [aws_lb_target_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_target_group) | resource |
+| [aws_lb_target_group_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_target_group_attachment) | resource |
+| [aws_route53_health_check.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_health_check) | resource |
+| [aws_route53_record.alb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource |
+| [aws_route53_record.latency](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource |
+| [aws_route53_zone.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route53_zone) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [agent\_hdd\_size\_gb](#input\_agent\_hdd\_size\_gb) | The HDD size in GB to configure for the Kasm Agent instances | `number` | `0` | no |
+| [agent\_instance\_type](#input\_agent\_instance\_type) | the instance type for the agents | `string` | `""` | no |
+| [agent\_security\_group\_id](#input\_agent\_security\_group\_id) | Kasm Agent security group ID | `string` | `""` | no |
+| [agent\_subnet\_id](#input\_agent\_subnet\_id) | Subnet ID created for agents | `string` | `""` | no |
+| [aws\_domain\_name](#input\_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` | n/a | yes |
+| [aws\_key\_pair](#input\_aws\_key\_pair) | The name of an aws keypair to use. | `string` | n/a | yes |
+| [aws\_ssm\_instance\_profile\_name](#input\_aws\_ssm\_instance\_profile\_name) | The name of the SSM EC2 Instance Profile to associate with Kasm VMs for SSH access | `string` | `""` | no |
+| [aws\_to\_kasm\_zone\_map](#input\_aws\_to\_kasm\_zone\_map) | AWS regions mapped to Kasm Deployment Zone names | `map(any)` | {
"af-south-1": "Africa-(Cape-Town)",
"ap-east-1": "China-(Hong-Kong)",
"ap-northeast-1": "Japan-(Tokyo)",
"ap-northeast-2": "S-Korea-(Seoul)",
"ap-northeast-3": "Japan-(Osaka)",
"ap-south-1": "India-(Mumbai)",
"ap-south-2": "India-(Hyderbad)",
"ap-southeast-1": "Singapore",
"ap-southeast-2": "Austrailia-(Sydney)",
"ap-southeast-3": "Indonesia-(Jakarta)",
"ap-southeast-4": "Austrailia-(Melbourne)",
"ca-central-1": "Canada-(Montreal)",
"eu-central-1": "Switzerland-(Zurich)",
"eu-north-1": "Sweden-(Stockholm)",
"eu-south-1": "Italy-(Milan)",
"eu-south-2": "Spain-(Aragon)",
"eu-west-1": "Ireland-(Dublin)",
"eu-west-2": "UK-(London)",
"eu-west-3": "France-(Paris)",
"me-central-1": "United-Arab-Emirates",
"me-south-1": "Manama-(Bahrain)",
"sa-east-1": "Brazil-(Sao-Paulo)",
"us-east-1": "USA-(Virginia)",
"us-east-2": "USA-(Ohio)",
"us-west-1": "USA-(California)",
"us-west-2": "USA-(Oregon)"
} | no |
+| [certificate\_arn](#input\_certificate\_arn) | The certificate ARN created in the primary region for use with all load balancers in the deployment. | `string` | n/a | yes |
+| [cpx\_hdd\_size\_gb](#input\_cpx\_hdd\_size\_gb) | The HDD size in GB to configure for the Kasm CPX instances | `number` | `0` | no |
+| [cpx\_instance\_type](#input\_cpx\_instance\_type) | the instance type for the CPX nodes | `string` | `""` | no |
+| [cpx\_security\_group\_id](#input\_cpx\_security\_group\_id) | CPX security group ID | `string` | `""` | no |
+| [cpx\_subnet\_id](#input\_cpx\_subnet\_id) | Subnet ID created for Kasm CPX nodes | `string` | `""` | no |
+| [database\_password](#input\_database\_password) | The password for the database. No special characters | `string` | n/a | yes |
+| [ec2\_ami](#input\_ec2\_ami) | The AMI used for the EC2 nodes. Recommended Ubuntu 20.04 LTS. | `string` | n/a | yes |
+| [faux\_aws\_region](#input\_faux\_aws\_region) | 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) | `string` | n/a | yes |
+| [kasm\_build](#input\_kasm\_build) | The URL for the Kasm Workspaces build | `string` | n/a | yes |
+| [kasm\_db\_ip](#input\_kasm\_db\_ip) | The IP/DNS name of the Kasm database | `string` | n/a | yes |
+| [load\_balancer\_log\_bucket](#input\_load\_balancer\_log\_bucket) | S3 bucket name for load balancers to forward access logs to | `string` | n/a | yes |
+| [load\_balancer\_security\_group\_id](#input\_load\_balancer\_security\_group\_id) | Security Group ID for the Primary region's load balancer | `string` | n/a | yes |
+| [load\_balancer\_subnet\_ids](#input\_load\_balancer\_subnet\_ids) | ALB subnet IDs created to host webapps in the primary region | `list(string)` | n/a | yes |
+| [manager\_token](#input\_manager\_token) | The Manager Token used by Kasm Agents to authenticate. No special characters | `string` | n/a | yes |
+| [num\_agents](#input\_num\_agents) | The number of Agent Role Servers to create in the deployment | `number` | `0` | no |
+| [num\_cpx\_nodes](#input\_num\_cpx\_nodes) | The number of cpx Role Servers to create in the deployment | `number` | `0` | no |
+| [num\_webapps](#input\_num\_webapps) | The number of WebApp role servers to create in the deployment | `number` | n/a | yes |
+| [primary\_aws\_region](#input\_primary\_aws\_region) | The AWS region for primary region of the deployment. (e.g us-east-1) | `string` | n/a | yes |
+| [primary\_vpc\_id](#input\_primary\_vpc\_id) | The VPC ID of the primary region | `string` | n/a | yes |
+| [project\_name](#input\_project\_name) | The name of the deployment (e.g dev, staging). A short single word | `string` | n/a | yes |
+| [redis\_password](#input\_redis\_password) | The password for the database. No special characters | `string` | n/a | yes |
+| [service\_registration\_token](#input\_service\_registration\_token) | The service registration token value for cpx RDP servers to authenticate to webapps. No special characters | `string` | `""` | no |
+| [swap\_size](#input\_swap\_size) | The amount of swap (in MB) to configure inside the compute instances | `number` | n/a | yes |
+| [webapp\_hdd\_size\_gb](#input\_webapp\_hdd\_size\_gb) | The HDD size in GB to configure for the Kasm WebApp instances | `number` | n/a | yes |
+| [webapp\_instance\_type](#input\_webapp\_instance\_type) | The instance type for the webapps | `string` | n/a | yes |
+| [webapp\_security\_group\_id](#input\_webapp\_security\_group\_id) | WebApp security group ID | `string` | n/a | yes |
+| [webapp\_subnet\_ids](#input\_webapp\_subnet\_ids) | WebApp subnet IDs created to host webapps in the primary region | `list(string)` | n/a | yes |
+| [zone\_name](#input\_zone\_name) | A name given to the Kasm deployment Zone | `string` | n/a | yes |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [kasm\_zone\_name](#output\_kasm\_zone\_name) | The zone name used for this region/zone in Kasm |
+
diff --git a/aws/multi_region/webapps/agent.tf b/aws/multi_region/webapps/agent.tf
index 299f515..8dfdc9b 100644
--- a/aws/multi_region/webapps/agent.tf
+++ b/aws/multi_region/webapps/agent.tf
@@ -1,10 +1,13 @@
-resource "aws_instance" "kasm-agent" {
- 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
+resource "aws_instance" "agent" {
+ 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
+ associate_public_ip_address = true
+ iam_instance_profile = var.aws_ssm_instance_profile_name
root_block_device {
volume_size = var.agent_hdd_size_gb
@@ -19,7 +22,14 @@ resource "aws_instance" "kasm-agent" {
}
)
+ metadata_options {
+ http_endpoint = "enabled"
+ http_tokens = "required"
+ http_put_response_hop_limit = 1
+ instance_metadata_tags = null
+ }
+
tags = {
- Name = "${var.project_name}-${var.zone_name}-kasm-agent"
+ Name = "${var.project_name}-${var.zone_name}-kasm-agent-${count.index}"
}
}
diff --git a/aws/multi_region/webapps/availability_zones.tf b/aws/multi_region/webapps/availability_zones.tf
deleted file mode 100644
index 87d8f48..0000000
--- a/aws/multi_region/webapps/availability_zones.tf
+++ /dev/null
@@ -1,3 +0,0 @@
-data "aws_availability_zones" "available" {
- state = "available"
-}
diff --git a/aws/multi_region/webapps/cpx.tf b/aws/multi_region/webapps/cpx.tf
new file mode 100644
index 0000000..0829519
--- /dev/null
+++ b/aws/multi_region/webapps/cpx.tf
@@ -0,0 +1,34 @@
+resource "aws_instance" "cpx" {
+ count = var.num_cpx_nodes
+
+ ami = var.ec2_ami
+ instance_type = var.cpx_instance_type
+ vpc_security_group_ids = [var.cpx_security_group_id]
+ subnet_id = var.cpx_subnet_id
+ key_name = var.aws_key_pair
+ iam_instance_profile = var.aws_ssm_instance_profile_name
+
+ root_block_device {
+ volume_size = var.cpx_hdd_size_gb
+ }
+
+ user_data = templatefile("${path.module}/../userdata/cpx_bootstrap.sh",
+ {
+ kasm_build_url = var.kasm_build
+ swap_size = var.swap_size
+ manager_address = var.aws_domain_name
+ service_registration_token = var.service_registration_token
+ }
+ )
+
+ metadata_options {
+ http_endpoint = "enabled"
+ http_tokens = "required"
+ http_put_response_hop_limit = 1
+ instance_metadata_tags = null
+ }
+
+ tags = {
+ Name = "${var.project_name}-${var.primary_aws_region}-kasm-cpx-${count.index}"
+ }
+}
diff --git a/aws/multi_region/webapps/dependencies.tf b/aws/multi_region/webapps/dependencies.tf
new file mode 100644
index 0000000..db16943
--- /dev/null
+++ b/aws/multi_region/webapps/dependencies.tf
@@ -0,0 +1,8 @@
+locals {
+ region_short_name_for_lb = join("", slice(split("-", var.faux_aws_region), 1, 3))
+}
+
+data "aws_route53_zone" "this" {
+ name = var.aws_domain_name
+ private_zone = false
+}
diff --git a/aws/multi_region/webapps/elb.tf b/aws/multi_region/webapps/elb.tf
index 994e22a..7774dd9 100644
--- a/aws/multi_region/webapps/elb.tf
+++ b/aws/multi_region/webapps/elb.tf
@@ -1,14 +1,9 @@
-data "aws_route53_zone" "kasm-route53-zone" {
- name = var.aws_domain_name
- private_zone = false
-}
-
-resource "aws_lb" "kasm-alb" {
- name = "${var.project_name}-lb"
+resource "aws_lb" "this" {
+ name = "${var.project_name}-${var.faux_aws_region}-lb"
internal = false
load_balancer_type = "application"
security_groups = [var.load_balancer_security_group_id]
- subnets = var.webapp_subnet_ids
+ subnets = var.load_balancer_subnet_ids
access_logs {
bucket = var.load_balancer_log_bucket
@@ -16,41 +11,20 @@ resource "aws_lb" "kasm-alb" {
}
}
-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 = var.primary_vpc_id
-
- health_check {
- path = "/api/__healthcheck"
- matcher = 200
- protocol = "HTTPS"
- }
-}
-
-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
+resource "aws_lb_listener" "https" {
+ load_balancer_arn = aws_lb.this.arn
port = "443"
protocol = "HTTPS"
certificate_arn = var.certificate_arn
default_action {
type = "forward"
- target_group_arn = data.aws_lb_target_group.data-kasm_target_group.arn
+ target_group_arn = aws_lb_target_group.this.arn
}
}
-resource "aws_lb_listener" "kasm_alb_listener_http" {
- load_balancer_arn = data.aws_lb.data-kasm_alb.arn
+resource "aws_lb_listener" "http" {
+ load_balancer_arn = aws_lb.this.arn
port = "80"
protocol = "HTTP"
@@ -65,34 +39,47 @@ resource "aws_lb_listener" "kasm_alb_listener_http" {
}
}
-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_apps[count.index].id
+resource "aws_lb_target_group" "this" {
+ name = "${var.project_name}-${var.faux_aws_region}-tg"
+ port = 443
+ protocol = "HTTPS"
+ vpc_id = var.primary_vpc_id
+
+ health_check {
+ path = "/api/__healthcheck"
+ matcher = 200
+ protocol = "HTTPS"
+ }
+}
+resource "aws_lb_target_group_attachment" "this" {
+ count = var.num_webapps
+
+ target_group_arn = aws_lb_target_group.this.arn
+ target_id = aws_instance.webapp[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}"
+resource "aws_route53_record" "alb" {
+ zone_id = data.aws_route53_zone.this.zone_id
+ name = "${local.region_short_name_for_lb}-lb.${var.aws_domain_name}"
type = "A"
alias {
- name = data.aws_lb.data-kasm_alb.dns_name
- zone_id = data.aws_lb.data-kasm_alb.zone_id
+ name = aws_lb.this.dns_name
+ zone_id = aws_lb.this.zone_id
evaluate_target_health = true
}
}
-resource "aws_route53_record" "kasm-app-url" {
- zone_id = data.aws_route53_zone.kasm-route53-zone.zone_id
+resource "aws_route53_record" "latency" {
+ zone_id = data.aws_route53_zone.this.zone_id
name = var.aws_domain_name
type = "A"
- set_identifier = "${var.project_name}-${var.zone_name}-set-id"
+ set_identifier = "${var.project_name}-${local.region_short_name_for_lb}-set-id"
alias {
- name = data.aws_lb.data-kasm_alb.dns_name
- zone_id = data.aws_lb.data-kasm_alb.zone_id
+ name = aws_lb.this.dns_name
+ zone_id = aws_lb.this.zone_id
evaluate_target_health = true
}
@@ -101,8 +88,8 @@ resource "aws_route53_record" "kasm-app-url" {
}
}
-resource "aws_route53_health_check" "kasm-elb-hc" {
- fqdn = "${var.zone_name}-lb.${var.aws_domain_name}"
+resource "aws_route53_health_check" "this" {
+ fqdn = "${local.region_short_name_for_lb}-lb.${var.aws_domain_name}"
port = 443
type = "HTTPS"
resource_path = "/api/__healthcheck"
@@ -110,6 +97,6 @@ resource "aws_route53_health_check" "kasm-elb-hc" {
request_interval = "30"
tags = {
- Name = "hc-${var.zone_name}-lb.${var.aws_domain_name}"
+ Name = "hc-${local.region_short_name_for_lb}-lb.${var.aws_domain_name}"
}
}
diff --git a/aws/multi_region/webapps/outputs.tf b/aws/multi_region/webapps/outputs.tf
new file mode 100644
index 0000000..8778f56
--- /dev/null
+++ b/aws/multi_region/webapps/outputs.tf
@@ -0,0 +1,4 @@
+output "kasm_zone_name" {
+ description = "The zone name used for this region/zone in Kasm"
+ value = var.aws_to_kasm_zone_map[(var.faux_aws_region)]
+}
diff --git a/aws/multi_region/webapps/provider.tf b/aws/multi_region/webapps/provider.tf
index 099cb9c..d50a6bd 100644
--- a/aws/multi_region/webapps/provider.tf
+++ b/aws/multi_region/webapps/provider.tf
@@ -1,8 +1,10 @@
terraform {
+ required_version = "~> 1.0"
+
required_providers {
aws = {
- source = "hashicorp/aws"
- #version = "4.56.0"
+ source = "hashicorp/aws"
+ version = "~> 5.0"
}
}
}
diff --git a/aws/multi_region/webapps/variables.tf b/aws/multi_region/webapps/variables.tf
index 65aaeb8..7f8e150 100644
--- a/aws/multi_region/webapps/variables.tf
+++ b/aws/multi_region/webapps/variables.tf
@@ -19,6 +19,12 @@ variable "agent_hdd_size_gb" {
default = 0
}
+variable "cpx_hdd_size_gb" {
+ description = "The HDD size in GB to configure for the Kasm CPX instances"
+ type = number
+ default = 0
+}
+
variable "database_password" {
description = "The password for the database. No special characters"
type = string
@@ -31,6 +37,13 @@ variable "redis_password" {
sensitive = true
}
+variable "service_registration_token" {
+ description = "The service registration token value for cpx RDP servers to authenticate to webapps. No special characters"
+ type = string
+ sensitive = true
+ default = ""
+}
+
variable "manager_token" {
description = "The Manager Token used by Kasm Agents to authenticate. No special characters"
type = string
@@ -45,13 +58,11 @@ variable "swap_size" {
variable "num_webapps" {
description = "The number of WebApp role servers to create in the deployment"
type = number
- default = 2
}
variable "webapp_instance_type" {
description = "The instance type for the webapps"
type = string
- default = "t3.small"
}
variable "webapp_security_group_id" {
@@ -59,11 +70,28 @@ variable "webapp_security_group_id" {
type = string
}
+variable "load_balancer_subnet_ids" {
+ description = "ALB subnet IDs created to host webapps in the primary region"
+ type = list(string)
+}
+
variable "webapp_subnet_ids" {
description = "WebApp subnet IDs created to host webapps in the primary region"
type = list(string)
}
+variable "cpx_instance_type" {
+ description = "the instance type for the CPX nodes"
+ type = string
+ default = ""
+}
+
+variable "cpx_subnet_id" {
+ description = "Subnet ID created for Kasm CPX nodes"
+ type = string
+ default = ""
+}
+
variable "num_agents" {
description = "The number of Agent Role Servers to create in the deployment"
type = number
@@ -73,7 +101,7 @@ variable "num_agents" {
variable "agent_instance_type" {
description = "the instance type for the agents"
type = string
- default = "t3.medium"
+ default = ""
}
variable "agent_subnet_id" {
@@ -98,6 +126,12 @@ variable "faux_aws_region" {
type = string
}
+variable "num_cpx_nodes" {
+ description = "The number of cpx Role Servers to create in the deployment"
+ type = number
+ default = 0
+}
+
variable "kasm_build" {
description = "The URL for the Kasm Workspaces build"
type = string
@@ -128,11 +162,6 @@ variable "certificate_arn" {
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
@@ -143,7 +172,53 @@ variable "primary_vpc_id" {
type = string
}
+variable "aws_ssm_instance_profile_name" {
+ description = "The name of the SSM EC2 Instance Profile to associate with Kasm VMs for SSH access"
+ type = string
+ default = ""
+}
+
variable "load_balancer_security_group_id" {
description = "Security Group ID for the Primary region's load balancer"
type = string
}
+
+variable "cpx_security_group_id" {
+ description = "CPX security group ID"
+ type = string
+ default = ""
+}
+
+variable "aws_to_kasm_zone_map" {
+ description = "AWS regions mapped to Kasm Deployment Zone names"
+ type = map(any)
+ default = {
+ us-east-1 = "USA-(Virginia)"
+ us-east-2 = "USA-(Ohio)"
+ us-west-1 = "USA-(California)"
+ us-west-2 = "USA-(Oregon)"
+ ap-south-1 = "India-(Mumbai)"
+ ap-northeast-3 = "Japan-(Osaka)"
+ ap-northeast-2 = "S-Korea-(Seoul)"
+ ap-southeast-1 = "Singapore"
+ ap-southeast-2 = "Austrailia-(Sydney)"
+ ap-northeast-1 = "Japan-(Tokyo)"
+ ca-central-1 = "Canada-(Montreal)"
+ eu-central-1 = "Germany-(Frankfurt)"
+ eu-west-1 = "Ireland-(Dublin)"
+ eu-west-2 = "UK-(London)"
+ eu-west-3 = "France-(Paris)"
+ eu-north-1 = "Sweden-(Stockholm)"
+ eu-south-1 = "Italy-(Milan)"
+ eu-south-2 = "Spain-(Aragon)"
+ eu-central-1 = "Switzerland-(Zurich)"
+ sa-east-1 = "Brazil-(Sao-Paulo)"
+ af-south-1 = "Africa-(Cape-Town)"
+ ap-east-1 = "China-(Hong-Kong)"
+ ap-south-2 = "India-(Hyderbad)"
+ ap-southeast-3 = "Indonesia-(Jakarta)"
+ ap-southeast-4 = "Austrailia-(Melbourne)"
+ me-south-1 = "Manama-(Bahrain)"
+ me-central-1 = "United-Arab-Emirates"
+ }
+}
diff --git a/aws/multi_region/webapps/webapp.tf b/aws/multi_region/webapps/webapp.tf
index 78accc9..0375658 100644
--- a/aws/multi_region/webapps/webapp.tf
+++ b/aws/multi_region/webapps/webapp.tf
@@ -1,10 +1,12 @@
-resource "aws_instance" "kasm-web-app" {
- count = var.num_webapps
+resource "aws_instance" "webapp" {
+ 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
+ iam_instance_profile = var.aws_ssm_instance_profile_name
root_block_device {
volume_size = var.webapp_hdd_size_gb
@@ -17,16 +19,18 @@ resource "aws_instance" "kasm-web-app" {
database_password = var.database_password
redis_password = var.redis_password
swap_size = var.swap_size
- zone_name = "default"
+ zone_name = var.aws_to_kasm_zone_map[(var.faux_aws_region)]
}
)
+ metadata_options {
+ http_endpoint = "enabled"
+ http_tokens = "required"
+ http_put_response_hop_limit = 1
+ instance_metadata_tags = null
+ }
+
tags = {
- Name = "${var.project_name}-${var.zone_name}-kasm-webapp"
+ Name = "${var.project_name}-${var.zone_name}-kasm-webapp-${count.index}"
}
}
-
-data "aws_instance" "data-kasm_web_apps" {
- count = var.num_webapps
- instance_id = aws_instance.kasm-web-app[count.index].id
-}
diff --git a/aws/standard/README.md b/aws/standard/README.md
index 09b7a50..2dbf732 100644
--- a/aws/standard/README.md
+++ b/aws/standard/README.md
@@ -2,12 +2,13 @@
This project will deploy Kasm Workspaces in a multi-server deployment in AWS within a single region of your choice.
Each role is placed in a separate subnet and traffic from user sessions on the Agent egresses out of a Nat Gateway.
-
![Diagram][Image_Diagram]
-[Image_Diagram]: https://f.hubspotusercontent30.net/hubfs/5856039/terraform/diagrams/aws-multi-server-nat-gw.png "Diagram"
+[Image_Diagram]: https://5856039.fs1.hubspotusercontent-na1.net/hubfs/5856039/terraform/diagrams/aws-multi-server-new.jpg "Diagram"
+> ***NOTE:*** This deployment has been tested and validated with both [Terraform](https://www.terraform.io/) and [OpenTofu](https://opentofu.org/)
+
# Pre-Configuration
Consider creating a special sub account for the Kasm deployment.
@@ -27,55 +28,90 @@ Create a user via the IAM console that will be used for the terraform deployment
terraform init
-2. Open `settings.tfvars` and update the variable values. The variable definitions, descriptions, and validation expectations can be found in the `variables.tf` file.
+2. Open `terraform.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.
+> ***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. If you would rather use Environment variables or some other AWS credential method in lieu of the `secrets.tfvars` file, check out the [AWS Terraform provider documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#environment-variables) for more information about configuring your environment.
3. Verify the configuration
- terraform plan -var-file settings.tfvars -var-file secrets.tfvars
+ terraform plan -var-file secrets.tfvars
4. Deploy
- terraform apply -var-file settings.tfvars -var-file secrets.tfvars
+ terraform apply -var-file secrets.tfvars
-5. Login to the Deployment as an Admin via the domain defined e.g `https://kasm.contoso.com`
+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)
+7. Now you are ready to add Workspaces via the registry and start using Kasm!
-# AWS Terraform Variable definitions
+
+## Requirements
-| 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.13.0.002947.tar.gz"` |
-| `aws_default_tags` | A Map of all tags you wish to apply to all TF created resources in this deployment. | Map(Any) | {
Service_name = "Kasm Workspaces"
Kasm_version = "1.12"
} |
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0 |
+| [aws](#requirement\_aws) | ~> 5.0 |
+## Providers
+
+No providers.
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [standard](#module\_standard) | ./module | n/a |
+
+## Resources
+
+No resources.
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [admin\_password](#input\_admin\_password) | The administrative user password. No special characters | `string` | n/a | yes |
+| [agent\_hdd\_size\_gb](#input\_agent\_hdd\_size\_gb) | The HDD size in GB to configure for the Kasm Agent instances | `number` | n/a | yes |
+| [agent\_instance\_type](#input\_agent\_instance\_type) | The instance type for the Agents | `string` | n/a | yes |
+| [aws\_access\_key](#input\_aws\_access\_key) | The AWS access key used for deployment | `string` | n/a | yes |
+| [aws\_default\_tags](#input\_aws\_default\_tags) | Default tags to apply to all AWS resources for this deployment | `map(any)` | `{}` | no |
+| [aws\_domain\_name](#input\_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` | n/a | yes |
+| [aws\_key\_pair](#input\_aws\_key\_pair) | The name of an aws keypair to use. | `string` | n/a | yes |
+| [aws\_region](#input\_aws\_region) | The AWS Region used for deployment | `string` | `"us-east-1"` | no |
+| [aws\_secret\_key](#input\_aws\_secret\_key) | The AWS secret key used for deployment | `string` | n/a | yes |
+| [aws\_ssm\_iam\_role\_name](#input\_aws\_ssm\_iam\_role\_name) | The name of the SSM EC2 role to associate with Kasm VMs for SSH access | `string` | `""` | no |
+| [aws\_ssm\_instance\_profile\_name](#input\_aws\_ssm\_instance\_profile\_name) | The name of the SSM EC2 Instance Profile to associate with Kasm VMs for SSH access | `string` | `""` | no |
+| [cpx\_hdd\_size\_gb](#input\_cpx\_hdd\_size\_gb) | The HDD size in GB to configure for the Kasm cpx RDP instances | `number` | n/a | yes |
+| [cpx\_instance\_type](#input\_cpx\_instance\_type) | The instance type for the cpxamole RDP nodes | `string` | n/a | yes |
+| [create\_aws\_ssm\_iam\_role](#input\_create\_aws\_ssm\_iam\_role) | Create an AWS SSM IAM role to attach to VMs for SSH/console access to VMs. | `bool` | `false` | no |
+| [database\_password](#input\_database\_password) | The password for the database. No special characters | `string` | n/a | yes |
+| [db\_hdd\_size\_gb](#input\_db\_hdd\_size\_gb) | The HDD size in GB to configure for the Kasm Database instances | `number` | n/a | yes |
+| [db\_instance\_type](#input\_db\_instance\_type) | The instance type for the Database | `string` | n/a | yes |
+| [ec2\_ami\_id](#input\_ec2\_ami\_id) | The AMI used for the EC2 nodes. Recommended Ubuntu 22.04 LTS. | `string` | n/a | yes |
+| [kasm\_build](#input\_kasm\_build) | The URL for the Kasm Workspaces build | `string` | n/a | yes |
+| [kasm\_zone\_name](#input\_kasm\_zone\_name) | A name given to the kasm deployment Zone | `string` | `"default"` | no |
+| [manager\_token](#input\_manager\_token) | The manager token value for Agents to authenticate to webapps. No special characters | `string` | n/a | yes |
+| [num\_agents](#input\_num\_agents) | The number of Agent Role Servers to create in the deployment | `number` | n/a | yes |
+| [num\_cpx\_nodes](#input\_num\_cpx\_nodes) | The number of Agent Role Servers to create in the deployment | `number` | n/a | yes |
+| [num\_webapps](#input\_num\_webapps) | The number of WebApp role servers to create in the deployment | `number` | n/a | yes |
+| [project\_name](#input\_project\_name) | The name of the deployment (e.g dev, staging). A short single word | `string` | n/a | yes |
+| [redis\_password](#input\_redis\_password) | The password for the Redis server. No special characters | `string` | n/a | yes |
+| [service\_registration\_token](#input\_service\_registration\_token) | The service registration token value for cpx RDP servers to authenticate to webapps. No special characters | `string` | n/a | yes |
+| [swap\_size](#input\_swap\_size) | The amount of swap (in MB) to configure inside the compute instances | `number` | n/a | yes |
+| [user\_password](#input\_user\_password) | The standard (non administrator) user password. No special characters | `string` | n/a | yes |
+| [vpc\_subnet\_cidr](#input\_vpc\_subnet\_cidr) | The subnet CIDR to use for the VPC | `string` | `"10.0.0.0/16"` | no |
+| [web\_access\_cidrs](#input\_web\_access\_cidrs) | CIDR notation of the bastion host allowed to SSH in to the machines | `list(string)` | n/a | yes |
+| [webapp\_hdd\_size\_gb](#input\_webapp\_hdd\_size\_gb) | The HDD size in GB to configure for the Kasm WebApp instances | `number` | n/a | yes |
+| [webapp\_instance\_type](#input\_webapp\_instance\_type) | The instance type for the webapps | `string` | n/a | yes |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [kasm\_zone\_settings](#output\_kasm\_zone\_settings) | Upstream Auth settings to apply to Kasm Zone configuration |
+
# Detailed Terraform Deployment Diagram
diff --git a/aws/standard/deployment.tf b/aws/standard/deployment.tf
index b3c978f..2a8c189 100644
--- a/aws/standard/deployment.tf
+++ b/aws/standard/deployment.tf
@@ -1,23 +1,29 @@
module "standard" {
- 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
+ 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_cpx_nodes = var.num_cpx_nodes
+ vpc_subnet_cidr = var.vpc_subnet_cidr
+ create_aws_ssm_iam_role = var.create_aws_ssm_iam_role
+ aws_ssm_iam_role_name = var.aws_ssm_iam_role_name
+ aws_ssm_instance_profile_name = var.aws_ssm_instance_profile_name
## Kasm Server settings
- agent_instance_type = var.agent_instance_type
- guac_instance_type = var.guac_instance_type
webapp_instance_type = var.webapp_instance_type
+ webapp_hdd_size_gb = var.webapp_hdd_size_gb
db_instance_type = var.db_instance_type
- ec2_ami = var.ec2_ami
+ db_hdd_size_gb = var.db_hdd_size_gb
+ agent_instance_type = var.agent_instance_type
+ agent_hdd_size_gb = var.agent_hdd_size_gb
+ cpx_instance_type = var.cpx_instance_type
+ cpx_hdd_size_gb = var.cpx_hdd_size_gb
+ ec2_ami = var.ec2_ami_id
swap_size = var.swap_size
- ssh_access_cidrs = var.ssh_access_cidrs
web_access_cidrs = var.web_access_cidrs
database_password = var.database_password
redis_password = var.redis_password
diff --git a/aws/standard/diagram/aws_multi_server.drawio b/aws/standard/diagram/aws_multi_server.drawio
index 1edf218..76b2e3f 100644
--- a/aws/standard/diagram/aws_multi_server.drawio
+++ b/aws/standard/diagram/aws_multi_server.drawio
@@ -1,32 +1,32 @@
map(object({
from_port = number
to_port = number
protocol = string
})) | {
"https": {
"from_port": 443,
"protocol": "tcp",
"to_port": 443
}
} | no |
+| [anywhere](#input\_anywhere) | Anywhere route subnet | `string` | `"0.0.0.0/0"` | no |
+| [aws\_domain\_name](#input\_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` | n/a | yes |
+| [aws\_key\_pair](#input\_aws\_key\_pair) | The name of an aws keypair to use. | `string` | n/a | yes |
+| [aws\_region](#input\_aws\_region) | The AWS region for the deployment. (e.g us-east-1) | `string` | n/a | yes |
+| [aws\_ssm\_iam\_role\_name](#input\_aws\_ssm\_iam\_role\_name) | The name of the SSM EC2 role to associate with Kasm VMs for SSH access | `string` | `""` | no |
+| [aws\_ssm\_instance\_profile\_name](#input\_aws\_ssm\_instance\_profile\_name) | The name of the SSM EC2 Instance Profile to associate with Kasm VMs for SSH access | `string` | `""` | no |
+| [cpx\_hdd\_size\_gb](#input\_cpx\_hdd\_size\_gb) | The HDD size for Kasm Guac RDP nodes | `number` | n/a | yes |
+| [cpx\_instance\_type](#input\_cpx\_instance\_type) | The instance type for the cpxamole RDP nodes | `string` | `"t3.medium"` | no |
+| [cpx\_security\_rules](#input\_cpx\_security\_rules) | A map of objects of security rules to apply to the Kasm Connection Proxy server | map(object({
from_port = number
to_port = number
protocol = string
})) | {
"https": {
"from_port": 443,
"protocol": "tcp",
"to_port": 443
}
} | no |
+| [create\_aws\_ssm\_iam\_role](#input\_create\_aws\_ssm\_iam\_role) | Create an AWS SSM IAM role to attach to VMs for SSH/console access to VMs. | `bool` | `false` | no |
+| [database\_password](#input\_database\_password) | The password for the database. No special characters | `string` | n/a | yes |
+| [db\_hdd\_size\_gb](#input\_db\_hdd\_size\_gb) | The HDD size for Kasm DB | `number` | n/a | yes |
+| [db\_instance\_type](#input\_db\_instance\_type) | The instance type for the Database | `string` | `"t3.small"` | no |
+| [db\_security\_rules](#input\_db\_security\_rules) | A map of objects of security rules to apply to the Kasm DB | map(object({
from_port = number
to_port = number
protocol = string
})) | {
"postgres": {
"from_port": 5432,
"protocol": "tcp",
"to_port": 5432
},
"redis": {
"from_port": 6379,
"protocol": "tcp",
"to_port": 6379
}
} | no |
+| [default\_egress](#input\_default\_egress) | Default egress security rule for all security groups | map(object({
from_port = number
to_port = number
protocol = string
cidr_subnets = list(string)
})) | {
"all": {
"cidr_subnets": [
"0.0.0.0/0"
],
"from_port": 0,
"protocol": "-1",
"to_port": 0
}
} | no |
+| [ec2\_ami](#input\_ec2\_ami) | The AMI used for the EC2 nodes. Recommended Ubuntu 20.04 LTS. | `string` | n/a | yes |
+| [kasm\_build](#input\_kasm\_build) | The URL for the Kasm Workspaces build | `string` | n/a | yes |
+| [kasm\_zone\_name](#input\_kasm\_zone\_name) | A name given to the kasm deployment Zone | `string` | `"default"` | no |
+| [manager\_token](#input\_manager\_token) | The manager token value for Agents to authenticate to webapps. No special characters | `string` | n/a | yes |
+| [num\_agents](#input\_num\_agents) | The number of Agent Role Servers to create in the deployment | `number` | `2` | no |
+| [num\_cpx\_nodes](#input\_num\_cpx\_nodes) | The number of cpx RDP Role Servers to create in the deployment | `number` | `2` | no |
+| [num\_webapps](#input\_num\_webapps) | The number of WebApp role servers to create in the deployment | `number` | `2` | no |
+| [private\_lb\_security\_rules](#input\_private\_lb\_security\_rules) | A map of objects of security rules to apply to the Private ALB | map(object({
from_port = number
to_port = number
protocol = string
})) | {
"https": {
"from_port": 443,
"protocol": "tcp",
"to_port": 443
}
} | no |
+| [project\_name](#input\_project\_name) | The name of the deployment (e.g dev, staging). A short single word | `string` | n/a | yes |
+| [public\_lb\_security\_rules](#input\_public\_lb\_security\_rules) | A map of objects of security rules to apply to the Public ALB | map(object({
from_port = number
to_port = number
protocol = string
})) | {
"http": {
"from_port": 80,
"protocol": "tcp",
"to_port": 80
},
"https": {
"from_port": 443,
"protocol": "tcp",
"to_port": 443
}
} | no |
+| [redis\_password](#input\_redis\_password) | The password for the Redis server. No special characters | `string` | n/a | yes |
+| [service\_registration\_token](#input\_service\_registration\_token) | The service registration token value for cpx RDP servers to authenticate to webapps. No special characters | `string` | n/a | yes |
+| [swap\_size](#input\_swap\_size) | The amount of swap (in MB) to configure inside the compute instances | `number` | n/a | yes |
+| [user\_password](#input\_user\_password) | The standard (non administrator) user password. No special characters | `string` | n/a | yes |
+| [vpc\_subnet\_cidr](#input\_vpc\_subnet\_cidr) | The subnet CIDR to use for the VPC | `string` | `"10.0.0.0/16"` | no |
+| [web\_access\_cidrs](#input\_web\_access\_cidrs) | CIDR notation of the bastion host allowed to SSH in to the machines | `list(string)` | [| no | +| [webapp\_hdd\_size\_gb](#input\_webapp\_hdd\_size\_gb) | The HDD size for Kasm Webapp nodes | `number` | n/a | yes | +| [webapp\_instance\_type](#input\_webapp\_instance\_type) | The instance type for the webapps | `string` | `"t3.small"` | no | +| [webapp\_security\_rules](#input\_webapp\_security\_rules) | A map of objects of security rules to apply to the Kasm WebApp server |
"0.0.0.0/0"
]
object({
from_port = number
to_port = number
protocol = string
}) | {
"from_port": 443,
"protocol": "tcp",
"to_port": 443
} | no |
+| [windows\_security\_rules](#input\_windows\_security\_rules) | A map of objects of security rules to apply to the Kasm Windows VMs | map(object({
from_port = number
to_port = number
protocol = string
})) | {
"cpx_api": {
"from_port": 4902,
"protocol": "tcp",
"to_port": 4902
},
"cpx_rdp": {
"from_port": 3389,
"protocol": "tcp",
"to_port": 3389
},
"webapp_api": {
"from_port": 4902,
"protocol": "tcp",
"to_port": 4902
}
} | no |
+
+## Outputs
+
+No outputs.
+
diff --git a/aws/standard/module/agent.tf b/aws/standard/module/agent.tf
index 4914007..045739b 100644
--- a/aws/standard/module/agent.tf
+++ b/aws/standard/module/agent.tf
@@ -1,14 +1,16 @@
-resource "aws_instance" "kasm-agent" {
- count = var.num_agents
+resource "aws_instance" "agent" {
+ 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
+ vpc_security_group_ids = [aws_security_group.agent.id]
+ subnet_id = aws_subnet.agent.id
key_name = var.aws_key_pair
- associate_public_ip_address = false
+ iam_instance_profile = one(aws_iam_instance_profile.this[*].id)
+ associate_public_ip_address = true
root_block_device {
- volume_size = 120
+ volume_size = var.agent_hdd_size_gb
}
user_data = templatefile("${path.module}/userdata/agent_bootstrap.sh",
@@ -20,7 +22,14 @@ resource "aws_instance" "kasm-agent" {
}
)
+ metadata_options {
+ http_endpoint = "enabled"
+ http_tokens = "required"
+ http_put_response_hop_limit = 1
+ instance_metadata_tags = null
+ }
+
tags = {
- Name = "${var.project_name}-${var.kasm_zone_name}-kasm-agent"
+ Name = "${var.project_name}-${var.kasm_zone_name}-kasm-agent-${count.index}"
}
}
diff --git a/aws/standard/module/alb_logs_s3_bucket.tf b/aws/standard/module/alb_logs_s3_bucket.tf
deleted file mode 100644
index bbfa0e0..0000000
--- a/aws/standard/module/alb_logs_s3_bucket.tf
+++ /dev/null
@@ -1,60 +0,0 @@
-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
-}
diff --git a/aws/standard/module/availability_zones.tf b/aws/standard/module/availability_zones.tf
deleted file mode 100644
index 87d8f48..0000000
--- a/aws/standard/module/availability_zones.tf
+++ /dev/null
@@ -1,3 +0,0 @@
-data "aws_availability_zones" "available" {
- state = "available"
-}
diff --git a/aws/standard/module/cert.tf b/aws/standard/module/cert.tf
index 2126e66..f95dfda 100644
--- a/aws/standard/module/cert.tf
+++ b/aws/standard/module/cert.tf
@@ -1,4 +1,4 @@
-resource "aws_acm_certificate" "kasm-alb-cert" {
+resource "aws_acm_certificate" "this" {
domain_name = var.aws_domain_name
subject_alternative_names = ["*.${var.aws_domain_name}"]
validation_method = "DNS"
@@ -8,9 +8,9 @@ resource "aws_acm_certificate" "kasm-alb-cert" {
}
}
-resource "aws_route53_record" "kasm-route53-cert-validation-record" {
+resource "aws_route53_record" "this" {
for_each = {
- for dvo in aws_acm_certificate.kasm-alb-cert.domain_validation_options : dvo.domain_name => {
+ for dvo in aws_acm_certificate.this.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
@@ -19,13 +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.this.id
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]
+resource "aws_acm_certificate_validation" "this" {
+ certificate_arn = aws_acm_certificate.this.arn
+ validation_record_fqdns = [for record in aws_route53_record.this : record.fqdn]
}
diff --git a/aws/standard/module/db.tf b/aws/standard/module/db.tf
index e802b50..5bc6f56 100644
--- a/aws/standard/module/db.tf
+++ b/aws/standard/module/db.tf
@@ -1,12 +1,13 @@
-resource "aws_instance" "kasm-db" {
+resource "aws_instance" "db" {
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
+ vpc_security_group_ids = [aws_security_group.db.id]
+ subnet_id = aws_subnet.db.id
key_name = var.aws_key_pair
+ iam_instance_profile = one(aws_iam_instance_profile.this[*].id)
root_block_device {
- volume_size = 40
+ volume_size = var.db_hdd_size_gb
}
user_data = templatefile("${path.module}/userdata/db_bootstrap.sh",
@@ -22,11 +23,14 @@ resource "aws_instance" "kasm-db" {
}
)
+ metadata_options {
+ http_endpoint = "enabled"
+ http_tokens = "required"
+ http_put_response_hop_limit = 1
+ instance_metadata_tags = null
+ }
+
tags = {
Name = "${var.project_name}-kasm-db"
}
}
-
-data "aws_instance" "data-kasm_db" {
- instance_id = aws_instance.kasm-db.id
-}
diff --git a/aws/standard/module/dependencies.tf b/aws/standard/module/dependencies.tf
new file mode 100644
index 0000000..6209fb9
--- /dev/null
+++ b/aws/standard/module/dependencies.tf
@@ -0,0 +1,14 @@
+locals {
+ private_lb_hostname = "${var.aws_region}-private.${var.aws_domain_name}"
+
+}
+
+data "aws_availability_zones" "available" {
+ state = "available"
+}
+
+data "aws_route53_zone" "this" {
+ name = var.aws_domain_name
+}
+
+data "aws_elb_service_account" "main" {}
diff --git a/aws/standard/module/elb_logs_s3_bucket.tf b/aws/standard/module/elb_logs_s3_bucket.tf
new file mode 100644
index 0000000..d0ad6a0
--- /dev/null
+++ b/aws/standard/module/elb_logs_s3_bucket.tf
@@ -0,0 +1,45 @@
+resource "aws_s3_bucket" "this" {
+ bucket_prefix = "${var.project_name}-${var.kasm_zone_name}-"
+ force_destroy = true
+}
+
+resource "aws_s3_bucket_policy" "this" {
+ bucket = aws_s3_bucket.this.id
+
+ policy = jsonencode({
+ Id = "Policy"
+ Version = "2012-10-17"
+ Statement = [
+ {
+ Action = [
+ "s3:PutObject"
+ ]
+ Effect = "Allow"
+ Resource = "${aws_s3_bucket.this.arn}/AWSLogs/*"
+ Principal = {
+ AWS = [
+ data.aws_elb_service_account.main.arn
+ ]
+ }
+ }
+ ]
+ })
+}
+
+resource "aws_s3_bucket_server_side_encryption_configuration" "this" {
+ bucket = aws_s3_bucket.this.id
+
+ rule {
+ apply_server_side_encryption_by_default {
+ sse_algorithm = "AES256"
+ }
+ }
+}
+
+resource "aws_s3_bucket_public_access_block" "this" {
+ bucket = aws_s3_bucket.this.id
+ block_public_acls = true
+ block_public_policy = true
+ ignore_public_acls = true
+ restrict_public_buckets = true
+}
diff --git a/aws/standard/module/guac_rdp.tf b/aws/standard/module/guac_rdp.tf
index b464ac9..d21f4ab 100644
--- a/aws/standard/module/guac_rdp.tf
+++ b/aws/standard/module/guac_rdp.tf
@@ -1,17 +1,18 @@
-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
+resource "aws_instance" "cpx" {
+ count = var.num_cpx_nodes
+
+ ami = var.ec2_ami
+ instance_type = var.cpx_instance_type
+ vpc_security_group_ids = aws_security_group.cpx[*].id
+ subnet_id = one(aws_subnet.cpx[*].id)
+ key_name = var.aws_key_pair
+ iam_instance_profile = one(aws_iam_instance_profile.this[*].id)
root_block_device {
- volume_size = 120
+ volume_size = var.cpx_hdd_size_gb
}
- user_data = templatefile("${path.module}/userdata/guac_bootstrap.sh",
+ user_data = templatefile("${path.module}/userdata/cpx_bootstrap.sh",
{
kasm_build_url = var.kasm_build
swap_size = var.swap_size
@@ -20,7 +21,14 @@ resource "aws_instance" "kasm-guac" {
}
)
+ metadata_options {
+ http_endpoint = "enabled"
+ http_tokens = "required"
+ http_put_response_hop_limit = 1
+ instance_metadata_tags = null
+ }
+
tags = {
- Name = "${var.project_name}-${var.kasm_zone_name}-kasm-guac"
+ Name = "${var.project_name}-${var.kasm_zone_name}-kasm-cpx-${count.index}"
}
}
diff --git a/aws/standard/module/natgw.tf b/aws/standard/module/natgw.tf
deleted file mode 100644
index b30eee9..0000000
--- a/aws/standard/module/natgw.tf
+++ /dev/null
@@ -1,14 +0,0 @@
-resource "aws_eip" "nat_gateway_eip" {
- vpc = true
-}
-
-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
-
- depends_on = [data.aws_internet_gateway.data-kasm-default-ig]
-}
-
-data "aws_nat_gateway" "data-agent_and_guac_natgw" {
- id = aws_nat_gateway.agent_and_guac_natgw.id
-}
diff --git a/aws/standard/module/private_alb.tf b/aws/standard/module/private_alb.tf
index 81c67cb..ae00787 100644
--- a/aws/standard/module/private_alb.tf
+++ b/aws/standard/module/private_alb.tf
@@ -1,16 +1,12 @@
-locals {
- private_lb_hostname = "${var.kasm_zone_name}-private-lb.${var.aws_domain_name}"
-}
-
-resource "aws_lb" "kasm-private-alb" {
+resource "aws_lb" "private" {
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
+ security_groups = [aws_security_group.private_lb.id]
+ subnets = aws_subnet.webapp[*].id
access_logs {
- bucket = data.aws_s3_bucket.data-kasm_s3_logs_bucket.bucket
+ bucket = aws_s3_bucket.this.bucket
enabled = true
}
@@ -19,15 +15,11 @@ resource "aws_lb" "kasm-private-alb" {
}
}
-data "aws_lb" "data-kasm_private_alb" {
- arn = aws_lb.kasm-private-alb.arn
-}
-
-resource "aws_lb_target_group" "kasm-private-target-group" {
+resource "aws_lb_target_group" "private" {
name = "${var.project_name}-private-target-group"
port = 443
protocol = "HTTPS"
- vpc_id = data.aws_vpc.data-kasm-default-vpc.id
+ vpc_id = aws_vpc.this.id
health_check {
path = "/api/__healthcheck"
@@ -40,19 +32,15 @@ resource "aws_lb_target_group" "kasm-private-target-group" {
}
}
-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
+resource "aws_lb_listener" "private" {
+ load_balancer_arn = aws_lb.private.arn
port = "443"
protocol = "HTTPS"
- certificate_arn = aws_acm_certificate_validation.kasm-elb-certificate-validation.certificate_arn
+ certificate_arn = aws_acm_certificate_validation.this.certificate_arn
default_action {
type = "forward"
- target_group_arn = data.aws_lb_target_group.data-kasm_private_target_group.arn
+ target_group_arn = aws_lb_target_group.private.arn
}
tags = {
@@ -60,34 +48,22 @@ resource "aws_lb_listener" "kasm-private-alb-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
+resource "aws_lb_target_group_attachment" "private" {
+ count = var.num_webapps
+
+ target_group_arn = aws_lb_target_group.private.arn
+ target_id = aws_instance.webapp[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
+resource "aws_route53_record" "private" {
+ zone_id = data.aws_route53_zone.this.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
+ name = aws_lb.private.dns_name
+ zone_id = aws_lb.private.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}"
- }
-}
diff --git a/aws/standard/module/provider.tf b/aws/standard/module/provider.tf
index 099cb9c..d50a6bd 100644
--- a/aws/standard/module/provider.tf
+++ b/aws/standard/module/provider.tf
@@ -1,8 +1,10 @@
terraform {
+ required_version = "~> 1.0"
+
required_providers {
aws = {
- source = "hashicorp/aws"
- #version = "4.56.0"
+ source = "hashicorp/aws"
+ version = "~> 5.0"
}
}
}
diff --git a/aws/standard/module/public_alb.tf b/aws/standard/module/public_alb.tf
index 2728cd1..dc42854 100644
--- a/aws/standard/module/public_alb.tf
+++ b/aws/standard/module/public_alb.tf
@@ -1,12 +1,12 @@
-resource "aws_lb" "kasm-alb" {
+resource "aws_lb" "public" {
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
+ security_groups = [aws_security_group.public_lb.id]
+ subnets = aws_subnet.alb[*].id
access_logs {
- bucket = data.aws_s3_bucket.data-kasm_s3_logs_bucket.bucket
+ bucket = aws_s3_bucket.this.bucket
enabled = true
}
@@ -15,40 +15,15 @@ resource "aws_lb" "kasm-alb" {
}
}
-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
+resource "aws_lb_listener" "https" {
+ load_balancer_arn = aws_lb.public.arn
port = "443"
protocol = "HTTPS"
- certificate_arn = aws_acm_certificate_validation.kasm-elb-certificate-validation.certificate_arn
+ certificate_arn = aws_acm_certificate_validation.this.certificate_arn
default_action {
type = "forward"
- target_group_arn = data.aws_lb_target_group.data-kasm_target_group.arn
+ target_group_arn = aws_lb_target_group.public.arn
}
tags = {
@@ -56,8 +31,8 @@ resource "aws_lb_listener" "kasm-alb-listener" {
}
}
-resource "aws_lb_listener" "kasm_alb_listener_http" {
- load_balancer_arn = data.aws_lb.data-kasm_alb.arn
+resource "aws_lb_listener" "http" {
+ load_balancer_arn = aws_lb.public.arn
port = "80"
protocol = "HTTP"
@@ -76,44 +51,45 @@ resource "aws_lb_listener" "kasm_alb_listener_http" {
}
}
-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
+resource "aws_lb_target_group" "public" {
+ name = "${var.project_name}-target-group"
+ port = 443
+ protocol = "HTTPS"
+ vpc_id = aws_vpc.this.id
+
+ health_check {
+ path = "/api/__healthcheck"
+ matcher = 200
+ protocol = "HTTPS"
+ }
+
+ tags = {
+ Name = "${var.project_name}-kasm-public-tg"
+ }
+}
+
+resource "aws_lb_target_group_attachment" "public" {
+ count = var.num_webapps
+
+ target_group_arn = aws_lb_target_group.public.arn
+ target_id = aws_instance.webapp[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}"
+resource "aws_route53_record" "public" {
+ zone_id = data.aws_route53_zone.this.zone_id
+ name = var.aws_domain_name
type = "A"
alias {
- name = aws_lb.kasm-alb.dns_name
- zone_id = aws_lb.kasm-alb.zone_id
+ name = aws_lb.public.dns_name
+ zone_id = aws_lb.public.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}"
+ fqdn = var.aws_domain_name
port = 443
type = "HTTPS"
resource_path = "/api/__healthcheck"
@@ -121,6 +97,6 @@ resource "aws_route53_health_check" "kasm-elb-hc" {
request_interval = "30"
tags = {
- Name = "hc-${var.kasm_zone_name}-lb.${var.aws_domain_name}"
+ Name = "hc-${var.aws_domain_name}"
}
}
diff --git a/aws/standard/module/routes.tf b/aws/standard/module/routes.tf
index db10bbb..693b101 100644
--- a/aws/standard/module/routes.tf
+++ b/aws/standard/module/routes.tf
@@ -1,9 +1,9 @@
-resource "aws_route_table" "internet_access" {
- vpc_id = data.aws_vpc.data-kasm-default-vpc.id
+resource "aws_route_table" "ig" {
+ vpc_id = aws_vpc.this.id
route {
cidr_block = var.anywhere
- gateway_id = data.aws_internet_gateway.data-kasm-default-ig.id
+ gateway_id = aws_internet_gateway.this.id
}
tags = {
@@ -11,27 +11,12 @@ resource "aws_route_table" "internet_access" {
}
}
-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
+resource "aws_route_table" "nat" {
+ vpc_id = aws_vpc.this.id
route {
- cidr_block = var.anywhere
- gateway_id = data.aws_nat_gateway.data-agent_and_guac_natgw.id
+ cidr_block = var.anywhere
+ nat_gateway_id = aws_nat_gateway.this.id
}
tags = {
@@ -39,16 +24,40 @@ resource "aws_route_table" "nat_route_table" {
}
}
-data "aws_route_table" "data-nat_route_table" {
- route_table_id = aws_route_table.nat_route_table.id
+resource "aws_route_table_association" "alb" {
+ count = 2
+
+ subnet_id = aws_subnet.alb[count.index].id
+ route_table_id = aws_route_table.ig.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" "webapp" {
+ count = var.num_webapps
+
+ subnet_id = aws_subnet.webapp[count.index].id
+ route_table_id = aws_route_table.nat.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
+resource "aws_route_table_association" "db" {
+ subnet_id = aws_subnet.db.id
+ route_table_id = aws_route_table.nat.id
+}
+
+resource "aws_route_table_association" "cpx" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+
+ subnet_id = one(aws_subnet.cpx[*].id)
+ route_table_id = aws_route_table.nat.id
+}
+
+resource "aws_route_table_association" "agent" {
+ subnet_id = aws_subnet.agent.id
+ route_table_id = aws_route_table.ig.id
+}
+
+resource "aws_route_table_association" "windows" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+
+ subnet_id = one(aws_subnet.windows[*].id)
+ route_table_id = aws_route_table.ig.id
}
diff --git a/aws/standard/module/security_group.tf b/aws/standard/module/security_group.tf
index 2b8558b..1076e98 100644
--- a/aws/standard/module/security_group.tf
+++ b/aws/standard/module/security_group.tf
@@ -1,174 +1,287 @@
-resource "aws_security_group" "kasm-default-elb-sg" {
- name = "${var.project_name}-kasm-allow-elb-access"
+resource "aws_security_group" "public_lb" {
+ name = "${var.project_name}-kasm-allow-public-lb-access"
description = "Security Group for ELB"
- vpc_id = data.aws_vpc.data-kasm-default-vpc.id
-
- ingress {
- from_port = 443
- to_port = 443
- protocol = "tcp"
- 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 = [var.anywhere]
- }
+ vpc_id = aws_vpc.this.id
tags = {
- Name = "${var.project_name}-kasm-allow-access"
+ Name = "${var.project_name}-kasm-public-lb-access"
}
}
-data "aws_security_group" "data-kasm_default_elb_sg" {
- id = aws_security_group.kasm-default-elb-sg.id
+resource "aws_security_group_rule" "public_lb_ingress" {
+ for_each = var.public_lb_security_rules
+
+ security_group_id = aws_security_group.public_lb.id
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = var.web_access_cidrs
}
-resource "aws_security_group" "kasm-webapp-sg" {
- name = "${var.project_name}-${var.kasm_zone_name}-kasm-webapp"
+resource "aws_security_group_rule" "public_lb_egress" {
+ for_each = var.default_egress
+
+ security_group_id = aws_security_group.public_lb.id
+ type = "egress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = each.value.cidr_subnets
+}
+
+resource "aws_security_group" "private_lb" {
+ name = "${var.project_name}-kasm-allow-private-lb-access"
+ description = "Security Group for ELB"
+ vpc_id = aws_vpc.this.id
+
+ tags = {
+ Name = "${var.project_name}-kasm-private-lb-access"
+ }
+}
+
+resource "aws_security_group_rule" "private_lb_egress" {
+ for_each = var.private_lb_security_rules
+
+ security_group_id = aws_security_group.private_lb.id
+ type = "egress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = aws_subnet.webapp[*].cidr_block
+}
+
+resource "aws_security_group_rule" "private_lb_agent" {
+ for_each = var.private_lb_security_rules
+
+ security_group_id = aws_security_group.private_lb.id
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ source_security_group_id = aws_security_group.agent.id
+}
+
+resource "aws_security_group" "webapp" {
+ name = "${var.project_name}-kasm-webapp"
description = "Allow access to webapps"
- vpc_id = data.aws_vpc.data-kasm-default-vpc.id
+ vpc_id = aws_vpc.this.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_default_elb_sg.id]
- }
-
- ingress {
- 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 = [var.anywhere]
+ tags = {
+ Name = "${var.project_name}-kasm-webapp-access"
}
}
-data "aws_security_group" "data-kasm_webapp_sg" {
- id = aws_security_group.kasm-webapp-sg.id
+resource "aws_security_group_rule" "webapp_agent_ingress" {
+ security_group_id = aws_security_group.webapp.id
+ type = "ingress"
+ from_port = var.webapp_security_rules.from_port
+ to_port = var.webapp_security_rules.to_port
+ protocol = var.webapp_security_rules.protocol
+ source_security_group_id = aws_security_group.agent.id
}
-resource "aws_security_group" "kasm-agent-sg" {
- name = "${var.project_name}-${var.kasm_zone_name}-kasm-agent-access"
+resource "aws_security_group_rule" "webapp_private_lb_ingress" {
+ security_group_id = aws_security_group.webapp.id
+ type = "ingress"
+ from_port = var.webapp_security_rules.from_port
+ to_port = var.webapp_security_rules.to_port
+ protocol = var.webapp_security_rules.protocol
+ source_security_group_id = aws_security_group.private_lb.id
+}
+
+resource "aws_security_group_rule" "webapp_public_lb_ingress" {
+ security_group_id = aws_security_group.webapp.id
+ type = "ingress"
+ from_port = var.webapp_security_rules.from_port
+ to_port = var.webapp_security_rules.to_port
+ protocol = var.webapp_security_rules.protocol
+ source_security_group_id = aws_security_group.public_lb.id
+}
+
+resource "aws_security_group_rule" "webapp_egress" {
+ for_each = var.default_egress
+
+ security_group_id = aws_security_group.webapp.id
+ type = "egress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = each.value.cidr_subnets
+}
+
+resource "aws_security_group" "agent" {
+ name = "${var.project_name}-kasm-agent-access"
description = "Allow access to agents"
- vpc_id = data.aws_vpc.data-kasm-default-vpc.id
+ vpc_id = aws_vpc.this.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]
+ tags = {
+ Name = "${var.project_name}-kasm-agent-access"
}
}
-data "aws_security_group" "data-kasm_agent_sg" {
- id = aws_security_group.kasm-agent-sg.id
+resource "aws_security_group_rule" "agent" {
+ for_each = var.agent_security_rules
+
+ security_group_id = aws_security_group.agent.id
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ source_security_group_id = aws_security_group.webapp.id
}
-resource "aws_security_group" "kasm-db-sg" {
- name = "${var.project_name}-${var.kasm_zone_name}-kasm-db-access"
+resource "aws_security_group_rule" "agent_egress" {
+ for_each = var.default_egress
+
+ security_group_id = aws_security_group.agent.id
+ type = "egress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = each.value.cidr_subnets
+}
+
+resource "aws_security_group" "db" {
+ name = "${var.project_name}-kasm-db-access"
description = "Allow access to webapps"
- vpc_id = data.aws_vpc.data-kasm-default-vpc.id
+ vpc_id = aws_vpc.this.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[*].cidr_block
- }
-
- ingress {
- from_port = 6379
- to_port = 6379
- 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]
+ tags = {
+ Name = "${var.project_name}-kasm-db-access"
}
}
-data "aws_security_group" "data-kasm_db_sg" {
- id = aws_security_group.kasm-db-sg.id
+resource "aws_security_group_rule" "db" {
+ for_each = var.db_security_rules
+
+ security_group_id = aws_security_group.db.id
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ source_security_group_id = aws_security_group.webapp.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
+resource "aws_security_group_rule" "db_egress" {
+ for_each = var.default_egress
- ingress {
- from_port = 22
- to_port = 22
- protocol = "tcp"
- cidr_blocks = var.ssh_access_cidrs
- }
+ security_group_id = aws_security_group.db.id
+ type = "egress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = each.value.cidr_subnets
+}
- ingress {
- from_port = 443
- to_port = 443
- protocol = "tcp"
- cidr_blocks = data.aws_subnet.data-kasm_webapp_subnets[*].cidr_block
- }
+resource "aws_security_group" "cpx" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
- egress {
- from_port = 0
- to_port = 0
- protocol = "-1"
- cidr_blocks = [var.anywhere]
+ name = "${var.project_name}-kasm-cpx-access"
+ description = "Allow access to cpx RDP nodes"
+ vpc_id = aws_vpc.this.id
+
+ tags = {
+ Name = "${var.project_name}-kasm-cpx-access"
}
}
-data "aws_security_group" "data-kasm_guac_sg" {
- id = aws_security_group.kasm-guac-sg.id
+resource "aws_security_group_rule" "cpx" {
+ for_each = var.num_cpx_nodes > 0 ? var.cpx_security_rules : {}
+
+ security_group_id = one(aws_security_group.cpx[*].id)
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ source_security_group_id = aws_security_group.webapp.id
+}
+
+resource "aws_security_group_rule" "private_lb_cpx" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+
+ security_group_id = aws_security_group.private_lb.id
+ type = "ingress"
+ from_port = var.private_lb_security_rules.https.from_port
+ to_port = var.private_lb_security_rules.https.to_port
+ protocol = var.private_lb_security_rules.https.protocol
+ source_security_group_id = one(aws_security_group.cpx[*].id)
+}
+
+resource "aws_security_group_rule" "webapp_cpx" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+
+ security_group_id = aws_security_group.webapp.id
+ type = "ingress"
+ from_port = var.webapp_security_rules.from_port
+ to_port = var.webapp_security_rules.to_port
+ protocol = var.webapp_security_rules.protocol
+ source_security_group_id = one(aws_security_group.cpx[*].id)
+}
+
+resource "aws_security_group_rule" "cpx_egress" {
+ for_each = var.num_cpx_nodes > 0 ? var.default_egress : {}
+
+ security_group_id = one(aws_security_group.cpx[*].id)
+ type = "egress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = each.value.cidr_subnets
+}
+
+resource "aws_security_group" "windows" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+
+ name = "${var.project_name}-kasm-windows-access"
+ description = "Allow access to Windows servers"
+ vpc_id = aws_vpc.this.id
+
+ tags = {
+ Name = "${var.project_name}-kasm-windows-access"
+ }
+}
+
+resource "aws_security_group_rule" "windows" {
+ for_each = var.num_cpx_nodes > 0 ? var.windows_security_rules : {}
+
+ security_group_id = one(aws_security_group.windows[*].id)
+ type = "ingress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ source_security_group_id = can(regex("(?i:cpx)", each.key)) ? one(aws_security_group.cpx[*].id) : aws_security_group.webapp.id
+}
+
+resource "aws_security_group_rule" "private_lb_windows" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+
+ security_group_id = aws_security_group.private_lb.id
+ type = "ingress"
+ from_port = var.private_lb_security_rules.https.from_port
+ to_port = var.private_lb_security_rules.https.to_port
+ protocol = var.private_lb_security_rules.https.protocol
+ source_security_group_id = one(aws_security_group.windows[*].id)
+}
+
+resource "aws_security_group_rule" "webapp_windows" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+
+ security_group_id = aws_security_group.webapp.id
+ type = "ingress"
+ from_port = var.webapp_security_rules.from_port
+ to_port = var.webapp_security_rules.to_port
+ protocol = var.webapp_security_rules.protocol
+ source_security_group_id = one(aws_security_group.windows[*].id)
+}
+
+resource "aws_security_group_rule" "windows_egress" {
+ for_each = var.num_cpx_nodes > 0 ? var.default_egress : {}
+
+ security_group_id = one(aws_security_group.windows[*].id)
+ type = "egress"
+ from_port = each.value.from_port
+ to_port = each.value.to_port
+ protocol = each.value.protocol
+ cidr_blocks = each.value.cidr_subnets
}
diff --git a/aws/standard/module/ssm.tf b/aws/standard/module/ssm.tf
new file mode 100644
index 0000000..98b6dd3
--- /dev/null
+++ b/aws/standard/module/ssm.tf
@@ -0,0 +1,35 @@
+data "aws_iam_policy_document" "this" {
+ statement {
+ effect = "Allow"
+
+ principals {
+ type = "Service"
+ identifiers = [
+ "ec2.amazonaws.com"
+ ]
+ }
+
+ actions = ["sts:AssumeRole"]
+ }
+}
+
+resource "aws_iam_role" "this" {
+ count = var.create_aws_ssm_iam_role ? 1 : 0
+
+ name = var.aws_ssm_iam_role_name != "" ? var.aws_ssm_iam_role_name : "Kasm_SSM_IAM_Instance_Role"
+ assume_role_policy = data.aws_iam_policy_document.this.json
+}
+
+resource "aws_iam_role_policy_attachment" "this" {
+ count = var.create_aws_ssm_iam_role ? 1 : 0
+
+ policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
+ role = one(aws_iam_role.this[*].name)
+}
+
+resource "aws_iam_instance_profile" "this" {
+ count = var.create_aws_ssm_iam_role ? 1 : 0
+
+ name = var.aws_ssm_instance_profile_name != "" ? var.aws_ssm_instance_profile_name : "Kasm_SSM_Instance_Profile"
+ role = one(aws_iam_role.this[*].name)
+}
diff --git a/aws/standard/module/subnet.tf b/aws/standard/module/subnet.tf
index 60a7ea5..33ca8c9 100644
--- a/aws/standard/module/subnet.tf
+++ b/aws/standard/module/subnet.tf
@@ -2,68 +2,81 @@ 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 = data.aws_vpc.data-kasm-default-vpc.id
- cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, 0)
+## Will create Agent subnet x.x.0.0/24 and x.x.1.0/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/21)
+resource "aws_subnet" "alb" {
+ count = 2
+
+ vpc_id = aws_vpc.this.id
+ cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, count.index)
+ availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true
-
+
+ tags = {
+ Name = "${var.project_name}-kasm-lb-subnet-${count.index}"
+ }
+}
+
+## Will create WebApp subnets x.x.2.0/24 and x.x.3.0/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/21)
+resource "aws_subnet" "webapp" {
+ count = var.num_webapps
+
+ vpc_id = aws_vpc.this.id
+ cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, (count.index + 2))
+ availability_zone = data.aws_availability_zones.available.names[count.index]
+
+ tags = {
+ Name = "${var.project_name}-kasm-webapp-subnet-${count.index}"
+ }
+}
+
+## Will create Agent subnet x.x.4.0/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/21)
+resource "aws_subnet" "db" {
+ vpc_id = aws_vpc.this.id
+ cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, 4)
+ availability_zone = data.aws_availability_zones.available.names[1]
+
tags = {
Name = "${var.project_name}-kasm-db-subnet"
}
}
-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]
+## Will create Agent subnet x.x.6.0/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/21)
+resource "aws_subnet" "agent" {
+ vpc_id = aws_vpc.this.id
+ cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, 5)
map_public_ip_on_launch = true
+ availability_zone = data.aws_availability_zones.available.names[1]
tags = {
- Name = "${var.project_name}-kasm-webapp-subnet"
+ Name = "${var.project_name}-agent-subnet"
}
}
-data "aws_subnet" "data-kasm_webapp_subnets" {
- count = var.num_webapps
- id = aws_subnet.kasm-webapp-subnets[count.index].id
-}
+## Will create CPX subnet x.x.5.0/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/21)
+resource "aws_subnet" "cpx" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
-## 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 = 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
+ vpc_id = aws_vpc.this.id
+ cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, 6)
+ availability_zone = data.aws_availability_zones.available.names[0]
tags = {
- Name = "${var.project_name}-agent-natgw-subnet"
+ Name = "${var.project_name}-cpx-subnet"
}
}
-data "aws_subnet" "data-kasm_agent_subnet" {
- id = aws_subnet.kasm-agent-subnet.id
-}
+## Will create cpx subnet x.x.7.0/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/21)
+resource "aws_subnet" "windows" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
-## 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))
+ vpc_id = aws_vpc.this.id
+ cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, 7)
map_public_ip_on_launch = true
+ availability_zone = data.aws_availability_zones.available.names[1]
tags = {
- Name = "${var.project_name}-guac-natgw-subnet"
+ Name = "${var.project_name}-windows-subnet"
}
}
-
-data "aws_subnet" "data-kasm_guac_subnet" {
- id = aws_subnet.kasm-guac-subnet.id
-}
diff --git a/aws/standard/module/userdata/agent_bootstrap.sh b/aws/standard/module/userdata/agent_bootstrap.sh
index ca26186..9294b71 100644
--- a/aws/standard/module/userdata/agent_bootstrap.sh
+++ b/aws/standard/module/userdata/agent_bootstrap.sh
@@ -24,6 +24,6 @@ do
done
echo "WebApp is alive"
-bash kasm_release/install.sh -S agent -e -p $PRIVATE_IP -m ${manager_address} -M ${manager_token}
+bash kasm_release/install.sh -S agent -e -H -p $PRIVATE_IP -m ${manager_address} -M ${manager_token}
echo "Done"
diff --git a/oci/standard/module/userdata/guac_bootstrap.sh b/aws/standard/module/userdata/cpx_bootstrap.sh
similarity index 85%
rename from oci/standard/module/userdata/guac_bootstrap.sh
rename to aws/standard/module/userdata/cpx_bootstrap.sh
index 484d063..51034c1 100644
--- a/oci/standard/module/userdata/guac_bootstrap.sh
+++ b/aws/standard/module/userdata/cpx_bootstrap.sh
@@ -24,6 +24,6 @@ do
done
echo "WebApp is alive"
-bash kasm_release/install.sh -S guac -e -p $PRIVATE_IP -n ${manager_address} -k ${service_registration_token}
+bash kasm_release/install.sh -S guac -e -H -p $PRIVATE_IP -n ${manager_address} -k ${service_registration_token}
echo "Done"
diff --git a/aws/standard/module/userdata/db_bootstrap.sh b/aws/standard/module/userdata/db_bootstrap.sh
index 5317314..96b3004 100644
--- a/aws/standard/module/userdata/db_bootstrap.sh
+++ b/aws/standard/module/userdata/db_bootstrap.sh
@@ -11,10 +11,8 @@ 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}
+bash kasm_release/install.sh -S db -e -H -Q ${database_password} -R ${redis_password} -U ${user_password} -P ${admin_password} -M ${manager_token} -k ${service_registration_token}
echo "Done"
diff --git a/aws/standard/module/userdata/webapp_bootstrap.sh b/aws/standard/module/userdata/webapp_bootstrap.sh
index 5f781f5..e861646 100644
--- a/aws/standard/module/userdata/webapp_bootstrap.sh
+++ b/aws/standard/module/userdata/webapp_bootstrap.sh
@@ -11,8 +11,6 @@ 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
@@ -31,6 +29,6 @@ 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}
+bash kasm_release/install.sh -S app -e -H -z ${zone_name} -q "${db_ip}" -Q ${database_password} -R ${redis_password}
echo "Done"
diff --git a/aws/standard/module/variables.tf b/aws/standard/module/variables.tf
index b9e0e7d..7d63f38 100644
--- a/aws/standard/module/variables.tf
+++ b/aws/standard/module/variables.tf
@@ -31,8 +31,8 @@ variable "num_agents" {
default = 2
}
-variable "num_guac_nodes" {
- description = "The number of Agent Role Servers to create in the deployment"
+variable "num_cpx_nodes" {
+ description = "The number of cpx RDP Role Servers to create in the deployment"
type = number
default = 2
}
@@ -55,16 +55,30 @@ variable "agent_instance_type" {
default = "t3.medium"
}
-variable "guac_instance_type" {
- description = "The instance type for the Guacamole RDP nodes"
+variable "cpx_instance_type" {
+ description = "The instance type for the cpxamole 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 "webapp_hdd_size_gb" {
+ description = "The HDD size for Kasm Webapp nodes"
+ type = number
+}
+
+variable "db_hdd_size_gb" {
+ description = "The HDD size for Kasm DB"
+ type = number
+}
+
+variable "cpx_hdd_size_gb" {
+ description = "The HDD size for Kasm Guac RDP nodes"
+ type = number
+}
+
+variable "agent_hdd_size_gb" {
+ description = "The HDD size for Kasm Agent nodes"
+ type = number
}
variable "web_access_cidrs" {
@@ -93,6 +107,24 @@ variable "swap_size" {
type = number
}
+variable "create_aws_ssm_iam_role" {
+ description = "Create an AWS SSM IAM role to attach to VMs for SSH/console access to VMs."
+ type = bool
+ default = false
+}
+
+variable "aws_ssm_iam_role_name" {
+ description = "The name of the SSM EC2 role to associate with Kasm VMs for SSH access"
+ type = string
+ default = ""
+}
+
+variable "aws_ssm_instance_profile_name" {
+ description = "The name of the SSM EC2 Instance Profile to associate with Kasm VMs for SSH access"
+ type = string
+ default = ""
+}
+
variable "database_password" {
description = "The password for the database. No special characters"
type = string
@@ -124,7 +156,7 @@ variable "manager_token" {
}
variable "service_registration_token" {
- description = "The service registration token value for Guac RDP servers to authenticate to webapps. No special characters"
+ description = "The service registration token value for cpx RDP servers to authenticate to webapps. No special characters"
type = string
sensitive = true
}
@@ -145,3 +177,159 @@ variable "anywhere" {
error_message = "Anywhere variable must be valid IPv4 CIDR - usually 0.0.0.0/0 for all default routes and default Security Group access."
}
}
+
+variable "public_lb_security_rules" {
+ description = "A map of objects of security rules to apply to the Public ALB"
+ type = map(object({
+ from_port = number
+ to_port = number
+ protocol = string
+ }))
+
+ default = {
+ https = {
+ from_port = 443
+ to_port = 443
+ protocol = "tcp"
+ }
+ http = {
+ from_port = 80
+ to_port = 80
+ protocol = "tcp"
+ }
+ }
+}
+
+variable "private_lb_security_rules" {
+ description = "A map of objects of security rules to apply to the Private ALB"
+ type = map(object({
+ from_port = number
+ to_port = number
+ protocol = string
+ }))
+
+ default = {
+ https = {
+ from_port = 443
+ to_port = 443
+ protocol = "tcp"
+ }
+ }
+}
+
+variable "webapp_security_rules" {
+ description = "A map of objects of security rules to apply to the Kasm WebApp server"
+ type = object({
+ from_port = number
+ to_port = number
+ protocol = string
+ })
+
+ default = {
+ from_port = 443
+ to_port = 443
+ protocol = "tcp"
+ }
+}
+
+variable "db_security_rules" {
+ description = "A map of objects of security rules to apply to the Kasm DB"
+ type = map(object({
+ from_port = number
+ to_port = number
+ protocol = string
+ }))
+
+ default = {
+ postgres = {
+ from_port = 5432
+ to_port = 5432
+ protocol = "tcp"
+ }
+ redis = {
+ from_port = 6379
+ to_port = 6379
+ protocol = "tcp"
+ }
+ }
+}
+
+variable "cpx_security_rules" {
+ description = "A map of objects of security rules to apply to the Kasm Connection Proxy server"
+ type = map(object({
+ from_port = number
+ to_port = number
+ protocol = string
+ }))
+
+ default = {
+ https = {
+ from_port = 443
+ to_port = 443
+ protocol = "tcp"
+ }
+ }
+}
+
+variable "agent_security_rules" {
+ description = "A map of objects of security rules to apply to the Kasm WebApp server"
+ type = map(object({
+ from_port = number
+ to_port = number
+ protocol = string
+ }))
+
+ default = {
+ https = {
+ from_port = 443
+ to_port = 443
+ protocol = "tcp"
+ }
+ }
+}
+
+variable "windows_security_rules" {
+ description = "A map of objects of security rules to apply to the Kasm Windows VMs"
+ type = map(object({
+ from_port = number
+ to_port = number
+ protocol = string
+ }))
+
+ default = {
+ cpx_rdp = {
+ from_port = 3389
+ to_port = 3389
+ protocol = "tcp"
+ }
+ cpx_api = {
+ from_port = 4902
+ to_port = 4902
+ protocol = "tcp"
+ }
+ webapp_api = {
+ from_port = 4902
+ to_port = 4902
+ protocol = "tcp"
+ }
+ }
+}
+
+variable "default_egress" {
+ description = "Default egress security rule for all security groups"
+ type = map(object({
+ from_port = number
+ to_port = number
+ protocol = string
+ cidr_subnets = list(string)
+ }))
+
+ default = {
+ all = {
+ from_port = 0
+ to_port = 0
+ protocol = "-1"
+ cidr_subnets = ["0.0.0.0/0"]
+ }
+ }
+}
diff --git a/aws/standard/module/vpc.tf b/aws/standard/module/vpc.tf
index 27442b5..edb43ee 100644
--- a/aws/standard/module/vpc.tf
+++ b/aws/standard/module/vpc.tf
@@ -1,23 +1,36 @@
-resource "aws_vpc" "kasm-default-vpc" {
+resource "aws_vpc" "this" {
cidr_block = var.vpc_subnet_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
- Name = "${var.project_name}-kasm-db-vpc"
+ Name = "${var.project_name}-kasm-vpc"
}
}
-data "aws_vpc" "data-kasm-default-vpc" {
- id = aws_vpc.kasm-default-vpc.id
-}
+resource "aws_internet_gateway" "this" {
+ vpc_id = aws_vpc.this.id
-resource "aws_internet_gateway" "kasm-default-ig" {
- vpc_id = data.aws_vpc.data-kasm-default-vpc.id
tags = {
Name = "${var.project_name}-kasm-ig"
}
}
-data "aws_internet_gateway" "data-kasm-default-ig" {
- internet_gateway_id = aws_internet_gateway.kasm-default-ig.id
+resource "aws_eip" "this" {
+ domain = "vpc"
+
+ tags = {
+ Name = "${var.project_name}-kasm-nat-gateway-eip"
+ }
+
+}
+
+resource "aws_nat_gateway" "this" {
+ allocation_id = aws_eip.this.id
+ subnet_id = aws_subnet.alb[0].id
+
+ tags = {
+ Name = "${var.project_name}-kasm-nat-gateway"
+ }
+
+ depends_on = [aws_internet_gateway.this]
}
diff --git a/aws/standard/module/webapp.tf b/aws/standard/module/webapp.tf
index 1361856..d29d35c 100644
--- a/aws/standard/module/webapp.tf
+++ b/aws/standard/module/webapp.tf
@@ -1,20 +1,21 @@
-resource "aws_instance" "kasm-web-app" {
- 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
+resource "aws_instance" "webapp" {
+ count = var.num_webapps
+
+ ami = var.ec2_ami
+ instance_type = var.webapp_instance_type
+ vpc_security_group_ids = [aws_security_group.webapp.id]
+ subnet_id = aws_subnet.webapp[count.index].id
+ key_name = var.aws_key_pair
+ iam_instance_profile = one(aws_iam_instance_profile.this[*].id)
root_block_device {
- volume_size = 40
+ volume_size = var.webapp_hdd_size_gb
}
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
+ db_ip = aws_instance.db.private_ip
database_password = var.database_password
redis_password = var.redis_password
swap_size = var.swap_size
@@ -22,12 +23,14 @@ resource "aws_instance" "kasm-web-app" {
}
)
+ metadata_options {
+ http_endpoint = "enabled"
+ http_tokens = "required"
+ http_put_response_hop_limit = 1
+ instance_metadata_tags = null
+ }
+
tags = {
- Name = "${var.project_name}-${var.kasm_zone_name}-kasm-webapp"
+ Name = "${var.project_name}-${var.kasm_zone_name}-kasm-webapp-${count.index}"
}
}
-
-data "aws_instance" "data-kasm_web_app" {
- count = var.num_webapps
- instance_id = aws_instance.kasm-web-app[count.index].id
-}
diff --git a/aws/standard/output.tf b/aws/standard/output.tf
new file mode 100644
index 0000000..f119c29
--- /dev/null
+++ b/aws/standard/output.tf
@@ -0,0 +1,7 @@
+output "kasm_zone_settings" {
+ description = "Upstream Auth settings to apply to Kasm Zone configuration"
+ value = <[| no | +| [allow\_ssh\_cidrs](#input\_allow\_ssh\_cidrs) | CIDR notation of the bastion host allowed to SSH in to the machines | `list(string)` |
"0.0.0.0/0"
]
[| no | +| [digital\_ocean\_droplet\_slug](#input\_digital\_ocean\_droplet\_slug) | The Default Digital Ocean Droplet Slug: https://slugs.do-api.dev/ | `string` | `"s-2vcpu-4gb-intel"` | no | +| [digital\_ocean\_image](#input\_digital\_ocean\_image) | Default Image for Ubuntu 20.04 LTS with Docker | `string` | `"docker-20-04"` | no | +| [digital\_ocean\_region](#input\_digital\_ocean\_region) | The Digital Ocean region where you wish to deploy Kasm | `string` | `"nyc3"` | no | +| [digital\_ocean\_token](#input\_digital\_ocean\_token) | Authentication Token For Digital Ocean | `string` | n/a | yes | +| [do\_domain\_name](#input\_do\_domain\_name) | The domain name that users will use to access Kasm | `string` | n/a | yes | +| [kasm\_build\_url](#input\_kasm\_build\_url) | The Kasm build file to install | `string` | `"https://kasm-static-content.s3.amazonaws.com/kasm_release_1.12.0.d4fd8a.tar.gz"` | no | +| [project\_name](#input\_project\_name) | The name of the project/deployment/company eg (acme). | `string` | n/a | yes | +| [ssh\_key\_fingerprints](#input\_ssh\_key\_fingerprints) | Keys used for sshing into kasm hosts | `list(string)` | n/a | yes | +| [swap\_size](#input\_swap\_size) | The amount of swap (in MB) to configure inside the compute instances | `number` | `2048` | no | +| [user\_password](#input\_user\_password) | The default password to be used for the default user@kasm.local account. Only use alphanumeric characters | `string` | `"changeme"` | no | +| [vpc\_subnet\_cidr](#input\_vpc\_subnet\_cidr) | VPC Subnet CIDR where you wish to deploy Kasm | `string` | `"10.0.0.0/24"` | no | + +## Outputs + +No outputs. + diff --git a/digitalocean/single_server/module/README.md b/digitalocean/single_server/module/README.md new file mode 100644 index 0000000..13390be --- /dev/null +++ b/digitalocean/single_server/module/README.md @@ -0,0 +1,64 @@ +# module + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | ~> 1.0 | +| [digitalocean](#requirement\_digitalocean) | ~> 2.0 | + +## Providers + +| Name | Version | +|------|---------| +| [digitalocean](#provider\_digitalocean) | 2.34.1 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [digitalocean_certificate.cert](https://registry.terraform.io/providers/digitalocean/digitalocean/latest/docs/resources/certificate) | resource | +| [digitalocean_domain.default](https://registry.terraform.io/providers/digitalocean/digitalocean/latest/docs/resources/domain) | resource | +| [digitalocean_droplet.kasm-server](https://registry.terraform.io/providers/digitalocean/digitalocean/latest/docs/resources/droplet) | resource | +| [digitalocean_firewall.workspaces-fw](https://registry.terraform.io/providers/digitalocean/digitalocean/latest/docs/resources/firewall) | resource | +| [digitalocean_loadbalancer.www-lb](https://registry.terraform.io/providers/digitalocean/digitalocean/latest/docs/resources/loadbalancer) | resource | +| [digitalocean_project.project](https://registry.terraform.io/providers/digitalocean/digitalocean/latest/docs/resources/project) | resource | +| [digitalocean_record.static](https://registry.terraform.io/providers/digitalocean/digitalocean/latest/docs/resources/record) | resource | +| [digitalocean_tag.project](https://registry.terraform.io/providers/digitalocean/digitalocean/latest/docs/resources/tag) | resource | +| [digitalocean_vpc.kasm_vpc](https://registry.terraform.io/providers/digitalocean/digitalocean/latest/docs/resources/vpc) | resource | +| [digitalocean_certificate.data-cert](https://registry.terraform.io/providers/digitalocean/digitalocean/latest/docs/data-sources/certificate) | data source | +| [digitalocean_domain.data-default](https://registry.terraform.io/providers/digitalocean/digitalocean/latest/docs/data-sources/domain) | data source | +| [digitalocean_droplet.data-kasm_server](https://registry.terraform.io/providers/digitalocean/digitalocean/latest/docs/data-sources/droplet) | data source | +| [digitalocean_tag.data-project](https://registry.terraform.io/providers/digitalocean/digitalocean/latest/docs/data-sources/tag) | data source | +| [digitalocean_vpc.data-kasm_vpc](https://registry.terraform.io/providers/digitalocean/digitalocean/latest/docs/data-sources/vpc) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [admin\_password](#input\_admin\_password) | The default password to be used for the default admin@kasm.local account. Only use alphanumeric characters | `string` | n/a | yes | +| [allow\_kasm\_web\_cidrs](#input\_allow\_kasm\_web\_cidrs) | CIDR notation of the bastion host allowed to SSH in to the machines | `list(string)` | n/a | yes | +| [allow\_ssh\_cidrs](#input\_allow\_ssh\_cidrs) | List of Subnets in CIDR notation for hosts allowed to SSH | `list(string)` | n/a | yes | +| [anywhere](#input\_anywhere) | Anywhere route subnet | `list(string)` |
"0.0.0.0/0"
]
[| no | +| [digital\_ocean\_droplet\_slug](#input\_digital\_ocean\_droplet\_slug) | The Default Digital Ocean Droplet Slug: https://slugs.do-api.dev/ | `string` | n/a | yes | +| [digital\_ocean\_image](#input\_digital\_ocean\_image) | Default Image for Ubuntu LTS | `string` | n/a | yes | +| [digital\_ocean\_region](#input\_digital\_ocean\_region) | The Default Digital Ocean Region Slug: https://docs.digitalocean.com/products/platform/availability-matrix/ | `string` | n/a | yes | +| [do\_domain\_name](#input\_do\_domain\_name) | The domain name that users will use to access kasm | `string` | n/a | yes | +| [kasm\_build\_url](#input\_kasm\_build\_url) | The Kasm build file to install | `string` | n/a | yes | +| [project\_name](#input\_project\_name) | The name of the project/deployment/company eg (acme). Lower case all one word as this will be used in a domain name | `string` | n/a | yes | +| [ssh\_key\_fingerprints](#input\_ssh\_key\_fingerprints) | Keys used for sshing into kasm hosts | `list(string)` | n/a | yes | +| [swap\_size](#input\_swap\_size) | The amount of swap (in MB) to configure inside the compute instances | `number` | n/a | yes | +| [user\_password](#input\_user\_password) | The default password to be used for the default user@kasm.local account. Only use alphanumeric characters | `string` | n/a | yes | +| [vpc\_subnet\_cidr](#input\_vpc\_subnet\_cidr) | VPC Subnet CIDR to deploy Kasm | `string` | n/a | yes | + +## Outputs + +| Name | Description | +|------|-------------| +| [kasm\_server\_ip](#output\_kasm\_server\_ip) | n/a | + diff --git a/digitalocean/single_server/module/firewall.tf b/digitalocean/single_server/module/firewall.tf index b8853dd..6fa87dc 100644 --- a/digitalocean/single_server/module/firewall.tf +++ b/digitalocean/single_server/module/firewall.tf @@ -1,7 +1,7 @@ resource "digitalocean_firewall" "workspaces-fw" { name = "${var.project_name}-fw" - tags = ["${digitalocean_tag.project.id}"] + tags = [digitalocean_tag.project.id] inbound_rule { protocol = "tcp" diff --git a/digitalocean/single_server/module/provider.tf b/digitalocean/single_server/module/provider.tf index 68aba8c..441a4be 100644 --- a/digitalocean/single_server/module/provider.tf +++ b/digitalocean/single_server/module/provider.tf @@ -1,4 +1,6 @@ terraform { + required_version = "~> 1.0" + required_providers { digitalocean = { source = "digitalocean/digitalocean" diff --git a/digitalocean/single_server/provider.tf b/digitalocean/single_server/provider.tf index 6225189..2572fc1 100644 --- a/digitalocean/single_server/provider.tf +++ b/digitalocean/single_server/provider.tf @@ -1,4 +1,6 @@ terraform { + required_version = "~> 1.0" + required_providers { digitalocean = { source = "digitalocean/digitalocean" diff --git a/digitalocean/single_server/secrets.tfvars.example b/digitalocean/single_server/secrets.tfvars.example new file mode 100644 index 0000000..9d7c029 --- /dev/null +++ b/digitalocean/single_server/secrets.tfvars.example @@ -0,0 +1 @@ +digital_ocean_token = "" \ No newline at end of file diff --git a/digitalocean/single_server/settings.tfvars b/digitalocean/single_server/terraform.tfvars similarity index 76% rename from digitalocean/single_server/settings.tfvars rename to digitalocean/single_server/terraform.tfvars index 24fe958..a22f219 100644 --- a/digitalocean/single_server/settings.tfvars +++ b/digitalocean/single_server/terraform.tfvars @@ -13,12 +13,12 @@ digital_ocean_droplet_slug = "s-2vcpu-4gb-intel" swap_size = 2048 ## Kasm passwords -user_password = "changeme" -admin_password = "changeme" +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.13.0.002947.tar.gz" \ No newline at end of file +kasm_build_url = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.14.0.3a7abb.tar.gz" \ No newline at end of file diff --git a/digitalocean/single_server/variables.tf b/digitalocean/single_server/variables.tf index bd7b230..efcd66c 100644 --- a/digitalocean/single_server/variables.tf +++ b/digitalocean/single_server/variables.tf @@ -126,6 +126,7 @@ variable "allow_kasm_web_cidrs" { variable "swap_size" { description = "The amount of swap (in MB) to configure inside the compute instances" + type = number default = 2048 validation { diff --git a/oci/single_server/README.md b/oci/single_server/README.md index 2053122..703e557 100644 --- a/oci/single_server/README.md +++ b/oci/single_server/README.md @@ -34,48 +34,76 @@ Create an SSL certificate that matches the desired domain for the deployment. e. terraform init 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 -var-file settings.tfvars + terraform plan 4. Deploy - terraform apply -var-file settings.tfvars + terraform apply 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 + +## Requirements -| 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.13.0.002947.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` | +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | ~> 1.0 | +| [acme](#requirement\_acme) | ~> 2.0 | +| [oci](#requirement\_oci) | ~> 5.0 | +| [tls](#requirement\_tls) | ~> 4.0 | +## Providers + +No providers. + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [kasm](#module\_kasm) | ./module | n/a | + +## Resources + +No resources. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [admin\_password](#input\_admin\_password) | The administrative user password. No special characters | `string` | n/a | yes | +| [allow\_ssh\_cidrs](#input\_allow\_ssh\_cidrs) | The CIDR notation to allow SSH access to the systems. | `list(string)` | n/a | yes | +| [allow\_web\_cidrs](#input\_allow\_web\_cidrs) | The CIDR notation to allow HTTPS access to the systems. | `list(string)` | n/a | yes | +| [compartment\_ocid](#input\_compartment\_ocid) | The Compartment OCID | `string` | n/a | yes | +| [fingerprint](#input\_fingerprint) | API Key Fingerprint | `string` | n/a | yes | +| [instance\_image\_ocid](#input\_instance\_image\_ocid) | The OCID for the instance image , such as ubuntu 20.04, to use. | `string` | n/a | yes | +| [instance\_shape](#input\_instance\_shape) | The instance shape to use. Should be a Flex type. | `string` | n/a | yes | +| [kasm\_build\_url](#input\_kasm\_build\_url) | The URL for the Kasm Workspaces build | `string` | n/a | yes | +| [kasm\_server\_cpus](#input\_kasm\_server\_cpus) | The number of CPUs to configure for the Kasm instance | `number` | n/a | yes | +| [kasm\_server\_hdd\_size](#input\_kasm\_server\_hdd\_size) | The size in GBs of the Kasm instance HDD | `number` | n/a | yes | +| [kasm\_server\_memory](#input\_kasm\_server\_memory) | The amount of memory to configure for the Kasm instance | `number` | n/a | yes | +| [kasm\_ssl\_crt\_path](#input\_kasm\_ssl\_crt\_path) | The file path to the PEM encoded SSL Certificate. Leave this empty if you are using Lets Encrypt to automatically generate your certificates. | `string` | `""` | no | +| [kasm\_ssl\_key\_path](#input\_kasm\_ssl\_key\_path) | The file path to the PEM encoded SSL Certificate Key. Leave this empty if you are using Lets Encrypt to automatically generate your certificates. | `string` | `""` | no | +| [letsencrypt\_cert\_support\_email](#input\_letsencrypt\_cert\_support\_email) | Email address to use for Let's Encrypt SSL certificates for OCI Deployment | `string` | `""` | no | +| [letsencrypt\_server\_type](#input\_letsencrypt\_server\_type) | SSL Server type to generate. Valid options are staging and prod, and prod certificates are limited to 5 certificates per week. | `string` | `""` | no | +| [oci\_domain\_name](#input\_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 via https | `string` | n/a | yes | +| [private\_key\_path](#input\_private\_key\_path) | The path to the OCI API Key PEM encoded Private Key | `string` | n/a | yes | +| [project\_name](#input\_project\_name) | The name of the deployment (e.g dev, staging). A short single word | `string` | n/a | yes | +| [region](#input\_region) | The OCI Region eg: (us-ashburn-1) | `string` | n/a | yes | +| [ssh\_authorized\_keys](#input\_ssh\_authorized\_keys) | The SSH Public Keys to be installed on the OCI compute instance | `string` | n/a | yes | +| [swap\_size](#input\_swap\_size) | The amount of swap (in MB) to configure inside the compute instances | `number` | n/a | yes | +| [tenancy\_ocid](#input\_tenancy\_ocid) | The Tenancy OCID. | `string` | n/a | yes | +| [user\_ocid](#input\_user\_ocid) | The User OCID. | `string` | n/a | yes | +| [user\_password](#input\_user\_password) | The standard (non administrator) user password. No special characters | `string` | n/a | yes | +| [vcn\_subnet\_cidr](#input\_vcn\_subnet\_cidr) | VCN Subnet CIDR where you wish to deploy Kasm | `string` | n/a | yes | + +## Outputs + +No outputs. + # Detailed Terraform Deployment Diagram diff --git a/oci/single_server/module/README.md b/oci/single_server/module/README.md new file mode 100644 index 0000000..67ce747 --- /dev/null +++ b/oci/single_server/module/README.md @@ -0,0 +1,79 @@ +# module + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | ~> 1.0 | +| [acme](#requirement\_acme) | ~> 2.0 | +| [oci](#requirement\_oci) | ~> 5.0 | +| [tls](#requirement\_tls) | ~> 4.0 | + +## Providers + +| Name | Version | +|------|---------| +| [acme](#provider\_acme) | 2.20.0 | +| [oci](#provider\_oci) | 5.28.0 | +| [tls](#provider\_tls) | 4.0.5 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [acme_certificate.certificate](https://registry.terraform.io/providers/vancluever/acme/latest/docs/resources/certificate) | resource | +| [acme_registration.registration](https://registry.terraform.io/providers/vancluever/acme/latest/docs/resources/registration) | resource | +| [oci_core_default_route_table.default_route_table](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_default_route_table) | resource | +| [oci_core_instance.kasm_instance](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_instance) | resource | +| [oci_core_internet_gateway.kasm_internet_gateway](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_internet_gateway) | resource | +| [oci_core_security_list.allow_ssh](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_security_list) | resource | +| [oci_core_security_list.allow_web](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_security_list) | resource | +| [oci_core_subnet.kasm_subnet](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_subnet) | resource | +| [oci_core_vcn.kasm_vcn](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_vcn) | resource | +| [oci_dns_rrset.kasm_a_record](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/dns_rrset) | resource | +| [tls_cert_request.kasm_certificate_request](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/cert_request) | resource | +| [tls_private_key.certificate_private_key](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/private_key) | resource | +| [tls_private_key.registration_private_key](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/private_key) | resource | +| [oci_dns_zones.kasm_dns_zone](https://registry.terraform.io/providers/oracle/oci/latest/docs/data-sources/dns_zones) | data source | +| [oci_identity_availability_domain.ad](https://registry.terraform.io/providers/oracle/oci/latest/docs/data-sources/identity_availability_domain) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [admin\_password](#input\_admin\_password) | The administrative user password. No special characters | `string` | n/a | yes | +| [allow\_ssh\_cidrs](#input\_allow\_ssh\_cidrs) | The CIDR notation to allow SSH access to the systems. | `list(string)` | n/a | yes | +| [allow\_web\_cidrs](#input\_allow\_web\_cidrs) | The CIDR notation to allow HTTPS access to the systems. | `list(string)` | n/a | yes | +| [anywhere](#input\_anywhere) | Anywhere route subnet | `string` | `"0.0.0.0/0"` | no | +| [compartment\_ocid](#input\_compartment\_ocid) | The Compartment OCID | `string` | n/a | yes | +| [fingerprint](#input\_fingerprint) | API Key Fingerprint | `string` | n/a | yes | +| [instance\_image\_ocid](#input\_instance\_image\_ocid) | The OCID for the instance image , such as ubuntu 20.04, to use. | `string` | n/a | yes | +| [instance\_shape](#input\_instance\_shape) | The instance shape to use. Should be a Flex type. | `string` | n/a | yes | +| [kasm\_build\_url](#input\_kasm\_build\_url) | The URL for the Kasm Workspaces build | `string` | n/a | yes | +| [kasm\_server\_cpus](#input\_kasm\_server\_cpus) | The number of CPUs to configure for the Kasm instance | `number` | n/a | yes | +| [kasm\_server\_hdd\_size](#input\_kasm\_server\_hdd\_size) | The size in GBs of the Kasm instance HDD | `number` | n/a | yes | +| [kasm\_server\_memory](#input\_kasm\_server\_memory) | The amount of memory to configure for the Kasm instance | `number` | n/a | yes | +| [kasm\_ssl\_crt\_path](#input\_kasm\_ssl\_crt\_path) | The file path to the PEM encoded SSL Certificate | `string` | n/a | yes | +| [kasm\_ssl\_key\_path](#input\_kasm\_ssl\_key\_path) | The file path to the PEM encoded SSL Certificate Key | `string` | n/a | yes | +| [letsencrypt\_cert\_support\_email](#input\_letsencrypt\_cert\_support\_email) | Email address to use for Let's Encrypt SSL certificates for OCI Deployment | `string` | n/a | yes | +| [letsencrypt\_server\_type](#input\_letsencrypt\_server\_type) | SSL Server type to generate. Valid options are staging, prod, and empty string. Prod certificates are limited to 5 per week per domain. | `string` | n/a | yes | +| [oci\_domain\_name](#input\_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 via https | `string` | n/a | yes | +| [private\_key\_path](#input\_private\_key\_path) | The path to the API Key PEM encoded Private Key | `string` | n/a | yes | +| [project\_name](#input\_project\_name) | The name of the deployment (e.g dev, staging). A short single word | `string` | n/a | yes | +| [region](#input\_region) | The OCI Region eg: (us-ashburn-1) | `string` | n/a | yes | +| [ssh\_authorized\_keys](#input\_ssh\_authorized\_keys) | The SSH Public Keys to be installed on the OCI compute instance | `string` | n/a | yes | +| [swap\_size](#input\_swap\_size) | The amount of swap (in MB) to configure inside the compute instances | `number` | n/a | yes | +| [tenancy\_ocid](#input\_tenancy\_ocid) | The Tenancy OCID. | `string` | n/a | yes | +| [user\_ocid](#input\_user\_ocid) | The User OCID. | `string` | n/a | yes | +| [user\_password](#input\_user\_password) | The standard (non administrator) user password. No special characters | `string` | n/a | yes | +| [vcn\_subnet\_cidr](#input\_vcn\_subnet\_cidr) | VPC Subnet CIDR where you wish to deploy Kasm | `string` | n/a | yes | + +## Outputs + +No outputs. + diff --git a/oci/single_server/module/provider.tf b/oci/single_server/module/provider.tf index 7539cab..2814e4c 100644 --- a/oci/single_server/module/provider.tf +++ b/oci/single_server/module/provider.tf @@ -1,16 +1,18 @@ terraform { + required_version = "~> 1.0" + required_providers { oci = { source = "oracle/oci" - version = ">= 4.0.0" + version = "~> 5.0" } acme = { source = "vancluever/acme" - version = ">= 2.0" + version = "~> 2.0" } tls = { source = "hashicorp/tls" - version = ">= 4.0.0" + version = "~> 4.0" } } } diff --git a/oci/single_server/provider.tf b/oci/single_server/provider.tf index e65d81e..743dcfb 100644 --- a/oci/single_server/provider.tf +++ b/oci/single_server/provider.tf @@ -1,16 +1,18 @@ terraform { + required_version = "~> 1.0" + required_providers { oci = { source = "oracle/oci" - version = ">= 4.0.0" + version = "~> 5.0" } acme = { source = "vancluever/acme" - version = ">= 2.0" + version = "~> 2.0" } tls = { source = "hashicorp/tls" - version = ">= 4.0.0" + version = "~> 4.0" } } } diff --git a/oci/single_server/settings.tfvars b/oci/single_server/terraform.tfvars similarity index 82% rename from oci/single_server/settings.tfvars rename to oci/single_server/terraform.tfvars index a5be31c..3324718 100644 --- a/oci/single_server/settings.tfvars +++ b/oci/single_server/terraform.tfvars @@ -32,7 +32,7 @@ user_password = "changeme" ssh_authorized_keys = "changeme" ## OCI VM Settings -instance_image_ocid = "ocid1.image.oc1.iad.aaaaaaaahiz6xym3a76xhwkmwmhrz6luyiehho7dpxpkphxhsq5q6z4m3nlq" +instance_image_ocid = "" instance_shape = "VM.Standard.E4.Flex" swap_size = 2048 kasm_server_cpus = 2 @@ -40,4 +40,4 @@ kasm_server_memory = 2 kasm_server_hdd_size = 120 ## Kasm download URL -kasm_build_url = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.13.0.002947.tar.gz" +kasm_build_url = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.14.0.3a7abb.tar.gz" diff --git a/oci/standard/README.md b/oci/standard/README.md index 5c55570..b3ed1a3 100644 --- a/oci/standard/README.md +++ b/oci/standard/README.md @@ -35,56 +35,84 @@ Create an SSL certificate that matches the desired domain for the deployment. e. terraform init 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 -var-file settings.tfvars + terraform plan 4. Deploy - terraform apply -var-file settings.tfvars + terraform apply 5. Login to the Deployment as an Admin via the domain defined e.g `https://kasm.contoso.com`. It may take several minutes for the deployment to fully come online. + +## Requirements -# OCI Terraform Variable definitions +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | ~> 1.0 | +| [acme](#requirement\_acme) | ~> 2.0 | +| [oci](#requirement\_oci) | ~> 5.0 | +| [tls](#requirement\_tls) | ~> 4.0 | -| 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"]` | -| `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` | -| `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_url` | The download URL for the desired Kasm Workspaces version. | String | `"https://kasm-static-content.s3.amazonaws.com/kasm_release_1.13.0.002947.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_webapp_vm_settings` | The number of CPUs, memory in GB, and HDD size to use for Kasm WebApps. | Map(Any) |
"0.0.0.0/0",
"::/0"
]
{
cpus = 2
memory = 2
hdd_size_gb = 50
} |
-| `kasm_database_vm_settings` | The number of CPUs, memory in GB, and HDD size to use for the Kasm Database server. | Map(Any) | {
cpus = 2
memory = 2
hdd_size_gb = 50
} |
-| `kasm_agent_vm_settings` | The number of CPUs, memory in GB, and HDD size to use for the Kasm Agent server(s). | Map(Any) | {
cpus = 4
memory = 8
hdd_size_gb = 120
} |
-| `kasm_guac_vm_settings` | The number of CPUs, memory in GB, and HDD size to use for the Kasm Guac RDP server(s). | Map(Any) | {
cpus = 4
memory = 4
hdd_size_gb = 50
} |
+## Providers
+No providers.
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [kasm](#module\_kasm) | ./module | n/a |
+
+## Resources
+
+No resources.
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [admin\_password](#input\_admin\_password) | The administrative user password. No special characters | `string` | n/a | yes |
+| [allow\_ssh\_cidrs](#input\_allow\_ssh\_cidrs) | The CIDR notation to allow SSH access to the systems. | `list(string)` | n/a | yes |
+| [allow\_web\_cidrs](#input\_allow\_web\_cidrs) | The CIDR notation to allow HTTPS access to the systems. | `list(string)` | n/a | yes |
+| [bastion\_vm\_settings](#input\_bastion\_vm\_settings) | The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm SSH Bastion instance | object({
cpus = number
memory = number
hdd_size_gb = number
}) | n/a | yes |
+| [compartment\_ocid](#input\_compartment\_ocid) | The Compartment OCID | `string` | n/a | yes |
+| [database\_password](#input\_database\_password) | The password for the database. No special characters | `string` | n/a | yes |
+| [fingerprint](#input\_fingerprint) | API Key Fingerprint | `string` | n/a | yes |
+| [instance\_image\_ocid](#input\_instance\_image\_ocid) | The OCID for the instance image, such as ubuntu 22.04, to use. | `string` | n/a | yes |
+| [instance\_shape](#input\_instance\_shape) | The instance shape to use. Should be a Flex type. | `string` | n/a | yes |
+| [kasm\_agent\_vm\_settings](#input\_kasm\_agent\_vm\_settings) | The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm Agent instances | object({
cpus = number
memory = number
hdd_size_gb = number
}) | n/a | yes |
+| [kasm\_build\_url](#input\_kasm\_build\_url) | The URL for the Kasm Workspaces build | `string` | n/a | yes |
+| [kasm\_cpx\_vm\_settings](#input\_kasm\_cpx\_vm\_settings) | The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm cpx RDP instances | object({
cpus = number
memory = number
hdd_size_gb = number
}) | n/a | yes |
+| [kasm\_database\_vm\_settings](#input\_kasm\_database\_vm\_settings) | The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm Database instance | object({
cpus = number
memory = number
hdd_size_gb = number
}) | n/a | yes |
+| [kasm\_ssl\_crt\_path](#input\_kasm\_ssl\_crt\_path) | The file path to the PEM encoded SSL Certificate | `string` | `""` | no |
+| [kasm\_ssl\_key\_path](#input\_kasm\_ssl\_key\_path) | The file path to the PEM encoded SSL Certificate Key | `string` | `""` | no |
+| [kasm\_webapp\_vm\_settings](#input\_kasm\_webapp\_vm\_settings) | The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm WebApp instances | object({
cpus = number
memory = number
hdd_size_gb = number
}) | n/a | yes |
+| [letsencrypt\_cert\_support\_email](#input\_letsencrypt\_cert\_support\_email) | Email address to use for Let's Encrypt SSL certificates for OCI Deployment | `string` | `""` | no |
+| [letsencrypt\_server\_type](#input\_letsencrypt\_server\_type) | SSL Server type to generate. Valid options are staging and prod, and prod certificates are limited to 5 certificates per week. | `string` | `""` | no |
+| [manager\_token](#input\_manager\_token) | The manager token value for Agents to authenticate to webapps. No special characters | `string` | n/a | yes |
+| [num\_agents](#input\_num\_agents) | The number of Agent Role Servers to create in the deployment | `number` | n/a | yes |
+| [num\_cpx\_nodes](#input\_num\_cpx\_nodes) | The number of cpx RDP Role Servers to create in the deployment | `number` | n/a | yes |
+| [num\_webapps](#input\_num\_webapps) | The number of WebApp role servers to create in the deployment | `number` | n/a | yes |
+| [oci\_domain\_name](#input\_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 via https | `string` | n/a | yes |
+| [private\_key\_path](#input\_private\_key\_path) | The path to the API Key PEM encoded Private Key | `string` | n/a | yes |
+| [project\_name](#input\_project\_name) | The name of the deployment (e.g dev, staging). A short single word | `string` | n/a | yes |
+| [redis\_password](#input\_redis\_password) | The password for the Redis server. No special characters | `string` | n/a | yes |
+| [region](#input\_region) | The OCI Region eg: (us-ashburn-1) | `string` | n/a | yes |
+| [service\_registration\_token](#input\_service\_registration\_token) | The service registration token value for cpx RDP servers to authenticate to webapps. No special characters | `string` | n/a | yes |
+| [ssh\_authorized\_keys](#input\_ssh\_authorized\_keys) | The SSH Public Keys to be installed on the OCI compute instance | `string` | n/a | yes |
+| [swap\_size](#input\_swap\_size) | The amount of swap (in MB) to configure inside the compute instances | `number` | n/a | yes |
+| [tenancy\_ocid](#input\_tenancy\_ocid) | The Tenancy OCID. | `string` | n/a | yes |
+| [user\_ocid](#input\_user\_ocid) | The User OCID. | `string` | n/a | yes |
+| [user\_password](#input\_user\_password) | The standard (non administrator) user password. No special characters | `string` | n/a | yes |
+| [vcn\_subnet\_cidr](#input\_vcn\_subnet\_cidr) | VCN Subnet CIDR where you wish to deploy Kasm | `string` | n/a | yes |
+
+## Outputs
+
+No outputs.
+
# Detailed Terraform Deployment Diagram
diff --git a/oci/standard/deployment.tf b/oci/standard/deployment.tf
index 842eeba..c36861b 100644
--- a/oci/standard/deployment.tf
+++ b/oci/standard/deployment.tf
@@ -18,6 +18,7 @@ module "kasm" {
# 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
@@ -26,14 +27,15 @@ module "kasm" {
instance_shape = var.instance_shape
num_agents = var.num_agents
num_webapps = var.num_webapps
- num_guac_rdp_nodes = var.num_guac_rdp_nodes
+ num_cpx_nodes = var.num_cpx_nodes
kasm_agent_vm_settings = var.kasm_agent_vm_settings
kasm_database_vm_settings = var.kasm_database_vm_settings
kasm_webapp_vm_settings = var.kasm_webapp_vm_settings
- kasm_guac_vm_settings = var.kasm_guac_vm_settings
+ kasm_cpx_vm_settings = var.kasm_cpx_vm_settings
allow_ssh_cidrs = var.allow_ssh_cidrs
allow_web_cidrs = var.allow_web_cidrs
swap_size = var.swap_size
+ bastion_vm_settings = var.bastion_vm_settings
manager_token = var.manager_token
admin_password = var.admin_password
diff --git a/oci/standard/module/README.md b/oci/standard/module/README.md
new file mode 100644
index 0000000..d17d8eb
--- /dev/null
+++ b/oci/standard/module/README.md
@@ -0,0 +1,111 @@
+# module
+
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0 |
+| [acme](#requirement\_acme) | ~> 2.0 |
+| [oci](#requirement\_oci) | ~> 5.0 |
+| [tls](#requirement\_tls) | ~> 4.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [acme](#provider\_acme) | 2.20.0 |
+| [oci](#provider\_oci) | 5.28.0 |
+| [tls](#provider\_tls) | 4.0.5 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [acme_certificate.this](https://registry.terraform.io/providers/vancluever/acme/latest/docs/resources/certificate) | resource |
+| [acme_registration.this](https://registry.terraform.io/providers/vancluever/acme/latest/docs/resources/registration) | resource |
+| [oci_core_instance.agent](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_instance) | resource |
+| [oci_core_instance.bastion](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_instance) | resource |
+| [oci_core_instance.cpx](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_instance) | resource |
+| [oci_core_instance.db](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_instance) | resource |
+| [oci_core_instance.webapp](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_instance) | resource |
+| [oci_core_internet_gateway.this](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_internet_gateway) | resource |
+| [oci_core_nat_gateway.this](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_nat_gateway) | resource |
+| [oci_core_route_table.internet_gateway](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_route_table) | resource |
+| [oci_core_route_table.nat_gateway](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_route_table) | resource |
+| [oci_core_security_list.allow_bastion_ssh](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_security_list) | resource |
+| [oci_core_security_list.allow_db_redis](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_security_list) | resource |
+| [oci_core_security_list.allow_public_ssh](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_security_list) | resource |
+| [oci_core_security_list.allow_rdp_to_windows](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_security_list) | resource |
+| [oci_core_security_list.allow_web](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_security_list) | resource |
+| [oci_core_security_list.allow_web_from_lb](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_security_list) | resource |
+| [oci_core_security_list.allow_web_from_webapp](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_security_list) | resource |
+| [oci_core_subnet.agent](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_subnet) | resource |
+| [oci_core_subnet.cpx](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_subnet) | resource |
+| [oci_core_subnet.db](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_subnet) | resource |
+| [oci_core_subnet.lb](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_subnet) | resource |
+| [oci_core_subnet.webapp](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_subnet) | resource |
+| [oci_core_subnet.windows](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_subnet) | resource |
+| [oci_core_vcn.this](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_vcn) | resource |
+| [oci_dns_rrset.kasm_a_record](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/dns_rrset) | resource |
+| [oci_load_balancer.public](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/load_balancer) | resource |
+| [oci_load_balancer_backend.public](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/load_balancer_backend) | resource |
+| [oci_load_balancer_backend_set.public](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/load_balancer_backend_set) | resource |
+| [oci_load_balancer_certificate.public](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/load_balancer_certificate) | resource |
+| [oci_load_balancer_listener.kasm_https_ssl_listener](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/load_balancer_listener) | resource |
+| [tls_cert_request.this](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/cert_request) | resource |
+| [tls_private_key.certificate](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/private_key) | resource |
+| [tls_private_key.registration](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/private_key) | resource |
+| [oci_dns_zones.this](https://registry.terraform.io/providers/oracle/oci/latest/docs/data-sources/dns_zones) | data source |
+| [oci_identity_availability_domains.kasm_ads](https://registry.terraform.io/providers/oracle/oci/latest/docs/data-sources/identity_availability_domains) | data source |
+| [oci_load_balancer_ssl_cipher_suite.this](https://registry.terraform.io/providers/oracle/oci/latest/docs/data-sources/load_balancer_ssl_cipher_suite) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [admin\_password](#input\_admin\_password) | The administrative user password. No special characters | `string` | n/a | yes |
+| [allow\_ssh\_cidrs](#input\_allow\_ssh\_cidrs) | The CIDR notation to allow SSH access to the systems. | `list(string)` | n/a | yes |
+| [allow\_web\_cidrs](#input\_allow\_web\_cidrs) | The CIDR notation to allow HTTPS access to the systems. | `list(string)` | n/a | yes |
+| [anywhere](#input\_anywhere) | Anywhere route subnet | `list(string)` | [| no | +| [bastion\_vm\_settings](#input\_bastion\_vm\_settings) | The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm SSH Bastion instance |
"0.0.0.0/0"
]
object({
cpus = number
memory = number
hdd_size_gb = number
}) | n/a | yes |
+| [bastion\_vm\_utilization](#input\_bastion\_vm\_utilization) | The VM compute utilization. Defaults to 12.5% to reduce costs on long-running instances. | `string` | `"BASELINE_1_8"` | no |
+| [compartment\_ocid](#input\_compartment\_ocid) | The Compartment OCID | `string` | n/a | yes |
+| [database\_password](#input\_database\_password) | The password for the database. No special characters | `string` | n/a | yes |
+| [fingerprint](#input\_fingerprint) | API Key Fingerprint | `string` | n/a | yes |
+| [instance\_image\_ocid](#input\_instance\_image\_ocid) | The OCID for the instance image , such as ubuntu 20.04, to use. | `string` | n/a | yes |
+| [instance\_shape](#input\_instance\_shape) | The instance shape to use. Should be a Flex type. | `string` | n/a | yes |
+| [kasm\_agent\_vm\_settings](#input\_kasm\_agent\_vm\_settings) | The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm Agent instances | object({
cpus = number
memory = number
hdd_size_gb = number
}) | n/a | yes |
+| [kasm\_build\_url](#input\_kasm\_build\_url) | The URL for the Kasm Workspaces build | `string` | n/a | yes |
+| [kasm\_cpx\_vm\_settings](#input\_kasm\_cpx\_vm\_settings) | The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm cpx RDP instances | object({
cpus = number
memory = number
hdd_size_gb = number
}) | n/a | yes |
+| [kasm\_database\_vm\_settings](#input\_kasm\_database\_vm\_settings) | The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm Database instance | object({
cpus = number
memory = number
hdd_size_gb = number
}) | n/a | yes |
+| [kasm\_ssl\_crt\_path](#input\_kasm\_ssl\_crt\_path) | The file path to the PEM encoded SSL Certificate | `string` | n/a | yes |
+| [kasm\_ssl\_key\_path](#input\_kasm\_ssl\_key\_path) | The file path to the PEM encoded SSL Certificate Key | `string` | n/a | yes |
+| [kasm\_webapp\_vm\_settings](#input\_kasm\_webapp\_vm\_settings) | The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm WebApp instances | object({
cpus = number
memory = number
hdd_size_gb = number
}) | n/a | yes |
+| [letsencrypt\_cert\_support\_email](#input\_letsencrypt\_cert\_support\_email) | Email address to use for Let's Encrypt SSL certificates for OCI Deployment | `string` | n/a | yes |
+| [letsencrypt\_server\_type](#input\_letsencrypt\_server\_type) | SSL Server type to generate. Valid options are staging and prod, and prod certificates are limited to 5 certificates per week. | `string` | n/a | yes |
+| [manager\_token](#input\_manager\_token) | The manager token value for Agents to authenticate to webapps. No special characters | `string` | n/a | yes |
+| [num\_agents](#input\_num\_agents) | The number of Agent Role Servers to create in the deployment | `number` | n/a | yes |
+| [num\_cpx\_nodes](#input\_num\_cpx\_nodes) | The number of WebApp role servers to create in the deployment | `number` | n/a | yes |
+| [num\_webapps](#input\_num\_webapps) | The number of WebApp role servers to create in the deployment | `number` | n/a | yes |
+| [oci\_domain\_name](#input\_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 via https | `string` | n/a | yes |
+| [private\_key\_path](#input\_private\_key\_path) | The path to the API Key PEM encoded Private Key | `string` | n/a | yes |
+| [project\_name](#input\_project\_name) | The name of the deployment (e.g dev, staging). A short single word | `string` | n/a | yes |
+| [redis\_password](#input\_redis\_password) | The password for the Redis server. No special characters | `string` | n/a | yes |
+| [region](#input\_region) | The OCI Region eg: (us-ashburn-1) | `string` | n/a | yes |
+| [service\_registration\_token](#input\_service\_registration\_token) | The service registration token value for cpx RDP servers to authenticate to webapps. No special characters | `string` | n/a | yes |
+| [ssh\_authorized\_keys](#input\_ssh\_authorized\_keys) | The SSH Public Keys to be installed on the OCI compute instance | `string` | n/a | yes |
+| [swap\_size](#input\_swap\_size) | The amount of swap (in MB) to configure inside the compute instances | `number` | n/a | yes |
+| [tenancy\_ocid](#input\_tenancy\_ocid) | The Tenancy OCID. | `string` | n/a | yes |
+| [user\_ocid](#input\_user\_ocid) | The User OCID. | `string` | n/a | yes |
+| [user\_password](#input\_user\_password) | The standard (non administrator) user password. No special characters | `string` | n/a | yes |
+| [vcn\_subnet\_cidr](#input\_vcn\_subnet\_cidr) | VCN Subnet CIDR where you wish to deploy Kasm | `string` | n/a | yes |
+
+## Outputs
+
+No outputs.
+
diff --git a/oci/standard/module/agent.tf b/oci/standard/module/agent.tf
index c149f0d..d23146b 100644
--- a/oci/standard/module/agent.tf
+++ b/oci/standard/module/agent.tf
@@ -1,6 +1,7 @@
-resource "oci_core_instance" "kasm_agent_instance" {
- count = var.num_agents
- availability_domain = data.oci_identity_availability_domains.kasm_ads.availability_domains[0].name
+resource "oci_core_instance" "agent" {
+ count = var.num_agents
+
+ availability_domain = local.availability_domains[0].name
compartment_id = var.compartment_ocid
display_name = "${var.project_name}-Kasm-Agent-${count.index}"
shape = var.instance_shape
@@ -11,8 +12,8 @@ resource "oci_core_instance" "kasm_agent_instance" {
}
create_vnic_details {
- subnet_id = data.oci_core_subnet.data-kasm_agent_subnet.id
- display_name = "${var.project_name}-Primaryvnic-${count.index}"
+ subnet_id = oci_core_subnet.agent.id
+ display_name = "${var.project_name}-Agent-Primaryvnic-${count.index}"
assign_public_ip = true
assign_private_dns_record = true
hostname_label = "${var.project_name}-Kasm-Agent-${count.index}"
diff --git a/oci/standard/module/bastion.tf b/oci/standard/module/bastion.tf
new file mode 100644
index 0000000..214bd30
--- /dev/null
+++ b/oci/standard/module/bastion.tf
@@ -0,0 +1,30 @@
+resource "oci_core_instance" "bastion" {
+ availability_domain = local.availability_domains[0].name
+ compartment_id = var.compartment_ocid
+ display_name = "${var.project_name}-Kasm-SSH-Bastion"
+ shape = var.instance_shape
+
+ shape_config {
+ baseline_ocpu_utilization = var.bastion_vm_utilization
+ ocpus = var.bastion_vm_settings.cpus
+ memory_in_gbs = var.bastion_vm_settings.memory
+ }
+
+ create_vnic_details {
+ subnet_id = oci_core_subnet.lb.id
+ display_name = "${var.project_name}-Bastion-Primaryvnic"
+ assign_public_ip = true
+ assign_private_dns_record = true
+ hostname_label = "${var.project_name}-Kasm-Bastion"
+ }
+
+ source_details {
+ source_type = "image"
+ source_id = var.instance_image_ocid
+ boot_volume_size_in_gbs = var.bastion_vm_settings.hdd_size_gb
+ }
+
+ metadata = {
+ ssh_authorized_keys = var.ssh_authorized_keys
+ }
+}
diff --git a/oci/standard/module/guac_rdp.tf b/oci/standard/module/cpx.tf
similarity index 50%
rename from oci/standard/module/guac_rdp.tf
rename to oci/standard/module/cpx.tf
index dc3d129..58ddc8c 100644
--- a/oci/standard/module/guac_rdp.tf
+++ b/oci/standard/module/cpx.tf
@@ -1,33 +1,34 @@
-resource "oci_core_instance" "kasm_guac_instance" {
- count = var.num_guac_rdp_nodes
- availability_domain = data.oci_identity_availability_domains.kasm_ads.availability_domains[0].name
+resource "oci_core_instance" "cpx" {
+ count = var.num_cpx_nodes
+
+ availability_domain = length(local.availability_domains) > 1 ? local.availability_domains[(count.index)].name : local.availability_domains[0].name
compartment_id = var.compartment_ocid
- display_name = "${var.project_name}-Kasm-Guac-${count.index}"
+ display_name = "${var.project_name}-Kasm-cpx-${count.index}"
shape = var.instance_shape
shape_config {
- ocpus = var.kasm_guac_vm_settings.cpus
- memory_in_gbs = var.kasm_guac_vm_settings.memory
+ ocpus = var.kasm_cpx_vm_settings.cpus
+ memory_in_gbs = var.kasm_cpx_vm_settings.memory
}
create_vnic_details {
- subnet_id = data.oci_core_subnet.data-kasm_guac_subnet.id
- display_name = "${var.project_name}-Primaryvnic-${count.index}"
+ subnet_id = one(oci_core_subnet.cpx[*].id)
+ display_name = "${var.project_name}-CPX-Primaryvnic-${count.index}"
assign_public_ip = true
assign_private_dns_record = true
- hostname_label = "${var.project_name}-Kasm-Guac-${count.index}"
+ hostname_label = "${var.project_name}-Kasm-cpx-${count.index}"
}
source_details {
source_type = "image"
source_id = var.instance_image_ocid
- boot_volume_size_in_gbs = var.kasm_guac_vm_settings.hdd_size_gb
+ boot_volume_size_in_gbs = var.kasm_cpx_vm_settings.hdd_size_gb
}
metadata = {
ssh_authorized_keys = var.ssh_authorized_keys
- user_data = base64encode(templatefile("${path.module}/userdata/guac_bootstrap.sh",
+ user_data = base64encode(templatefile("${path.module}/userdata/cpx_bootstrap.sh",
{
kasm_build_url = var.kasm_build_url
swap_size = var.swap_size
diff --git a/oci/standard/module/db.tf b/oci/standard/module/db.tf
index fb150dc..1c8694f 100644
--- a/oci/standard/module/db.tf
+++ b/oci/standard/module/db.tf
@@ -1,5 +1,5 @@
-resource "oci_core_instance" "kasm_db_instance" {
- availability_domain = data.oci_identity_availability_domains.kasm_ads.availability_domains[0].name
+resource "oci_core_instance" "db" {
+ availability_domain = local.availability_domains[0].name
compartment_id = var.compartment_ocid
display_name = "${var.project_name}-Kasm-DB"
shape = var.instance_shape
@@ -10,8 +10,8 @@ resource "oci_core_instance" "kasm_db_instance" {
}
create_vnic_details {
- subnet_id = oci_core_subnet.kasm-db-subnet.id
- display_name = "${var.project_name}-Primaryvnic"
+ subnet_id = oci_core_subnet.db.id
+ display_name = "${var.project_name}-DB-Primaryvnic"
assign_public_ip = true
assign_private_dns_record = true
hostname_label = "${var.project_name}-Kasm-DB"
@@ -39,7 +39,3 @@ resource "oci_core_instance" "kasm_db_instance" {
))
}
}
-
-data "oci_core_instance" "data-kasm_db_instance" {
- instance_id = oci_core_instance.kasm_db_instance.id
-}
diff --git a/oci/standard/module/dependencies.tf b/oci/standard/module/dependencies.tf
new file mode 100644
index 0000000..c2f4afc
--- /dev/null
+++ b/oci/standard/module/dependencies.tf
@@ -0,0 +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 < 3 ? 3 : local.kasm_server_subnet_cidr_calculation
+
+ availability_domains = data.oci_identity_availability_domains.kasm_ads.availability_domains
+}
+
+data "oci_dns_zones" "this" {
+ compartment_id = var.compartment_ocid
+ name = var.oci_domain_name
+}
+
+data "oci_identity_availability_domains" "kasm_ads" {
+ compartment_id = var.compartment_ocid
+}
diff --git a/oci/standard/module/dns.tf b/oci/standard/module/dns.tf
index fbe4c4b..da27b0f 100644
--- a/oci/standard/module/dns.tf
+++ b/oci/standard/module/dns.tf
@@ -1,16 +1,12 @@
-data "oci_dns_zones" "kasm_dns_zone" {
- compartment_id = var.compartment_ocid
- name = var.oci_domain_name
-}
-
resource "oci_dns_rrset" "kasm_a_record" {
compartment_id = var.compartment_ocid
domain = var.oci_domain_name
- zone_name_or_id = data.oci_dns_zones.kasm_dns_zone.zones[0].name
+ zone_name_or_id = data.oci_dns_zones.this.zones[0].name
rtype = "A"
+
items {
domain = var.oci_domain_name
- rdata = oci_load_balancer.kasm_load_balancer.ip_address_details[0].ip_address
+ rdata = oci_load_balancer.public.ip_address_details[0].ip_address
rtype = "A"
ttl = 300
}
diff --git a/oci/standard/module/letsencrypt.tf b/oci/standard/module/letsencrypt.tf
index b9bf330..940b8c8 100644
--- a/oci/standard/module/letsencrypt.tf
+++ b/oci/standard/module/letsencrypt.tf
@@ -1,28 +1,33 @@
-resource "tls_private_key" "registration_private_key" {
+resource "tls_private_key" "registration" {
algorithm = "RSA"
}
-resource "tls_private_key" "certificate_private_key" {
+resource "tls_private_key" "certificate" {
algorithm = "RSA"
}
-resource "acme_registration" "registration" {
- account_key_pem = tls_private_key.registration_private_key.private_key_pem
+resource "acme_registration" "this" {
+ account_key_pem = tls_private_key.registration.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}"]
+resource "tls_cert_request" "this" {
+ private_key_pem = tls_private_key.certificate.private_key_pem
+
+ dns_names = [
+ var.oci_domain_name,
+ "*.${var.oci_domain_name}"
+ ]
subject {
- common_name = data.oci_dns_zones.kasm_dns_zone.zones[0].name
+ common_name = var.oci_domain_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
+resource "acme_certificate" "this" {
+ account_key_pem = acme_registration.this.account_key_pem
+ certificate_request_pem = tls_cert_request.this.cert_request_pem
+
recursive_nameservers = [
"8.8.8.8:53",
"4.4.2.2:53"
@@ -44,5 +49,5 @@ resource "acme_certificate" "certificate" {
}
}
- depends_on = [acme_registration.registration]
+ depends_on = [acme_registration.this]
}
diff --git a/oci/standard/module/load_balancer.tf b/oci/standard/module/load_balancer.tf
index 7f791e1..075e4be 100644
--- a/oci/standard/module/load_balancer.tf
+++ b/oci/standard/module/load_balancer.tf
@@ -1,32 +1,32 @@
-resource "oci_load_balancer" "kasm_load_balancer" {
+resource "oci_load_balancer" "public" {
shape = "flexible"
compartment_id = var.compartment_ocid
- subnet_ids = [for subnet_id in data.oci_core_subnets.data-kasm_webapp_subnets : subnet_id.subnets[0].id]
+ subnet_ids = [oci_core_subnet.lb.id]
shape_details {
minimum_bandwidth_in_mbps = 10
- maximum_bandwidth_in_mbps = 100
+ maximum_bandwidth_in_mbps = 1000
}
display_name = "${var.project_name}-kasm-load_balancer"
}
-resource "oci_load_balancer_certificate" "kasm_lb_certificate" {
+resource "oci_load_balancer_certificate" "public" {
certificate_name = "${var.project_name}-kasm-cert"
- load_balancer_id = oci_load_balancer.kasm_load_balancer.id
+ load_balancer_id = oci_load_balancer.public.id
- ca_certificate = var.letsencrypt_server_type == "" ? file(var.kasm_ssl_crt_path) : acme_certificate.certificate.certificate_pem
- public_certificate = var.letsencrypt_server_type == "" ? file(var.kasm_ssl_crt_path) : acme_certificate.certificate.certificate_pem
- private_key = var.letsencrypt_server_type == "" ? file(var.kasm_ssl_key_path) : tls_private_key.certificate_private_key.private_key_pem
+ ca_certificate = var.letsencrypt_server_type == "" ? file(var.kasm_ssl_crt_path) : acme_certificate.this.certificate_pem
+ public_certificate = var.letsencrypt_server_type == "" ? file(var.kasm_ssl_crt_path) : acme_certificate.this.certificate_pem
+ private_key = var.letsencrypt_server_type == "" ? file(var.kasm_ssl_key_path) : tls_private_key.certificate.private_key_pem
lifecycle {
create_before_destroy = true
}
}
-resource "oci_load_balancer_backend_set" "kasm_load_balancer_backend_set" {
+resource "oci_load_balancer_backend_set" "public" {
name = "${var.project_name}-kasm-backend_set"
- load_balancer_id = oci_load_balancer.kasm_load_balancer.id
+ load_balancer_id = oci_load_balancer.public.id
policy = "ROUND_ROBIN"
health_checker {
@@ -42,22 +42,22 @@ resource "oci_load_balancer_backend_set" "kasm_load_balancer_backend_set" {
ssl_configuration {
protocols = [
- "TLSv1.1",
"TLSv1.2"
]
- cipher_suite_name = data.oci_load_balancer_ssl_cipher_suite.data-kasm_load_balancer_cipher_suite.name
- certificate_name = oci_load_balancer_certificate.kasm_lb_certificate.certificate_name
+ cipher_suite_name = data.oci_load_balancer_ssl_cipher_suite.this.name
+ certificate_name = oci_load_balancer_certificate.public.certificate_name
verify_peer_certificate = false
}
}
-resource "oci_load_balancer_backend" "kasm_webapp_load_balancer_backend" {
- count = var.num_webapps
- backendset_name = oci_load_balancer_backend_set.kasm_load_balancer_backend_set.name
+resource "oci_load_balancer_backend" "public" {
+ count = var.num_webapps
+
+ backendset_name = oci_load_balancer_backend_set.public.name
backup = false
drain = false
- load_balancer_id = oci_load_balancer.kasm_load_balancer.id
- ip_address = data.oci_core_instance.data-kasm_webapp_instances[count.index].private_ip
+ load_balancer_id = oci_load_balancer.public.id
+ ip_address = oci_core_instance.webapp[(count.index)].private_ip
offline = false
port = 443
weight = 1
@@ -65,24 +65,23 @@ resource "oci_load_balancer_backend" "kasm_webapp_load_balancer_backend" {
resource "oci_load_balancer_listener" "kasm_https_ssl_listener" {
name = "${var.project_name}-https-ssl-listener"
- load_balancer_id = oci_load_balancer.kasm_load_balancer.id
- default_backend_set_name = oci_load_balancer_backend_set.kasm_load_balancer_backend_set.name
+ load_balancer_id = oci_load_balancer.public.id
+ default_backend_set_name = oci_load_balancer_backend_set.public.name
port = "443"
protocol = "HTTP"
ssl_configuration {
protocols = [
- "TLSv1.1",
"TLSv1.2"
]
server_order_preference = "ENABLED"
verify_peer_certificate = false
- cipher_suite_name = data.oci_load_balancer_ssl_cipher_suite.data-kasm_load_balancer_cipher_suite.name
- certificate_name = oci_load_balancer_certificate.kasm_lb_certificate.certificate_name
+ cipher_suite_name = data.oci_load_balancer_ssl_cipher_suite.this.name
+ certificate_name = oci_load_balancer_certificate.public.certificate_name
}
}
-data "oci_load_balancer_ssl_cipher_suite" "data-kasm_load_balancer_cipher_suite" {
+data "oci_load_balancer_ssl_cipher_suite" "this" {
name = "oci-default-ssl-cipher-suite-v1"
- load_balancer_id = oci_load_balancer.kasm_load_balancer.id
+ load_balancer_id = oci_load_balancer.public.id
}
diff --git a/oci/standard/module/provider.tf b/oci/standard/module/provider.tf
index 9e55cc0..2814e4c 100644
--- a/oci/standard/module/provider.tf
+++ b/oci/standard/module/provider.tf
@@ -1,12 +1,18 @@
terraform {
+ required_version = "~> 1.0"
+
required_providers {
oci = {
source = "oracle/oci"
- version = ">= 4.0.0"
+ version = "~> 5.0"
}
acme = {
source = "vancluever/acme"
- version = ">= 2.0.0"
+ version = "~> 2.0"
+ }
+ tls = {
+ source = "hashicorp/tls"
+ version = "~> 4.0"
}
}
}
diff --git a/oci/standard/module/security_lists.tf b/oci/standard/module/security_lists.tf
index 946824f..7eba570 100644
--- a/oci/standard/module/security_lists.tf
+++ b/oci/standard/module/security_lists.tf
@@ -1,6 +1,6 @@
resource "oci_core_security_list" "allow_web" {
compartment_id = var.compartment_ocid
- vcn_id = oci_core_vcn.kasm_vcn.id
+ vcn_id = oci_core_vcn.this.id
display_name = "allow_web"
dynamic "egress_security_rules" {
@@ -26,15 +26,10 @@ resource "oci_core_security_list" "allow_web" {
}
}
-data "oci_core_security_lists" "data-allow_web" {
+resource "oci_core_security_list" "allow_public_ssh" {
compartment_id = var.compartment_ocid
- display_name = oci_core_security_list.allow_web.display_name
-}
-
-resource "oci_core_security_list" "allow_ssh" {
- compartment_id = var.compartment_ocid
- vcn_id = oci_core_vcn.kasm_vcn.id
- display_name = "allow_ssh"
+ vcn_id = oci_core_vcn.this.id
+ display_name = "allow_public_ssh"
dynamic "egress_security_rules" {
for_each = var.anywhere
@@ -59,14 +54,24 @@ resource "oci_core_security_list" "allow_ssh" {
}
}
-data "oci_core_security_lists" "data-allow_ssh" {
+resource "oci_core_security_list" "allow_bastion_ssh" {
compartment_id = var.compartment_ocid
- display_name = oci_core_security_list.allow_ssh.display_name
+ vcn_id = oci_core_vcn.this.id
+ display_name = "allow_bastion_ssh"
+
+ ingress_security_rules {
+ protocol = "6"
+ source = "${oci_core_instance.bastion.private_ip}/32"
+ tcp_options {
+ max = "22"
+ min = "22"
+ }
+ }
}
resource "oci_core_security_list" "allow_db_redis" {
compartment_id = var.compartment_ocid
- vcn_id = oci_core_vcn.kasm_vcn.id
+ vcn_id = oci_core_vcn.this.id
display_name = "allow_db_redis"
dynamic "egress_security_rules" {
@@ -79,39 +84,28 @@ resource "oci_core_security_list" "allow_db_redis" {
}
}
- dynamic "ingress_security_rules" {
- for_each = [for cidr_block in data.oci_core_subnets.data-kasm_webapp_subnets : cidr_block.subnets[0].cidr_block]
- content {
- protocol = "6"
- source = ingress_security_rules.value
- tcp_options {
- max = "5432"
- min = "5432"
- }
+ ingress_security_rules {
+ protocol = "6"
+ source = oci_core_subnet.webapp.cidr_block
+ tcp_options {
+ max = "5432"
+ min = "5432"
}
}
- dynamic "ingress_security_rules" {
- for_each = [for cidr_block in data.oci_core_subnets.data-kasm_webapp_subnets : cidr_block.subnets[0].cidr_block]
- content {
- protocol = "6"
- source = ingress_security_rules.value
- tcp_options {
- max = "6379"
- min = "6379"
- }
+ ingress_security_rules {
+ protocol = "6"
+ source = oci_core_subnet.webapp.cidr_block
+ tcp_options {
+ max = "6379"
+ min = "6379"
}
}
}
-data "oci_core_security_lists" "data-allow_db_redis" {
+resource "oci_core_security_list" "allow_web_from_lb" {
compartment_id = var.compartment_ocid
- display_name = oci_core_security_list.allow_db_redis.display_name
-}
-
-resource "oci_core_security_list" "allow_web_from_webapp" {
- compartment_id = var.compartment_ocid
- vcn_id = oci_core_vcn.kasm_vcn.id
+ vcn_id = oci_core_vcn.this.id
display_name = "allow_web_from_webapp"
dynamic "egress_security_rules" {
@@ -124,20 +118,82 @@ resource "oci_core_security_list" "allow_web_from_webapp" {
}
}
- dynamic "ingress_security_rules" {
- for_each = [for cidr_block in data.oci_core_subnets.data-kasm_webapp_subnets : cidr_block.subnets[0].cidr_block]
- content {
- protocol = "6"
- source = ingress_security_rules.value
- tcp_options {
- max = "443"
- min = "443"
- }
+ ingress_security_rules {
+ protocol = "6"
+ source = oci_core_subnet.lb.cidr_block
+ tcp_options {
+ max = "443"
+ min = "443"
}
}
}
-data "oci_core_security_lists" "data-allow_web_from_webapp" {
+resource "oci_core_security_list" "allow_web_from_webapp" {
compartment_id = var.compartment_ocid
- display_name = oci_core_security_list.allow_web_from_webapp.display_name
+ vcn_id = oci_core_vcn.this.id
+ display_name = "allow_web_from_webapp"
+
+ dynamic "egress_security_rules" {
+ for_each = var.anywhere
+
+ content {
+ destination = egress_security_rules.value
+ protocol = "all"
+ stateless = "false"
+ }
+ }
+
+ ingress_security_rules {
+ protocol = "6"
+ source = oci_core_subnet.webapp.cidr_block
+ tcp_options {
+ max = "443"
+ min = "443"
+ }
+ }
+}
+
+resource "oci_core_security_list" "allow_rdp_to_windows" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+
+ compartment_id = var.compartment_ocid
+ vcn_id = oci_core_vcn.this.id
+ display_name = "allow_rdp_for_windows"
+
+ dynamic "egress_security_rules" {
+ for_each = var.anywhere
+
+ content {
+ destination = egress_security_rules.value
+ protocol = "all"
+ stateless = "false"
+ }
+ }
+
+ ingress_security_rules {
+ protocol = "6"
+ source = oci_core_subnet.webapp.cidr_block
+ tcp_options {
+ max = "4902"
+ min = "4902"
+ }
+ }
+
+ ingress_security_rules {
+ protocol = "6"
+ source = one(oci_core_subnet.cpx[*].cidr_block)
+ tcp_options {
+ max = "3389"
+ min = "3389"
+ }
+ }
+
+ ingress_security_rules {
+ protocol = "6"
+ source = one(oci_core_subnet.cpx[*].cidr_block)
+ tcp_options {
+ max = "4902"
+ min = "4902"
+ }
+ }
}
diff --git a/oci/standard/module/subnet.tf b/oci/standard/module/subnet.tf
deleted file mode 100644
index e6ffbee..0000000
--- a/oci/standard/module/subnet.tf
+++ /dev/null
@@ -1,90 +0,0 @@
-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 < 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 "oci_core_subnet" "kasm-db-subnet" {
- compartment_id = var.compartment_ocid
- vcn_id = data.oci_core_vcn.data-kasm_vcn.id
- route_table_id = oci_core_route_table.default_route_table.id
- dhcp_options_id = data.oci_core_vcn.data-kasm_vcn.default_dhcp_options_id
- availability_domain = data.oci_identity_availability_domains.kasm_ads.availability_domains[0].name
- cidr_block = cidrsubnet(var.vcn_subnet_cidr, local.kasm_server_subnet_cidr_size, 0)
- display_name = "${var.project_name}-db-subnet"
- dns_label = "${var.project_name}db"
- security_list_ids = [
- data.oci_core_security_lists.data-allow_db_redis.security_lists[0].id,
- data.oci_core_security_lists.data-allow_ssh.security_lists[0].id
- ]
-}
-
-data "oci_core_subnet" "data-kasm_db_subnet" {
- subnet_id = oci_core_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, and 2 WebApps)
-resource "oci_core_subnet" "kasm-webapp-subnets" {
- count = var.num_webapps
- compartment_id = var.compartment_ocid
- vcn_id = data.oci_core_vcn.data-kasm_vcn.id
- route_table_id = oci_core_route_table.default_route_table.id
- dhcp_options_id = data.oci_core_vcn.data-kasm_vcn.default_dhcp_options_id
- availability_domain = data.oci_identity_availability_domains.kasm_ads.availability_domains[count.index].name
- cidr_block = cidrsubnet(var.vcn_subnet_cidr, local.kasm_server_subnet_cidr_size, (count.index + 1))
- display_name = "${var.project_name}-webapp-subnet${count.index}"
- dns_label = "${var.project_name}webapp${count.index}"
- security_list_ids = [
- data.oci_core_security_lists.data-allow_web.security_lists[0].id,
- data.oci_core_security_lists.data-allow_ssh.security_lists[0].id
- ]
-}
-
-data "oci_core_subnets" "data-kasm_webapp_subnets" {
- count = var.num_webapps
- compartment_id = var.compartment_ocid
- vcn_id = data.oci_core_vcn.data-kasm_vcn.id
- display_name = oci_core_subnet.kasm-webapp-subnets[count.index].display_name
-}
-
-## 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 "oci_core_subnet" "kasm-agent-subnet" {
- compartment_id = var.compartment_ocid
- vcn_id = data.oci_core_vcn.data-kasm_vcn.id
- route_table_id = oci_core_route_table.default_route_table.id
- dhcp_options_id = data.oci_core_vcn.data-kasm_vcn.default_dhcp_options_id
- availability_domain = data.oci_identity_availability_domains.kasm_ads.availability_domains[0].name
- cidr_block = cidrsubnet(var.vcn_subnet_cidr, local.kasm_server_subnet_cidr_size, local.kasm_agent_subnet_id)
- display_name = "${var.project_name}-agent-subnet"
- dns_label = "${var.project_name}agent"
- security_list_ids = [
- data.oci_core_security_lists.data-allow_web_from_webapp.security_lists[0].id,
- data.oci_core_security_lists.data-allow_ssh.security_lists[0].id
- ]
-}
-
-data "oci_core_subnet" "data-kasm_agent_subnet" {
- subnet_id = oci_core_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 "oci_core_subnet" "kasm-guac-subnet" {
- compartment_id = var.compartment_ocid
- vcn_id = data.oci_core_vcn.data-kasm_vcn.id
- route_table_id = oci_core_route_table.default_route_table.id
- dhcp_options_id = data.oci_core_vcn.data-kasm_vcn.default_dhcp_options_id
- availability_domain = data.oci_identity_availability_domains.kasm_ads.availability_domains[0].name
- cidr_block = cidrsubnet(var.vcn_subnet_cidr, local.kasm_server_subnet_cidr_size, (local.kasm_agent_subnet_id + 1))
- display_name = "${var.project_name}-guac-subnet"
- dns_label = "${var.project_name}guac"
- security_list_ids = [
- data.oci_core_security_lists.data-allow_web_from_webapp.security_lists[0].id,
- data.oci_core_security_lists.data-allow_ssh.security_lists[0].id
- ]
-}
-
-data "oci_core_subnet" "data-kasm_guac_subnet" {
- subnet_id = oci_core_subnet.kasm-guac-subnet.id
-}
diff --git a/oci/standard/module/subnets.tf b/oci/standard/module/subnets.tf
new file mode 100644
index 0000000..fbea323
--- /dev/null
+++ b/oci/standard/module/subnets.tf
@@ -0,0 +1,90 @@
+## Will create WebApp subnets x.x.0.x/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/21)
+resource "oci_core_subnet" "lb" {
+ compartment_id = var.compartment_ocid
+ vcn_id = oci_core_vcn.this.id
+ route_table_id = oci_core_route_table.internet_gateway.id
+ dhcp_options_id = oci_core_vcn.this.default_dhcp_options_id
+ cidr_block = cidrsubnet(var.vcn_subnet_cidr, local.kasm_server_subnet_cidr_size, 0)
+ display_name = "${var.project_name}-public-lb-subnet"
+ dns_label = "${var.project_name}lb"
+ security_list_ids = [
+ oci_core_security_list.allow_web.id,
+ oci_core_security_list.allow_public_ssh.id
+ ]
+}
+
+## Will create WebApp subnets x.x.1.x/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/21)
+resource "oci_core_subnet" "webapp" {
+ compartment_id = var.compartment_ocid
+ vcn_id = oci_core_vcn.this.id
+ route_table_id = oci_core_route_table.nat_gateway.id
+ dhcp_options_id = oci_core_vcn.this.default_dhcp_options_id
+ cidr_block = cidrsubnet(var.vcn_subnet_cidr, local.kasm_server_subnet_cidr_size, 1)
+ display_name = "${var.project_name}-webapp-subnet"
+ dns_label = "${var.project_name}webapp"
+ security_list_ids = [
+ oci_core_security_list.allow_web_from_lb.id,
+ oci_core_security_list.allow_bastion_ssh.id
+ ]
+}
+
+## Will create Agent subnet x.x.2.x/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/21)
+resource "oci_core_subnet" "db" {
+ compartment_id = var.compartment_ocid
+ vcn_id = oci_core_vcn.this.id
+ route_table_id = oci_core_route_table.nat_gateway.id
+ dhcp_options_id = oci_core_vcn.this.default_dhcp_options_id
+ cidr_block = cidrsubnet(var.vcn_subnet_cidr, local.kasm_server_subnet_cidr_size, 2)
+ display_name = "${var.project_name}-db-subnet"
+ dns_label = "${var.project_name}db"
+ security_list_ids = [
+ oci_core_security_list.allow_db_redis.id,
+ oci_core_security_list.allow_bastion_ssh.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 "oci_core_subnet" "agent" {
+ compartment_id = var.compartment_ocid
+ vcn_id = oci_core_vcn.this.id
+ route_table_id = oci_core_route_table.internet_gateway.id
+ dhcp_options_id = oci_core_vcn.this.default_dhcp_options_id
+ cidr_block = cidrsubnet(var.vcn_subnet_cidr, local.kasm_server_subnet_cidr_size, 3)
+ display_name = "${var.project_name}-agent-subnet"
+ dns_label = "${var.project_name}agent"
+ security_list_ids = [
+ oci_core_security_list.allow_web_from_webapp.id,
+ oci_core_security_list.allow_bastion_ssh.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 "oci_core_subnet" "cpx" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+
+ compartment_id = var.compartment_ocid
+ vcn_id = oci_core_vcn.this.id
+ route_table_id = oci_core_route_table.nat_gateway.id
+ dhcp_options_id = oci_core_vcn.this.default_dhcp_options_id
+ cidr_block = cidrsubnet(var.vcn_subnet_cidr, local.kasm_server_subnet_cidr_size, 4)
+ display_name = "${var.project_name}-cpx-subnet"
+ dns_label = "${var.project_name}cpx"
+ security_list_ids = [
+ oci_core_security_list.allow_web_from_webapp.id,
+ oci_core_security_list.allow_bastion_ssh.id
+ ]
+}
+
+## Will create Guac subnet x.x.5.x/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/21)
+resource "oci_core_subnet" "windows" {
+ count = var.num_cpx_nodes > 0 ? 1 : 0
+
+ compartment_id = var.compartment_ocid
+ vcn_id = oci_core_vcn.this.id
+ route_table_id = oci_core_route_table.internet_gateway.id
+ dhcp_options_id = oci_core_vcn.this.default_dhcp_options_id
+ cidr_block = cidrsubnet(var.vcn_subnet_cidr, local.kasm_server_subnet_cidr_size, 5)
+ display_name = "${var.project_name}-windows-subnet"
+ dns_label = "${var.project_name}win"
+ security_list_ids = oci_core_security_list.allow_rdp_to_windows[*].id
+}
diff --git a/aws/standard/module/userdata/guac_bootstrap.sh b/oci/standard/module/userdata/cpx_bootstrap.sh
similarity index 100%
rename from aws/standard/module/userdata/guac_bootstrap.sh
rename to oci/standard/module/userdata/cpx_bootstrap.sh
diff --git a/oci/standard/module/variables.tf b/oci/standard/module/variables.tf
index f0d19ad..785fd32 100644
--- a/oci/standard/module/variables.tf
+++ b/oci/standard/module/variables.tf
@@ -94,7 +94,7 @@ variable "num_webapps" {
type = number
}
-variable "num_guac_rdp_nodes" {
+variable "num_cpx_nodes" {
description = "The number of WebApp role servers to create in the deployment"
type = number
}
@@ -130,7 +130,7 @@ variable "manager_token" {
}
variable "service_registration_token" {
- description = "The service registration token value for Guac RDP servers to authenticate to webapps. No special characters"
+ description = "The service registration token value for cpx RDP servers to authenticate to webapps. No special characters"
type = string
sensitive = true
}
@@ -151,23 +151,54 @@ variable "instance_shape" {
}
variable "kasm_webapp_vm_settings" {
- description = "The amount of memory, in GB, to configure for the Kasm WebApp instance"
- type = map(any)
+ description = "The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm WebApp instances"
+ type = object({
+ cpus = number
+ memory = number
+ hdd_size_gb = number
+ })
}
variable "kasm_database_vm_settings" {
- description = "The amount of memory, in GB, to configure for the Kasm DB instance"
- type = map(any)
+ description = "The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm Database instance"
+ type = object({
+ cpus = number
+ memory = number
+ hdd_size_gb = number
+ })
}
variable "kasm_agent_vm_settings" {
- description = "The amount of memory, in GB, to configure for the Kasm Agent instance"
- type = map(any)
+ description = "The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm Agent instances"
+ type = object({
+ cpus = number
+ memory = number
+ hdd_size_gb = number
+ })
}
-variable "kasm_guac_vm_settings" {
- description = "The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm Guac RDP instance"
- type = map(any)
+variable "kasm_cpx_vm_settings" {
+ description = "The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm cpx RDP instances"
+ type = object({
+ cpus = number
+ memory = number
+ hdd_size_gb = number
+ })
+}
+
+variable "bastion_vm_settings" {
+ description = "The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm SSH Bastion instance"
+ type = object({
+ cpus = number
+ memory = number
+ hdd_size_gb = number
+ })
+}
+
+variable "bastion_vm_utilization" {
+ description = "The VM compute utilization. Defaults to 12.5% to reduce costs on long-running instances."
+ type = string
+ default = "BASELINE_1_8"
}
## Pre-set values
diff --git a/oci/standard/module/vcn.tf b/oci/standard/module/vcn.tf
index de2acb8..aa38dc7 100644
--- a/oci/standard/module/vcn.tf
+++ b/oci/standard/module/vcn.tf
@@ -1,43 +1,42 @@
-resource "oci_core_vcn" "kasm_vcn" {
+resource "oci_core_vcn" "this" {
cidr_block = "10.0.0.0/16"
compartment_id = var.compartment_ocid
display_name = "${var.project_name}-VCN"
dns_label = "${var.project_name}vcn"
}
-data "oci_core_vcn" "data-kasm_vcn" {
- vcn_id = oci_core_vcn.kasm_vcn.id
+resource "oci_core_internet_gateway" "this" {
+ compartment_id = var.compartment_ocid
+ display_name = "${var.project_name}-Internet-Gateway"
+ vcn_id = oci_core_vcn.this.id
}
-resource "oci_core_internet_gateway" "kasm_internet_gateway" {
+resource "oci_core_nat_gateway" "this" {
compartment_id = var.compartment_ocid
- display_name = "${var.project_name}-Gateway"
- vcn_id = oci_core_vcn.kasm_vcn.id
+ display_name = "${var.project_name}-NAT-Gateway"
+ vcn_id = oci_core_vcn.this.id
}
-data "oci_core_internet_gateways" "data-kasm_internet_gateway" {
+resource "oci_core_route_table" "internet_gateway" {
compartment_id = var.compartment_ocid
- vcn_id = data.oci_core_vcn.data-kasm_vcn.id
-}
-
-resource "oci_core_route_table" "default_route_table" {
- compartment_id = var.compartment_ocid
- vcn_id = data.oci_core_vcn.data-kasm_vcn.id
- display_name = "KasmRouteTable"
+ vcn_id = oci_core_vcn.this.id
+ display_name = "Kasm-IG-RouteTable"
route_rules {
destination = var.anywhere[0]
destination_type = "CIDR_BLOCK"
- network_entity_id = oci_core_internet_gateway.kasm_internet_gateway.id #data.oci_core_internet_gateways.data-kasm_internet_gateway.gateways[0].id
+ network_entity_id = oci_core_internet_gateway.this.id
}
}
-# data "oci_core_route_tables" "data-default_route_table" {
-# compartment_id = var.compartment_ocid
-# vcn_id = data.oci_core_vcn.data-kasm_vcn.id
-# display_name = oci_core_route_table.default_route_table.display_name
-# }
+resource "oci_core_route_table" "nat_gateway" {
+ compartment_id = var.compartment_ocid
+ vcn_id = oci_core_vcn.this.id
+ display_name = "Kasm-NAT-RouteTable"
-data "oci_identity_availability_domains" "kasm_ads" {
- compartment_id = var.tenancy_ocid
+ route_rules {
+ destination = var.anywhere[0]
+ destination_type = "CIDR_BLOCK"
+ network_entity_id = oci_core_nat_gateway.this.id
+ }
}
diff --git a/oci/standard/module/webapp.tf b/oci/standard/module/webapp.tf
index 380a120..b881218 100644
--- a/oci/standard/module/webapp.tf
+++ b/oci/standard/module/webapp.tf
@@ -1,6 +1,7 @@
-resource "oci_core_instance" "kasm_webapp_instance" {
- count = var.num_webapps
- availability_domain = data.oci_identity_availability_domains.kasm_ads.availability_domains[count.index].name
+resource "oci_core_instance" "webapp" {
+ count = var.num_webapps
+
+ availability_domain = length(local.availability_domains) > 1 ? local.availability_domains[(count.index)].name : local.availability_domains[0].name
compartment_id = var.compartment_ocid
display_name = "${var.project_name}-Kasm-Webapp-${count.index}"
shape = var.instance_shape
@@ -11,8 +12,8 @@ resource "oci_core_instance" "kasm_webapp_instance" {
}
create_vnic_details {
- subnet_id = data.oci_core_subnets.data-kasm_webapp_subnets[count.index].subnets[0].id
- display_name = "${var.project_name}-Primaryvnic"
+ subnet_id = oci_core_subnet.webapp.id
+ display_name = "${var.project_name}-WebApp-Primaryvnic"
assign_public_ip = true
assign_private_dns_record = true
hostname_label = "${var.project_name}-Kasm-Webapp-${count.index}"
@@ -29,7 +30,7 @@ resource "oci_core_instance" "kasm_webapp_instance" {
user_data = base64encode(templatefile("${path.module}/userdata/webapp_bootstrap.sh",
{
kasm_build_url = var.kasm_build_url
- db_ip = data.oci_core_instance.data-kasm_db_instance.private_ip
+ db_ip = oci_core_instance.db.private_ip
database_password = var.database_password
redis_password = var.redis_password
swap_size = var.swap_size
@@ -39,8 +40,3 @@ resource "oci_core_instance" "kasm_webapp_instance" {
}
}
-
-data "oci_core_instance" "data-kasm_webapp_instances" {
- count = var.num_webapps
- instance_id = oci_core_instance.kasm_webapp_instance[count.index].id
-}
diff --git a/oci/standard/provider.tf b/oci/standard/provider.tf
index e65d81e..743dcfb 100644
--- a/oci/standard/provider.tf
+++ b/oci/standard/provider.tf
@@ -1,16 +1,18 @@
terraform {
+ required_version = "~> 1.0"
+
required_providers {
oci = {
source = "oracle/oci"
- version = ">= 4.0.0"
+ version = "~> 5.0"
}
acme = {
source = "vancluever/acme"
- version = ">= 2.0"
+ version = "~> 2.0"
}
tls = {
source = "hashicorp/tls"
- version = ">= 4.0.0"
+ version = "~> 4.0"
}
}
}
diff --git a/oci/standard/settings.tfvars b/oci/standard/terraform.tfvars
similarity index 87%
rename from oci/standard/settings.tfvars
rename to oci/standard/terraform.tfvars
index 22f5c3b..139125a 100644
--- a/oci/standard/settings.tfvars
+++ b/oci/standard/terraform.tfvars
@@ -1,7 +1,7 @@
## Kasm deployment settings
oci_domain_name = "kasm.contoso.com"
project_name = "contoso"
-kasm_build_url = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.13.0.002947.tar.gz"
+kasm_build_url = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.14.0.3a7abb.tar.gz"
vcn_subnet_cidr = "10.0.0.0/16"
## OCI Authentication variables
@@ -33,16 +33,16 @@ redis_password = "changeme"
database_password = "changeme"
service_registration_token = "changeme"
-## SSH Public Keys
+## SSH Public Key
ssh_authorized_keys = "changeme"
## OCI VM Settings
-instance_image_ocid = "ocid1.image.oc1.iad.aaaaaaaahiz6xym3a76xhwkmwmhrz6luyiehho7dpxpkphxhsq5q6z4m3nlq"
+instance_image_ocid = ""
instance_shape = "VM.Standard.E4.Flex"
swap_size = 2048
num_webapps = 2
num_agents = 2
-num_guac_rdp_nodes = 1
+num_cpx_nodes = 1
kasm_webapp_vm_settings = {
cpus = 2
@@ -62,8 +62,14 @@ kasm_agent_vm_settings = {
hdd_size_gb = 120
}
-kasm_guac_vm_settings = {
+kasm_cpx_vm_settings = {
cpus = 4
memory = 4
hdd_size_gb = 50
-}
\ No newline at end of file
+}
+
+bastion_vm_settings = {
+ cpus = 1
+ memory = 2
+ hdd_size_gb = 50
+}
diff --git a/oci/standard/variables.tf b/oci/standard/variables.tf
index fbb86c3..2261d24 100644
--- a/oci/standard/variables.tf
+++ b/oci/standard/variables.tf
@@ -104,8 +104,8 @@ variable "ssh_authorized_keys" {
}
variable "instance_image_ocid" {
- description = "The OCID for the instance image , such as ubuntu 20.04, to use."
- default = "ocid1.image.oc1.iad.aaaaaaaafg6lg7dejwjebjqontwzyvutgf6qs5awyze6fgoiqepyj5qkvcuq"
+ description = "The OCID for the instance image, such as ubuntu 22.04, to use."
+ type = string
validation {
condition = can(regex("^(ocid\\d)\\.(image)\\.(oc\\d)\\.[a-z]{3,}\\.[a-z0-9]{60}", var.instance_image_ocid))
@@ -244,7 +244,7 @@ variable "manager_token" {
}
variable "service_registration_token" {
- description = "The service registration token value for Guac RDP servers to authenticate to webapps. No special characters"
+ description = "The service registration token value for cpx RDP servers to authenticate to webapps. No special characters"
type = string
sensitive = true
@@ -264,13 +264,13 @@ variable "num_agents" {
}
}
-variable "num_guac_rdp_nodes" {
- description = "The number of Guac RDP Role Servers to create in the deployment"
+variable "num_cpx_nodes" {
+ description = "The number of cpx RDP Role Servers to create in the deployment"
type = number
validation {
- condition = var.num_guac_rdp_nodes >= 0 && var.num_guac_rdp_nodes <= 100 && floor(var.num_guac_rdp_nodes) == var.num_guac_rdp_nodes
- error_message = "Acceptable number of Kasm Guac RDP nodes range between 0-100."
+ condition = var.num_cpx_nodes >= 0 && var.num_cpx_nodes <= 100 && floor(var.num_cpx_nodes) == var.num_cpx_nodes
+ error_message = "Acceptable number of Kasm cpx RDP nodes range between 0-100."
}
}
@@ -333,7 +333,7 @@ variable "kasm_database_vm_settings" {
error_message = "Kasm Webapps should have at least 2 GB Memory to ensure enough resources for Kasm services."
}
validation {
- condition = car.kasm_database_vm_settings.hdd_size_gb >= 50
+ condition = var.kasm_database_vm_settings.hdd_size_gb >= 50
error_message = "Kasm Webapps should have at least a 50 GB HDD to meet OCI minimum requirements, and ensure enough space Kasm services."
}
}
@@ -360,8 +360,8 @@ variable "kasm_agent_vm_settings" {
}
}
-variable "kasm_guac_vm_settings" {
- description = "The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm Guac RDP instances"
+variable "kasm_cpx_vm_settings" {
+ description = "The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm cpx RDP instances"
type = object({
cpus = number
memory = number
@@ -369,16 +369,38 @@ variable "kasm_guac_vm_settings" {
})
validation {
- condition = var.kasm_guac_vm_settings.cpus >= 2
- error_message = "Kasm Guac RDP servers should have at least 2 CPUs to ensure enough resources for Kasm services."
+ condition = var.kasm_cpx_vm_settings.cpus >= 2
+ error_message = "Kasm cpx RDP servers should have at least 2 CPUs to ensure enough resources for Kasm services."
}
validation {
- condition = var.kasm_guac_vm_settings.memory >= 2
- error_message = "Kasm Guac RDP servers should have at least 2 GB Memory to ensure enough resources for Kasm services."
+ condition = var.kasm_cpx_vm_settings.memory >= 2
+ error_message = "Kasm cpx RDP servers should have at least 2 GB Memory to ensure enough resources for Kasm services."
}
validation {
- condition = var.kasm_guac_vm_settings.hdd_size_gb >= 50
- error_message = "Kasm Guac RDP servers should have at least a 50 GB HDD to meet OCI minimum requirements, and ensure enough space Kasm services."
+ condition = var.kasm_cpx_vm_settings.hdd_size_gb >= 50
+ error_message = "Kasm cpx RDP servers should have at least a 50 GB HDD to meet OCI minimum requirements, and ensure enough space Kasm services."
+ }
+}
+
+variable "bastion_vm_settings" {
+ description = "The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm SSH Bastion instance"
+ type = object({
+ cpus = number
+ memory = number
+ hdd_size_gb = number
+ })
+
+ validation {
+ condition = var.bastion_vm_settings.cpus >= 1
+ error_message = "Kasm SSH Bastion should have at least 2 CPUs to ensure enough resources for Kasm services."
+ }
+ validation {
+ condition = var.bastion_vm_settings.memory >= 1
+ error_message = "Kasm SSH Bastion should have at least 2 GB Memory to ensure enough resources for Kasm services."
+ }
+ validation {
+ condition = var.bastion_vm_settings.hdd_size_gb >= 50
+ error_message = "Kasm SSH Bastion should have at least a 50 GB HDD to meet OCI minimum requirements."
}
}