Skip to content

Commit 472cc5f

Browse files
npalmgithub-aws-runners-pr|botdependabot[bot]runners-releaser[bot]
authored
feat: migrate launch template to use SSM for AMI lookup (#4517)
# Description This PR migrates the launch template to use SSM to foor looking up AMI ID. This PR is inteded to migrate to use SSM for AMI lookups. In later PR we will remove logic from scale-up and remove old parateters. By default, the module still uses the same AMI filters, but difference is the resulting AMI ID is stored in SSM instead of the launch template. As alternative the module user can provide `ami_id_ssm_parameter_arn` pointing to an SSM parameter containing the AMI ID to be used (data type aws:ec2:image). When using a custom managed AMI this will avoid drift in terraform when `ami.id_ssm_parameter_arn` is used instead of the deprecated `ami_id_ssm_parameter_name`. Another way to avoid the drift is to ensure the filter is poiting to the same image. See also #4460 In PR #4488 and updater via Lambda is introduced. I think we should firt think how we can better support the AMI id in the core. What this PR is supposed todo. NExt the update can be an nice way to auto update AMI's without running terraform. The PR also refactor the variables for `ami_*` and move the to a dedicated object `ami`. The old ones remains till the next major release. Deprecattion warnings are added to the output. ## Notes - Adjuest multi runner examples - Test with multi runners - Test with default runners + pool ## Fix - Deprecation warning inline_poilicy for pool --------- Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: github-aws-runners-pr|bot <github-aws-runners-pr[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: runners-releaser[bot] <194412594+runners-releaser[bot]@users.noreply.github.com>
1 parent b3e91e0 commit 472cc5f

30 files changed

+321
-82
lines changed

README.md

+7-5
Original file line numberDiff line numberDiff line change
@@ -106,16 +106,17 @@ Join our discord community via [this invite link](https://discord.gg/bxgXW8jJGh)
106106

107107
| Name | Description | Type | Default | Required |
108108
|------|-------------|------|---------|:--------:|
109-
| <a name="input_ami_filter"></a> [ami\_filter](#input\_ami\_filter) | Map of lists used to create the AMI filter for the action runner AMI. | `map(list(string))` | <pre>{<br/> "state": [<br/> "available"<br/> ]<br/>}</pre> | no |
109+
| <a name="input_ami"></a> [ami](#input\_ami) | AMI configuration for the action runner instances. This object allows you to specify all AMI-related settings in one place.<br/><br/>Parameters:<br/>- `filter`: Map of lists to filter AMIs by various criteria (e.g., { name = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-*"], state = ["available"] })<br/>- `owners`: List of AMI owners to limit the search. Common values: ["amazon"], ["self"], or specific AWS account IDs<br/>- `id_ssm_parameter_name`: Name of an SSM parameter containing the AMI ID. If specified, this overrides the AMI filter<br/>- `id_ssm_parameter_arn`: ARN of an SSM parameter containing the AMI ID. If specified, this overrides both AMI filter and parameter name<br/>- `kms_key_arn`: Optional KMS key ARN if the AMI is encrypted with a customer managed key<br/><br/>Defaults to null, in which case the module falls back to individual AMI variables (deprecated). | <pre>object({<br/> filter = optional(map(list(string)), { state = ["available"] })<br/> owners = optional(list(string), ["amazon"])<br/> id_ssm_parameter_arn = optional(string, null)<br/> kms_key_arn = optional(string, null)<br/> })</pre> | `null` | no |
110+
| <a name="input_ami_filter"></a> [ami\_filter](#input\_ami\_filter) | [DEPRECATED: Use ami.filter] Map of lists used to create the AMI filter for the action runner AMI. | `map(list(string))` | <pre>{<br/> "state": [<br/> "available"<br/> ]<br/>}</pre> | no |
110111
| <a name="input_ami_housekeeper_cleanup_config"></a> [ami\_housekeeper\_cleanup\_config](#input\_ami\_housekeeper\_cleanup\_config) | Configuration for AMI cleanup.<br/><br/> `amiFilters` - Filters to use when searching for AMIs to cleanup. Default filter for images owned by the account and that are available.<br/> `dryRun` - If true, no AMIs will be deregistered. Default false.<br/> `launchTemplateNames` - Launch template names to use when searching for AMIs to cleanup. Default no launch templates.<br/> `maxItems` - The maximum numer of AMI's tha will be queried for cleanup. Default no maximum.<br/> `minimumDaysOld` - Minimum number of days old an AMI must be to be considered for cleanup. Default 30.<br/> `ssmParameterNames` - SSM parameter names to use when searching for AMIs to cleanup. This parameter should be set when using SSM to configure the AMI to use. Default no SSM parameters. | <pre>object({<br/> amiFilters = optional(list(object({<br/> Name = string<br/> Values = list(string)<br/> })),<br/> [{<br/> Name : "state",<br/> Values : ["available"],<br/> },<br/> {<br/> Name : "image-type",<br/> Values : ["machine"],<br/> }]<br/> )<br/> dryRun = optional(bool, false)<br/> launchTemplateNames = optional(list(string))<br/> maxItems = optional(number)<br/> minimumDaysOld = optional(number, 30)<br/> ssmParameterNames = optional(list(string))<br/> })</pre> | `{}` | no |
111112
| <a name="input_ami_housekeeper_lambda_s3_key"></a> [ami\_housekeeper\_lambda\_s3\_key](#input\_ami\_housekeeper\_lambda\_s3\_key) | S3 key for syncer lambda function. Required if using S3 bucket to specify lambdas. | `string` | `null` | no |
112113
| <a name="input_ami_housekeeper_lambda_s3_object_version"></a> [ami\_housekeeper\_lambda\_s3\_object\_version](#input\_ami\_housekeeper\_lambda\_s3\_object\_version) | S3 object version for syncer lambda function. Useful if S3 versioning is enabled on source bucket. | `string` | `null` | no |
113114
| <a name="input_ami_housekeeper_lambda_schedule_expression"></a> [ami\_housekeeper\_lambda\_schedule\_expression](#input\_ami\_housekeeper\_lambda\_schedule\_expression) | Scheduler expression for action runner binary syncer. | `string` | `"rate(1 day)"` | no |
114115
| <a name="input_ami_housekeeper_lambda_timeout"></a> [ami\_housekeeper\_lambda\_timeout](#input\_ami\_housekeeper\_lambda\_timeout) | Time out of the lambda in seconds. | `number` | `300` | no |
115116
| <a name="input_ami_housekeeper_lambda_zip"></a> [ami\_housekeeper\_lambda\_zip](#input\_ami\_housekeeper\_lambda\_zip) | File location of the lambda zip file. | `string` | `null` | no |
116-
| <a name="input_ami_id_ssm_parameter_name"></a> [ami\_id\_ssm\_parameter\_name](#input\_ami\_id\_ssm\_parameter\_name) | Externally managed SSM parameter (of data type aws:ec2:image) that contains the AMI ID to launch runner instances from. Overrides ami\_filter | `string` | `null` | no |
117-
| <a name="input_ami_kms_key_arn"></a> [ami\_kms\_key\_arn](#input\_ami\_kms\_key\_arn) | Optional CMK Key ARN to be used to launch an instance from a shared encrypted AMI | `string` | `null` | no |
118-
| <a name="input_ami_owners"></a> [ami\_owners](#input\_ami\_owners) | The list of owners used to select the AMI of action runner instances. | `list(string)` | <pre>[<br/> "amazon"<br/>]</pre> | no |
117+
| <a name="input_ami_id_ssm_parameter_name"></a> [ami\_id\_ssm\_parameter\_name](#input\_ami\_id\_ssm\_parameter\_name) | [DEPRECATED: Use ami.id\_ssm\_parameter\_name] String used to construct the SSM parameter name used to resolve the latest AMI ID for the runner instances. The SSM parameter should be of type String and contain a valid AMI ID. The default behavior is to use the latest Ubuntu 22.04 AMI. | `string` | `null` | no |
118+
| <a name="input_ami_kms_key_arn"></a> [ami\_kms\_key\_arn](#input\_ami\_kms\_key\_arn) | [DEPRECATED: Use ami.kms\_key\_arn] Optional CMK Key ARN to be used to launch an instance from a shared encrypted AMI | `string` | `null` | no |
119+
| <a name="input_ami_owners"></a> [ami\_owners](#input\_ami\_owners) | [DEPRECATED: Use ami.owners] The list of owners that should be used to find the AMI. | `list(string)` | <pre>[<br/> "amazon"<br/>]</pre> | no |
119120
| <a name="input_associate_public_ipv4_address"></a> [associate\_public\_ipv4\_address](#input\_associate\_public\_ipv4\_address) | Associate public IPv4 with the runner. Only tested with IPv4 | `bool` | `false` | no |
120121
| <a name="input_aws_partition"></a> [aws\_partition](#input\_aws\_partition) | (optiona) partition in the arn namespace to use if not 'aws' | `string` | `"aws"` | no |
121122
| <a name="input_aws_region"></a> [aws\_region](#input\_aws\_region) | AWS region. | `string` | n/a | yes |
@@ -141,7 +142,7 @@ Join our discord community via [this invite link](https://discord.gg/bxgXW8jJGh)
141142
| <a name="input_eventbridge"></a> [eventbridge](#input\_eventbridge) | Enable the use of EventBridge by the module. By enabling this feature events will be put on the EventBridge by the webhook instead of directly dispatching to queues for scaling.<br/><br/> `enable`: Enable the EventBridge feature.<br/> `accept_events`: List can be used to only allow specific events to be putted on the EventBridge. By default all events, empty list will be be interpreted as all events. | <pre>object({<br/> enable = optional(bool, true)<br/> accept_events = optional(list(string), null)<br/> })</pre> | `{}` | no |
142143
| <a name="input_ghes_ssl_verify"></a> [ghes\_ssl\_verify](#input\_ghes\_ssl\_verify) | GitHub Enterprise SSL verification. Set to 'false' when custom certificate (chains) is used for GitHub Enterprise Server (insecure). | `bool` | `true` | no |
143144
| <a name="input_ghes_url"></a> [ghes\_url](#input\_ghes\_url) | GitHub Enterprise Server URL. Example: https://github.internal.co - DO NOT SET IF USING PUBLIC GITHUB. However if you are using Github Enterprise Cloud with data-residency (ghe.com), set the endpoint here. Example - https://companyname.ghe.com | `string` | `null` | no |
144-
| <a name="input_github_app"></a> [github\_app](#input\_github\_app) | GitHub app parameters, see your github app. <br/> You can optionally create the SSM parameters yourself and provide the ARN and name here, through the `*_ssm` attributes.<br/> If you chose to provide the configuration values directly here, <br/> please ensure the key is the base64-encoded `.pem` file (the output of `base64 app.private-key.pem`, not the content of `private-key.pem`).<br/> Note: the provided SSM parameters arn and name have a precedence over the actual value (i.e `key_base64_ssm` has a precedence over `key_base64` etc). | <pre>object({<br/> key_base64 = optional(string)<br/> key_base64_ssm = optional(object({<br/> arn = string<br/> name = string<br/> }))<br/> id = optional(string)<br/> id_ssm = optional(object({<br/> arn = string<br/> name = string<br/> }))<br/> webhook_secret = optional(string)<br/> webhook_secret_ssm = optional(object({<br/> arn = string<br/> name = string<br/> }))<br/> })</pre> | n/a | yes |
145+
| <a name="input_github_app"></a> [github\_app](#input\_github\_app) | GitHub app parameters, see your github app.<br/> You can optionally create the SSM parameters yourself and provide the ARN and name here, through the `*_ssm` attributes.<br/> If you chose to provide the configuration values directly here,<br/> please ensure the key is the base64-encoded `.pem` file (the output of `base64 app.private-key.pem`, not the content of `private-key.pem`).<br/> Note: the provided SSM parameters arn and name have a precedence over the actual value (i.e `key_base64_ssm` has a precedence over `key_base64` etc). | <pre>object({<br/> key_base64 = optional(string)<br/> key_base64_ssm = optional(object({<br/> arn = string<br/> name = string<br/> }))<br/> id = optional(string)<br/> id_ssm = optional(object({<br/> arn = string<br/> name = string<br/> }))<br/> webhook_secret = optional(string)<br/> webhook_secret_ssm = optional(object({<br/> arn = string<br/> name = string<br/> }))<br/> })</pre> | n/a | yes |
145146
| <a name="input_idle_config"></a> [idle\_config](#input\_idle\_config) | List of time periods, defined as a cron expression, to keep a minimum amount of runners active instead of scaling down to 0. By defining this list you can ensure that in time periods that match the cron expression within 5 seconds a runner is kept idle. | <pre>list(object({<br/> cron = string<br/> timeZone = string<br/> idleCount = number<br/> evictionStrategy = optional(string, "oldest_first")<br/> }))</pre> | `[]` | no |
146147
| <a name="input_instance_allocation_strategy"></a> [instance\_allocation\_strategy](#input\_instance\_allocation\_strategy) | The allocation strategy for spot instances. AWS recommends using `price-capacity-optimized` however the AWS default is `lowest-price`. | `string` | `"lowest-price"` | no |
147148
| <a name="input_instance_max_spot_price"></a> [instance\_max\_spot\_price](#input\_instance\_max\_spot\_price) | Max price price for spot instances per hour. This variable will be passed to the create fleet as max spot price for the fleet. | `string` | `null` | no |
@@ -239,6 +240,7 @@ Join our discord community via [this invite link](https://discord.gg/bxgXW8jJGh)
239240
| Name | Description |
240241
|------|-------------|
241242
| <a name="output_binaries_syncer"></a> [binaries\_syncer](#output\_binaries\_syncer) | n/a |
243+
| <a name="output_deprecated_variables_warning"></a> [deprecated\_variables\_warning](#output\_deprecated\_variables\_warning) | Warning for deprecated variables usage. These variables will be removed in a future release. Please migrate to using the consolidated 'ami' object. |
242244
| <a name="output_instance_termination_handler"></a> [instance\_termination\_handler](#output\_instance\_termination\_handler) | n/a |
243245
| <a name="output_instance_termination_watcher"></a> [instance\_termination\_watcher](#output\_instance\_termination\_watcher) | n/a |
244246
| <a name="output_queues"></a> [queues](#output\_queues) | SQS queues. |

docs/configuration.md

+36
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,42 @@ The option `job_retry.delay_in_seconds` is the delay before the job status is ch
163163

164164
This module also allows you to run agents from a prebuilt AMI to gain faster startup times. The module provides several examples to build your own custom AMI. To remove old images, an [AMI housekeeper module](modules/public/ami-housekeeper.md) can be used. See the [AMI examples](ami-examples/index.md) for more details.
165165

166+
## AMI Configuration
167+
168+
By default, the module will automatically select appropriate AMI images:
169+
- For Linux x64: Amazon Linux 2023 x86_64
170+
- For Linux ARM64: Amazon Linux 2023 ARM64
171+
- For Windows: Windows Server 2022 English Full ECS Optimized
172+
173+
However, you can override these defaults using the `ami` object in two ways:
174+
175+
1. **Using AMI Filters**
176+
177+
You can define filters and owners to look up an AMI. The module will store the AMI ID in an SSM parameter that is managed by the module.
178+
179+
```hcl
180+
ami = {
181+
filter = {
182+
name = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-*"]
183+
state = ["available"]
184+
}
185+
owners = ["amazon"]
186+
}
187+
```
188+
189+
2. **Using SSM Parameter**
190+
191+
Provide a parameter in SSM that contains the AMI ID. The parameter should be of type `String` and the module will grant the required lambdas access to this parameter.
192+
193+
```hcl
194+
ami = {
195+
id_ssm_parameter_arn = "arn:aws:ssm:region:account:parameter/path/to/ami/parameter"
196+
}
197+
```
198+
199+
> **Note:** The old way of configuring AMIs using individual variables (`ami_filter`, `ami_owners`, `ami_kms_key_arn`) is deprecated and will be removed in a future version. It is recommended to migrate to the new consolidated `ami` object.
200+
201+
166202
## Logging
167203

168204
The module uses [AWS Lambda Powertools](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/) for logging. By default the log level is set to `info`, by setting the log level to `debug` the incoming events of the Lambda are logged as well.

examples/default/.terraform.lock.hcl

+30-30
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/default/README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ terraform output -raw webhook_secret
4242

4343
| Name | Version |
4444
|------|---------|
45-
| <a name="provider_random"></a> [random](#provider\_random) | 3.6.3 |
45+
| <a name="provider_random"></a> [random](#provider\_random) | 3.7.1 |
4646

4747
## Modules
4848

@@ -70,6 +70,7 @@ terraform output -raw webhook_secret
7070

7171
| Name | Description |
7272
|------|-------------|
73+
| <a name="output_deprecated_variables_warning"></a> [deprecated\_variables\_warning](#output\_deprecated\_variables\_warning) | n/a |
7374
| <a name="output_runners"></a> [runners](#output\_runners) | n/a |
7475
| <a name="output_webhook_endpoint"></a> [webhook\_endpoint](#output\_webhook\_endpoint) | n/a |
7576
| <a name="output_webhook_secret"></a> [webhook\_secret](#output\_webhook\_secret) | n/a |

examples/default/main.tf

+1
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ module "runners" {
141141

142142
# enable CMK instead of aws managed key for encryptions
143143
# kms_key_arn = aws_kms_key.github.arn
144+
144145
}
145146

146147
module "webhook_github_app" {

examples/default/outputs.tf

+5
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,8 @@ output "webhook_secret" {
1313
value = random_id.random.hex
1414
}
1515

16+
output "deprecated_variables_warning" {
17+
value = join("", [
18+
module.runners.deprecated_variables_warning,
19+
])
20+
}

0 commit comments

Comments
 (0)