Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
377d2a2
feat(control-plane): [issue-4833] AWS SSM Parameter store tags
wadherv Oct 19, 2025
36f4f61
adding fix for variable mismatch type
wadherv Oct 20, 2025
a9d685d
docs: auto update terraform docs
github-actions[bot] Oct 20, 2025
7361092
fix yarn format check
wadherv Oct 20, 2025
9bf790d
Merge branch 'main' into main
wadherv Nov 2, 2025
340a39a
updating default value
wadherv Nov 2, 2025
3ac7b16
Merge branch 'main' into main
npalm Nov 4, 2025
1590623
Merge branch 'main' into main
npalm Nov 7, 2025
1a5e241
Merge branch 'main' into main
npalm Nov 13, 2025
8120634
Update (#2)
wadherv Nov 14, 2025
8cd43d6
Merge branch 'main' into main
wadherv Nov 14, 2025
73a4f5b
Merge branch 'main' into main
wadherv Nov 18, 2025
e6befee
Merge branch 'main' into main
wadherv Nov 20, 2025
60e0d07
docs: auto update terraform docs
github-actions[bot] Nov 20, 2025
323333d
Merge branch 'main' into main
wadherv Nov 23, 2025
cf1b880
Merge branch 'main' into main
npalm Nov 24, 2025
e7e0477
docs: auto update terraform docs
github-actions[bot] Nov 24, 2025
6f6c89b
Update modules/runners/local.tf
wadherv Nov 25, 2025
7da8216
Update (#3)
wadherv Nov 25, 2025
b64df62
fix yarn format-check
wadherv Nov 25, 2025
d43ea2f
fix
wadherv Nov 25, 2025
bb522d2
Merge branch 'main' into main
wadherv Nov 25, 2025
b141a18
Merge branch 'main' into main
wadherv Nov 27, 2025
0b58a2c
Merge branch 'main' into main
wadherv Nov 29, 2025
a1798fb
Merge branch 'main' into main
npalm Dec 6, 2025
655c67b
Merge branch 'main' into main
wadherv Dec 8, 2025
af201fd
docs: auto update terraform docs
github-actions[bot] Dec 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ Join our discord community via [this invite link](https://discord.gg/bxgXW8jJGh)
| <a name="input_matcher_config_parameter_store_tier"></a> [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 |
| <a name="input_metrics"></a> [metrics](#input\_metrics) | Configuration for metrics created by the module, by default disabled to avoid additional costs. When metrics are enable all metrics are created unless explicit configured otherwise. | <pre>object({<br/> enable = optional(bool, false)<br/> namespace = optional(string, "GitHub Runners")<br/> metric = optional(object({<br/> enable_github_app_rate_limit = optional(bool, true)<br/> enable_job_retry = optional(bool, true)<br/> enable_spot_termination_warning = optional(bool, true)<br/> }), {})<br/> })</pre> | `{}` | no |
| <a name="input_minimum_running_time_in_minutes"></a> [minimum\_running\_time\_in\_minutes](#input\_minimum\_running\_time\_in\_minutes) | The time an ec2 action runner should be running at minimum before terminated, if not busy. | `number` | `null` | no |
| <a name="input_parameter_store_tags"></a> [parameter\_store\_tags](#input\_parameter\_store\_tags) | Map of tags that will be added to all the SSM Parameter Store parameters created by the Lambda function. | `map(string)` | `{}` | no |
| <a name="input_pool_config"></a> [pool\_config](#input\_pool\_config) | The configuration for updating the pool. The `pool_size` to adjust to by the events triggered by the `schedule_expression`. For example you can configure a cron expression for weekdays to adjust the pool to 10 and another expression for the weekend to adjust the pool to 1. Use `schedule_expression_timezone` to override the schedule time zone (defaults to UTC). | <pre>list(object({<br/> schedule_expression = string<br/> schedule_expression_timezone = optional(string)<br/> size = number<br/> }))</pre> | `[]` | no |
| <a name="input_pool_lambda_memory_size"></a> [pool\_lambda\_memory\_size](#input\_pool\_lambda\_memory\_size) | Memory size limit for scale-up lambda. | `number` | `512` | no |
| <a name="input_pool_lambda_reserved_concurrent_executions"></a> [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 |
Expand Down
4 changes: 4 additions & 0 deletions lambdas/functions/control-plane/src/pool/pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ export async function adjust(event: PoolEvent): Promise<void> {
const onDemandFailoverOnError = process.env.ENABLE_ON_DEMAND_FAILOVER_FOR_ERRORS
? (JSON.parse(process.env.ENABLE_ON_DEMAND_FAILOVER_FOR_ERRORS) as [string])
: [];
const ssmParameterStoreTags = process.env.SSM_PARAMETER_STORE_TAGS
? JSON.parse(process.env.SSM_PARAMETER_STORE_TAGS)
: {};

const { ghesApiUrl, ghesBaseUrl } = getGitHubEnterpriseApiUrl();

Expand Down Expand Up @@ -81,6 +84,7 @@ export async function adjust(event: PoolEvent): Promise<void> {
disableAutoUpdate: disableAutoUpdate,
ssmTokenPath,
ssmConfigPath,
ssmParameterStoreTags,
},
{
ec2instanceCriteria: {
Expand Down
13 changes: 11 additions & 2 deletions lambdas/functions/control-plane/src/scale-runners/scale-up.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ interface CreateGitHubRunnerConfig {
disableAutoUpdate: boolean;
ssmTokenPath: string;
ssmConfigPath: string;
ssmParameterStoreTags: { Key: string; Value: string }[];
}

interface CreateEC2RunnerConfig {
Expand Down Expand Up @@ -182,6 +183,9 @@ async function getRunnerGroupId(githubRunnerConfig: CreateGitHubRunnerConfig, gh
`${githubRunnerConfig.ssmConfigPath}/runner-group/${githubRunnerConfig.runnerGroup}`,
runnerGroupId.toString(),
false,
{
tags: githubRunnerConfig.ssmParameterStoreTags,
},
);
} catch (err) {
logger.debug('Error storing runner group id in SSM Parameter Store', err as Error);
Expand Down Expand Up @@ -251,6 +255,10 @@ export async function scaleUp(eventSource: string, payload: ActionRequestMessage
const onDemandFailoverOnError = process.env.ENABLE_ON_DEMAND_FAILOVER_FOR_ERRORS
? (JSON.parse(process.env.ENABLE_ON_DEMAND_FAILOVER_FOR_ERRORS) as [string])
: [];
const ssmParameterStoreTags: { Key: string; Value: string }[] =
process.env.SSM_PARAMETER_STORE_TAGS && process.env.SSM_PARAMETER_STORE_TAGS.trim() !== ''
? JSON.parse(process.env.SSM_PARAMETER_STORE_TAGS)
: [];

if (ephemeralEnabled && payload.eventType !== 'workflow_job') {
logger.warn(`${payload.eventType} event is not supported in combination with ephemeral runners.`);
Expand Down Expand Up @@ -321,6 +329,7 @@ export async function scaleUp(eventSource: string, payload: ActionRequestMessage
disableAutoUpdate,
ssmTokenPath,
ssmConfigPath,
ssmParameterStoreTags,
},
{
ec2instanceCriteria: {
Expand Down Expand Up @@ -407,7 +416,7 @@ async function createRegistrationTokenConfig(

for (const instance of instances) {
await putParameter(`${githubRunnerConfig.ssmTokenPath}/${instance}`, runnerServiceConfig.join(' '), true, {
tags: [{ Key: 'InstanceId', Value: instance }],
tags: [{ Key: 'InstanceId', Value: instance }, ...githubRunnerConfig.ssmParameterStoreTags],
});
if (isDelay) {
// Delay to prevent AWS ssm rate limits by being within the max throughput limit
Expand Down Expand Up @@ -465,7 +474,7 @@ async function createJitConfig(githubRunnerConfig: CreateGitHubRunnerConfig, ins
instance: instance,
});
await putParameter(`${githubRunnerConfig.ssmTokenPath}/${instance}`, runnerConfig.data.encoded_jit_config, true, {
tags: [{ Key: 'InstanceId', Value: instance }],
tags: [{ Key: 'InstanceId', Value: instance }, ...githubRunnerConfig.ssmParameterStoreTags],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change was not working, made a suggestion to locals.tf. But effect was this line was casuign an exception since the tags were not proper formatted. The change in locals.tf is fixing this. Although if you see any option here to validate the tags (without API) call as safe gurd that woudl be great.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

function validateSsmParameterStoreTags(tagsJson: string): { Key: string; Value: string }[] {
to validate the tags

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

});
if (isDelay) {
// Delay to prevent AWS ssm rate limits by being within the max throughput limit
Expand Down
1 change: 1 addition & 0 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ module "runners" {
runner_log_files = var.runner_log_files
runner_group_name = var.runner_group_name
runner_name_prefix = var.runner_name_prefix
parameter_store_tags = var.parameter_store_tags

scale_up_reserved_concurrent_executions = var.scale_up_reserved_concurrent_executions

Expand Down
1 change: 1 addition & 0 deletions modules/multi-runner/README.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions modules/multi-runner/runners.tf
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ module "runners" {
runner_log_files = each.value.runner_config.runner_log_files
runner_group_name = each.value.runner_config.runner_group_name
runner_name_prefix = each.value.runner_config.runner_name_prefix
parameter_store_tags = var.parameter_store_tags

scale_up_reserved_concurrent_executions = each.value.runner_config.scale_up_reserved_concurrent_executions

Expand Down
6 changes: 6 additions & 0 deletions modules/multi-runner/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -718,3 +718,9 @@ variable "user_agent" {
type = string
default = "github-aws-runners"
}

variable "parameter_store_tags" {
description = "Map of tags that will be added to all the SSM Parameter Store parameters created by the Lambda function."
type = map(string)
default = {}
}
1 change: 1 addition & 0 deletions modules/runners/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ yarn run dist
| <a name="input_metrics"></a> [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. | <pre>object({<br/> enable = optional(bool, false)<br/> namespace = optional(string, "GitHub Runners")<br/> metric = optional(object({<br/> enable_github_app_rate_limit = optional(bool, true)<br/> enable_job_retry = optional(bool, true)<br/> enable_spot_termination_warning = optional(bool, true)<br/> }), {})<br/> })</pre> | `{}` | no |
| <a name="input_minimum_running_time_in_minutes"></a> [minimum\_running\_time\_in\_minutes](#input\_minimum\_running\_time\_in\_minutes) | The time an ec2 action runner should be running at minimum before terminated if non busy. If not set the default is calculated based on the OS. | `number` | `null` | no |
| <a name="input_overrides"></a> [overrides](#input\_overrides) | This map provides the possibility to override some defaults. The following attributes are supported: `name_sg` overrides the `Name` tag for all security groups created by this module. `name_runner_agent_instance` overrides the `Name` tag for the ec2 instance defined in the auto launch configuration. `name_docker_machine_runners` overrides the `Name` tag spot instances created by the runner agent. | `map(string)` | <pre>{<br/> "name_runner": "",<br/> "name_sg": ""<br/>}</pre> | no |
| <a name="input_parameter_store_tags"></a> [parameter\_store\_tags](#input\_parameter\_store\_tags) | Map of tags that will be added to all the SSM Parameter Store parameters created by the Lambda function. | `map(string)` | `{}` | no |
| <a name="input_pool_config"></a> [pool\_config](#input\_pool\_config) | The configuration for updating the pool. The `pool_size` to adjust to by the events triggered by the `schedule_expression`. For example you can configure a cron expression for week days to adjust the pool to 10 and another expression for the weekend to adjust the pool to 1. Use `schedule_expression_timezone ` to override the schedule time zone (defaults to UTC). | <pre>list(object({<br/> schedule_expression = string<br/> schedule_expression_timezone = optional(string)<br/> size = number<br/> }))</pre> | `[]` | no |
| <a name="input_pool_lambda_memory_size"></a> [pool\_lambda\_memory\_size](#input\_pool\_lambda\_memory\_size) | Lambda Memory size limit in MB for pool lambda | `number` | `512` | no |
| <a name="input_pool_lambda_reserved_concurrent_executions"></a> [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 |
Expand Down
5 changes: 5 additions & 0 deletions modules/runners/local.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
locals {
parameter_store_tags = "[${join(", ", [
for key, value in var.parameter_store_tags : "{ key = \"${key}\", value = \"${value}\" }"
])}]"
}
1 change: 1 addition & 0 deletions modules/runners/pool.tf
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ module "pool" {
runtime = var.lambda_runtime
timeout = var.pool_lambda_timeout
zip = local.lambda_zip
parameter_store_tags = local.parameter_store_tags
}
pool = var.pool_config
role_path = local.role_path
Expand Down
2 changes: 1 addition & 1 deletion modules/runners/pool/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ No modules.
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_aws_partition"></a> [aws\_partition](#input\_aws\_partition) | (optional) partition for the arn if not 'aws' | `string` | `"aws"` | no |
| <a name="input_config"></a> [config](#input\_config) | Lookup details in parent module. | <pre>object({<br/> lambda = object({<br/> log_level = string<br/> logging_retention_in_days = number<br/> logging_kms_key_id = string<br/> reserved_concurrent_executions = number<br/> s3_bucket = string<br/> s3_key = string<br/> s3_object_version = string<br/> security_group_ids = list(string)<br/> runtime = string<br/> architecture = string<br/> memory_size = number<br/> timeout = number<br/> zip = string<br/> subnet_ids = list(string)<br/> })<br/> tags = map(string)<br/> ghes = object({<br/> url = string<br/> ssl_verify = string<br/> })<br/> github_app_parameters = object({<br/> key_base64 = map(string)<br/> id = map(string)<br/> })<br/> subnet_ids = list(string)<br/> runner = object({<br/> disable_runner_autoupdate = bool<br/> ephemeral = bool<br/> enable_jit_config = bool<br/> enable_on_demand_failover_for_errors = list(string)<br/> boot_time_in_minutes = number<br/> labels = list(string)<br/> launch_template = object({<br/> name = string<br/> })<br/> group_name = string<br/> name_prefix = string<br/> pool_owner = string<br/> role = object({<br/> arn = string<br/> })<br/> })<br/> instance_types = list(string)<br/> instance_target_capacity_type = string<br/> instance_allocation_strategy = string<br/> instance_max_spot_price = string<br/> prefix = string<br/> pool = list(object({<br/> schedule_expression = string<br/> schedule_expression_timezone = string<br/> size = number<br/> }))<br/> role_permissions_boundary = string<br/> kms_key_arn = string<br/> ami_kms_key_arn = string<br/> ami_id_ssm_parameter_arn = string<br/> role_path = string<br/> ssm_token_path = string<br/> ssm_config_path = string<br/> ami_id_ssm_parameter_name = string<br/> ami_id_ssm_parameter_read_policy_arn = string<br/> arn_ssm_parameters_path_config = string<br/> lambda_tags = map(string)<br/> user_agent = string<br/> })</pre> | n/a | yes |
| <a name="input_config"></a> [config](#input\_config) | Lookup details in parent module. | <pre>object({<br/> lambda = object({<br/> log_level = string<br/> logging_retention_in_days = number<br/> logging_kms_key_id = string<br/> reserved_concurrent_executions = number<br/> s3_bucket = string<br/> s3_key = string<br/> s3_object_version = string<br/> security_group_ids = list(string)<br/> runtime = string<br/> architecture = string<br/> memory_size = number<br/> timeout = number<br/> zip = string<br/> subnet_ids = list(string)<br/> parameter_store_tags = string<br/> })<br/> tags = map(string)<br/> ghes = object({<br/> url = string<br/> ssl_verify = string<br/> })<br/> github_app_parameters = object({<br/> key_base64 = map(string)<br/> id = map(string)<br/> })<br/> subnet_ids = list(string)<br/> runner = object({<br/> disable_runner_autoupdate = bool<br/> ephemeral = bool<br/> enable_jit_config = bool<br/> enable_on_demand_failover_for_errors = list(string)<br/> boot_time_in_minutes = number<br/> labels = list(string)<br/> launch_template = object({<br/> name = string<br/> })<br/> group_name = string<br/> name_prefix = string<br/> pool_owner = string<br/> role = object({<br/> arn = string<br/> })<br/> })<br/> instance_types = list(string)<br/> instance_target_capacity_type = string<br/> instance_allocation_strategy = string<br/> instance_max_spot_price = string<br/> prefix = string<br/> pool = list(object({<br/> schedule_expression = string<br/> schedule_expression_timezone = string<br/> size = number<br/> }))<br/> role_permissions_boundary = string<br/> kms_key_arn = string<br/> ami_kms_key_arn = string<br/> ami_id_ssm_parameter_arn = string<br/> role_path = string<br/> ssm_token_path = string<br/> ssm_config_path = string<br/> ami_id_ssm_parameter_name = string<br/> ami_id_ssm_parameter_read_policy_arn = string<br/> arn_ssm_parameters_path_config = string<br/> lambda_tags = map(string)<br/> user_agent = string<br/> })</pre> | n/a | yes |
| <a name="input_tracing_config"></a> [tracing\_config](#input\_tracing\_config) | Configuration for lambda tracing. | <pre>object({<br/> mode = optional(string, null)<br/> capture_http_requests = optional(bool, false)<br/> capture_error = optional(bool, false)<br/> })</pre> | `{}` | no |

## Outputs
Expand Down
1 change: 1 addition & 0 deletions modules/runners/pool/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ resource "aws_lambda_function" "pool" {
POWERTOOLS_TRACER_CAPTURE_HTTPS_REQUESTS = var.tracing_config.capture_http_requests
POWERTOOLS_TRACER_CAPTURE_ERROR = var.tracing_config.capture_error
ENABLE_ON_DEMAND_FAILOVER_FOR_ERRORS = jsonencode(var.config.runner.enable_on_demand_failover_for_errors)
SSM_PARAMETER_STORE_TAGS = var.config.lambda.parameter_store_tags
}
}

Expand Down
1 change: 1 addition & 0 deletions modules/runners/pool/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ variable "config" {
timeout = number
zip = string
subnet_ids = list(string)
parameter_store_tags = string
})
tags = map(string)
ghes = object({
Expand Down
1 change: 1 addition & 0 deletions modules/runners/scale-up.tf
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ resource "aws_lambda_function" "scale_up" {
POWERTOOLS_SERVICE_NAME = "runners-scale-up"
SSM_TOKEN_PATH = local.token_path
SSM_CONFIG_PATH = "${var.ssm_paths.root}/${var.ssm_paths.config}"
SSM_PARAMETER_STORE_TAGS = local.parameter_store_tags
SUBNET_IDS = join(",", var.subnet_ids)
ENABLE_ON_DEMAND_FAILOVER_FOR_ERRORS = jsonencode(var.enable_on_demand_failover_for_errors)
JOB_RETRY_CONFIG = jsonencode(local.job_retry_config)
Expand Down
6 changes: 6 additions & 0 deletions modules/runners/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -770,3 +770,9 @@ variable "user_agent" {
type = string
default = null
}

variable "parameter_store_tags" {
description = "Map of tags that will be added to all the SSM Parameter Store parameters created by the Lambda function."
type = map(string)
default = {}
}
6 changes: 6 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -1016,3 +1016,9 @@ variable "user_agent" {
type = string
default = "github-aws-runners"
}

variable "parameter_store_tags" {
description = "Map of tags that will be added to all the SSM Parameter Store parameters created by the Lambda function."
type = map(string)
default = {}
}
Loading