main.tf 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. locals {
  2. tags = merge(
  3. {
  4. "Name" = format("%s-action-runner", var.prefix)
  5. },
  6. var.tags,
  7. )
  8. name_sg = var.overrides["name_sg"] == "" ? local.tags["Name"] : var.overrides["name_sg"]
  9. name_runner = var.overrides["name_runner"] == "" ? local.tags["Name"] : var.overrides["name_runner"]
  10. role_path = var.role_path == null ? "/${var.prefix}/" : var.role_path
  11. instance_profile_path = var.instance_profile_path == null ? "/${var.prefix}/" : var.instance_profile_path
  12. lambda_zip = var.lambda_zip == null ? "${path.module}/lambdas/runners/runners.zip" : var.lambda_zip
  13. userdata_template = var.userdata_template == null ? local.default_userdata_template[var.runner_os] : var.userdata_template
  14. kms_key_arn = var.kms_key_arn != null ? var.kms_key_arn : ""
  15. default_ami = {
  16. "windows" = { name = ["Windows_Server-20H2-English-Core-ContainersLatest-*"] }
  17. "linux" = var.runner_architecture == "arm64" ? { name = ["amzn2-ami-kernel-5.*-hvm-*-arm64-gp2"] } : { name = ["amzn2-ami-kernel-5.*-hvm-*-x86_64-gp2"] }
  18. }
  19. default_userdata_template = {
  20. "windows" = "${path.module}/templates/user-data.ps1"
  21. "linux" = "${path.module}/templates/user-data.sh"
  22. }
  23. userdata_install_runner = {
  24. "windows" = "${path.module}/templates/install-runner.ps1"
  25. "linux" = "${path.module}/templates/install-runner.sh"
  26. }
  27. userdata_start_runner = {
  28. "windows" = "${path.module}/templates/start-runner.ps1"
  29. "linux" = "${path.module}/templates/start-runner.sh"
  30. }
  31. ami_filter = coalesce(var.ami_filter, local.default_ami[var.runner_os])
  32. enable_job_queued_check = var.enable_job_queued_check == null ? !var.enable_ephemeral_runners : var.enable_job_queued_check
  33. }
  34. data "aws_ami" "runner" {
  35. most_recent = "true"
  36. dynamic "filter" {
  37. for_each = local.ami_filter
  38. content {
  39. name = filter.key
  40. values = filter.value
  41. }
  42. }
  43. owners = var.ami_owners
  44. }
  45. # tfsec:ignore:aws-ec2-enforce-http-token-imds Saltstack doesn't use s3 sources appropriately; see https://github.com/saltstack/salt/issues/60668
  46. resource "aws_launch_template" "runner" {
  47. # checkov:skip=CKV_AWS_79: see tfsec explanation
  48. name = "${var.prefix}-action-runner"
  49. dynamic "block_device_mappings" {
  50. for_each = var.block_device_mappings != null ? var.block_device_mappings : []
  51. content {
  52. device_name = block_device_mappings.value.device_name
  53. ebs {
  54. delete_on_termination = block_device_mappings.value.delete_on_termination
  55. volume_type = block_device_mappings.value.volume_type
  56. volume_size = block_device_mappings.value.volume_size
  57. encrypted = block_device_mappings.value.encrypted
  58. iops = block_device_mappings.value.iops
  59. }
  60. }
  61. }
  62. dynamic "metadata_options" {
  63. for_each = var.metadata_options != null ? [var.metadata_options] : []
  64. content {
  65. http_endpoint = metadata_options.value.http_endpoint
  66. http_tokens = metadata_options.value.http_tokens
  67. http_put_response_hop_limit = metadata_options.value.http_put_response_hop_limit
  68. }
  69. }
  70. monitoring {
  71. enabled = var.enable_runner_detailed_monitoring
  72. }
  73. iam_instance_profile {
  74. name = aws_iam_instance_profile.runner.name
  75. }
  76. instance_initiated_shutdown_behavior = "terminate"
  77. image_id = data.aws_ami.runner.id
  78. key_name = var.key_name
  79. vpc_security_group_ids = compact(concat(
  80. var.enable_managed_runner_security_group ? [aws_security_group.runner_sg[0].id] : [],
  81. var.runner_additional_security_group_ids,
  82. ))
  83. tag_specifications {
  84. resource_type = "instance"
  85. tags = merge(
  86. local.tags,
  87. {
  88. "Name" = format("%s", local.name_runner)
  89. },
  90. var.runner_ec2_tags
  91. )
  92. }
  93. tag_specifications {
  94. resource_type = "volume"
  95. tags = merge(
  96. local.tags,
  97. {
  98. "Name" = format("%s", local.name_runner)
  99. },
  100. )
  101. }
  102. user_data = var.enabled_userdata ? base64encode(templatefile(local.userdata_template, {
  103. pre_install = var.userdata_pre_install
  104. install_runner = templatefile(local.userdata_install_runner[var.runner_os], {
  105. S3_LOCATION_RUNNER_DISTRIBUTION = var.s3_location_runner_binaries
  106. RUNNER_ARCHITECTURE = var.runner_architecture
  107. })
  108. post_install = var.userdata_post_install
  109. start_runner = templatefile(local.userdata_start_runner[var.runner_os], {})
  110. ghes_url = var.ghes_url
  111. ghes_ssl_verify = var.ghes_ssl_verify
  112. ## retain these for backwards compatibility
  113. environment = var.prefix
  114. enable_cloudwatch_agent = var.enable_cloudwatch_agent
  115. ssm_key_cloudwatch_agent_config = var.enable_cloudwatch_agent ? aws_ssm_parameter.cloudwatch_agent_config_runner[0].name : ""
  116. })) : ""
  117. tags = local.tags
  118. update_default_version = true
  119. }
  120. #----------------------------------------------------------------------------
  121. # GH Actions Security Group
  122. #----------------------------------------------------------------------------
  123. # tfsec:ignore:aws-ec2-no-public-egress-sgr GH runner requires /0 egress access
  124. resource "aws_security_group" "runner_sg" {
  125. count = var.enable_managed_runner_security_group ? 1 : 0
  126. name_prefix = "${var.prefix}-github-actions-runner-sg"
  127. description = "Github Actions Runner security group"
  128. vpc_id = var.vpc_id
  129. #----------------------------------------------------------------------------
  130. # EGRESS
  131. #----------------------------------------------------------------------------
  132. dynamic "egress" {
  133. for_each = var.egress_rules
  134. iterator = each
  135. content {
  136. cidr_blocks = each.value.cidr_blocks
  137. ipv6_cidr_blocks = each.value.ipv6_cidr_blocks
  138. prefix_list_ids = each.value.prefix_list_ids
  139. from_port = each.value.from_port
  140. protocol = each.value.protocol
  141. security_groups = each.value.security_groups
  142. self = each.value.self
  143. to_port = each.value.to_port
  144. description = each.value.description
  145. }
  146. }
  147. tags = merge(
  148. local.tags,
  149. {
  150. "Name" = format("%s", local.name_sg)
  151. },
  152. )
  153. }