diff --git a/README.md b/README.md index 67a7438819..e264bdc3d5 100644 --- a/README.md +++ b/README.md @@ -106,16 +106,17 @@ Join our discord community via [this invite link](https://discord.gg/bxgXW8jJGh) | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [ami\_filter](#input\_ami\_filter) | Map of lists used to create the AMI filter for the action runner AMI. | `map(list(string))` |
{| no | +| [ami](#input\_ami) | AMI configuration for the action runner instances. This object allows you to specify all AMI-related settings in one place.
"state": [
"available"
]
}
object({| `null` | no | +| [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))` |
filter = optional(map(list(string)), { state = ["available"] })
owners = optional(list(string), ["amazon"])
id_ssm_parameter_arn = optional(string, null)
kms_key_arn = optional(string, null)
})
{| no | | [ami\_housekeeper\_cleanup\_config](#input\_ami\_housekeeper\_cleanup\_config) | Configuration for AMI cleanup.
"state": [
"available"
]
}
object({| `{}` | no | | [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 | | [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 | | [ami\_housekeeper\_lambda\_schedule\_expression](#input\_ami\_housekeeper\_lambda\_schedule\_expression) | Scheduler expression for action runner binary syncer. | `string` | `"rate(1 day)"` | no | | [ami\_housekeeper\_lambda\_timeout](#input\_ami\_housekeeper\_lambda\_timeout) | Time out of the lambda in seconds. | `number` | `300` | no | | [ami\_housekeeper\_lambda\_zip](#input\_ami\_housekeeper\_lambda\_zip) | File location of the lambda zip file. | `string` | `null` | no | -| [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 | -| [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 | -| [ami\_owners](#input\_ami\_owners) | The list of owners used to select the AMI of action runner instances. | `list(string)` |
amiFilters = optional(list(object({
Name = string
Values = list(string)
})),
[{
Name : "state",
Values : ["available"],
},
{
Name : "image-type",
Values : ["machine"],
}]
)
dryRun = optional(bool, false)
launchTemplateNames = optional(list(string))
maxItems = optional(number)
minimumDaysOld = optional(number, 30)
ssmParameterNames = optional(list(string))
})
[| no | +| [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 | +| [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 | +| [ami\_owners](#input\_ami\_owners) | [DEPRECATED: Use ami.owners] The list of owners that should be used to find the AMI. | `list(string)` |
"amazon"
]
[| no | | [associate\_public\_ipv4\_address](#input\_associate\_public\_ipv4\_address) | Associate public IPv4 with the runner. Only tested with IPv4 | `bool` | `false` | no | | [aws\_partition](#input\_aws\_partition) | (optiona) partition in the arn namespace to use if not 'aws' | `string` | `"aws"` | no | | [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) | [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.
"amazon"
]
object({| `{}` | no | | [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 | | [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 | -| [github\_app](#input\_github\_app) | GitHub app parameters, see your github app.
enable = optional(bool, true)
accept_events = optional(list(string), null)
})
object({| n/a | yes | +| [github\_app](#input\_github\_app) | GitHub app parameters, see your github app.
key_base64 = optional(string)
key_base64_ssm = optional(object({
arn = string
name = string
}))
id = optional(string)
id_ssm = optional(object({
arn = string
name = string
}))
webhook_secret = optional(string)
webhook_secret_ssm = optional(object({
arn = string
name = string
}))
})
object({| n/a | yes | | [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. |
key_base64 = optional(string)
key_base64_ssm = optional(object({
arn = string
name = string
}))
id = optional(string)
id_ssm = optional(object({
arn = string
name = string
}))
webhook_secret = optional(string)
webhook_secret_ssm = optional(object({
arn = string
name = string
}))
})
list(object({| `[]` | no | | [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 | | [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) | Name | Description | |------|-------------| | [binaries\_syncer](#output\_binaries\_syncer) | n/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. | | [instance\_termination\_handler](#output\_instance\_termination\_handler) | n/a | | [instance\_termination\_watcher](#output\_instance\_termination\_watcher) | n/a | | [queues](#output\_queues) | SQS queues. | diff --git a/docs/configuration.md b/docs/configuration.md index 39240b24d9..bcf6d13aa1 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -163,6 +163,42 @@ The option `job_retry.delay_in_seconds` is the delay before the job status is ch 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. +## AMI Configuration + +By default, the module will automatically select appropriate AMI images: +- For Linux x64: Amazon Linux 2023 x86_64 +- For Linux ARM64: Amazon Linux 2023 ARM64 +- For Windows: Windows Server 2022 English Full ECS Optimized + +However, you can override these defaults using the `ami` object in two ways: + +1. **Using AMI Filters** + +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. + +```hcl +ami = { + filter = { + name = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-*"] + state = ["available"] + } + owners = ["amazon"] +} +``` + +2. **Using SSM Parameter** + +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. + +```hcl +ami = { + id_ssm_parameter_arn = "arn:aws:ssm:region:account:parameter/path/to/ami/parameter" +} +``` + +> **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. + + ## Logging 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. diff --git a/examples/default/.terraform.lock.hcl b/examples/default/.terraform.lock.hcl index 045fb7350a..0e980ea45b 100644 --- a/examples/default/.terraform.lock.hcl +++ b/examples/default/.terraform.lock.hcl @@ -2,25 +2,25 @@ # Manual edits may be lost in future updates. provider "registry.terraform.io/hashicorp/aws" { - version = "5.82.1" - constraints = ">= 5.0.0, ~> 5.0, ~> 5.27" + version = "5.93.0" + constraints = ">= 5.0.0, ~> 5.0, ~> 5.27, ~> 5.77" hashes = [ - "h1:QTOtDMehUfiD3wDbbDuXYuTqGgLDkKK9Agkd5NCUEic=", - "zh:0fde8533282973f1f5d33b2c4f82d962a2c78860d39b42ac20a9ce399f06f62c", - "zh:1fd1a252bffe91668f35be8eac4e0a980f022120254eae1674c3c05049aff88a", - "zh:31bbd380cd7d74bf9a8c961fc64da4222bed40ffbdb27b011e637fa8b2d33641", - "zh:333ee400cf6f62fa199dc1270bf8efac6ffe56659f86918070b8351b8636e03b", - "zh:42ea9fee0a152d344d548eab43583299a13bcd73fae9e53e7e1a708720ac1315", - "zh:4b78f25a8cda3316eb56aa01909a403ec2f325a2eb0512c9a73966068c26cf29", - "zh:5e9cf9a275eda8f7940a41e32abe0b92ba76b5744def4af5124b343b5f33eb94", - "zh:6a46c8630c16b9e1338c2daed6006118db951420108b58b8b886403c69317439", - "zh:6efe11cf1a01f98a8d8043cdcd8c0ee5fe93a0e582c2b69ebb73ea073f5068c3", - "zh:88ab5c768c7d8133dab94eff48071e764424ad2b7cfeee5abe6d5bb16e4b85c6", + "h1:SbzGotY1leY5nnLo/PJOcwIlNTHdZpAErxJSrfr2tTg=", + "zh:00e1b15e6f02cdc788fe855232b63ccce6652930080eac3ba4b8a2e35db02b23", + "zh:3a77ee12e4f5ab2e7b320a0f507389c9171ab82c50d39ae7caa5a1fb2bd95cb3", + "zh:3e32d58e139d098d867eef37914fef01fffb08504d828e0f384c2ffc18d71f80", + "zh:41cf69a525f0fbe0fdb71d26be7ff5e20bb90ccdf5af32c83ed53f0ca2f071b5", + "zh:43055bdd0786855cf7242638a74b579f74f4f1a8e7c7e5e0e50230c8f6b908cb", + "zh:4ac4c29aa0de842ad91145c5a5fba21338531ffca13a510927d445e007a24938", + "zh:57e510498b3aeb6d6155c10fa195e1d5502e763899251057e59e73f653d1e262", + "zh:8f749645b27dba1a07d06aaf9d5596fc4213123f12f3808d68539e78ab16996e", "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", - "zh:a614beb312574342b27dbc34d65b450997f63fa3e948d0d30f441e4f69337380", - "zh:c1f486e27130610a9b64cacb0bd928009c433d62b3be515488185e6467b4aa1f", - "zh:dccd166e89e1a02e7ce658df3c42d040edec4b09c6f7906aa5743938518148b1", - "zh:e75a3ae0fb42b7ea5a0bb5dffd8f8468004c9700fcc934eb04c264fda2ba9984", + "zh:aaca5934ac6273d48922ad7685c5fc2aa7ef5275346a9e70366b7a180a788d41", + "zh:b7585b720a97467302f2e29f0688a5a746778f7b73c30eb085c25831decba1e1", + "zh:c16ae0a46d796858c49a89dd90e5ca92f793e646474fadeafaf701def4a4aa83", + "zh:d66bdc9cd5108452d9dba44082e504ff5e3a3001c8f853bbcaff850cb2127a21", + "zh:ee1aec6c44b117a6c8b7159ee7dc82f1ddac6ba434b4e6c493717738326f0a99", + "zh:f0da48692e00ecacea72d7104714d9721f6be40ba094490c442bb3e68d2e2604", ] } @@ -65,21 +65,21 @@ provider "registry.terraform.io/hashicorp/null" { } provider "registry.terraform.io/hashicorp/random" { - version = "3.6.3" + version = "3.7.1" constraints = "~> 3.0" hashes = [ - "h1:zG9uFP8l9u+yGZZvi5Te7PV62j50azpgwPunq2vTm1E=", - "zh:04ceb65210251339f07cd4611885d242cd4d0c7306e86dda9785396807c00451", - "zh:448f56199f3e99ff75d5c0afacae867ee795e4dfda6cb5f8e3b2a72ec3583dd8", - "zh:4b4c11ccfba7319e901df2dac836b1ae8f12185e37249e8d870ee10bb87a13fe", - "zh:4fa45c44c0de582c2edb8a2e054f55124520c16a39b2dfc0355929063b6395b1", - "zh:588508280501a06259e023b0695f6a18149a3816d259655c424d068982cbdd36", - "zh:737c4d99a87d2a4d1ac0a54a73d2cb62974ccb2edbd234f333abd079a32ebc9e", + "h1:t152MY0tQH4a8fLzTtEWx70ITd3azVOrFDn/pQblbto=", + "zh:3193b89b43bf5805493e290374cdda5132578de6535f8009547c8b5d7a351585", + "zh:3218320de4be943e5812ed3de995946056db86eb8d03aa3f074e0c7316599bef", + "zh:419861805a37fa443e7d63b69fb3279926ccf98a79d256c422d5d82f0f387d1d", + "zh:4df9bd9d839b8fc11a3b8098a604b9b46e2235eb65ef15f4432bde0e175f9ca6", + "zh:5814be3f9c9cc39d2955d6f083bae793050d75c572e70ca11ccceb5517ced6b1", + "zh:63c6548a06de1231c8ee5570e42ca09c4b3db336578ded39b938f2156f06dd2e", + "zh:697e434c6bdee0502cc3deb098263b8dcd63948e8a96d61722811628dce2eba1", "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:a357ab512e5ebc6d1fda1382503109766e21bbfdfaa9ccda43d313c122069b30", - "zh:c51bfb15e7d52cc1a2eaec2a903ac2aff15d162c172b1b4c17675190e8147615", - "zh:e0951ee6fa9df90433728b96381fb867e3db98f66f735e0c3e24f8f16903f0ad", - "zh:e3cdcb4e73740621dabd82ee6a37d6cfce7fee2a03d8074df65086760f5cf556", - "zh:eff58323099f1bd9a0bec7cb04f717e7f1b2774c7d612bf7581797e1622613a0", + "zh:a0b8e44927e6327852bbfdc9d408d802569367f1e22a95bcdd7181b1c3b07601", + "zh:b7d3af018683ef22794eea9c218bc72d7c35a2b3ede9233b69653b3c782ee436", + "zh:d63b911d618a6fe446c65bfc21e793a7663e934b2fef833d42d3ccd38dd8d68d", + "zh:fa985cd0b11e6d651f47cff3055f0a9fd085ec190b6dbe99bf5448174434cdea", ] } diff --git a/examples/default/README.md b/examples/default/README.md index f3129d71bc..fb14cf7b10 100644 --- a/examples/default/README.md +++ b/examples/default/README.md @@ -42,7 +42,7 @@ terraform output -raw webhook_secret | Name | Version | |------|---------| -| [random](#provider\_random) | 3.6.3 | +| [random](#provider\_random) | 3.7.1 | ## Modules @@ -70,6 +70,7 @@ terraform output -raw webhook_secret | Name | Description | |------|-------------| +| [deprecated\_variables\_warning](#output\_deprecated\_variables\_warning) | n/a | | [runners](#output\_runners) | n/a | | [webhook\_endpoint](#output\_webhook\_endpoint) | n/a | | [webhook\_secret](#output\_webhook\_secret) | n/a | diff --git a/examples/default/main.tf b/examples/default/main.tf index 42608fae40..ca04eca78c 100644 --- a/examples/default/main.tf +++ b/examples/default/main.tf @@ -141,6 +141,7 @@ module "runners" { # enable CMK instead of aws managed key for encryptions # kms_key_arn = aws_kms_key.github.arn + } module "webhook_github_app" { diff --git a/examples/default/outputs.tf b/examples/default/outputs.tf index c50214f566..fb9dccc223 100644 --- a/examples/default/outputs.tf +++ b/examples/default/outputs.tf @@ -13,3 +13,8 @@ output "webhook_secret" { value = random_id.random.hex } +output "deprecated_variables_warning" { + value = join("", [ + module.runners.deprecated_variables_warning, + ]) +} diff --git a/examples/multi-runner/README.md b/examples/multi-runner/README.md index 0a4bb295e1..3185036e19 100644 --- a/examples/multi-runner/README.md +++ b/examples/multi-runner/README.md @@ -60,6 +60,7 @@ terraform output -raw webhook_secret | Name | Version | |------|---------| +| [aws](#provider\_aws) | 5.82.1 | | [random](#provider\_random) | 3.6.3 | ## Modules @@ -74,7 +75,11 @@ terraform output -raw webhook_secret | Name | Type | |------|------| +| [aws_ssm_parameter.al2023_arm64](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ssm_parameter) | resource | | [random_id.random](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_ssm_parameter.al2023_arm64](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter) | data source | +| [aws_ssm_parameter.al2023_x64](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter) | data source | ## Inputs @@ -88,6 +93,7 @@ terraform output -raw webhook_secret | Name | Description | |------|-------------| +| [deprecated\_variables\_warning](#output\_deprecated\_variables\_warning) | n/a | | [webhook\_endpoint](#output\_webhook\_endpoint) | n/a | | [webhook\_secret](#output\_webhook\_secret) | n/a | diff --git a/examples/multi-runner/main.tf b/examples/multi-runner/main.tf index 74cb5efa21..acbcdb8081 100644 --- a/examples/multi-runner/main.tf +++ b/examples/multi-runner/main.tf @@ -1,13 +1,47 @@ +# The module provides several ways to chose the AMI ID for the runners. The recommended way is to use the SSM parameter ARN. +# The default is (still) a build in filter that creates internally an SSM parameter for the AMI ID. +# +# Here we show two other options +# 1. Use the SSM parameter ARN directly via a public available SSM parameter +# 2. Use the SSM parameter ARN via a private SSM parameter injected to the module +# 3. Other runners like ubuntu, windows, etc. are using the build in one parameter. + +data "aws_ssm_parameter" "al2023_x64" { + name = "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64" +} + +data "aws_ssm_parameter" "al2023_arm64" { + name = "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-arm64" +} + +resource "aws_ssm_parameter" "al2023_arm64" { + name = local.al2023_arm64_name + type = "String" + data_type = "aws:ec2:image" + value = data.aws_ssm_parameter.al2023_arm64.value +} + +data "aws_caller_identity" "current" {} + locals { environment = var.environment != null ? var.environment : "multi-runner" aws_region = var.aws_region + # create map only with amazon linux 2023 x64 and arm64 to overwrite the default + al2023_arm64_name = "/examples/multi-runner/aws-github-runners/ami/amazon-linux-2023-arm64" + ssm_ami_arns = { + "linux-x64" = data.aws_ssm_parameter.al2023_x64.arn + # construct the arn to avoid terraform count errors + "linux-arm64" = "arn:aws:ssm:${var.aws_region}:${data.aws_caller_identity.current.account_id}:parameter${local.al2023_arm64_name}" + } + # Load runner configurations from Yaml files multi_runner_config_files = { for c in fileset("${path.module}/templates/runner-configs", "*.yaml") : trimsuffix(c, ".yaml") => yamldecode(file("${path.module}/templates/runner-configs/${c}")) } + multi_runner_config = { for k, v in local.multi_runner_config_files : @@ -19,6 +53,12 @@ locals { { subnet_ids = lookup(v.runner_config, "subnet_ids", null) != null ? [module.base.vpc.private_subnets[0]] : null vpc_id = lookup(v.runner_config, "vpc_id", null) != null ? module.base.vpc.vpc_id : null + ami = contains(keys(v.runner_config), "ami") ? merge( + v.runner_config.ami, + { + id_ssm_parameter_arn = lookup(local.ssm_ami_arns, k, null) != null ? local.ssm_ami_arns[k] : null + } + ) : null } ) } diff --git a/examples/multi-runner/outputs.tf b/examples/multi-runner/outputs.tf index 1feaf2e671..8a1c330077 100644 --- a/examples/multi-runner/outputs.tf +++ b/examples/multi-runner/outputs.tf @@ -6,3 +6,9 @@ output "webhook_secret" { sensitive = true value = random_id.random.hex } + +output "deprecated_variables_warning" { + value = join("", [ + module.runners.deprecated_variables_warning, + ]) +} diff --git a/examples/multi-runner/templates/runner-configs/linux-arm64.yaml b/examples/multi-runner/templates/runner-configs/linux-arm64.yaml index 42902ee0dd..0c6cae01b5 100644 --- a/examples/multi-runner/templates/runner-configs/linux-arm64.yaml +++ b/examples/multi-runner/templates/runner-configs/linux-arm64.yaml @@ -15,6 +15,8 @@ runner_config: instance_types: - t4g.large - c6g.large + ami: + id_ssm_parameter_arn: ${ami_id_ssm_parameter_arn} runners_maximum_count: 1 delay_webhook_event: 0 scale_down_schedule_expression: cron(* * * * ? *) diff --git a/examples/multi-runner/templates/runner-configs/linux-x64-ubuntu.yaml b/examples/multi-runner/templates/runner-configs/linux-x64-ubuntu.yaml index 4b555d194c..a296e8606e 100644 --- a/examples/multi-runner/templates/runner-configs/linux-x64-ubuntu.yaml +++ b/examples/multi-runner/templates/runner-configs/linux-x64-ubuntu.yaml @@ -22,13 +22,14 @@ runner_config: delay_webhook_event: 0 scale_down_schedule_expression: cron(* * * * ? *) userdata_template: ./templates/user-data.sh - ami_owners: - - "099720109477" # Canonical's Amazon account ID - ami_filter: - name: - - ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-* - state: - - available + ami: + owners: + - "099720109477" # Canonical's Amazon account ID + filter: + name: + - ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-* + state: + - available block_device_mappings: - device_name: /dev/sda1 delete_on_termination: true diff --git a/examples/multi-runner/templates/runner-configs/linux-x64.yaml b/examples/multi-runner/templates/runner-configs/linux-x64.yaml index bc3527baca..146c340836 100644 --- a/examples/multi-runner/templates/runner-configs/linux-x64.yaml +++ b/examples/multi-runner/templates/runner-configs/linux-x64.yaml @@ -14,6 +14,8 @@ runner_config: instance_types: - m5ad.large - m5a.large + ami: + id_ssm_parameter_arn: ${ami_id_ssm_parameter_arn} runners_maximum_count: 1 enable_ephemeral_runners: true enable_on_demand_failover_for_errors: ['InsufficientInstanceCapacity'] diff --git a/examples/prebuilt/main.tf b/examples/prebuilt/main.tf index 5e5f23703c..dbfbdf9523 100644 --- a/examples/prebuilt/main.tf +++ b/examples/prebuilt/main.tf @@ -45,10 +45,6 @@ module "runners" { ami_filter = { name = [var.ami_name_filter], state = ["available"] } ami_owners = [data.aws_caller_identity.current.account_id] - # Look up runner AMI ID from an AWS SSM parameter (overrides ami_filter at instance launch time) - # NOTE: the parameter must be managed outside of this module (e.g. in a runner AMI build workflow) - # ami_id_ssm_parameter_name = "my-runner-ami-id" - # disable binary syncer since github agent is already installed in the AMI. enable_runner_binaries_syncer = false diff --git a/main.tf b/main.tf index b9456c0a52..759b8169f6 100644 --- a/main.tf +++ b/main.tf @@ -178,6 +178,7 @@ module "runners" { block_device_mappings = var.block_device_mappings runner_architecture = var.runner_architecture + ami = var.ami ami_filter = var.ami_filter ami_owners = var.ami_owners ami_id_ssm_parameter_name = var.ami_id_ssm_parameter_name diff --git a/modules/multi-runner/README.md b/modules/multi-runner/README.md index dca32e2662..c43d00e245 100644 --- a/modules/multi-runner/README.md +++ b/modules/multi-runner/README.md @@ -131,7 +131,7 @@ module "multi-runner" { | [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. |
cron = string
timeZone = string
idleCount = number
evictionStrategy = optional(string, "oldest_first")
}))
object({| `{}` | no | | [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 | | [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 | -| [github\_app](#input\_github\_app) | GitHub app parameters, see your github app.
enable = optional(bool, true)
accept_events = optional(list(string), [])
})
object({| n/a | yes | +| [github\_app](#input\_github\_app) | GitHub app parameters, see your github app.
key_base64 = optional(string)
key_base64_ssm = optional(object({
arn = string
name = string
}))
id = optional(string)
id_ssm = optional(object({
arn = string
name = string
}))
webhook_secret = optional(string)
webhook_secret_ssm = optional(object({
arn = string
name = string
}))
})
object({| n/a | yes | | [instance\_profile\_path](#input\_instance\_profile\_path) | The path that will be added to the instance\_profile, if not set the environment name will be used. | `string` | `null` | no | | [instance\_termination\_watcher](#input\_instance\_termination\_watcher) | Configuration for the spot termination watcher lambda function. This feature is Beta, changes will not trigger a major release as long in beta.
key_base64 = optional(string)
key_base64_ssm = optional(object({
arn = string
name = string
}))
id = optional(string)
id_ssm = optional(object({
arn = string
name = string
}))
webhook_secret = optional(string)
webhook_secret_ssm = optional(object({
arn = string
name = string
}))
})
object({| `{}` | no | | [key\_name](#input\_key\_name) | Key pair name | `string` | `null` | no | @@ -148,7 +148,7 @@ module "multi-runner" { | [logging\_retention\_in\_days](#input\_logging\_retention\_in\_days) | Specifies the number of days you want to retain log events for the lambda log group. Possible values are: 0, 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, and 3653. | `number` | `180` | no | | [matcher\_config\_parameter\_store\_tier](#input\_matcher\_config\_parameter\_store\_tier) | The tier of the parameter store for the matcher configuration. Valid values are `Standard`, and `Advanced`. | `string` | `"Standard"` | no | | [metrics](#input\_metrics) | Configuration for metrics created by the module, by default metrics are disabled to avoid additional costs. When metrics are enable all metrics are created unless explicit configured otherwise. |
enable = optional(bool, false)
features = optional(object({
enable_spot_termination_handler = optional(bool, true)
enable_spot_termination_notification_watcher = optional(bool, true)
}), {})
memory_size = optional(number, null)
s3_key = optional(string, null)
s3_object_version = optional(string, null)
timeout = optional(number, null)
zip = optional(string, null)
})
object({| `{}` | no | -| [multi\_runner\_config](#input\_multi\_runner\_config) | multi\_runner\_config = {
enable = optional(bool, false)
namespace = optional(string, "GitHub Runners")
metric = optional(object({
enable_github_app_rate_limit = optional(bool, true)
enable_job_retry = optional(bool, true)
enable_spot_termination_warning = optional(bool, true)
}), {})
})
map(object({| n/a | yes | +| [multi\_runner\_config](#input\_multi\_runner\_config) | multi\_runner\_config = {
runner_config = object({
runner_os = string
runner_architecture = string
runner_metadata_options = optional(map(any), {
instance_metadata_tags = "enabled"
http_endpoint = "enabled"
http_tokens = "required"
http_put_response_hop_limit = 1
})
ami_filter = optional(map(list(string)), { state = ["available"] })
ami_owners = optional(list(string), ["amazon"])
ami_id_ssm_parameter_name = optional(string, null)
ami_kms_key_arn = optional(string, "")
create_service_linked_role_spot = optional(bool, false)
credit_specification = optional(string, null)
delay_webhook_event = optional(number, 30)
disable_runner_autoupdate = optional(bool, false)
ebs_optimized = optional(bool, false)
enable_ephemeral_runners = optional(bool, false)
enable_job_queued_check = optional(bool, null)
enable_on_demand_failover_for_errors = optional(list(string), [])
enable_organization_runners = optional(bool, false)
enable_runner_binaries_syncer = optional(bool, true)
enable_ssm_on_runners = optional(bool, false)
enable_userdata = optional(bool, true)
instance_allocation_strategy = optional(string, "lowest-price")
instance_max_spot_price = optional(string, null)
instance_target_capacity_type = optional(string, "spot")
instance_types = list(string)
job_queue_retention_in_seconds = optional(number, 86400)
minimum_running_time_in_minutes = optional(number, null)
pool_runner_owner = optional(string, null)
runner_as_root = optional(bool, false)
runner_boot_time_in_minutes = optional(number, 5)
runner_disable_default_labels = optional(bool, false)
runner_extra_labels = optional(list(string), [])
runner_group_name = optional(string, "Default")
runner_name_prefix = optional(string, "")
runner_run_as = optional(string, "ec2-user")
runners_maximum_count = number
runner_additional_security_group_ids = optional(list(string), [])
scale_down_schedule_expression = optional(string, "cron(*/5 * * * ? *)")
scale_up_reserved_concurrent_executions = optional(number, 1)
userdata_template = optional(string, null)
userdata_content = optional(string, null)
enable_jit_config = optional(bool, null)
enable_runner_detailed_monitoring = optional(bool, false)
enable_cloudwatch_agent = optional(bool, true)
cloudwatch_config = optional(string, null)
userdata_pre_install = optional(string, "")
userdata_post_install = optional(string, "")
runner_hook_job_started = optional(string, "")
runner_hook_job_completed = optional(string, "")
runner_ec2_tags = optional(map(string), {})
runner_iam_role_managed_policy_arns = optional(list(string), [])
vpc_id = optional(string, null)
subnet_ids = optional(list(string), null)
idle_config = optional(list(object({
cron = string
timeZone = string
idleCount = number
evictionStrategy = optional(string, "oldest_first")
})), [])
runner_log_files = optional(list(object({
log_group_name = string
prefix_log_group = bool
file_path = string
log_stream_name = string
})), null)
block_device_mappings = optional(list(object({
delete_on_termination = optional(bool, true)
device_name = optional(string, "/dev/xvda")
encrypted = optional(bool, true)
iops = optional(number)
kms_key_id = optional(string)
snapshot_id = optional(string)
throughput = optional(number)
volume_size = number
volume_type = optional(string, "gp3")
})), [{
volume_size = 30
}])
pool_config = optional(list(object({
schedule_expression = string
schedule_expression_timezone = optional(string)
size = number
})), [])
job_retry = optional(object({
enable = optional(bool, false)
delay_in_seconds = optional(number, 300)
delay_backoff = optional(number, 2)
lambda_memory_size = optional(number, 256)
lambda_timeout = optional(number, 30)
max_attempts = optional(number, 1)
}), {})
})
matcherConfig = object({
labelMatchers = list(list(string))
exactMatch = optional(bool, false)
priority = optional(number, 999)
})
redrive_build_queue = optional(object({
enabled = bool
maxReceiveCount = number
}), {
enabled = false
maxReceiveCount = null
})
}))
map(object({| n/a | yes | | [pool\_lambda\_reserved\_concurrent\_executions](#input\_pool\_lambda\_reserved\_concurrent\_executions) | Amount of reserved concurrent executions for the scale-up lambda function. A value of 0 disables lambda from being triggered and -1 removes any concurrency limitations. | `number` | `1` | no | | [pool\_lambda\_timeout](#input\_pool\_lambda\_timeout) | Time out for the pool lambda in seconds. | `number` | `60` | no | | [prefix](#input\_prefix) | The prefix used for naming resources | `string` | `"github-actions"` | no | @@ -192,6 +192,7 @@ module "multi-runner" { | Name | Description | |------|-------------| | [binaries\_syncer\_map](#output\_binaries\_syncer\_map) | n/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 in each runner configuration. | | [instance\_termination\_handler](#output\_instance\_termination\_handler) | n/a | | [instance\_termination\_watcher](#output\_instance\_termination\_watcher) | n/a | | [runners\_map](#output\_runners\_map) | n/a | diff --git a/modules/multi-runner/outputs.tf b/modules/multi-runner/outputs.tf index 7ce7171faf..2f2b1d3458 100644 --- a/modules/multi-runner/outputs.tf +++ b/modules/multi-runner/outputs.tf @@ -67,3 +67,23 @@ output "instance_termination_handler" { lambda_role = module.instance_termination_watcher[0].spot_termination_handler.lambda_role } : null } + +output "deprecated_variables_warning" { + description = "Warning for deprecated variables usage. These variables will be removed in a future release. Please migrate to using the consolidated 'ami' object in each runner configuration." + value = join("", [ + for key, runner_config in var.multi_runner_config : ( + join("", [ + # Show object migration warning only when ami is null and old variables are used + try(runner_config.runner_config.ami, null) == null ? ( + (try(runner_config.runner_config.ami_filter, { state = ["available"] }) != { state = ["available"] } || + try(runner_config.runner_config.ami_owners, ["amazon"]) != ["amazon"] || + try(runner_config.runner_config.ami_kms_key_arn, "") != "") ? + "DEPRECATION WARNING: Runner '${key}' is using deprecated AMI variables (ami_filter, ami_owners, ami_kms_key_arn). These variables will be removed in a future version. Please migrate to using the consolidated 'ami' object.\n" : "" + ) : "", + # Always show warning for ami_id_ssm_parameter_name to migrate to ami_id_ssm_parameter_arn + try(runner_config.runner_config.ami_id_ssm_parameter_name, null) != null ? + "DEPRECATION WARNING: Runner '${key}' is using deprecated variable 'ami_id_ssm_parameter_name'. Please use 'ami.id_ssm_parameter_arn' instead.\n" : "" + ]) + ) + ]) +} diff --git a/modules/multi-runner/runners.tf b/modules/multi-runner/runners.tf index 8fe23d506d..9f5d1bb456 100644 --- a/modules/multi-runner/runners.tf +++ b/modules/multi-runner/runners.tf @@ -25,11 +25,11 @@ module "runners" { instance_max_spot_price = each.value.runner_config.instance_max_spot_price block_device_mappings = each.value.runner_config.block_device_mappings - runner_architecture = each.value.runner_config.runner_architecture - ami_filter = each.value.runner_config.ami_filter - ami_owners = each.value.runner_config.ami_owners - ami_id_ssm_parameter_name = each.value.runner_config.ami_id_ssm_parameter_name - ami_kms_key_arn = each.value.runner_config.ami_kms_key_arn + runner_architecture = each.value.runner_config.runner_architecture + ami = each.value.runner_config.ami + ami_filter = each.value.runner_config.ami_filter + ami_owners = each.value.runner_config.ami_owners + ami_kms_key_arn = each.value.runner_config.ami_kms_key_arn sqs_build_queue = { "arn" : each.value.arn, "url" : each.value.url } github_app_parameters = local.github_app_parameters diff --git a/modules/multi-runner/variables.tf b/modules/multi-runner/variables.tf index ff4419d4d9..b138205459 100644 --- a/modules/multi-runner/variables.tf +++ b/modules/multi-runner/variables.tf @@ -1,8 +1,8 @@ variable "github_app" { description = <
runner_config = object({
runner_os = string
runner_architecture = string
runner_metadata_options = optional(map(any), {
instance_metadata_tags = "enabled"
http_endpoint = "enabled"
http_tokens = "required"
http_put_response_hop_limit = 1
})
ami = optional(object({
filter = optional(map(list(string)), { state = ["available"] })
owners = optional(list(string), ["amazon"])
id_ssm_parameter_arn = optional(string, null)
kms_key_arn = optional(string, null)
}), null) # Defaults to null, in which case the module falls back to individual AMI variables (deprecated)
# Deprecated: Use ami object instead
ami_filter = optional(map(list(string)), { state = ["available"] })
ami_owners = optional(list(string), ["amazon"])
ami_id_ssm_parameter_name = optional(string, null)
ami_kms_key_arn = optional(string, "")
create_service_linked_role_spot = optional(bool, false)
credit_specification = optional(string, null)
delay_webhook_event = optional(number, 30)
disable_runner_autoupdate = optional(bool, false)
ebs_optimized = optional(bool, false)
enable_ephemeral_runners = optional(bool, false)
enable_job_queued_check = optional(bool, null)
enable_on_demand_failover_for_errors = optional(list(string), [])
enable_organization_runners = optional(bool, false)
enable_runner_binaries_syncer = optional(bool, true)
enable_ssm_on_runners = optional(bool, false)
enable_userdata = optional(bool, true)
instance_allocation_strategy = optional(string, "lowest-price")
instance_max_spot_price = optional(string, null)
instance_target_capacity_type = optional(string, "spot")
instance_types = list(string)
job_queue_retention_in_seconds = optional(number, 86400)
minimum_running_time_in_minutes = optional(number, null)
pool_runner_owner = optional(string, null)
runner_as_root = optional(bool, false)
runner_boot_time_in_minutes = optional(number, 5)
runner_disable_default_labels = optional(bool, false)
runner_extra_labels = optional(list(string), [])
runner_group_name = optional(string, "Default")
runner_name_prefix = optional(string, "")
runner_run_as = optional(string, "ec2-user")
runners_maximum_count = number
runner_additional_security_group_ids = optional(list(string), [])
scale_down_schedule_expression = optional(string, "cron(*/5 * * * ? *)")
scale_up_reserved_concurrent_executions = optional(number, 1)
userdata_template = optional(string, null)
userdata_content = optional(string, null)
enable_jit_config = optional(bool, null)
enable_runner_detailed_monitoring = optional(bool, false)
enable_cloudwatch_agent = optional(bool, true)
cloudwatch_config = optional(string, null)
userdata_pre_install = optional(string, "")
userdata_post_install = optional(string, "")
runner_hook_job_started = optional(string, "")
runner_hook_job_completed = optional(string, "")
runner_ec2_tags = optional(map(string), {})
runner_iam_role_managed_policy_arns = optional(list(string), [])
vpc_id = optional(string, null)
subnet_ids = optional(list(string), null)
idle_config = optional(list(object({
cron = string
timeZone = string
idleCount = number
evictionStrategy = optional(string, "oldest_first")
})), [])
runner_log_files = optional(list(object({
log_group_name = string
prefix_log_group = bool
file_path = string
log_stream_name = string
})), null)
block_device_mappings = optional(list(object({
delete_on_termination = optional(bool, true)
device_name = optional(string, "/dev/xvda")
encrypted = optional(bool, true)
iops = optional(number)
kms_key_id = optional(string)
snapshot_id = optional(string)
throughput = optional(number)
volume_size = number
volume_type = optional(string, "gp3")
})), [{
volume_size = 30
}])
pool_config = optional(list(object({
schedule_expression = string
schedule_expression_timezone = optional(string)
size = number
})), [])
job_retry = optional(object({
enable = optional(bool, false)
delay_in_seconds = optional(number, 300)
delay_backoff = optional(number, 2)
lambda_memory_size = optional(number, 256)
lambda_timeout = optional(number, 30)
max_attempts = optional(number, 1)
}), {})
})
matcherConfig = object({
labelMatchers = list(list(string))
exactMatch = optional(bool, false)
priority = optional(number, 999)
})
redrive_build_queue = optional(object({
enabled = bool
maxReceiveCount = number
}), {
enabled = false
maxReceiveCount = null
})
}))
{| no | -| [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 | -| [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 | -| [ami\_owners](#input\_ami\_owners) | The list of owners used to select the AMI of action runner instances. | `list(string)` |
"state": [
"available"
]
}
[| no | +| [ami](#input\_ami) | AMI configuration for the action runner instances. This object allows you to specify all AMI-related settings in one place.
"amazon"
]
object({| `null` | no | +| [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))` |
filter = optional(map(list(string)), { state = ["available"] })
owners = optional(list(string), ["amazon"])
id_ssm_parameter_arn = optional(string, null)
kms_key_arn = optional(string, null)
})
{| no | +| [ami\_id\_ssm\_parameter\_name](#input\_ami\_id\_ssm\_parameter\_name) | [DEPRECATED: Use 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 | +| [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 | +| [ami\_owners](#input\_ami\_owners) | [DEPRECATED: Use ami.owners] The list of owners used to select the AMI of action runner instances. | `list(string)` |
"state": [
"available"
]
}
[| no | | [associate\_public\_ipv4\_address](#input\_associate\_public\_ipv4\_address) | Associate public IPv4 with the runner. Only tested with IPv4 | `bool` | `false` | no | | [aws\_partition](#input\_aws\_partition) | (optional) partition for the base arn if not 'aws' | `string` | `"aws"` | no | | [aws\_region](#input\_aws\_region) | AWS region. | `string` | n/a | yes | diff --git a/modules/runners/main.tf b/modules/runners/main.tf index 051d6713cd..5baaa09672 100644 --- a/modules/runners/main.tf +++ b/modules/runners/main.tf @@ -37,8 +37,16 @@ locals { "linux" = "${path.module}/templates/start-runner.sh" } - ami_kms_key_arn = var.ami_kms_key_arn != null ? var.ami_kms_key_arn : "" - ami_filter = merge(local.default_ami[var.runner_os], var.ami_filter) + # Handle AMI configuration from either the new object or old variables + ami_config = var.ami != null ? var.ami : { + filter = var.ami_filter + owners = var.ami_owners + id_ssm_parameter_arn = null + kms_key_arn = var.ami_kms_key_arn + } + ami_kms_key_arn = local.ami_config.kms_key_arn != null ? local.ami_config.kms_key_arn : "" + ami_filter = merge(local.default_ami[var.runner_os], local.ami_config.filter) + ami_id_ssm_module_managed = local.ami_config.id_ssm_parameter_arn == null enable_job_queued_check = var.enable_job_queued_check == null ? !var.enable_ephemeral_runners : var.enable_job_queued_check @@ -81,7 +89,28 @@ data "aws_ami" "runner" { } } - owners = var.ami_owners + owners = local.ami_config.owners +} + +resource "aws_ssm_parameter" "runner_ami_id" { + count = local.ami_id_ssm_module_managed ? 1 : 0 + name = "${var.ssm_paths.root}/${var.ssm_paths.config}/ami_id" + type = "String" + data_type = "aws:ec2:image" + value = data.aws_ami.runner.id + + tags = merge( + local.tags, + { + "ghr:ami_name" = data.aws_ami.runner.name + }, + { + "ghr:ami_creation_date" = data.aws_ami.runner.creation_date + }, + { + "ghr:ami_deprecation_time" = data.aws_ami.runner.deprecation_time + } + ) } resource "aws_launch_template" "runner" { @@ -140,7 +169,7 @@ resource "aws_launch_template" "runner" { } instance_initiated_shutdown_behavior = "terminate" - image_id = data.aws_ami.runner.id + image_id = "resolve:ssm:${local.ami_id_ssm_module_managed ? aws_ssm_parameter.runner_ami_id[0].arn : var.ami.id_ssm_parameter_arn}" key_name = var.key_name ebs_optimized = var.ebs_optimized diff --git a/modules/runners/policies/lambda-scale-up.json b/modules/runners/policies/lambda-scale-up.json index 1c5e942b2f..1c6946b945 100644 --- a/modules/runners/policies/lambda-scale-up.json +++ b/modules/runners/policies/lambda-scale-up.json @@ -38,6 +38,15 @@ "${ssm_config_path}/*" ] }, + { + "Effect": "Allow", + "Action": [ + "ssm:GetParameters" + ], + "Resource": [ + "${ssm_ami_id_parameter_arn}" + ] + }, { "Effect": "Allow", "Action": [ diff --git a/modules/runners/pool.tf b/modules/runners/pool.tf index 16a13aeccd..2762008ebf 100644 --- a/modules/runners/pool.tf +++ b/modules/runners/pool.tf @@ -17,6 +17,7 @@ module "pool" { instance_types = var.instance_types kms_key_arn = local.kms_key_arn ami_kms_key_arn = local.ami_kms_key_arn + ami_id_ssm_parameter_arn = local.ami_id_ssm_module_managed ? aws_ssm_parameter.runner_ami_id[0].arn : var.ami.id_ssm_parameter_arn lambda = { log_level = var.log_level logging_retention_in_days = var.logging_retention_in_days diff --git a/modules/runners/pool/README.md b/modules/runners/pool/README.md index cffad1213a..4ed0f3f056 100644 --- a/modules/runners/pool/README.md +++ b/modules/runners/pool/README.md @@ -33,6 +33,7 @@ No modules. | [aws_iam_role_policy.pool](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | | [aws_iam_role_policy.pool_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | | [aws_iam_role_policy.pool_xray](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [aws_iam_role_policy.scheduler](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | | [aws_iam_role_policy_attachment.ami_id_ssm_parameter_read](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.pool_vpc_execution_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_lambda_function.pool](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource | @@ -48,7 +49,7 @@ No modules. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | [aws\_partition](#input\_aws\_partition) | (optional) partition for the arn if not 'aws' | `string` | `"aws"` | no | -| [config](#input\_config) | Lookup details in parent module. |
"amazon"
]
object({| n/a | yes | +| [config](#input\_config) | Lookup details in parent module. |
lambda = object({
log_level = string
logging_retention_in_days = number
logging_kms_key_id = string
reserved_concurrent_executions = number
s3_bucket = string
s3_key = string
s3_object_version = string
security_group_ids = list(string)
runtime = string
architecture = string
memory_size = number
timeout = number
zip = string
subnet_ids = list(string)
})
tags = map(string)
ghes = object({
url = string
ssl_verify = string
})
github_app_parameters = object({
key_base64 = map(string)
id = map(string)
})
subnet_ids = list(string)
runner = object({
disable_runner_autoupdate = bool
ephemeral = bool
enable_jit_config = bool
enable_on_demand_failover_for_errors = list(string)
boot_time_in_minutes = number
labels = list(string)
launch_template = object({
name = string
})
group_name = string
name_prefix = string
pool_owner = string
role = object({
arn = string
})
})
instance_types = list(string)
instance_target_capacity_type = string
instance_allocation_strategy = string
instance_max_spot_price = string
prefix = string
pool = list(object({
schedule_expression = string
schedule_expression_timezone = string
size = number
}))
role_permissions_boundary = string
kms_key_arn = string
ami_kms_key_arn = string
role_path = string
ssm_token_path = string
ssm_config_path = string
ami_id_ssm_parameter_name = string
ami_id_ssm_parameter_read_policy_arn = string
arn_ssm_parameters_path_config = string
lambda_tags = map(string)
user_agent = string
})
object({| n/a | yes | | [tracing\_config](#input\_tracing\_config) | Configuration for lambda tracing. |
lambda = object({
log_level = string
logging_retention_in_days = number
logging_kms_key_id = string
reserved_concurrent_executions = number
s3_bucket = string
s3_key = string
s3_object_version = string
security_group_ids = list(string)
runtime = string
architecture = string
memory_size = number
timeout = number
zip = string
subnet_ids = list(string)
})
tags = map(string)
ghes = object({
url = string
ssl_verify = string
})
github_app_parameters = object({
key_base64 = map(string)
id = map(string)
})
subnet_ids = list(string)
runner = object({
disable_runner_autoupdate = bool
ephemeral = bool
enable_jit_config = bool
enable_on_demand_failover_for_errors = list(string)
boot_time_in_minutes = number
labels = list(string)
launch_template = object({
name = string
})
group_name = string
name_prefix = string
pool_owner = string
role = object({
arn = string
})
})
instance_types = list(string)
instance_target_capacity_type = string
instance_allocation_strategy = string
instance_max_spot_price = string
prefix = string
pool = list(object({
schedule_expression = string
schedule_expression_timezone = string
size = number
}))
role_permissions_boundary = string
kms_key_arn = string
ami_kms_key_arn = string
ami_id_ssm_parameter_arn = string
role_path = string
ssm_token_path = string
ssm_config_path = string
ami_id_ssm_parameter_name = string
ami_id_ssm_parameter_read_policy_arn = string
arn_ssm_parameters_path_config = string
lambda_tags = map(string)
user_agent = string
})
object({| `{}` | no | ## Outputs diff --git a/modules/runners/pool/main.tf b/modules/runners/pool/main.tf index 364d315439..a10bdd042a 100644 --- a/modules/runners/pool/main.tf +++ b/modules/runners/pool/main.tf @@ -91,6 +91,7 @@ resource "aws_iam_role_policy" "pool" { github_app_key_base64_arn = var.config.github_app_parameters.key_base64.arn kms_key_arn = var.config.kms_key_arn ami_kms_key_arn = var.config.ami_kms_key_arn + ssm_ami_id_parameter_arn = var.config.ami_id_ssm_parameter_arn }) } @@ -188,15 +189,15 @@ resource "aws_iam_role" "scheduler" { permissions_boundary = var.config.role_permissions_boundary assume_role_policy = data.aws_iam_policy_document.scheduler_assume.json - - inline_policy { - name = "terraform" - policy = data.aws_iam_policy_document.scheduler.json - } - tags = var.config.tags } +resource "aws_iam_role_policy" "scheduler" { + name = "terraform" + role = aws_iam_role.scheduler.name + policy = data.aws_iam_policy_document.scheduler.json +} + resource "aws_scheduler_schedule" "pool" { for_each = { for i, v in var.config.pool : i => v } diff --git a/modules/runners/pool/policies/lambda-pool.json b/modules/runners/pool/policies/lambda-pool.json index f8e3f39a23..b0360a825c 100644 --- a/modules/runners/pool/policies/lambda-pool.json +++ b/modules/runners/pool/policies/lambda-pool.json @@ -39,6 +39,15 @@ "${arn_ssm_parameters_path_config}/*" ] }, + { + "Effect": "Allow", + "Action": [ + "ssm:GetParameters" + ], + "Resource": [ + "${ssm_ami_id_parameter_arn}" + ] + }, { "Effect": "Allow", "Action": [ diff --git a/modules/runners/pool/variables.tf b/modules/runners/pool/variables.tf index baf9746bbb..f1e841cde6 100644 --- a/modules/runners/pool/variables.tf +++ b/modules/runners/pool/variables.tf @@ -57,6 +57,7 @@ variable "config" { role_permissions_boundary = string kms_key_arn = string ami_kms_key_arn = string + ami_id_ssm_parameter_arn = string role_path = string ssm_token_path = string ssm_config_path = string diff --git a/modules/runners/scale-up.tf b/modules/runners/scale-up.tf index 538487ca8a..ad96c496a4 100644 --- a/modules/runners/scale-up.tf +++ b/modules/runners/scale-up.tf @@ -119,6 +119,7 @@ resource "aws_iam_role_policy" "scale_up" { ssm_config_path = "arn:${var.aws_partition}:ssm:${var.aws_region}:${data.aws_caller_identity.current.account_id}:parameter${var.ssm_paths.root}/${var.ssm_paths.config}" kms_key_arn = local.kms_key_arn ami_kms_key_arn = local.ami_kms_key_arn + ssm_ami_id_parameter_arn = local.ami_id_ssm_module_managed ? aws_ssm_parameter.runner_ami_id[0].arn : var.ami.id_ssm_parameter_arn }) } diff --git a/modules/runners/variables.tf b/modules/runners/variables.tf index 08109008fd..f70e80b9cc 100644 --- a/modules/runners/variables.tf +++ b/modules/runners/variables.tf @@ -1,3 +1,25 @@ +variable "ami" { + description = <
mode = optional(string, null)
capture_http_requests = optional(bool, false)
capture_error = optional(bool, false)
})