Skip to content

Commit

Permalink
Merge branch 'immutable-optional-elb'
Browse files Browse the repository at this point in the history
  • Loading branch information
Guillaume DA SILVA committed May 12, 2023
2 parents 3a9c0a5 + 14f0fa1 commit 49a88a0
Show file tree
Hide file tree
Showing 5 changed files with 238 additions and 180 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

# Module directory
.terraform/
.terraform.lock.hcl

# Jetbrains
.idea/
57 changes: 29 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,10 @@ No modules.
|------|-------------|------|---------|:--------:|
| <a name="input_allow_ssh_commands"></a> [allow\_ssh\_commands](#input\_allow\_ssh\_commands) | Allows the SSH user to execute one-off commands. Pass true to enable. Warning: These commands are not logged and increase the vulnerability of the system. Use at your own discretion. | `bool` | `false` | no |
| <a name="input_associate_public_ip_address"></a> [associate\_public\_ip\_address](#input\_associate\_public\_ip\_address) | n/a | `bool` | `true` | no |
| <a name="input_auto_scaling_group_subnets"></a> [auto\_scaling\_group\_subnets](#input\_auto\_scaling\_group\_subnets) | List of subnets where the Auto Scalling Group will deploy the instances | `list(string)` | n/a | yes |
| <a name="input_auto_scaling_group_subnets"></a> [auto\_scaling\_group\_subnets](#input\_auto\_scaling\_group\_subnets) | List of subnets where the Auto Scaling Group will deploy the instances | `list(string)` | n/a | yes |
| <a name="input_bastion_additional_security_groups"></a> [bastion\_additional\_security\_groups](#input\_bastion\_additional\_security\_groups) | List of additional security groups to attach to the launch template | `list(string)` | `[]` | no |
| <a name="input_bastion_ami"></a> [bastion\_ami](#input\_bastion\_ami) | The AMI that the Bastion Host will use. | `string` | `""` | no |
| <a name="input_bastion_host_key_pair"></a> [bastion\_host\_key\_pair](#input\_bastion\_host\_key\_pair) | Select the key pair to use to launch the bastion host | `any` | n/a | yes |
| <a name="input_bastion_host_key_pair"></a> [bastion\_host\_key\_pair](#input\_bastion\_host\_key\_pair) | Select the key pair to use to launch the bastion host | `string` | n/a | yes |
| <a name="input_bastion_iam_permissions_boundary"></a> [bastion\_iam\_permissions\_boundary](#input\_bastion\_iam\_permissions\_boundary) | IAM Role Permissions Boundary to constrain the bastion host role | `string` | `""` | no |
| <a name="input_bastion_iam_policy_name"></a> [bastion\_iam\_policy\_name](#input\_bastion\_iam\_policy\_name) | IAM policy name to create for granting the instance role access to the bucket | `string` | `"BastionHost"` | no |
| <a name="input_bastion_iam_role_name"></a> [bastion\_iam\_role\_name](#input\_bastion\_iam\_role\_name) | IAM role name to create | `string` | `null` | no |
Expand All @@ -127,50 +127,51 @@ No modules.
| <a name="input_bastion_record_name"></a> [bastion\_record\_name](#input\_bastion\_record\_name) | DNS record name to use for the bastion | `string` | `""` | no |
| <a name="input_bastion_security_group_id"></a> [bastion\_security\_group\_id](#input\_bastion\_security\_group\_id) | Custom security group to use | `string` | `""` | no |
| <a name="input_bucket_force_destroy"></a> [bucket\_force\_destroy](#input\_bucket\_force\_destroy) | The bucket and all objects should be destroyed when using true | `bool` | `false` | no |
| <a name="input_bucket_name"></a> [bucket\_name](#input\_bucket\_name) | Bucket name where the bastion will store the logs | `any` | n/a | yes |
| <a name="input_bucket_name"></a> [bucket\_name](#input\_bucket\_name) | Bucket name where the bastion will store the logs | `string` | n/a | yes |
| <a name="input_bucket_versioning"></a> [bucket\_versioning](#input\_bucket\_versioning) | Enable bucket versioning or not | `bool` | `true` | no |
| <a name="input_cidrs"></a> [cidrs](#input\_cidrs) | List of CIDRs than can access to the bastion. Default : 0.0.0.0/0 | `list(string)` | <pre>[<br> "0.0.0.0/0"<br>]</pre> | no |
| <a name="input_create_dns_record"></a> [create\_dns\_record](#input\_create\_dns\_record) | Choose if you want to create a record name for the bastion (LB). If true 'hosted\_zone\_id' and 'bastion\_record\_name' are mandatory | `any` | n/a | yes |
| <a name="input_disk_encrypt"></a> [disk\_encrypt](#input\_disk\_encrypt) | Instance EBS encrypt | `bool` | `true` | no |
| <a name="input_cidrs"></a> [cidrs](#input\_cidrs) | List of CIDRs that can access the bastion. Default: 0.0.0.0/0 | `list(string)` | <pre>[<br> "0.0.0.0/0"<br>]</pre> | no |
| <a name="input_create_dns_record"></a> [create\_dns\_record](#input\_create\_dns\_record) | Choose if you want to create a record name for the bastion (LB). If true, 'hosted\_zone\_id' and 'bastion\_record\_name' are mandatory | `bool` | n/a | yes |
| <a name="input_create_elb"></a> [create\_elb](#input\_create\_elb) | Choose if you want to deploy an ELB for accessing bastion hosts. If true, you must set elb\_subnets and is\_lb\_private | `bool` | `true` | no |
| <a name="input_disk_encrypt"></a> [disk\_encrypt](#input\_disk\_encrypt) | Instance EBS encryption | `bool` | `true` | no |
| <a name="input_disk_size"></a> [disk\_size](#input\_disk\_size) | Root EBS size in GB | `number` | `8` | no |
| <a name="input_elb_subnets"></a> [elb\_subnets](#input\_elb\_subnets) | List of subnets where the ELB will be deployed | `list(string)` | n/a | yes |
| <a name="input_enable_http_protocol_ipv6"></a> [enable\_http\_protocol\_ipv6](#input\_enable\_http\_protocol\_ipv6) | Enables or disables the IPv6 endpoint for the instance metadata service. | `bool` | `false` | no |
| <a name="input_enable_instance_metadata_tags"></a> [enable\_instance\_metadata\_tags](#input\_enable\_instance\_metadata\_tags) | Enables or disables access to instance tags from the instance metadata service. | `bool` | `false` | no |
| <a name="input_elb_subnets"></a> [elb\_subnets](#input\_elb\_subnets) | List of subnets where the ELB will be deployed | `list(string)` | `[]` | no |
| <a name="input_enable_http_protocol_ipv6"></a> [enable\_http\_protocol\_ipv6](#input\_enable\_http\_protocol\_ipv6) | Enables or disables the IPv6 endpoint for the instance metadata service | `bool` | `false` | no |
| <a name="input_enable_instance_metadata_tags"></a> [enable\_instance\_metadata\_tags](#input\_enable\_instance\_metadata\_tags) | Enables or disables access to instance tags from the instance metadata service | `bool` | `false` | no |
| <a name="input_enable_logs_s3_sync"></a> [enable\_logs\_s3\_sync](#input\_enable\_logs\_s3\_sync) | Enable cron job to copy logs to S3 | `bool` | `true` | no |
| <a name="input_extra_user_data_content"></a> [extra\_user\_data\_content](#input\_extra\_user\_data\_content) | Additional scripting to pass to the bastion host. For example, this can include installing postgresql for the `psql` command. | `string` | `""` | no |
| <a name="input_extra_user_data_content"></a> [extra\_user\_data\_content](#input\_extra\_user\_data\_content) | Additional scripting to pass to the bastion host. For example, this can include installing PostgreSQL for the `psql` command. | `string` | `""` | no |
| <a name="input_hosted_zone_id"></a> [hosted\_zone\_id](#input\_hosted\_zone\_id) | Name of the hosted zone where we'll register the bastion DNS name | `string` | `""` | no |
| <a name="input_http_endpoint"></a> [http\_endpoint](#input\_http\_endpoint) | Whether the metadata service is available. | `bool` | `true` | no |
| <a name="input_http_put_response_hop_limit"></a> [http\_put\_response\_hop\_limit](#input\_http\_put\_response\_hop\_limit) | The desired HTTP PUT response hop limit for instance metadata requests. | `number` | `1` | no |
| <a name="input_http_endpoint"></a> [http\_endpoint](#input\_http\_endpoint) | Whether the metadata service is available | `bool` | `true` | no |
| <a name="input_http_put_response_hop_limit"></a> [http\_put\_response\_hop\_limit](#input\_http\_put\_response\_hop\_limit) | The desired HTTP PUT response hop limit for instance metadata requests | `number` | `1` | no |
| <a name="input_instance_type"></a> [instance\_type](#input\_instance\_type) | Instance size of the bastion | `string` | `"t3.nano"` | no |
| <a name="input_ipv6_cidrs"></a> [ipv6\_cidrs](#input\_ipv6\_cidrs) | List of IPv6 CIDRs than can access to the bastion. Default : ::/0 | `list(string)` | <pre>[<br> "::/0"<br>]</pre> | no |
| <a name="input_is_lb_private"></a> [is\_lb\_private](#input\_is\_lb\_private) | If TRUE the load balancer scheme will be "internal" else "internet-facing" | `any` | n/a | yes |
| <a name="input_ipv6_cidrs"></a> [ipv6\_cidrs](#input\_ipv6\_cidrs) | List of IPv6 CIDRs that can access the bastion. Default: ::/0 | `list(string)` | <pre>[<br> "::/0"<br>]</pre> | no |
| <a name="input_is_lb_private"></a> [is\_lb\_private](#input\_is\_lb\_private) | If TRUE, the load balancer scheme will be "internal" else "internet-facing" | `bool` | `null` | no |
| <a name="input_kms_enable_key_rotation"></a> [kms\_enable\_key\_rotation](#input\_kms\_enable\_key\_rotation) | Enable key rotation for the KMS key | `bool` | `false` | no |
| <a name="input_log_auto_clean"></a> [log\_auto\_clean](#input\_log\_auto\_clean) | Enable or not the lifecycle | `bool` | `false` | no |
| <a name="input_log_auto_clean"></a> [log\_auto\_clean](#input\_log\_auto\_clean) | Enable or disable the lifecycle | `bool` | `false` | no |
| <a name="input_log_expiry_days"></a> [log\_expiry\_days](#input\_log\_expiry\_days) | Number of days before logs expiration | `number` | `90` | no |
| <a name="input_log_glacier_days"></a> [log\_glacier\_days](#input\_log\_glacier\_days) | Number of days before moving logs to Glacier | `number` | `60` | no |
| <a name="input_log_standard_ia_days"></a> [log\_standard\_ia\_days](#input\_log\_standard\_ia\_days) | Number of days before moving logs to IA Storage | `number` | `30` | no |
| <a name="input_private_ssh_port"></a> [private\_ssh\_port](#input\_private\_ssh\_port) | Set the SSH port to use between the bastion and private instance | `number` | `22` | no |
| <a name="input_public_ssh_port"></a> [public\_ssh\_port](#input\_public\_ssh\_port) | Set the SSH port to use from desktop to the bastion | `number` | `22` | no |
| <a name="input_region"></a> [region](#input\_region) | n/a | `any` | n/a | yes |
| <a name="input_region"></a> [region](#input\_region) | n/a | `string` | n/a | yes |
| <a name="input_tags"></a> [tags](#input\_tags) | A mapping of tags to assign | `map(string)` | `{}` | no |
| <a name="input_use_imds_v2"></a> [use\_imds\_v2](#input\_use\_imds\_v2) | Use (IMDSv2) Instance Metadata Service V2 | `bool` | `false` | no |
| <a name="input_vpc_id"></a> [vpc\_id](#input\_vpc\_id) | VPC id where we'll deploy the bastion | `any` | n/a | yes |
| <a name="input_vpc_id"></a> [vpc\_id](#input\_vpc\_id) | VPC ID where we'll deploy the bastion | `string` | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_bastion_auto_scaling_group_name"></a> [bastion\_auto\_scaling\_group\_name](#output\_bastion\_auto\_scaling\_group\_name) | n/a |
| <a name="output_bastion_elb_id"></a> [bastion\_elb\_id](#output\_bastion\_elb\_id) | n/a |
| <a name="output_bastion_host_security_group"></a> [bastion\_host\_security\_group](#output\_bastion\_host\_security\_group) | n/a |
| <a name="output_bucket_arn"></a> [bucket\_arn](#output\_bucket\_arn) | n/a |
| <a name="output_bucket_kms_key_alias"></a> [bucket\_kms\_key\_alias](#output\_bucket\_kms\_key\_alias) | n/a |
| <a name="output_bucket_kms_key_arn"></a> [bucket\_kms\_key\_arn](#output\_bucket\_kms\_key\_arn) | n/a |
| <a name="output_bucket_name"></a> [bucket\_name](#output\_bucket\_name) | n/a |
| <a name="output_elb_arn"></a> [elb\_arn](#output\_elb\_arn) | n/a |
| <a name="output_elb_ip"></a> [elb\_ip](#output\_elb\_ip) | n/a |
| <a name="output_private_instances_security_group"></a> [private\_instances\_security\_group](#output\_private\_instances\_security\_group) | n/a |
| <a name="output_target_group_arn"></a> [target\_group\_arn](#output\_target\_group\_arn) | n/a |
| <a name="output_bastion_auto_scaling_group_name"></a> [bastion\_auto\_scaling\_group\_name](#output\_bastion\_auto\_scaling\_group\_name) | The name of the Auto Scaling Group for bastion hosts |
| <a name="output_bastion_elb_id"></a> [bastion\_elb\_id](#output\_bastion\_elb\_id) | The ID of the ELB for bastion hosts |
| <a name="output_bastion_host_security_group"></a> [bastion\_host\_security\_group](#output\_bastion\_host\_security\_group) | The ID of the bastion host security group |
| <a name="output_bucket_arn"></a> [bucket\_arn](#output\_bucket\_arn) | The ARN of the S3 bucket |
| <a name="output_bucket_kms_key_alias"></a> [bucket\_kms\_key\_alias](#output\_bucket\_kms\_key\_alias) | The name of the KMS key alias for the bucket |
| <a name="output_bucket_kms_key_arn"></a> [bucket\_kms\_key\_arn](#output\_bucket\_kms\_key\_arn) | The ARN of the KMS key for the bucket |
| <a name="output_bucket_name"></a> [bucket\_name](#output\_bucket\_name) | The ID of the S3 bucket |
| <a name="output_elb_arn"></a> [elb\_arn](#output\_elb\_arn) | The ARN of the ELB for bastion hosts |
| <a name="output_elb_ip"></a> [elb\_ip](#output\_elb\_ip) | The DNS name of the ELB for bastion hosts |
| <a name="output_private_instances_security_group"></a> [private\_instances\_security\_group](#output\_private\_instances\_security\_group) | The ID of the security group for private instances |
| <a name="output_target_group_arn"></a> [target\_group\_arn](#output\_target\_group\_arn) | The ARN of the target group for the ELB |
<!-- END_TF_DOCS -->

Known issues
Expand Down
31 changes: 22 additions & 9 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ resource "aws_security_group" "bastion_host_security_group" {
}

resource "aws_security_group_rule" "ingress_bastion" {
count = var.bastion_security_group_id == "" ? 1 : 0
count = var.bastion_security_group_id == "" && var.create_elb ? 1 : 0
description = "Incoming traffic to bastion"
type = "ingress"
from_port = var.public_ssh_port
Expand Down Expand Up @@ -148,26 +148,37 @@ resource "aws_route53_record" "bastion_record_name" {
name = var.bastion_record_name
zone_id = var.hosted_zone_id
type = "A"
count = var.create_dns_record ? 1 : 0
count = var.create_dns_record && var.create_elb ? 1 : 0

alias {
evaluate_target_health = true
name = aws_lb.bastion_lb.dns_name
zone_id = aws_lb.bastion_lb.zone_id
name = aws_lb.bastion_lb[0].dns_name
zone_id = aws_lb.bastion_lb[0].zone_id
}
}

resource "aws_lb" "bastion_lb" {
count = var.create_elb ? 1 : 0

internal = var.is_lb_private
name = "${local.name_prefix}-lb"

subnets = var.elb_subnets

load_balancer_type = "network"
tags = merge(var.tags)

lifecycle {
precondition {
condition = !var.create_elb || (length(var.elb_subnets) > 0 && var.is_lb_private != null)
error_message = "elb_subnets and is_lb_private must be set when creating a load balancer"
}
}
}

resource "aws_lb_target_group" "bastion_lb_target_group" {
count = var.create_elb ? 1 : 0

name = "${local.name_prefix}-lb-target"
port = var.public_ssh_port
protocol = "TCP"
Expand All @@ -183,12 +194,14 @@ resource "aws_lb_target_group" "bastion_lb_target_group" {
}

resource "aws_lb_listener" "bastion_lb_listener_22" {
count = var.create_elb ? 1 : 0

default_action {
target_group_arn = aws_lb_target_group.bastion_lb_target_group.arn
target_group_arn = aws_lb_target_group.bastion_lb_target_group[0].arn
type = "forward"
}

load_balancer_arn = aws_lb.bastion_lb.arn
load_balancer_arn = aws_lb.bastion_lb[0].arn
port = var.public_ssh_port
protocol = "TCP"
}
Expand Down Expand Up @@ -275,9 +288,9 @@ resource "aws_autoscaling_group" "bastion_auto_scaling_group" {
health_check_grace_period = 180
health_check_type = "EC2"

target_group_arns = [
aws_lb_target_group.bastion_lb_target_group.arn,
]
target_group_arns = var.create_elb ? [
aws_lb_target_group.bastion_lb_target_group[0].arn,
] : null

termination_policies = [
"OldestLaunchConfiguration",
Expand Down
55 changes: 33 additions & 22 deletions outputs.tf
Original file line number Diff line number Diff line change
@@ -1,43 +1,54 @@
output "bastion_host_security_group" {
value = aws_security_group.bastion_host_security_group[*].id
output "bastion_auto_scaling_group_name" {
description = "The name of the Auto Scaling Group for bastion hosts"
value = aws_autoscaling_group.bastion_auto_scaling_group.name
}

output "bucket_kms_key_alias" {
value = aws_kms_alias.alias.name
output "bastion_elb_id" {
description = "The ID of the ELB for bastion hosts"
value = aws_lb.bastion_lb.id
}

output "bucket_kms_key_arn" {
value = aws_kms_key.key.arn
output "bastion_host_security_group" {
description = "The ID of the bastion host security group"
value = aws_security_group.bastion_host_security_group[*].id
}

output "bucket_name" {
value = aws_s3_bucket.bucket.id
output "bucket_arn" {
description = "The ARN of the S3 bucket"
value = aws_s3_bucket.bucket.arn
}

output "bucket_arn" {
value = aws_s3_bucket.bucket.arn
output "bucket_kms_key_alias" {
description = "The name of the KMS key alias for the bucket"
value = aws_kms_alias.alias.name
}

output "elb_ip" {
value = aws_lb.bastion_lb.dns_name
output "bucket_kms_key_arn" {
description = "The ARN of the KMS key for the bucket"
value = aws_kms_key.key.arn
}

output "elb_arn" {
value = aws_lb.bastion_lb.arn
output "bucket_name" {
description = "The ID of the S3 bucket"
value = aws_s3_bucket.bucket.id
}

output "target_group_arn" {
value = aws_lb_target_group.bastion_lb_target_group.arn
output "elb_arn" {
description = "The ARN of the ELB for bastion hosts"
value = var.create_elb ? aws_lb.bastion_lb[0].arn : null
}

output "private_instances_security_group" {
value = aws_security_group.private_instances_security_group.id
output "elb_ip" {
description = "The DNS name of the ELB for bastion hosts"
value = var.create_elb ? aws_lb.bastion_lb[0].dns_name : null
}

output "bastion_auto_scaling_group_name" {
value = aws_autoscaling_group.bastion_auto_scaling_group.name
output "private_instances_security_group" {
description = "The ID of the security group for private instances"
value = aws_security_group.private_instances_security_group.id
}

output "bastion_elb_id" {
value = aws_lb.bastion_lb.id
output "target_group_arn" {
description = "The ARN of the target group for the ELB"
value = var.create_elb ? aws_lb_target_group.bastion_lb_target_group[0].arn : null
}
Loading

0 comments on commit 49a88a0

Please sign in to comment.