From 4d6d2378ca2a259ff0c69d4f9d760b305aec075c Mon Sep 17 00:00:00 2001 From: Matt Gowie Date: Sat, 17 Feb 2024 23:57:16 -0700 Subject: [PATCH 1/2] feat: roll instances + modify ASG sizes + add aqua --- README.md | 10 +++++----- aqua.yaml | 15 +++++++++++++++ main.tf | 45 ++++++++++++++++++++++++++++++--------------- variables.tf | 28 ++++++++++++++++++++-------- versions.tf | 4 +--- 5 files changed, 71 insertions(+), 31 deletions(-) create mode 100644 aqua.yaml diff --git a/README.md b/README.md index 3511821..bea2fcc 100644 --- a/README.md +++ b/README.md @@ -74,15 +74,13 @@ Use [the awesome `gossm` project](https://github.com/gjbae1212/gossm). | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 0.13.0 | -| [aws](#requirement\_aws) | >= 4.0 | -| [local](#requirement\_local) | >= 1.2 | -| [null](#requirement\_null) | >= 2.0 | +| [aws](#requirement\_aws) | >= 5.0 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 4.0 | +| [aws](#provider\_aws) | >= 5.0 | ## Modules @@ -129,19 +127,21 @@ Use [the awesome `gossm` project](https://github.com/gjbae1212/gossm). | [create\_run\_shell\_document](#input\_create\_run\_shell\_document) | Whether or not to create the SSM-SessionManagerRunShell SSM Document. | `bool` | `true` | no | | [delimiter](#input\_delimiter) | Delimiter to be used between ID elements.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | | [descriptor\_formats](#input\_descriptor\_formats) | Describe additional descriptors to be output in the `descriptors` output map.
Map of maps. Keys are names of descriptors. Values are maps of the form
`{
format = string
labels = list(string)
}`
(Type is `any` so the map values can later be enhanced to provide additional options.)
`format` is a Terraform format string to be passed to the `format()` function.
`labels` is a list of labels, in order, to pass to `format()` function.
Label values will be normalized before being passed to `format()` so they will be
identical to how they appear in `id`.
Default is `{}` (`descriptors` output will be empty). | `any` | `{}` | no | +| [desired\_capacity](#input\_desired\_capacity) | Desired number of instances in the Auto Scaling Group | `number` | `1` | no | | [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no | | [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | | [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`. | `number` | `null` | no | -| [instance\_count](#input\_instance\_count) | The number of SSM Agent instances you would like to deploy. | `number` | `1` | no | | [instance\_type](#input\_instance\_type) | The instance type to use for the SSM Agent EC2 Instnace. | `string` | `"t3.nano"` | no | | [key\_pair\_name](#input\_key\_pair\_name) | The name of the key-pair to associate with the SSM Agent instances. This can be (and probably should) left empty unless you specifically plan to use `AWS-StartSSHSession`. | `string` | `null` | no | | [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.
Does not affect keys of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | | [label\_order](#input\_label\_order) | The order in which the labels (ID elements) appear in the `id`.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no | | [label\_value\_case](#input\_label\_value\_case) | Controls the letter case of ID elements (labels) as included in `id`,
set as tag values, and output by this module individually.
Does not affect values of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.
Default value: `lower`. | `string` | `null` | no | | [labels\_as\_tags](#input\_labels\_as\_tags) | Set of labels (ID elements) to include as tags in the `tags` output.
Default is to include all labels.
Tags with empty values will not be included in the `tags` output.
Set to `[]` to suppress all generated tags.
**Notes:**
The value of the `name` tag, if included, will be the `id`, not the `name`.
Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be
changed in later chained modules. Attempts to change it will be silently ignored. | `set(string)` |
[
"default"
]
| no | +| [max\_size](#input\_max\_size) | Maximum number of instances in the Auto Scaling Group | `number` | `2` | no | | [metadata\_http\_endpoint\_enabled](#input\_metadata\_http\_endpoint\_enabled) | Whether or not to enable the metadata http endpoint | `bool` | `true` | no | | [metadata\_http\_protocol\_ipv6\_enabled](#input\_metadata\_http\_protocol\_ipv6\_enabled) | Enable IPv6 metadata endpoint | `bool` | `false` | no | | [metadata\_imdsv2\_enabled](#input\_metadata\_imdsv2\_enabled) | Whether or not the metadata service requires session tokens,
also referred to as Instance Metadata Service Version 2 (IMDSv2). | `bool` | `true` | no | +| [min\_size](#input\_min\_size) | Minimum number of instances in the Auto Scaling Group | `number` | `1` | no | | [monitoring\_enabled](#input\_monitoring\_enabled) | Enable detailed monitoring of instance | `bool` | `true` | no | | [name](#input\_name) | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.
This is the only ID element not also included as a `tag`.
The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input. | `string` | `null` | no | | [namespace](#input\_namespace) | ID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique | `string` | `null` | no | diff --git a/aqua.yaml b/aqua.yaml new file mode 100644 index 0000000..e0c692e --- /dev/null +++ b/aqua.yaml @@ -0,0 +1,15 @@ +--- +# aqua - Declarative CLI Version Manager +# https://aquaproj.github.io/ +# checksum: +# enabled: true +# require_checksum: true +# supported_envs: +# - all +registries: +- type: standard + ref: v4.137.0 # renovate: depName=aquaproj/aqua-registry +packages: +- name: terraform-docs/terraform-docs@v0.17.0 +- name: hashicorp/terraform@v1.7.3 +- name: opentofu/opentofu@v1.6.1 diff --git a/main.tf b/main.tf index b1be649..50b7065 100644 --- a/main.tf +++ b/main.tf @@ -275,6 +275,8 @@ resource "aws_launch_template" "default" { key_name = var.key_pair_name user_data = base64encode(var.user_data) + update_default_version = true + monitoring { enabled = var.monitoring_enabled } @@ -312,22 +314,13 @@ resource "aws_launch_template" "default" { resource "aws_autoscaling_group" "default" { name_prefix = "${module.this.id}-asg" - dynamic "tag" { - for_each = module.this.tags - content { - key = tag.key - value = tag.value - propagate_at_launch = true - } - } - launch_template { - id = aws_launch_template.default.id - version = "$Latest" - } - max_size = var.instance_count - min_size = var.instance_count - desired_capacity = var.instance_count + max_size = var.max_size + min_size = var.min_size + desired_capacity = var.desired_capacity + + # We don't care to protect from scale in by default, as we want to roll instances frequently + protect_from_scale_in = false vpc_zone_identifier = var.subnet_ids @@ -339,6 +332,28 @@ resource "aws_autoscaling_group" "default" { "OldestLaunchConfiguration", ] + launch_template { + id = aws_launch_template.default.id + version = aws_launch_template.default.latest_version + } + + instance_refresh { + strategy = "Rolling" + triggers = ["tag"] + preferences { + min_healthy_percentage = 50 + } + } + + dynamic "tag" { + for_each = module.this.tags + content { + key = tag.key + value = tag.value + propagate_at_launch = true + } + } + lifecycle { create_before_destroy = true } diff --git a/variables.tf b/variables.tf index 44a29be..80fb5ee 100644 --- a/variables.tf +++ b/variables.tf @@ -30,12 +30,6 @@ variable "ami" { description = "The AMI to use for the SSM Agent EC2 Instance. If not provided, the latest Amazon Linux 2 AMI will be used. Note: This will update periodically as AWS releases updates to their AL2 AMI. Pin to a specific AMI if you would like to avoid these updates." } -variable "instance_count" { - default = 1 - type = number - description = "The number of SSM Agent instances you would like to deploy." -} - variable "user_data" { default = < Date: Mon, 19 Feb 2024 11:25:13 -0700 Subject: [PATCH 2/2] chore: @gberenice's feedback + bumps 1.0 tf + time provider --- README.md | 9 ++++++--- main.tf | 7 ++++--- variables.tf | 21 +++++++++++++++++++-- versions.tf | 12 ++++++++++-- 4 files changed, 39 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index bea2fcc..b786ec2 100644 --- a/README.md +++ b/README.md @@ -73,14 +73,15 @@ Use [the awesome `gossm` project](https://github.com/gjbae1212/gossm). | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 0.13.0 | +| [terraform](#requirement\_terraform) | >= 1.0 | | [aws](#requirement\_aws) | >= 5.0 | +| [time](#requirement\_time) | >= 0.7 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.0 | +| [aws](#provider\_aws) | 5.37.0 | ## Modules @@ -131,7 +132,7 @@ Use [the awesome `gossm` project](https://github.com/gjbae1212/gossm). | [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no | | [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | | [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`. | `number` | `null` | no | -| [instance\_type](#input\_instance\_type) | The instance type to use for the SSM Agent EC2 Instnace. | `string` | `"t3.nano"` | no | +| [instance\_type](#input\_instance\_type) | The instance type to use for the SSM Agent EC2 instance. | `string` | `"t4g.nano"` | no | | [key\_pair\_name](#input\_key\_pair\_name) | The name of the key-pair to associate with the SSM Agent instances. This can be (and probably should) left empty unless you specifically plan to use `AWS-StartSSHSession`. | `string` | `null` | no | | [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.
Does not affect keys of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | | [label\_order](#input\_label\_order) | The order in which the labels (ID elements) appear in the `id`.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no | @@ -146,8 +147,10 @@ Use [the awesome `gossm` project](https://github.com/gjbae1212/gossm). | [name](#input\_name) | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.
This is the only ID element not also included as a `tag`.
The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input. | `string` | `null` | no | | [namespace](#input\_namespace) | ID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique | `string` | `null` | no | | [permissions\_boundary](#input\_permissions\_boundary) | The ARN of the permissions boundary that will be applied to the SSM Agent role. | `string` | `""` | no | +| [protect\_from\_scale\_in](#input\_protect\_from\_scale\_in) | Allows setting instance protection for scale in actions on the ASG. | `bool` | `false` | no | | [regex\_replace\_chars](#input\_regex\_replace\_chars) | Terraform regular expression (regex) string.
Characters matching the regex will be removed from the ID elements.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | | [region](#input\_region) | The region to deploy the S3 bucket for session logs. If not supplied, the module will use the current region. | `string` | `""` | no | +| [scale\_in\_protected\_instances](#input\_scale\_in\_protected\_instances) | Behavior when encountering instances protected from scale in are found. Available behaviors are Refresh, Ignore, and Wait. Default is Ignore. | `string` | `"Ignore"` | no | | [session\_logging\_bucket\_name](#input\_session\_logging\_bucket\_name) | The name of the S3 Bucket to ship session logs to. This will remove creation of an independent session logging bucket. This is only relevant if the session\_logging\_enabled variable is `true`. | `string` | `""` | no | | [session\_logging\_enabled](#input\_session\_logging\_enabled) | To enable CloudWatch and S3 session logging or not. Note this does not apply to SSH sessions as AWS cannot log those sessions. | `bool` | `true` | no | | [session\_logging\_encryption\_enabled](#input\_session\_logging\_encryption\_enabled) | To enable CloudWatch and S3 session logging encryption or not. | `bool` | `true` | no | diff --git a/main.tf b/main.tf index 50b7065..ed9a7da 100644 --- a/main.tf +++ b/main.tf @@ -319,8 +319,8 @@ resource "aws_autoscaling_group" "default" { min_size = var.min_size desired_capacity = var.desired_capacity - # We don't care to protect from scale in by default, as we want to roll instances frequently - protect_from_scale_in = false + # By default, we don't care to protect from scale in as we want to roll instances frequently + protect_from_scale_in = var.protect_from_scale_in vpc_zone_identifier = var.subnet_ids @@ -341,7 +341,8 @@ resource "aws_autoscaling_group" "default" { strategy = "Rolling" triggers = ["tag"] preferences { - min_healthy_percentage = 50 + scale_in_protected_instances = var.scale_in_protected_instances + min_healthy_percentage = 50 } } diff --git a/variables.tf b/variables.tf index 80fb5ee..3a0cbfd 100644 --- a/variables.tf +++ b/variables.tf @@ -19,9 +19,9 @@ variable "permissions_boundary" { #################### variable "instance_type" { - default = "t3.nano" + default = "t4g.nano" type = string - description = "The instance type to use for the SSM Agent EC2 Instnace." + description = "The instance type to use for the SSM Agent EC2 instance." } variable "ami" { @@ -166,3 +166,20 @@ variable "desired_capacity" { type = number default = 1 } + +variable "protect_from_scale_in" { + description = "Allows setting instance protection for scale in actions on the ASG." + type = bool + default = false +} + +variable "scale_in_protected_instances" { + description = "Behavior when encountering instances protected from scale in are found. Available behaviors are Refresh, Ignore, and Wait. Default is Ignore." + type = string + default = "Ignore" + + validation { + condition = contains(["Refresh", "Ignore", "Wait"], var.scale_in_protected_instances) + error_message = "scale_in_protected_instances must be one of Refresh, Ignore, or Wait" + } +} diff --git a/versions.tf b/versions.tf index eb67af6..0b95c6e 100644 --- a/versions.tf +++ b/versions.tf @@ -1,7 +1,15 @@ terraform { - required_version = ">= 0.13.0" + required_version = ">= 1.0" required_providers { - aws = ">= 5.0" + aws = { + source = "hashicorp/aws" + version = ">= 5.0" + } + + time = { + source = "hashicorp/time" + version = ">= 0.7" + } } }