Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
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 @@ -205,6 +205,7 @@ Join our discord community via [this invite link](https://discord.gg/bxgXW8jJGh)
| <a name="input_runner_group_name"></a> [runner\_group\_name](#input\_runner\_group\_name) | Name of the runner group. | `string` | `"Default"` | no |
| <a name="input_runner_hook_job_completed"></a> [runner\_hook\_job\_completed](#input\_runner\_hook\_job\_completed) | Script to be ran in the runner environment at the end of every job | `string` | `""` | no |
| <a name="input_runner_hook_job_started"></a> [runner\_hook\_job\_started](#input\_runner\_hook\_job\_started) | Script to be ran in the runner environment at the beginning of every job | `string` | `""` | no |
| <a name="input_runner_iam_role_additional_trust_policy_statements"></a> [runner\_iam\_role\_additional\_trust\_policy\_statements](#input\_runner\_iam\_role\_additional\_trust\_policy\_statements) | Additional statements appended to the trust policy (assume role policy) of the runner IAM role. Statements are in the IAM policy statement format. For example to allow the EC2 service to pass session tags add `[{ Effect = "Allow", Principal = { Service = "ec2.amazonaws.com" }, Action = "sts:TagSession" }]`. | `any` | `[]` | no |
| <a name="input_runner_iam_role_managed_policy_arns"></a> [runner\_iam\_role\_managed\_policy\_arns](#input\_runner\_iam\_role\_managed\_policy\_arns) | Attach AWS or customer-managed IAM policies (by ARN) to the runner IAM role | `list(string)` | `[]` | no |
| <a name="input_runner_license_specifications"></a> [runner\_license\_specifications](#input\_runner\_license\_specifications) | Optional EC2 License Manager license configuration ARNs for the runner launch template. Required for macOS dedicated-host runners when the host resource group uses a Mac dedicated host license configuration. See https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/launch_template#license_specification for details. | <pre>list(object({<br/> license_configuration_arn = string<br/> }))</pre> | `[]` | no |
| <a name="input_runner_log_files"></a> [runner\_log\_files](#input\_runner\_log\_files) | (optional) List of logfiles to send to CloudWatch, will only be used if `enable_cloudwatch_agent` is set to true. Object description: `log_group_name`: Name of the log group, `prefix_log_group`: If true, the log group name will be prefixed with `/github-self-hosted-runners/<var.prefix>`, `file_path`: path to the log file, `log_stream_name`: name of the log stream, `log_class`: The log class of the log group. Valid values are `STANDARD` or `INFREQUENT_ACCESS`. Defaults to `STANDARD`. | <pre>list(object({<br/> log_group_name = string<br/> prefix_log_group = bool<br/> file_path = string<br/> log_stream_name = string<br/> log_class = optional(string, "STANDARD")<br/> }))</pre> | `null` | no |
Expand Down
3 changes: 2 additions & 1 deletion main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,8 @@ module "runners" {

create_service_linked_role_spot = var.create_service_linked_role_spot

runner_iam_role_managed_policy_arns = var.runner_iam_role_managed_policy_arns
runner_iam_role_managed_policy_arns = var.runner_iam_role_managed_policy_arns
runner_iam_role_additional_trust_policy_statements = var.runner_iam_role_additional_trust_policy_statements

ghes_url = var.ghes_url
ghes_ssl_verify = var.ghes_ssl_verify
Expand Down
2 changes: 1 addition & 1 deletion modules/multi-runner/README.md

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions modules/multi-runner/runners.tf
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,9 @@ module "runners" {

create_service_linked_role_spot = each.value.runner_config.create_service_linked_role_spot

runner_iam_role_managed_policy_arns = each.value.runner_config.runner_iam_role_managed_policy_arns
iam_overrides = each.value.runner_config.iam_overrides
runner_iam_role_managed_policy_arns = each.value.runner_config.runner_iam_role_managed_policy_arns
runner_iam_role_additional_trust_policy_statements = each.value.runner_config.runner_iam_role_additional_trust_policy_statements
iam_overrides = each.value.runner_config.iam_overrides

ghes_url = var.ghes_url
ghes_ssl_verify = var.ghes_ssl_verify
Expand Down
2 changes: 2 additions & 0 deletions modules/multi-runner/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ variable "multi_runner_config" {
runner_hook_job_completed = optional(string, "")
runner_ec2_tags = optional(map(string), {})
runner_iam_role_managed_policy_arns = optional(list(string), [])
runner_iam_role_additional_trust_policy_statements = optional(any, [])
vpc_id = optional(string, null)
subnet_ids = optional(list(string), null)
idle_config = optional(list(object({
Expand Down Expand Up @@ -302,6 +303,7 @@ variable "multi_runner_config" {
runner_hook_job_completed: "Script to be ran in the runner environment at the end of every job"
runner_ec2_tags: "Map of tags that will be added to the launch template instance tag specifications."
runner_iam_role_managed_policy_arns: "Attach AWS or customer-managed IAM policies (by ARN) to the runner IAM role"
runner_iam_role_additional_trust_policy_statements: "Additional statements appended to the trust policy (assume role policy) of the runner IAM role. Statements are in the IAM policy statement format."
vpc_id: "The VPC for security groups of the action runners. If not set uses the value of `var.vpc_id`."
subnet_ids: "List of subnets in which the action runners will be launched, the subnets needs to be subnets in the `vpc_id`. If not set, uses the value of `var.subnet_ids`."
idle_config: "List of time period that can be defined as 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."
Expand Down
1 change: 1 addition & 0 deletions modules/runners/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ yarn run dist
| <a name="input_runner_group_name"></a> [runner\_group\_name](#input\_runner\_group\_name) | Name of the runner group. | `string` | `"Default"` | no |
| <a name="input_runner_hook_job_completed"></a> [runner\_hook\_job\_completed](#input\_runner\_hook\_job\_completed) | Script to be ran in the runner environment at the end of every job | `string` | `""` | no |
| <a name="input_runner_hook_job_started"></a> [runner\_hook\_job\_started](#input\_runner\_hook\_job\_started) | Script to be ran in the runner environment at the beginning of every job | `string` | `""` | no |
| <a name="input_runner_iam_role_additional_trust_policy_statements"></a> [runner\_iam\_role\_additional\_trust\_policy\_statements](#input\_runner\_iam\_role\_additional\_trust\_policy\_statements) | Additional statements appended to the trust policy (assume role policy) of the runner IAM role. Statements are in the IAM policy statement format. For example to allow the EC2 service to pass session tags add `[{ Effect = "Allow", Principal = { Service = "ec2.amazonaws.com" }, Action = "sts:TagSession" }]`. | `any` | `[]` | no |
| <a name="input_runner_iam_role_managed_policy_arns"></a> [runner\_iam\_role\_managed\_policy\_arns](#input\_runner\_iam\_role\_managed\_policy\_arns) | Attach AWS or customer-managed IAM policies (by ARN) to the runner IAM role | `list(string)` | `[]` | no |
| <a name="input_runner_labels"></a> [runner\_labels](#input\_runner\_labels) | All the labels for the runners (GitHub) including the default one's(e.g: self-hosted, linux, x64, label1, label2). Separate each label by a comma | `list(string)` | n/a | yes |
| <a name="input_runner_log_files"></a> [runner\_log\_files](#input\_runner\_log\_files) | (optional) List of logfiles to send to CloudWatch, will only be used if `enable_cloudwatch_agent` is set to true. Object description: `log_group_name`: Name of the log group, `prefix_log_group`: If true, the log group name will be prefixed with `/github-self-hosted-runners/<var.prefix>`, `file_path`: path to the log file, `log_stream_name`: name of the log stream, `log_class`: The log class of the log group. Valid values are `STANDARD` or `INFREQUENT_ACCESS`. Defaults to `STANDARD`. | <pre>list(object({<br/> log_group_name = string<br/> prefix_log_group = bool<br/> file_path = string<br/> log_stream_name = string<br/> log_class = optional(string, "STANDARD")<br/> }))</pre> | `null` | no |
Expand Down
15 changes: 12 additions & 3 deletions modules/runners/policies-runner.tf
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
data "aws_caller_identity" "current" {}

locals {
runner_role_trust_policy = jsondecode(file("${path.module}/policies/instance-role-trust-policy.json"))
}

resource "aws_iam_role" "runner" {
count = var.iam_overrides["override_runner_role"] ? 0 : 1
name = "${substr("${var.prefix}-runner", 0, 54)}-${substr(md5("${var.prefix}-runner"), 0, 8)}"
assume_role_policy = templatefile("${path.module}/policies/instance-role-trust-policy.json", {})
count = var.iam_overrides["override_runner_role"] ? 0 : 1
name = "${substr("${var.prefix}-runner", 0, 54)}-${substr(md5("${var.prefix}-runner"), 0, 8)}"
assume_role_policy = jsonencode(merge(local.runner_role_trust_policy, {
Statement = concat(
local.runner_role_trust_policy.Statement,
var.runner_iam_role_additional_trust_policy_statements
Comment thread
chris-griffin marked this conversation as resolved.
Outdated
)
}))
path = local.role_path
permissions_boundary = var.role_permissions_boundary
tags = local.tags
Expand Down
100 changes: 100 additions & 0 deletions modules/runners/tests/runner-trust-policy.tftest.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
mock_provider "aws" {
mock_data "aws_iam_policy_document" {
defaults = {
json = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"lambda.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"
}
}
}

variables {
aws_region = "eu-west-1"
vpc_id = "vpc-12345678"
subnet_ids = ["subnet-12345678"]

instance_types = ["m5.large"]

s3_runner_binaries = {
arn = "arn:aws:s3:::my-bucket"
id = "my-bucket"
key = "runners/linux/actions-runner.tar.gz"
}

sqs_build_queue = {
arn = "arn:aws:sqs:eu-west-1:123456789012:build-queue"
url = "https://sqs.eu-west-1.amazonaws.com/123456789012/build-queue"
}

enable_organization_runners = true
enable_ssm_on_runners = true
runner_labels = ["self-hosted", "linux", "x64"]

# Use S3 bucket to avoid filebase64sha256 needing local zip files
lambda_s3_bucket = "my-lambda-bucket"
runners_lambda_s3_key = "runners.zip"

github_app_parameters = {
key_base64 = [{ name = "/github-runner/key-base64", arn = "arn:aws:ssm:eu-west-1:123456789012:parameter/github-runner/key-base64" }]
id = [{ name = "/github-runner/app-id", arn = "arn:aws:ssm:eu-west-1:123456789012:parameter/github-runner/app-id" }]
installation_id = [null]
}

ssm_paths = {
root = "/github-runner"
tokens = "tokens"
config = "config"
}
}

run "default_trust_policy" {
command = plan

assert {
condition = length(jsondecode(aws_iam_role.runner[0].assume_role_policy).Statement) == 1
error_message = "By default the runner role trust policy should only contain the EC2 service statement"
}

assert {
condition = jsondecode(aws_iam_role.runner[0].assume_role_policy).Statement[0].Action == "sts:AssumeRole"
error_message = "The default runner role trust policy should allow sts:AssumeRole"
}
}

run "additional_trust_policy_statements" {
command = plan

variables {
runner_iam_role_additional_trust_policy_statements = [
{
Effect = "Allow"
Principal = { Service = "ec2.amazonaws.com" }
Action = "sts:TagSession"
},
{
Sid = "AllowBuildAccount"
Effect = "Allow"
Principal = { AWS = ["arn:aws:iam::123456789012:root"] }
Action = ["sts:AssumeRole", "sts:TagSession"]
}
]
}

assert {
condition = length(jsondecode(aws_iam_role.runner[0].assume_role_policy).Statement) == 3
error_message = "Additional trust policy statements should be appended to the default statement"
}

assert {
condition = jsondecode(aws_iam_role.runner[0].assume_role_policy).Statement[0].Action == "sts:AssumeRole"
error_message = "The default statement should be kept as first statement"
}

assert {
condition = jsondecode(aws_iam_role.runner[0].assume_role_policy).Statement[1].Action == "sts:TagSession"
error_message = "The additional statements should be added in the provided order"
}

assert {
condition = jsondecode(aws_iam_role.runner[0].assume_role_policy).Statement[2].Sid == "AllowBuildAccount"
error_message = "The additional statements should be added in the provided order"
}
}
11 changes: 11 additions & 0 deletions modules/runners/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,17 @@ variable "runner_iam_role_managed_policy_arns" {
default = []
}

variable "runner_iam_role_additional_trust_policy_statements" {
description = "Additional statements appended to the trust policy (assume role policy) of the runner IAM role. Statements are in the IAM policy statement format. For example to allow the EC2 service to pass session tags add `[{ Effect = \"Allow\", Principal = { Service = \"ec2.amazonaws.com\" }, Action = \"sts:TagSession\" }]`."
type = any
default = []

validation {
condition = can([for statement in var.runner_iam_role_additional_trust_policy_statements : statement])
error_message = "The variable `runner_iam_role_additional_trust_policy_statements` must be a list of IAM policy statements."
}
}
Comment thread
chris-griffin marked this conversation as resolved.

variable "enable_cloudwatch_agent" {
description = "Enabling the cloudwatch agent on the ec2 runner instances, the runner contains default config. Configuration can be overridden via `cloudwatch_config`."
type = bool
Expand Down
11 changes: 11 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,17 @@ variable "runner_iam_role_managed_policy_arns" {
default = []
}

variable "runner_iam_role_additional_trust_policy_statements" {
description = "Additional statements appended to the trust policy (assume role policy) of the runner IAM role. Statements are in the IAM policy statement format. For example to allow the EC2 service to pass session tags add `[{ Effect = \"Allow\", Principal = { Service = \"ec2.amazonaws.com\" }, Action = \"sts:TagSession\" }]`."
type = any
default = []

validation {
condition = can([for statement in var.runner_iam_role_additional_trust_policy_statements : statement])
error_message = "The variable `runner_iam_role_additional_trust_policy_statements` must be a list of IAM policy statements."
}
}
Comment thread
chris-griffin marked this conversation as resolved.

variable "enable_cloudwatch_agent" {
description = "Enables the cloudwatch agent on the ec2 runner instances. The runner uses a default config that can be overridden via `cloudwatch_config`."
type = bool
Expand Down
Loading