From 2f22f372b0b7a0e071cb92af8b30251f33490bb4 Mon Sep 17 00:00:00 2001 From: Michael Fraenkel Date: Fri, 2 Dec 2022 15:03:22 -0700 Subject: [PATCH] PLAT-5801: Allow bastion instance type to be specified (#13) Combine all bastion details into a single object. The existence means you want to create the bastion. --- .circleci/config.yml | 2 +- .pre-commit-config.yaml | 7 +++++-- README.md | 7 +++---- main.tf | 23 ++++++++++++----------- outputs.tf | 2 +- submodules/bastion/README.md | 7 ++++--- submodules/bastion/main.tf | 12 ++++++------ submodules/bastion/variables.tf | 16 +++++++++++----- tests/main.tf | 2 +- variables.tf | 18 +++++++----------- 10 files changed, 51 insertions(+), 45 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 25d3a65c..d07c3471 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -18,7 +18,7 @@ jobs: - checkout - terraform/install: - terraform_version: '1.3.4' + terraform_version: '1.3.5' - terraform/fmt: path: . diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4b06a7a9..f14d75cf 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,6 +14,11 @@ repos: - repo: https://github.com/antonbabenko/pre-commit-terraform rev: v1.75.0 hooks: + - id: terraform_providers_lock + args: + - --tf-init-args=-upgrade + - id: terraform_fmt + - id: terraform_validate - id: terraform_docs args: - '--hook-config=--path-to-file=README.md' @@ -22,7 +27,6 @@ repos: - '--hook-config=--recursive.enabled=true' - '--hook-config=--recursive.path=submodules' - '--hook-config=--lockfile=false' - - id: terraform_fmt - id: terraform_tflint args: - '--args=--config=__GIT_WORKING_DIR__/.tflint.hcl' @@ -39,7 +43,6 @@ repos: - '--args=--only=terraform_required_providers' - '--args=--only=terraform_standard_module_structure' - '--args=--only=terraform_workspace_remote' - - id: terraform_validate # - id: terrascan # Skipping until they update lifecycle block; Data resources do not have lifecycle settings, so a lifecycle block is not allowed. # args: # - '--args=--non-recursive' diff --git a/README.md b/README.md index c8c24339..0eadfffd 100644 --- a/README.md +++ b/README.md @@ -76,8 +76,8 @@ aws s3 rb s3://"${AWS_TERRAFORM_REMOTE_STATE_BUCKET}" --force | Name | Version | |------|---------| -| [aws](#provider\_aws) | 4.36.1 | -| [tls](#provider\_tls) | 4.0.3 | +| [aws](#provider\_aws) | 4.40.0 | +| [tls](#provider\_tls) | 4.0.4 | ## Modules @@ -111,9 +111,8 @@ aws s3 rb s3://"${AWS_TERRAFORM_REMOTE_STATE_BUCKET}" --force |------|-------------|------|---------|:--------:| | [additional\_node\_groups](#input\_additional\_node\_groups) | Additional EKS managed node groups definition. |
map(object({
ami = optional(string)
bootstrap_extra_args = optional(string, "")
instance_types = list(string)
spot = optional(bool, false)
min_per_az = number
max_per_az = number
desired_per_az = number
labels = map(string)
taints = optional(list(object({ key = string, value = optional(string), effect = string })), [])
tags = optional(map(string), {})
volume = object({
size = string
type = string
})
}))
| `{}` | no | | [availability\_zones](#input\_availability\_zones) | List of Availibility zones to distribute the deployment, EKS needs at least 2,https://docs.aws.amazon.com/eks/latest/userguide/network_reqs.html.
Note that setting this variable bypasses validation of the status of the zones data 'aws\_availability\_zones' 'available'.
Caller is responsible for validating status of these zones. | `list(string)` | `[]` | no | -| [bastion\_ami\_id](#input\_bastion\_ami\_id) | AMI ID for the bastion EC2 instance, otherwise we will use the latest 'amazon\_linux\_2' ami | `string` | `""` | no | +| [bastion](#input\_bastion) | if specifed, a bastion is created with the specified details |
object({
ami = optional(string, null) # default will use the latest 'amazon_linux_2' ami
instance_type = optional(string, "t2.micro")
})
| `null` | no | | [cidr](#input\_cidr) | The IPv4 CIDR block for the VPC. | `string` | `"10.0.0.0/16"` | no | -| [create\_bastion](#input\_create\_bastion) | Create bastion toggle. | `bool` | `false` | no | | [default\_node\_groups](#input\_default\_node\_groups) | EKS managed node groups definition. |
object(
{
compute = object(
{
ami = optional(string)
bootstrap_extra_args = optional(string, "")
instance_types = optional(list(string), ["m5.2xlarge"])
spot = optional(bool, false)
min_per_az = optional(number, 0)
max_per_az = optional(number, 10)
desired_per_az = optional(number, 1)
labels = optional(map(string), {
"dominodatalab.com/node-pool" = "default"
})
taints = optional(list(object({ key = string, value = optional(string), effect = string })), [])
tags = optional(map(string), {})
volume = optional(object(
{
size = optional(number, 100)
type = optional(string, "gp3")
}),
{
size = 100
type = "gp3"
}
)
}),
platform = object(
{
ami = optional(string)
bootstrap_extra_args = optional(string, "")
instance_types = optional(list(string), ["m5.4xlarge"])
spot = optional(bool, false)
min_per_az = optional(number, 1)
max_per_az = optional(number, 10)
desired_per_az = optional(number, 1)
labels = optional(map(string), {
"dominodatalab.com/node-pool" = "platform"
})
taints = optional(list(object({ key = string, value = optional(string), effect = string })), [])
tags = optional(map(string), {})
volume = optional(object(
{
size = optional(number, 100)
type = optional(string, "gp3")
}),
{
size = 100
type = "gp3"
}
)
}),
gpu = object(
{
ami = optional(string)
bootstrap_extra_args = optional(string, "")
instance_types = optional(list(string), ["g4dn.xlarge"])
spot = optional(bool, false)
min_per_az = optional(number, 0)
max_per_az = optional(number, 10)
desired_per_az = optional(number, 0)
labels = optional(map(string), {
"dominodatalab.com/node-pool" = "default-gpu"
"nvidia.com/gpu" = true
})
taints = optional(list(object({ key = string, value = optional(string), effect = string })), [
{ key = "nvidia.com/gpu", value = "true", effect = "NO_SCHEDULE" }
])
tags = optional(map(string), {})
volume = optional(object(
{
size = optional(number, 100)
type = optional(string, "gp3")
}),
{
size = 100
type = "gp3"
}
)
})
})
|
{
"compute": {},
"gpu": {},
"platform": {}
}
| no | | [deploy\_id](#input\_deploy\_id) | Domino Deployment ID. | `string` | `"domino-eks"` | no | | [efs\_access\_point\_path](#input\_efs\_access\_point\_path) | Filesystem path for efs. | `string` | `"/domino"` | no | diff --git a/main.tf b/main.tf index c8be529a..d3e4cc2f 100644 --- a/main.tf +++ b/main.tf @@ -111,15 +111,16 @@ locals { } module "bastion" { - count = var.create_bastion ? 1 : 0 + count = var.bastion != null ? 1 : 0 - source = "./submodules/bastion" - deploy_id = var.deploy_id - region = var.region - vpc_id = local.vpc_id - ssh_pvt_key_path = aws_key_pair.domino.key_name - bastion_public_subnet_id = local.public_subnets[0].subnet_id - bastion_ami_id = var.bastion_ami_id + source = "./submodules/bastion" + deploy_id = var.deploy_id + region = var.region + vpc_id = local.vpc_id + ssh_pvt_key_path = aws_key_pair.domino.key_name + public_subnet_id = local.public_subnets[0].subnet_id + ami_id = var.bastion.ami + instance_type = var.bastion.instance_type } module "eks" { @@ -131,7 +132,7 @@ module "eks" { private_subnets = local.private_subnets ssh_pvt_key_path = aws_key_pair.domino.key_name bastion_security_group_id = try(module.bastion[0].security_group_id, "") - create_bastion_sg = var.create_bastion + create_bastion_sg = var.bastion != null kubeconfig_path = local.kubeconfig_path default_node_groups = var.default_node_groups additional_node_groups = var.additional_node_groups @@ -144,12 +145,12 @@ module "eks" { } data "aws_iam_role" "eks_master_roles" { - for_each = var.create_bastion ? toset(var.eks_master_role_names) : [] + for_each = var.bastion != null ? toset(var.eks_master_role_names) : [] name = each.key } module "k8s_setup" { - count = var.create_bastion ? 1 : 0 + count = var.bastion != null ? 1 : 0 source = "./submodules/k8s" ssh_pvt_key_path = local.ssh_pvt_key_path bastion_user = local.bastion_user diff --git a/outputs.tf b/outputs.tf index 260ad909..cc1034b6 100755 --- a/outputs.tf +++ b/outputs.tf @@ -5,7 +5,7 @@ output "ssh_bastion_command" { output "bastion_ip" { description = "public ip of the bastion" - value = var.create_bastion ? module.bastion[0].public_ip : "" + value = var.bastion != null ? module.bastion[0].public_ip : "" } output "hostname" { diff --git a/submodules/bastion/README.md b/submodules/bastion/README.md index fd1ac08c..d17cc8da 100644 --- a/submodules/bastion/README.md +++ b/submodules/bastion/README.md @@ -41,11 +41,12 @@ No modules. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [bastion\_ami\_id](#input\_bastion\_ami\_id) | AMI ID for the bastion EC2 instance, otherwise we will use the latest 'amazon\_linux\_2' ami. | `string` | `""` | no | -| [bastion\_public\_subnet\_id](#input\_bastion\_public\_subnet\_id) | Public subnet to create bastion host in. | `string` | n/a | yes | -| [bastion\_security\_group\_rules](#input\_bastion\_security\_group\_rules) | Bastion host security group rules. |
map(object({
protocol = string
from_port = string
to_port = string
type = string
description = string
cidr_blocks = list(string)
source_security_group_id = string

}))
|
{
"bastion_inbound_ssh": {
"cidr_blocks": [
"0.0.0.0/0"
],
"description": "Inbound ssh",
"from_port": "22",
"protocol": "-1",
"source_security_group_id": null,
"to_port": "22",
"type": "ingress"
},
"bastion_outbound_traffic": {
"cidr_blocks": [
"0.0.0.0/0"
],
"description": "Allow all outbound traffic by default",
"from_port": "0",
"protocol": "-1",
"source_security_group_id": null,
"to_port": "0",
"type": "egress"
}
}
| no | +| [ami\_id](#input\_ami\_id) | AMI ID for the bastion EC2 instance, otherwise we will use the latest 'amazon\_linux\_2' ami. | `string` | `null` | no | | [deploy\_id](#input\_deploy\_id) | Domino Deployment ID | `string` | n/a | yes | +| [instance\_type](#input\_instance\_type) | the bastion's instance type, if null, t2.micro is used | `string` | `null` | no | +| [public\_subnet\_id](#input\_public\_subnet\_id) | Public subnet to create bastion host in. | `string` | n/a | yes | | [region](#input\_region) | AWS region for the deployment | `string` | n/a | yes | +| [security\_group\_rules](#input\_security\_group\_rules) | Bastion host security group rules. |
map(object({
protocol = string
from_port = string
to_port = string
type = string
description = string
cidr_blocks = list(string)
source_security_group_id = string

}))
|
{
"bastion_inbound_ssh": {
"cidr_blocks": [
"0.0.0.0/0"
],
"description": "Inbound ssh",
"from_port": "22",
"protocol": "-1",
"source_security_group_id": null,
"to_port": "22",
"type": "ingress"
},
"bastion_outbound_traffic": {
"cidr_blocks": [
"0.0.0.0/0"
],
"description": "Allow all outbound traffic by default",
"from_port": "0",
"protocol": "-1",
"source_security_group_id": null,
"to_port": "0",
"type": "egress"
}
}
| no | | [ssh\_pvt\_key\_path](#input\_ssh\_pvt\_key\_path) | SSH private key filepath. | `string` | n/a | yes | | [vpc\_id](#input\_vpc\_id) | VPC ID. | `string` | n/a | yes | diff --git a/submodules/bastion/main.tf b/submodules/bastion/main.tf index 192d7e17..bf8120b0 100644 --- a/submodules/bastion/main.tf +++ b/submodules/bastion/main.tf @@ -20,7 +20,7 @@ resource "aws_security_group" "bastion" { } } resource "aws_security_group_rule" "bastion" { - for_each = var.bastion_security_group_rules + for_each = var.security_group_rules security_group_id = aws_security_group.bastion.id protocol = each.value.protocol @@ -72,7 +72,7 @@ resource "aws_iam_instance_profile" "bastion" { } data "aws_ami" "amazon_linux_2" { - count = var.bastion_ami_id == "" ? 1 : 0 + count = var.ami_id == null ? 1 : 0 most_recent = true owners = ["amazon"] @@ -83,11 +83,11 @@ data "aws_ami" "amazon_linux_2" { } locals { - bastion_ami_id = var.bastion_ami_id != "" ? var.bastion_ami_id : data.aws_ami.amazon_linux_2[0].id + ami_id = var.ami_id != null ? var.ami_id : data.aws_ami.amazon_linux_2[0].id } resource "aws_instance" "bastion" { - ami = local.bastion_ami_id + ami = local.ami_id associate_public_ip_address = true iam_instance_profile = aws_iam_instance_profile.bastion.name monitoring = true @@ -106,7 +106,7 @@ resource "aws_instance" "bastion" { get_password_data = false hibernation = false instance_initiated_shutdown_behavior = "stop" - instance_type = "t2.micro" + instance_type = var.instance_type != null ? var.instance_type : "t2.micro" key_name = var.ssh_pvt_key_path metadata_options { @@ -126,7 +126,7 @@ resource "aws_instance" "bastion" { } source_dest_check = true - subnet_id = var.bastion_public_subnet_id + subnet_id = var.public_subnet_id vpc_security_group_ids = [aws_security_group.bastion.id] tags = { diff --git a/submodules/bastion/variables.tf b/submodules/bastion/variables.tf index 03e1b557..2ac70b06 100644 --- a/submodules/bastion/variables.tf +++ b/submodules/bastion/variables.tf @@ -3,11 +3,18 @@ variable "deploy_id" { description = "Domino Deployment ID" } -variable "bastion_ami_id" { +variable "ami_id" { description = "AMI ID for the bastion EC2 instance, otherwise we will use the latest 'amazon_linux_2' ami." type = string - default = "" + default = null } + +variable "instance_type" { + description = "the bastion's instance type, if null, t2.micro is used" + type = string + default = null +} + variable "region" { description = "AWS region for the deployment" type = string @@ -23,12 +30,12 @@ variable "ssh_pvt_key_path" { type = string } -variable "bastion_public_subnet_id" { +variable "public_subnet_id" { description = "Public subnet to create bastion host in." type = string } -variable "bastion_security_group_rules" { +variable "security_group_rules" { description = "Bastion host security group rules." type = map(object({ @@ -62,5 +69,4 @@ variable "bastion_security_group_rules" { source_security_group_id = null } } - } diff --git a/tests/main.tf b/tests/main.tf index 9ee766e0..8f6964d1 100755 --- a/tests/main.tf +++ b/tests/main.tf @@ -18,7 +18,7 @@ module "domino_eks" { route53_hosted_zone_name = "deploys-delta.domino.tech" eks_master_role_names = ["okta-poweruser", "okta-fulladmin"] s3_force_destroy_on_deletion = true - create_bastion = true + bastion = {} ssh_pvt_key_path = "domino.pem" tags = var.tags default_node_groups = { diff --git a/variables.tf b/variables.tf index 4e965b16..fc5378ce 100755 --- a/variables.tf +++ b/variables.tf @@ -224,23 +224,19 @@ variable "private_subnets" { default = null } -variable "create_bastion" { - type = bool - description = "Create bastion toggle." - default = false -} - -variable "bastion_ami_id" { - description = "AMI ID for the bastion EC2 instance, otherwise we will use the latest 'amazon_linux_2' ami" - type = string - default = "" +variable "bastion" { + type = object({ + ami = optional(string, null) # default will use the latest 'amazon_linux_2' ami + instance_type = optional(string, "t2.micro") + }) + description = "if specifed, a bastion is created with the specified details" + default = null } variable "efs_access_point_path" { type = string description = "Filesystem path for efs." default = "/domino" - } variable "ssh_pvt_key_path" {