Преглед на файлове

Adds module for github runners using philips labs 3rd party module

Adds a github runner to the test GHE.
Currently runs amazon linux, so not good enough for prod yet.

Uses third party module from https://github.com/philips-labs/terraform-aws-github-runner

To be tagged v5.1.9
Fred Damstra [afs macbook] преди 3 години
родител
ревизия
4e2cfe2ba7
променени са 100 файла, в които са добавени 3436 реда и са изтрити 0 реда
  1. 5 0
      base/account_standards/iam.tf
  2. 1 0
      base/account_standards_c2/account_alerts.tf
  3. 1 0
      base/account_standards_c2/config_aggregator.tf
  4. 1 0
      base/account_standards_c2/elb_bucket.tf
  5. 1 0
      base/account_standards_c2/iam.moose-hf.tf
  6. 47 0
      base/account_standards_c2/secrets.tf
  7. 49 0
      base/github-runners/README.md
  8. 1 0
      base/github-runners/constants.tf
  9. 1 0
      base/github-runners/globals.tf
  10. 6 0
      base/github-runners/locals.tf
  11. 94 0
      base/github-runners/main.tf
  12. 15 0
      base/github-runners/outputs.tf
  13. 28 0
      base/github-runners/secrets.tf
  14. 20 0
      base/github-runners/vars.tf
  15. 8 0
      thirdparty/terraform-aws-github-runner/CHANGELOG.md
  16. 140 0
      thirdparty/terraform-aws-github-runner/CONTRIBUTING.md
  17. 7 0
      thirdparty/terraform-aws-github-runner/LICENSE.md
  18. 2 0
      thirdparty/terraform-aws-github-runner/MAINTAINERS.md
  19. 53 0
      thirdparty/terraform-aws-github-runner/README.XDR.md
  20. 523 0
      thirdparty/terraform-aws-github-runner/README.md
  21. 0 0
      thirdparty/terraform-aws-github-runner/docs/architecture.drawio
  22. 2 0
      thirdparty/terraform-aws-github-runner/docs/architecture.svg
  23. 2 0
      thirdparty/terraform-aws-github-runner/docs/component-overview.svg
  24. 88 0
      thirdparty/terraform-aws-github-runner/docs/test-lambda-local.md
  25. 60 0
      thirdparty/terraform-aws-github-runner/examples/arm64/.terraform.lock.hcl
  26. 31 0
      thirdparty/terraform-aws-github-runner/examples/arm64/README.md
  27. 25 0
      thirdparty/terraform-aws-github-runner/examples/arm64/lambdas-download/main.tf
  28. 77 0
      thirdparty/terraform-aws-github-runner/examples/arm64/main.tf
  29. 15 0
      thirdparty/terraform-aws-github-runner/examples/arm64/outputs.tf
  30. 3 0
      thirdparty/terraform-aws-github-runner/examples/arm64/providers.tf
  31. 4 0
      thirdparty/terraform-aws-github-runner/examples/arm64/variables.tf
  32. 15 0
      thirdparty/terraform-aws-github-runner/examples/arm64/versions.tf
  33. 7 0
      thirdparty/terraform-aws-github-runner/examples/arm64/vpc.tf
  34. 60 0
      thirdparty/terraform-aws-github-runner/examples/default/.terraform.lock.hcl
  35. 31 0
      thirdparty/terraform-aws-github-runner/examples/default/README.md
  36. 25 0
      thirdparty/terraform-aws-github-runner/examples/default/lambdas-download/main.tf
  37. 84 0
      thirdparty/terraform-aws-github-runner/examples/default/main.tf
  38. 15 0
      thirdparty/terraform-aws-github-runner/examples/default/outputs.tf
  39. 3 0
      thirdparty/terraform-aws-github-runner/examples/default/providers.tf
  40. 4 0
      thirdparty/terraform-aws-github-runner/examples/default/variables.tf
  41. 15 0
      thirdparty/terraform-aws-github-runner/examples/default/versions.tf
  42. 21 0
      thirdparty/terraform-aws-github-runner/examples/default/vpc.tf
  43. 60 0
      thirdparty/terraform-aws-github-runner/examples/ephemeral/.terraform.lock.hcl
  44. 30 0
      thirdparty/terraform-aws-github-runner/examples/ephemeral/README.md
  45. 25 0
      thirdparty/terraform-aws-github-runner/examples/ephemeral/lambdas-download/main.tf
  46. 84 0
      thirdparty/terraform-aws-github-runner/examples/ephemeral/main.tf
  47. 15 0
      thirdparty/terraform-aws-github-runner/examples/ephemeral/outputs.tf
  48. 3 0
      thirdparty/terraform-aws-github-runner/examples/ephemeral/providers.tf
  49. 5 0
      thirdparty/terraform-aws-github-runner/examples/ephemeral/variables.tf
  50. 15 0
      thirdparty/terraform-aws-github-runner/examples/ephemeral/versions.tf
  51. 21 0
      thirdparty/terraform-aws-github-runner/examples/ephemeral/vpc.tf
  52. 60 0
      thirdparty/terraform-aws-github-runner/examples/permissions-boundary/.terraform.lock.hcl
  53. 35 0
      thirdparty/terraform-aws-github-runner/examples/permissions-boundary/README.md
  54. 25 0
      thirdparty/terraform-aws-github-runner/examples/permissions-boundary/lambdas-download/main.tf
  55. 60 0
      thirdparty/terraform-aws-github-runner/examples/permissions-boundary/main.tf
  56. 12 0
      thirdparty/terraform-aws-github-runner/examples/permissions-boundary/outputs.tf
  57. 7 0
      thirdparty/terraform-aws-github-runner/examples/permissions-boundary/providers.tf
  58. 22 0
      thirdparty/terraform-aws-github-runner/examples/permissions-boundary/setup/.terraform.lock.hcl
  59. 15 0
      thirdparty/terraform-aws-github-runner/examples/permissions-boundary/setup/main.tf
  60. 7 0
      thirdparty/terraform-aws-github-runner/examples/permissions-boundary/setup/outputs.tf
  61. 3 0
      thirdparty/terraform-aws-github-runner/examples/permissions-boundary/setup/providers.tf
  62. 9 0
      thirdparty/terraform-aws-github-runner/examples/permissions-boundary/setup/versions.tf
  63. 8 0
      thirdparty/terraform-aws-github-runner/examples/permissions-boundary/variables.tf
  64. 15 0
      thirdparty/terraform-aws-github-runner/examples/permissions-boundary/versions.tf
  65. 21 0
      thirdparty/terraform-aws-github-runner/examples/permissions-boundary/vpc.tf
  66. 60 0
      thirdparty/terraform-aws-github-runner/examples/prebuilt/.terraform.lock.hcl
  67. 93 0
      thirdparty/terraform-aws-github-runner/examples/prebuilt/README.md
  68. 25 0
      thirdparty/terraform-aws-github-runner/examples/prebuilt/lambdas-download/main.tf
  69. 47 0
      thirdparty/terraform-aws-github-runner/examples/prebuilt/main.tf
  70. 15 0
      thirdparty/terraform-aws-github-runner/examples/prebuilt/outputs.tf
  71. 3 0
      thirdparty/terraform-aws-github-runner/examples/prebuilt/providers.tf
  72. 19 0
      thirdparty/terraform-aws-github-runner/examples/prebuilt/variables.tf
  73. 15 0
      thirdparty/terraform-aws-github-runner/examples/prebuilt/versions.tf
  74. 21 0
      thirdparty/terraform-aws-github-runner/examples/prebuilt/vpc.tf
  75. 60 0
      thirdparty/terraform-aws-github-runner/examples/ubuntu/.terraform.lock.hcl
  76. 24 0
      thirdparty/terraform-aws-github-runner/examples/ubuntu/README.md
  77. 25 0
      thirdparty/terraform-aws-github-runner/examples/ubuntu/lambdas-download/main.tf
  78. 102 0
      thirdparty/terraform-aws-github-runner/examples/ubuntu/main.tf
  79. 15 0
      thirdparty/terraform-aws-github-runner/examples/ubuntu/outputs.tf
  80. 11 0
      thirdparty/terraform-aws-github-runner/examples/ubuntu/providers.tf
  81. 73 0
      thirdparty/terraform-aws-github-runner/examples/ubuntu/templates/user-data.sh
  82. 4 0
      thirdparty/terraform-aws-github-runner/examples/ubuntu/variables.tf
  83. 15 0
      thirdparty/terraform-aws-github-runner/examples/ubuntu/versions.tf
  84. 21 0
      thirdparty/terraform-aws-github-runner/examples/ubuntu/vpc.tf
  85. 60 0
      thirdparty/terraform-aws-github-runner/examples/windows/.terraform.lock.hcl
  86. 26 0
      thirdparty/terraform-aws-github-runner/examples/windows/README.md
  87. 25 0
      thirdparty/terraform-aws-github-runner/examples/windows/lambdas-download/main.tf
  88. 48 0
      thirdparty/terraform-aws-github-runner/examples/windows/main.tf
  89. 15 0
      thirdparty/terraform-aws-github-runner/examples/windows/outputs.tf
  90. 3 0
      thirdparty/terraform-aws-github-runner/examples/windows/providers.tf
  91. 4 0
      thirdparty/terraform-aws-github-runner/examples/windows/variables.tf
  92. 15 0
      thirdparty/terraform-aws-github-runner/examples/windows/versions.tf
  93. 21 0
      thirdparty/terraform-aws-github-runner/examples/windows/vpc.tf
  94. 37 0
      thirdparty/terraform-aws-github-runner/images/README.md
  95. 8 0
      thirdparty/terraform-aws-github-runner/images/install-runner.ps1
  96. 8 0
      thirdparty/terraform-aws-github-runner/images/install-runner.sh
  97. 174 0
      thirdparty/terraform-aws-github-runner/images/linux-amzn2/github_agent.linux.pkr.hcl
  98. 3 0
      thirdparty/terraform-aws-github-runner/images/start-runner.ps1
  99. 9 0
      thirdparty/terraform-aws-github-runner/images/start-runner.sh
  100. 185 0
      thirdparty/terraform-aws-github-runner/images/ubuntu-focal/github_agent.ubuntu.pkr.hcl

+ 5 - 0
base/account_standards/iam.tf

@@ -340,3 +340,8 @@ resource "aws_iam_role_policy" "splunk_addon_for_aws" {
   role   = aws_iam_role.splunk_addon_for_aws.id
   policy = data.aws_iam_policy_document.policy.json
 }
+
+## Service Linked Role - For GitHub Runners and Others
+resource "aws_iam_service_linked_role" "spot" {
+  aws_service_name = "spot.amazonaws.com"
+}

+ 1 - 0
base/account_standards_c2/account_alerts.tf

@@ -1,4 +1,5 @@
 # An SNS queue for email alerts
+# tfsec:ignore:aws-sns-enable-topic-encryption
 resource "aws_sns_topic" "account-alerts" {
   name = "account-alerts"
   tags = merge(local.standard_tags, var.tags)

+ 1 - 0
base/account_standards_c2/config_aggregator.tf

@@ -7,6 +7,7 @@ resource "aws_config_configuration_aggregator" "account" {
   }
 }
 
+# tfsec:ignore:aws-sns-enable-topic-encryption
 resource "aws_sns_topic" "config-notifications" {
   name = "config-notifications"
   #kms_master_key_id = aws_kms_key.config-notifications-key.id # TODO

+ 1 - 0
base/account_standards_c2/elb_bucket.tf

@@ -43,6 +43,7 @@ resource "aws_s3_bucket_logging" "elb_logging_bucket" {
   target_prefix = "${var.aws_account_id}-${var.aws_region}-elblogs/"
 }
 
+# tfsec:ignore:aws-s3-encryption-customer-key
 resource "aws_s3_bucket_server_side_encryption_configuration" "s3_sse_elb_logging_bucket" {
   bucket = aws_s3_bucket.elb_logging_bucket.id
 

+ 1 - 0
base/account_standards_c2/iam.moose-hf.tf

@@ -111,6 +111,7 @@ resource "aws_iam_user" "moose-hf" {
   tags = merge(local.standard_tags, var.tags)
 }
 
+# tfsec:ignore:aws-iam-enforce-mfa
 resource "aws_iam_group" "moose-hf" {
   name = "moose-hf"
   path = "/instance/"

+ 47 - 0
base/account_standards_c2/secrets.tf

@@ -3,6 +3,7 @@ output "secrets_manager_reminder" {
   value = "REMINDER: If this is your first time, don't forget to update the secrets in secrets manager."
 }
 
+# tfsec:ignore:aws-ssm-secret-use-customer-key
 resource "aws_secretsmanager_secret" "codebuild_ghe_key" {
   name                    = "GHE/mdr-aws-codebuild/key"
   description             = "GitHub Personal Access Key for the mdr-aws-codebuild account"
@@ -15,3 +16,49 @@ resource "aws_secretsmanager_secret_version" "codebuild_ghe_secret_version" {
   secret_id     = aws_secretsmanager_secret.codebuild_ghe_key.id
   secret_string = "SETME"
 }
+
+#####################
+# GitHub Runners Need WebHook Secrets
+# and Keys
+locals {
+  ghe_orgs_with_runners = {
+    test = toset([
+      "MDR-Engineering"
+    ]),
+    prod = toset([
+      "mdr-engineering"
+    ])
+  }[var.environment]
+}
+
+# tfsec:ignore:aws-ssm-secret-use-customer-key
+resource "aws_secretsmanager_secret" "github-runners-webhook-secret" {
+  for_each                = local.ghe_orgs_with_runners
+  name                    = "GHE/runners/${each.value}/webhook_secret"
+  description             = "Webhook Secret for GitHub Runners for ${each.value}"
+  recovery_window_in_days = 30
+  tags                    = merge(local.standard_tags, var.tags)
+}
+
+# This just seeds an initial value. It will not be overwritten each update.
+resource "aws_secretsmanager_secret_version" "github-runners-webhook-secret" {
+  for_each      = local.ghe_orgs_with_runners
+  secret_id     = aws_secretsmanager_secret.github-runners-webhook-secret[each.value].id
+  secret_string = "SETME"
+}
+
+# tfsec:ignore:aws-ssm-secret-use-customer-key
+resource "aws_secretsmanager_secret" "github-runners-webhook-key" {
+  for_each                = local.ghe_orgs_with_runners
+  name                    = "GHE/runners/${each.value}/webhook_key"
+  description             = "Base64 Encoded Webhook Key for GitHub Runners for ${each.value}"
+  recovery_window_in_days = 30
+  tags                    = merge(local.standard_tags, var.tags)
+}
+
+# This just seeds an initial value. It will not be overwritten each update.
+resource "aws_secretsmanager_secret_version" "github-runners" {
+  for_each      = local.ghe_orgs_with_runners
+  secret_id     = aws_secretsmanager_secret.github-runners-webhook-key[each.value].id
+  secret_string = "SETME"
+}

+ 49 - 0
base/github-runners/README.md

@@ -0,0 +1,49 @@
+# Module to Add GitHub Runners to an organization using instances that stand up on demand.
+
+Keep the costs low! Uses spot instances. Based off https://github.com/philips-labs/terraform-aws-github-runner
+
+Most of this code is from the 'examples' directory. 
+
+See also the XDR readme in `xdr-terraform-modules/thirdparty/terraform-aws-github-runner/README.XDR.md`
+
+## To add runners to a new organization
+
+### Step 1: Prepare the Secrets
+1. Add the organization to the `ghe_orgs_with_runners` variable in `~/xdr-terraform-modules/base/account_standards_c2/secrets.tf`.
+1. Update the module and apply. It should create a number of 'SETME' secrets entries.
+1. Follow normal PR procedures and apply.
+
+### Step 2: Initial Configuration of the GitHub App
+1. Follow the instructions for ["Setup GitHub App (part 1)"](https://github.com/philips-labs/terraform-aws-github-runner#setup-github-app-part-1)
+  a. Note the "App ID" and "Client ID" parameters
+  b. Temporarily save the app.private-key.pem file
+1. Convert the private key to base64
+```
+cat app.private-key.pem | base64
+```
+1. Log into the AWS Console, go to the C2 account->Secrets Manager, and record the base64 string under `GHE/runners/<GHE ORG>/webhook_key`
+
+### Step 3: Copy the Module in xdr-terraform-live
+
+1. Copy the module for a new organization
+```
+cp -a ~/xdr-terraform-live/test/aws-us-gov/mdr-test-c2/093-github-runners-mdr-engineering ~/xdr-terraform-live/test/aws-us-gov/mdr-test-c2/093-github-runners-NEWORG`
+```
+1. Edit the terragrunt.hcl in the new module and set the org and `github_app_id` appropriately
+1. Follow normal PR procedures and apply.
+1. Run `terragrunt output webhook_secret` and record the output
+
+### Step 4: Finish the App Installation
+
+1. Follow the instructions for ["Setup the webhook / GitHub App (part 2)"](https://github.com/philips-labs/terraform-aws-github-runner#setup-the-webhook--github-app-part-2)
+  a. Choose option #2 to configure the webhook for the app
+  b. Don't forget to install the app itself.
+
+## TESTING
+
+There is a sample repo at https://github.xdrtest.accenturefederalcyber.com/MDR-Engineering/xdr-test-runners that has an extremely simple workflow job. Clone the repo,
+update `NUM`, commit, and push back to main.
+
+Then check two things:
+a) In the AWS EC2 console, go to instances, and search for 'runners'. An instance should be created.
+b) On https://github.xdrtest.accenturefederalcyber.com/MDR-Engineering/xdr-test-runners/actions

+ 1 - 0
base/github-runners/constants.tf

@@ -0,0 +1 @@
+../../variables/constants.tf

+ 1 - 0
base/github-runners/globals.tf

@@ -0,0 +1 @@
+../../variables/globals.tf

+ 6 - 0
base/github-runners/locals.tf

@@ -0,0 +1,6 @@
+locals {
+  ghes_url = {
+    test = "https://github.xdrtest.accenturefederalcyber.com"
+    prod = "https://github.xdr.accenturefederalcyber.com"
+  }[var.environment]
+}

+ 94 - 0
base/github-runners/main.tf

@@ -0,0 +1,94 @@
+resource "random_id" "random" {
+  byte_length = 20
+}
+
+
+################################################################################
+### Hybrid account
+################################################################################
+
+# Ignoring tfsec issues within the third party module:
+# TODO: Revisit these
+# tfsec:ignore:aws-vpc-no-public-egress-sgr
+# tfsec:ignore:aws-sqs-enable-queue-encryption
+# tfsec:ignore:aws-s3-encryption-customer-key
+# tfsec:ignore:aws-s3-enable-bucket-encryption
+# tfsec:ignore:aws-autoscaling-enforce-http-token-imds
+# tfsec:ignore:aws-s3-enable-versioning
+# tfsec:ignore:aws-api-gateway-enable-access-logging
+module "runners" {
+  source                          = "../../thirdparty/terraform-aws-github-runner"
+  create_service_linked_role_spot = false
+  aws_partition                   = var.aws_partition
+  aws_region                      = var.aws_region
+  vpc_id                          = var.vpc_id
+  subnet_ids                      = var.public_subnets # should these be private?
+
+  ghes_url = local.ghes_url
+  prefix   = lower("${var.org}-github-runners")
+  tags     = merge(local.standard_tags, var.tags, { org = var.org })
+
+  github_app = {
+    key_base64     = local.webhook_key
+    id             = var.github_app_id
+    webhook_secret = random_id.random.hex
+  }
+
+  # Spot or on-demand
+  instance_target_capacity_type = "spot"
+
+  # configure the block device mappings, default for Amazon Linux2
+  block_device_mappings = [{
+    device_name           = "/dev/xvda"
+    delete_on_termination = true
+    volume_type           = "gp3"
+    volume_size           = 10
+    encrypted             = true
+    iops                  = null
+  }]
+
+  lambda_s3_bucket      = "afsxdr-binaries"
+  webhook_lambda_s3_key = "terraform-aws-github/webhook.zip"
+  syncer_lambda_s3_key  = "terraform-aws-github/runner-binaries-syncer.zip"
+  runners_lambda_s3_key = "terraform-aws-github/runners.zip"
+
+  enable_organization_runners = true
+  runner_extra_labels         = "default"
+
+  role_path             = "/lambda/"
+  instance_profile_path = "/lambda/"
+
+  # enable access to the runners via SSM
+  enable_ssm_on_runners = true
+
+  # use S3 or KMS SSE to runners S3 bucket
+  runner_binaries_s3_sse_configuration = {
+    rule = {
+      apply_server_side_encryption_by_default = {
+        sse_algorithm = "AES256"
+      }
+    }
+  }
+
+  # Uncommet idle config to have idle runners from 9 to 5 in time zone Amsterdam
+  # idle_config = [{
+  #   cron      = "* * 9-17 * * *"
+  #   timeZone  = "Europe/Amsterdam"
+  #   idleCount = 1
+  # }]
+
+  # Let the module manage the service linked role
+  # create_service_linked_role_spot = true
+
+  instance_types = ["m5a.large", "c5a.large"]
+
+  # override delay of events in seconds
+  delay_webhook_event   = 5
+  runners_maximum_count = 1
+
+  # set up a fifo queue to remain order
+  fifo_build_queue = true
+
+  # override scaling down
+  #scale_down_schedule_expression = "cron(* * * * ? *)"
+}

+ 15 - 0
base/github-runners/outputs.tf

@@ -0,0 +1,15 @@
+output "runners" {
+  value = {
+    lambda_syncer_name = module.runners.binaries_syncer.lambda.function_name
+  }
+}
+
+output "webhook_endpoint" {
+  value = module.runners.webhook.endpoint
+}
+
+output "webhook_secret" {
+  sensitive = true
+  value     = random_id.random.hex
+}
+

+ 28 - 0
base/github-runners/secrets.tf

@@ -0,0 +1,28 @@
+# Webhook and secrets are stored in secrets manager in the C2 account.
+data "aws_secretsmanager_secret" "webhook_secret" {
+  name     = "GHE/runners/${var.org}/webhook_secret"
+  provider = aws.c2
+}
+
+data "aws_secretsmanager_secret_version" "webhook_secret" {
+  secret_id = data.aws_secretsmanager_secret.webhook_secret.id
+  provider  = aws.c2
+}
+
+locals {
+  webhook_secret = data.aws_secretsmanager_secret_version.webhook_secret.secret_string
+}
+
+data "aws_secretsmanager_secret" "webhook_key" {
+  name     = "GHE/runners/${var.org}/webhook_key"
+  provider = aws.c2
+}
+
+data "aws_secretsmanager_secret_version" "webhook_key" {
+  secret_id = data.aws_secretsmanager_secret.webhook_key.id
+  provider  = aws.c2
+}
+
+locals {
+  webhook_key = data.aws_secretsmanager_secret_version.webhook_key.secret_string
+}

+ 20 - 0
base/github-runners/vars.tf

@@ -0,0 +1,20 @@
+variable "org" {
+  type        = string
+  description = "GitHub Organization"
+}
+
+variable "github_app_id" {
+  type        = number
+  description = "Github App ID from the App Configuration"
+}
+
+variable "vpc_id" { type = string }
+variable "azs" { type = list(string) }
+variable "public_subnets" { type = list(string) }
+variable "private_subnets" { type = list(string) }
+
+variable "tags" {
+  description = "Tags to add to the resource (in addition to global standard tags)"
+  type        = map(any)
+  default     = {}
+}

Файловите разлики са ограничени, защото са твърде много
+ 8 - 0
thirdparty/terraform-aws-github-runner/CHANGELOG.md


+ 140 - 0
thirdparty/terraform-aws-github-runner/CONTRIBUTING.md

@@ -0,0 +1,140 @@
+# Contributing to Forest Terraform
+
+We'd love for you to contribute to our source code and to make the Forest even better than it is today! Here are the guidelines we'd like you to follow:
+
+* [Question or Problem?](#question)
+* [Issues and Bugs](#issue)
+* [Feature Requests](#feature)
+* [Submission Guidelines](#submit)
+* [Further Info](#info)
+
+## <a name="question"></a> Got a Question or Problem?
+
+If you have questions about how to use the Forest, please direct these to the [Slack group / philips-software][slack].
+
+[![Slack](https://philips-software-slackin.now.sh/badge.svg)](https://philips-software-slackin.now.sh)
+
+## <a name="issue"></a> Found an Issue?
+
+If you find a bug in the source code or a mistake in the documentation, you can help us by submitting an issue to our [Github Repository][github]. Even better you can submit a Pull Request with a fix.
+
+**Please see the [Submission Guidelines](#submit) below.**
+
+## <a name="feature"></a> Want a Feature?
+
+You can request a new feature by submitting an issue to our [Github Repository][github]. If you would like to implement a new feature then consider what kind of change it is:
+
+* **Major Changes** that you wish to contribute to the project should be discussed first on our [Slack group][slack] so that we can better coordinate our efforts, prevent duplication of work, and help you to craft the change so that it is successfully accepted into the project.
+* **Small Changes** can be crafted and submitted to the [Github Repository][github] as a Pull Request.
+
+## <a name="docs"></a> Want a Doc Fix?
+
+If you want to help improve the docs, it's a good idea to let others know what you're working on to minimize duplication of effort. Create a new issue (or comment on a related existing one) to let others know what you're working on.
+
+For large fixes, please build and test the documentation before submitting the MR to be sure you haven't accidentally introduced any layout or formatting issues. You should also make sure that your commit message starts with "docs" and follows the **[Commit Message Guidelines](#commit)** outlined below.
+
+## <a name="submit"></a> Submission Guidelines
+
+### Submitting an Issue
+
+Before you submit your issue search the archive, maybe your question was already answered.
+
+If your issue appears to be a bug, and hasn't been reported, open a new issue. Help us to maximize the effort we can spend fixing issues and adding new features, by not reporting duplicate issues. Providing the following information will increase the chances of your issue being dealt with quickly:
+
+* **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps
+* **Motivation for or Use Case** - explain why this is a bug for you
+* **Forest Version(s)** - is it a regression?
+* **Reproduce the Error** - try to describe how to reproduce the error
+* **Related Issues** - has a similar issue been reported before?
+* **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be
+  causing the problem (line of code or commit)
+
+**If you get help, help others. Good karma rulez!**
+
+### Submitting a Merge Request
+
+Before you submit your merge request consider the following guidelines:
+
+* Make your changes in a new git branch:
+
+    ```shell
+    git checkout -b my-fix-branch develop
+    ```
+
+* Create your patch, **including appropriate test cases**.
+* Install [Terraform](https://www.terraform.io/). We lock the version with [tvenv](https://github.com/tfutils/tfenv), check `required_version` in `versions.tf` for the current development version of the module.
+* Install [pre-commit hooks](https://pre-commit.com/). The hooks runs some basic checks and update the docs. The commit will run the hooks, you can invoke the hooks manually `pre-commit run --all-files` as well.
+* Commit your changes using a descriptive commit message.
+
+    ```shell
+    git commit -a
+    ```
+
+  Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
+
+* Build your changes locally to ensure all the tests pass:
+* Push your branch to Github:
+
+    ```shell
+    git push origin my-fix-branch
+    ```
+
+In Github, send a pull request to original develop branch: f.e. `terraform-aws-github-runner:develop`.
+If we suggest changes, then:
+
+* Make the required updates.
+* Re-run the test suite to ensure tests are still passing.
+* Commit your changes to your branch (e.g. `my-fix-branch`).
+* Push the changes to your Github repository (this will update your Pull Request).
+
+If the PR gets too outdated we may ask you to rebase and force push to update the PR:
+
+```shell
+git rebase develop -i
+git push origin my-fix-branch -f
+```
+
+_WARNING: Squashing or reverting commits and force-pushing thereafter may remove Github comments on code that were previously made by you or others in your commits. Avoid any form of rebasing unless necessary._
+
+That's it! Thank you for your contribution!
+
+#### After your merge request is merged
+
+After your pull request is merged, you can safely delete your branch and pull the changes
+from the main (upstream) repository:
+
+* Delete the remote branch on Github either through the Github web UI or your local shell as follows:
+
+    ```shell
+    git push origin --delete my-fix-branch
+    ```
+
+* Check out the develop branch:
+
+    ```shell
+    git checkout develop -f
+    ```
+
+* Delete the local branch:
+
+    ```shell
+    git branch -D my-fix-branch
+    ```
+
+* Update your develop with the latest upstream version:
+
+    ```shell
+    git pull --ff upstream develop
+    ```
+
+## <a name="info"></a> Info
+
+For more info, please reach out to the team on [Slack group / philips-software][slack] in the #forest channel.
+
+Use the badge to sign-up.
+
+[![Slack](https://philips-software-slackin.now.sh/badge.svg)](https://philips-software-slackin.now.sh)
+
+[contribute]: CONTRIBUTING.md
+[github]: https://github.com/philips-labs/terraform-aws-github-runner/issues
+[slack]: https://philips-software.slack.com/home

+ 7 - 0
thirdparty/terraform-aws-github-runner/LICENSE.md

@@ -0,0 +1,7 @@
+The MIT License (MIT) Copyright © 2020 Koninklijke Philips N.V, https://www.philips.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 2 - 0
thirdparty/terraform-aws-github-runner/MAINTAINERS.md

@@ -0,0 +1,2 @@
+Gertjan Maas <gertjan.maas@philips.com>
+Niek Palm <niek.palm@philips.com>

+ 53 - 0
thirdparty/terraform-aws-github-runner/README.XDR.md

@@ -0,0 +1,53 @@
+# XDR's Submodule for GitHub Runners
+
+Original Source: https://github.com/philips-labs/terraform-aws-github-runner
+
+## For USAGE, see the module documentation at
+```
+~/xdr-terraform-modules/base/github-runners/README.md
+```
+
+## Significant Changes
+
+* in `modules/runners/policies/lambda-scale-up.json`, added section for KMS access:
+```
+        {
+            "Effect": "Allow",
+            "Action": [
+                "kms:CreateGrant",
+                "kms:Decrypt",
+                "kms:DescribeKey",
+                "kms:Encrypt",
+                "kms:GenerateDataKey*",
+                "kms:ReEncrypt*"
+            ],
+            "Resource": "*"
+```
+* in `modules/runners/scale-{up,down}.tf`, `modules/webhook/webhook.tf`, and `./modules/runner-binaries-syncer/runner-binaries-syncer.tf` changed architectures line to be:
+```
+  architectures     = var.lambda_architecture == "x86_64" ? [] : [var.lambda_architecture]
+```
+This solves an issue where terraform thinks there's a change every time.
+* Similarly, for `./modules/runners/pool/main.tf`, changed architectures line to be:
+```
+  architectures     = var.config.lambda_architecture == "x86_64" ? [] : [var.config.lambda_architecture]
+```
+
+## Process
+
+1. Cloned repo
+1. `rm -rf .git`
+1. Follow the `Setup GitHub App (part 1)` instructions at https://github.com/philips-labs/terraform-aws-github-runner#setup-github-app-part-1
+  a. App name: `mdr-engineering-runners`
+  b. Everything else as instructed.
+1. Download the lambdas from the ['releases' page](https://github.com/philips-labs/terraform-aws-github-runner/releases) into `~/Downloads/terraform-aws-github`
+1. Upload the lambdas:
+```
+cd ~/Downloads/
+aws --profile mdr-common-services-gov s3 sync terraform-aws-github s3://afsxdr-binaries/terraform-aws-github
+aws --profile mdr-common-services     s3 sync terraform-aws-github s3://afsxdr-binaries/terraform-aws-github
+```
+1. Add variables to ~/xdr-terraform-modules/base/github-runners/locals.tf
+1. Modify variables in ~/xdr-terraform-live/test/aws-us-gov/mdr-test-c2/093-github-runners-mdr-engineering
+1. `terragrunt-local init && terragrunt-local apply`
+1. Follow the instructions at ['Setup the webhook'](https://github.com/philips-labs/terraform-aws-github-runner#setup-the-webhook--github-app-part-2)

+ 523 - 0
thirdparty/terraform-aws-github-runner/README.md

@@ -0,0 +1,523 @@
+# Terraform module for scalable self hosted GitHub action runners <!-- omit in toc -->
+
+[![awesome-runners](https://img.shields.io/badge/listed%20on-awesome--runners-blue.svg)](https://github.com/jonico/awesome-runners)[![Terraform registry](https://img.shields.io/github/v/release/philips-labs/terraform-aws-github-runner?label=Terraform%20Registry)](https://registry.terraform.io/modules/philips-labs/github-runner/aws/) ![Terraform checks](https://github.com/philips-labs/terraform-aws-github-runner/workflows/Terraform%20root%20module%20checks/badge.svg) ![Lambda Webhook](https://github.com/philips-labs/terraform-aws-github-runner/workflows/Lambda%20Agent%20Webhook/badge.svg) ![Lambda Runners](https://github.com/philips-labs/terraform-aws-github-runner/workflows/Lambda%20Runners/badge.svg) ![Lambda Syncer](https://github.com/philips-labs/terraform-aws-github-runner/workflows/Lambda%20Runner%20Binaries%20Syncer/badge.svg)
+
+This [Terraform](https://www.terraform.io/) module creates the required infrastructure needed to host [GitHub Actions](https://github.com/features/actions) self-hosted, auto-scaling runners on [AWS spot instances](https://aws.amazon.com/ec2/spot/). It provides the required logic to handle the life cycle for scaling up and down using a set of AWS Lambda functions. Runners are scaled down to zero to avoid costs when no workflows are active.
+
+> 📢 HELP WANTED: We are running the AWS self-hosted GitHub runners OS project in Philips Labs for over two years! And we are incredibly happy with all the feedback and contribution of the open-source community. In the next months we will speak at some conferences to share the solution and story of running this open-source project. Via [this questionaire](https://forms.office.com/r/j03CUzdLFp) we would like to gather  feedback from the community to use in our talks.
+
+- [Motivation](#motivation)
+- [Overview](#overview)
+  - [Major configuration options.](#major-configuration-options)
+    - [ARM64 support via Graviton/Graviton2 instance-types](#arm64-support-via-gravitongraviton2-instance-types)
+- [Usages](#usages)
+  - [Setup GitHub App (part 1)](#setup-github-app-part-1)
+  - [Setup terraform module](#setup-terraform-module)
+  - [Setup the webhook / GitHub App (part 2)](#setup-the-webhook--github-app-part-2)
+    - [Option 1: Webhook](#option-1-webhook)
+    - [Option 2: App](#option-2-app)
+    - [Install app](#install-app)
+  - [Encryption](#encryption)
+  - [Pool](#pool)
+  - [Idle runners](#idle-runners)
+  - [Ephemeral runners](#ephemeral-runners)
+  - [Prebuilt Images](#prebuilt-images)
+- [Examples](#examples)
+- [Sub modules](#sub-modules)
+  - [ARM64 configuration for submodules](#arm64-configuration-for-submodules)
+- [Debugging](#debugging)
+- [Requirements](#requirements)
+- [Providers](#providers)
+- [Modules](#modules)
+- [Resources](#resources)
+- [Inputs](#inputs)
+- [Outputs](#outputs)
+- [Contribution](#contribution)
+- [Philips Forest](#philips-forest)
+
+## Motivation
+
+GitHub Actions `self-hosted` runners provide a flexible option to run CI workloads on the infrastructure of your choice. Currently, no option is provided to automate the creation and scaling of action runners. This module creates the AWS infrastructure to host action runners on spot instances. It provides lambda modules to orchestrate the life cycle of the action runners.
+
+Lambda is chosen as the runtime for two major reasons. First, it allows the creation of small components with minimal access to AWS and GitHub. Secondly, it provides a scalable setup with minimal costs that works on repo level and scales to organization level. The lambdas will create Linux based EC2 instances with Docker to serve CI workloads that can run on Linux and/or Docker. The main goal is to support Docker-based workloads.
+
+A logical question would be, why not Kubernetes? In the current approach, we stay close to how the GitHub action runners are available today. The approach is to install the runner on a host where the required software is available. With this setup, we stay quite close to the current GitHub approach. Another logical choice would be AWS Auto Scaling groups. However, this choice would typically require much more permissions on instance level to GitHub. And besides that, scaling up and down is not trivial.
+
+## Overview
+
+The moment a GitHub action workflow requiring a `self-hosted` runner is triggered, GitHub will try to find a runner which can execute the workload. This module reacts to GitHub's [`check_run` event](https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#check_run) or [`workflow_job` event](https://docs.github.com/en/free-pro-team@latest/developers/webhooks-and-events/webhook-events-and-payloads#workflow_job) for the triggered workflow and creates a new runner if necessary.
+
+For receiving the `check_run` or `workflow_job` event by the webhook (lambda), a webhook needs to be created in GitHub. The `workflow_job` is the preferred option, and the `check_run` option will be maintained for backward compatibility. The advantage of the `workflow_job` event is that the runner checks if the received event can run on the configured runners by matching the labels, which avoid instances being scaled up and never used. The following options are available:
+
+- `workflow_job`: **(preferred option)** create a webhook on enterprise, org or app level. Select this option for ephemeral runners.
+- `check_run`: create a webhook on enterprise, org, repo or app level. When using the app option, the app needs to be installed to repo's are using the self-hosted runners.
+-  a Webhook needs to be created. The webhook hook can be defined on enterprise, org, repo, or app level.
+
+In AWS a [API gateway](https://docs.aws.amazon.com/apigateway/index.html) endpoint is created that is able to receive the GitHub webhook events via HTTP post. The gateway triggers the webhook lambda which will verify the signature of the event. This check guarantees the event is sent by the GitHub App. The lambda only handles `workflow_job` or `check_run` events with status `queued` and matching the runner labels (only for `workflow_job`). The accepted events are posted on a SQS queue. Messages on this queue will be delayed for a configurable amount of seconds (default 30 seconds) to give the available runners time to pick up this build.
+
+The "scale up runner" lambda listens to the SQS queue and picks up events. The lambda runs various checks to decide whether a new EC2 spot instance needs to be created. For example, the instance is not created if the build is already started by an existing runner, or the maximum number of runners is reached.
+
+The Lambda first requests a registration token from GitHub, which is needed later by the runner to register itself. This avoids that the EC2 instance, which later in the process will install the agent, needs administration permissions to register the runner. Next, the EC2 spot instance is created via the launch template. The launch template defines the specifications of the required instance and contains a [`user_data`](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html) script. This script will install the required software and configure it. The registration token for the action runner is stored in the parameter store (SSM), from which the user data script will fetch it and delete it once it has been retrieved. Once the user data script is finished, the action runner should be online, and the workflow will start in seconds.
+
+Scaling down the runners is at the moment brute-forced, every configurable amount of minutes a lambda will check every runner (instance) if it is busy. In case the runner is not busy it will be removed from GitHub and the instance terminated in AWS. At the moment there seems no other option to scale down more smoothly.
+
+Downloading the GitHub Action Runner distribution can be occasionally slow (more than 10 minutes). Therefore a lambda is introduced that synchronizes the action runner binary from GitHub to an S3 bucket. The EC2 instance will fetch the distribution from the S3 bucket instead of the internet.
+
+Secrets and private keys are stored in SSM Parameter Store. These values are encrypted using the default KMS key for SSM or passing in a custom KMS key.
+
+![Architecture](docs/component-overview.svg)
+
+Permission are managed on several places. Below the most important ones. For details check the Terraform sources.
+
+- The GitHub App requires access to actions and publish `workflow_job` events to the AWS webhook (API gateway).
+- The scale up lambda should have access to EC2 for creating and tagging instances.
+- The scale down lambda should have access to EC2 to terminate instances.
+
+Besides these permissions, the lambdas also need permission to CloudWatch (for logging and scheduling), SSM and S3. For more details about the required permissions see the [documentation](./modules/setup-iam-permissions/README.md) of the IAM module which uses permission boundaries.
+
+### Major configuration options.
+
+To be able to support a number of use-cases the module has quite a lot of configuration options. We try to choose reasonable defaults. The several examples also show for the main cases how to configure the runners.
+
+- Org vs Repo level. You can configure the module to connect the runners in GitHub on an org level and share the runners in your org. Or set the runners on repo level and the module will install the runner to the repo. There can be multiple repos but runners are not shared between repos.
+- Checkrun vs Workflow job event. You can configure the webhook in GitHub to send checkrun or workflow job events to the webhook. Workflow job events are introduced by GitHub in September 2021 and are designed to support scalable runners. We advise when possible using the workflow job event, you can set `runner_enable_workflow_job_labels_check = true` to let the webhook only accept jobs based on the labels configured. The webhook will check the custom labels provided via the variable `runner_extra_labels` and the GitHub managed labels, "self-hosted", OS and architecture. The OS and architecture are derived from the settings. By default the check is disabled.
+- Linux vs Windows. you can configure the OS types linux and win. Linux will be used by default.
+- Re-use vs Ephemeral. By default runners are re-used for till detected idle. Once idle they will be removed from the pool. To improve security we are introducing ephemeral runners. Those runners are only used for one job. Ephemeral runners are only working in combination with the workflow job event. We also suggest using a pre-build AMI to improve the start time of jobs.
+- GitHub Cloud vs GitHub Enterprise Server (GHES). The runner support GitHub Cloud as well GitHub Enterprise Server. For GHES we rely on our community to test and support. We have no possibility to test ourselves on GHES.
+- Spot vs on-demand. The runners use either the EC2 spot or on-demand life cycle. Runners will be created via the AWS [CreateFleet API](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateFleet.html). The module (scale up lambda) will request via the CreateFleet API to create instances in one of the subnets and of the specified instance types.
+
+
+#### ARM64 support via Graviton/Graviton2 instance-types
+
+When using the default example or top-level module, specifying `instance_types` that match a Graviton/Graviton 2 (ARM64) architecture (e.g. a1, t4g or any 6th-gen `g` or `gd` type), you must also specify `runner_architecture = "arm64"` and the sub-modules will be automatically configured to provision with ARM64 AMIs and leverage GitHub's ARM64 action runner. See below for more details.
+
+## Usages
+
+Examples are provided in [the example directory](examples/). Please ensure you have installed the following tools.
+
+- Terraform, or [tfenv](https://github.com/tfutils/tfenv).
+- Bash shell or compatible
+- Docker (optional, to build lambdas without node).
+- AWS cli (optional)
+- Node and yarn (for lambda development).
+
+The module supports two main scenarios for creating runners. On repository level a runner will be dedicated to only one repository, no other repository can use the runner. On organization level you can use the runner(s) for all the repositories within the organization. See [GitHub self-hosted runner instructions](https://help.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners) for more information. Before starting the deployment you have to choose one option.
+
+The setup consists of running Terraform to create all AWS resources and manually configuring the GitHub App. The Terraform module requires configuration from the GitHub App and the GitHub app requires output from Terraform. Therefore you first create the GitHub App and configure the basics, then run Terraform, and afterwards finalize the configuration of the GitHub App.
+
+### Setup GitHub App (part 1)
+
+Go to GitHub and [create a new app](https://docs.github.com/en/developers/apps/creating-a-github-app). Beware you can create apps your organization or for a user. For now we support only organization level apps.
+
+1. Create app in Github
+2. Choose a name
+3. Choose a website (mandatory, not required for the module).
+4. Disable the webhook for now (we will configure this later or create an alternative webhook).
+5. Permissions for all runners:
+    - Repository:
+      - `Actions`: Read-only (check for queued jobs)
+      - `Checks`: Read-only (receive events for new builds)
+      - `Metadata`: Read-only (default/required)
+6. _Permissions for repo level runners only_:
+   - Repository:
+     - `Administration`: Read & write (to register runner)
+7. _Permissions for organization level runners only_:
+   - Organization
+     - `Self-hosted runners`: Read & write (to register runner)
+8. Save the new app.
+9. On the General page, make a note of the "App ID" and "Client ID" parameters.
+10. Generate a new private key and save the `app.private-key.pem` file.
+
+### Setup terraform module
+
+#### Download lambdas <!-- omit in toc -->
+
+To apply the terraform module, the compiled lambdas (.zip files) need to be available either locally or in an S3 bucket. They can be either downloaded from the GitHub release page or build locally.
+
+To read the files from S3, set the `lambda_s3_bucket` variable and the specific object key for each lambda.
+
+The lambdas can be downloaded manually from the [release page](https://github.com/philips-labs/terraform-aws-github-runner/releases) or using the [download-lambda](./modules/download-lambda) terraform module (requires `curl` to be installed on your machine). In the `download-lambda` directory, run `terraform init && terraform apply`. The lambdas will be saved to the same directory.
+
+For local development you can build all the lambdas at once using `.ci/build.sh` or individually using `yarn dist`.
+
+#### Service-linked role <!-- omit in toc -->
+
+To create spot instances the `AWSServiceRoleForEC2Spot` role needs to be added to your account. You can do that manually by following the [AWS docs](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-requests.html#service-linked-roles-spot-instance-requests). To use terraform for creating the role, either add the following resource or let the module manage the the service linked role by setting `create_service_linked_role_spot` to `true`. Be aware this is an account global role, so maybe you don't want to manage it via a specific deployment.
+
+```hcl
+resource "aws_iam_service_linked_role" "spot" {
+  aws_service_name = "spot.amazonaws.com"
+}
+```
+
+#### Terraform module <!-- omit in toc -->
+
+Next create a second terraform workspace and initiate the module, or adapt one of the [examples](./examples).
+
+Note that `github_app.key_base64` needs to be a base64-encoded string of the `.pem` file i.e. the output of `base64 app.private-key.pem`. The decoded string can either be a multiline value or a single line value with new lines represented with literal `\n` characters.
+
+```terraform
+module "github-runner" {
+  source  = "philips-labs/github-runner/aws"
+  version = "REPLACE_WITH_VERSION"
+
+  aws_region = "eu-west-1"
+  vpc_id     = "vpc-123"
+  subnet_ids = ["subnet-123", "subnet-456"]
+
+  environment = "gh-ci"
+
+  github_app = {
+    key_base64     = "base64string"
+    id             = "1"
+    webhook_secret = "webhook_secret"
+  }
+
+  webhook_lambda_zip                = "lambdas-download/webhook.zip"
+  runner_binaries_syncer_lambda_zip = "lambdas-download/runner-binaries-syncer.zip"
+  runners_lambda_zip                = "lambdas-download/runners.zip"
+  enable_organization_runners = true
+}
+```
+
+Run terraform by using the following commands
+
+```bash
+terraform init
+terraform apply
+```
+
+The terraform output displays the API gateway url (endpoint) and secret, which you need in the next step.
+
+The lambda for syncing the GitHub distribution to S3 is triggered via CloudWatch (by default once per hour). After deployment the function is triggered via S3 to ensure the distribution is cached.
+
+### Setup the webhook / GitHub App (part 2)
+
+At this point you have 2 options. Either create a separate webhook (enterprise,
+org, or repo), or create webhook in the App.
+
+#### Option 1: Webhook
+
+1. Create a new webhook on repo level for repo level for repo level runner, or org (or enterprise level) for an org level runner.
+2. Provide the webhook url, should be part of the output of terraform.
+3. Provide the webhook secret (`terraform output -raw <NAME_OUTPUT_VAR>`).
+4. Ensure content type as `application/json`.
+5. In the "Permissions & Events" section and then "Subscribe to Events" subsection, check either "Workflow Job" or "Check Run" (choose only 1 option!!!).
+6. In the "Install App" section, install the App in your organization, either in all or in selected repositories.
+
+#### Option 2: App
+
+Go back to the GitHub App and update the following settings.
+
+1. Enable the webhook.
+2. Provide the webhook url, should be part of the output of terraform.
+3. Provide the webhook secret (`terraform output -raw <NAME_OUTPUT_VAR>`).
+4. In the "Permissions & Events" section and then "Subscribe to Events" subsection, check either "Workflow Job" or "Check Run" (choose only 1 option!!!).
+
+#### Install app
+
+Finally you need to ensure the app is installed to all or selected repositories.
+
+Go back to the GitHub App and update the following settings.
+
+1. In the "Install App" section, install the App in your organization, either in all or in selected repositories.
+
+### Encryption
+
+The module support 2 scenarios to manage environment secrets and private key of the Lambda functions.
+
+#### Encrypted via a module managed KMS key (default) <!-- omit in toc -->
+
+This is the default, no additional configuration is required.
+
+#### Encrypted via a provided KMS key <!-- omit in toc -->
+
+You have to create an configure you KMS key. The module will use the context with key: `Environment` and value `var.environment` as encryption context.
+
+```hcl
+resource "aws_kms_key" "github" {
+  is_enabled = true
+}
+
+module "runners" {
+
+  ...
+  kms_key_arn = aws_kms_key.github.arn
+  ...
+
+```
+
+### Pool
+
+The module basically supports two options for keeping a pool of runners. One is via a pool which only supports org-level runners, the second option is [keeping runners idle](#idle-runners).
+
+The pool is introduced in combination with the ephemeral runners and is primary meant to ensure if any event is unexpected dropped, and no runner was created the pool can pick up the job. The pool is maintained by a lambda. Each time the lambda is triggered a check is preformed if the number of idler runners managed by the module are meeting the expected pool size. If not, the pool will be adjusted. Keep in mind that the scale down function is still active and will terminate instances that are detected as idle.
+
+```hcl
+pool_runner_owner = "my-org"                  # Org to which the runners are added
+pool_config = [{
+  size                = 20                    # size of the pool
+  schedule_expression = "cron(* * * * ? *)"   # cron expression to trigger the adjustment of the pool
+}]
+```
+
+The pool is NOT enabled by default and can be enabled by setting at least one object of the pool config list. The [ephemeral example](./examples/ephemeral/README.md) contains configuration options (commented out).
+
+### Idle runners
+
+The module will scale down to zero runners by default. By specifying a `idle_config` config, idle runners can be kept active. The scale down lambda checks if any of the cron expressions matches the current time with a margin of 5 seconds. When there is a match, the number of runners specified in the idle config will be kept active. In case multiple cron expressions matches, only the first one is taken into account. Below is an idle configuration for keeping runners active from 9 to 5 on working days.
+
+```hcl
+idle_config = [{
+   cron      = "* * 9-17 * * 1-5"
+   timeZone  = "Europe/Amsterdam"
+   idleCount = 2
+}]
+```
+
+_**Note**_: When using Windows runners it's recommended to keep a few runners warmed up due to the minutes-long cold start time.
+
+
+#### Supported config <!-- omit in toc -->
+
+Cron expressions are parsed by [cron-parser](https://github.com/harrisiirak/cron-parser#readme). The supported syntax.
+
+```bash
+*    *    *    *    *    *
+┬    ┬    ┬    ┬    ┬    ┬
+│    │    │    │    │    |
+│    │    │    │    │    └ day of week (0 - 7) (0 or 7 is Sun)
+│    │    │    │    └───── month (1 - 12)
+│    │    │    └────────── day of month (1 - 31)
+│    │    └─────────────── hour (0 - 23)
+│    └──────────────────── minute (0 - 59)
+└───────────────────────── second (0 - 59, optional)
+```
+
+For time zones please check [TZ database name column](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) for the supported values.
+
+### Ephemeral runners
+
+Currently a beta feature! You can configure runners to be ephemeral, runners will be used only for one job. The feature should be used in conjunction with listening for the workflow job event. Please consider the following:
+
+- The scale down lambda is still active, and should only remove orphan instances. But there is no strict check in place. So ensure you configure the `minimum_running_time_in_minutes` to a value that is high enough to got your runner booted and connected to avoid it got terminated before executing a job.
+- The messages sent from the webhook lambda to scale-up lambda are by default delayed delayed by SQS, to give available runners to option to start the job before the decision is made to scale more runners. For ephemeral runners there is no need to wait. Set `delay_webhook_event` to `0`.
+- All events on the queue will lead to a new runner crated by the lambda. By setting `enable_job_queued_check` to `true` you can enforce only create a runner if the event has a correlated queued job. Setting this can avoid creating useless runners, for example whn jobs got cancelled before a runner is created. We suggest to use this in combination with a pool.
+- To ensure runners are created in the same order GitHub sends the events we use by default a FIFO queue, this is mainly relevant for repo level runners. For ephemeral runners you can set `fifo_build_queue` to `false`.
+- Error related to scaling should be retried via SQS. You can configure `job_queue_retention_in_seconds` `redrive_build_queue` to tune the behavior. We have no mechanism to avoid events will never processed, which means potential no runner could be created and the job in GitHub can time out in 6 hours.
+
+The example for [ephemeral runners](./examples/ephemeral) is based on the [default example](./examples/default). Have look on the diff to see the major configuration differences.
+
+### Prebuilt Images
+
+This module also allows you to run agents from a prebuilt AMI to gain faster startup times. You can find more information in [the image README.md](/images/README.md)
+
+
+## Examples
+
+Examples are located in the [examples](./examples) directory. The following examples are provided:
+
+- _[Default](examples/default/README.md)_: The default example of the module
+- _[ARM64](examples/arm64/README.md)_: Example usage with ARM64 architecture
+- _[Ubuntu](examples/ubuntu/README.md)_: Example usage of creating a runner using Ubuntu AMIs.
+- _[Windows](examples/windows/README.md)_: Example usage of creating a runner using Windows as the OS.
+- _[Ephemeral](examples/ephemeral/README.md)_: Example usages of ephemeral runners based on the default example.
+- _[Prebuilt Images](examples/prebuilt/README.md)_: Example usages of deploying runners with a custom prebuilt image.
+- _[Permissions boundary](examples/permissions-boundary/README.md)_: Example usages of permissions boundaries.
+
+## Sub modules
+
+The module contains several submodules, you can use the module via the main module or assemble your own setup by initializing the submodules yourself.
+
+The following submodules are the core of the module and are mandatory:
+
+- _[runner-binaries-syncer](./modules/runner-binaries-syncer/README.md)_ - Syncs the action runner distribution.
+- _[runners](./modules/runners/README.md)_ - Scales the action runners up and down
+- _[webhook](./modules/webhook/README.md)_ - Handles GitHub webhooks
+
+The following sub modules are optional and are provided as example or utility:
+
+- _[download-lambda](./modules/download-lambda/README.md)_ - Utility module to download lambda artifacts from GitHub Release
+- _[setup-iam-permissions](./modules/setup-iam-permissions/README.md)_ - Example module to setup permission boundaries
+
+### ARM64 configuration for submodules
+
+When using the top level module configure `runner_architecture = "arm64"` and ensure the list of `instance_types` matches. When not using the top-level, ensure these properties are set on the submodules.
+
+## Debugging
+
+In case the setup does not work as intended follow the trace of events:
+
+- In the GitHub App configuration, the Advanced page displays all webhook events that were sent.
+- In AWS CloudWatch, every lambda has a log group. Look at the logs of the `webhook` and `scale-up` lambdas.
+- In AWS SQS you can see messages available or in flight.
+- Once an EC2 instance is running, you can connect to it in the EC2 user interface using Session Manager (use `enable_ssm_on_runners = true`). Check the user data script using `cat /var/log/user-data.log`. By default several log files of the instances are streamed to AWS CloudWatch, look for a log group named `<environment>/runners`. In the log group you should see at least the log streams for the user data installation and runner agent.
+- Registered instances should show up in the Settings - Actions page of the repository or organization (depending on the installation mode).
+
+<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
+## Requirements
+
+| Name | Version |
+|------|---------|
+| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 0.14.1 |
+| <a name="requirement_aws"></a> [aws](#requirement\_aws) | ~> 4.15 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| <a name="provider_aws"></a> [aws](#provider\_aws) | ~> 4.15 |
+| <a name="provider_random"></a> [random](#provider\_random) | n/a |
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| <a name="module_runner_binaries"></a> [runner\_binaries](#module\_runner\_binaries) | ./modules/runner-binaries-syncer | n/a |
+| <a name="module_runners"></a> [runners](#module\_runners) | ./modules/runners | n/a |
+| <a name="module_ssm"></a> [ssm](#module\_ssm) | ./modules/ssm | n/a |
+| <a name="module_webhook"></a> [webhook](#module\_webhook) | ./modules/webhook | n/a |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_resourcegroups_group.resourcegroups_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/resourcegroups_group) | resource |
+| [aws_sqs_queue.queued_builds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sqs_queue) | resource |
+| [aws_sqs_queue.queued_builds_dlq](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sqs_queue) | resource |
+| [aws_sqs_queue_policy.build_queue_dlq_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sqs_queue_policy) | resource |
+| [aws_sqs_queue_policy.build_queue_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sqs_queue_policy) | resource |
+| [random_string.random](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | resource |
+| [aws_iam_policy_document.deny_unsecure_transport](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| <a name="input_ami_filter"></a> [ami\_filter](#input\_ami\_filter) | List of maps used to create the AMI filter for the action runner AMI. By default amazon linux 2 is used. | `map(list(string))` | `null` | no |
+| <a name="input_ami_owners"></a> [ami\_owners](#input\_ami\_owners) | The list of owners used to select the AMI of action runner instances. | `list(string)` | <pre>[<br>  "amazon"<br>]</pre> | no |
+| <a name="input_aws_partition"></a> [aws\_partition](#input\_aws\_partition) | (optiona) partition in the arn namespace to use if not 'aws' | `string` | `"aws"` | no |
+| <a name="input_aws_region"></a> [aws\_region](#input\_aws\_region) | AWS region. | `string` | n/a | yes |
+| <a name="input_block_device_mappings"></a> [block\_device\_mappings](#input\_block\_device\_mappings) | The EC2 instance block device configuration. Takes the following keys: `device_name`, `delete_on_termination`, `volume_type`, `volume_size`, `encrypted`, `iops` | <pre>list(object({<br>    device_name           = string<br>    delete_on_termination = bool<br>    volume_type           = string<br>    volume_size           = number<br>    encrypted             = bool<br>    iops                  = number<br>  }))</pre> | <pre>[<br>  {<br>    "delete_on_termination": true,<br>    "device_name": "/dev/xvda",<br>    "encrypted": true,<br>    "iops": null,<br>    "volume_size": 30,<br>    "volume_type": "gp3"<br>  }<br>]</pre> | no |
+| <a name="input_cloudwatch_config"></a> [cloudwatch\_config](#input\_cloudwatch\_config) | (optional) Replaces the module default cloudwatch log config. See https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Agent-Configuration-File-Details.html for details. | `string` | `null` | no |
+| <a name="input_create_service_linked_role_spot"></a> [create\_service\_linked\_role\_spot](#input\_create\_service\_linked\_role\_spot) | (optional) create the serviced linked role for spot instances that is required by the scale-up lambda. | `bool` | `false` | no |
+| <a name="input_delay_webhook_event"></a> [delay\_webhook\_event](#input\_delay\_webhook\_event) | The number of seconds the event accepted by the webhook is invisible on the queue before the scale up lambda will receive the event. | `number` | `30` | no |
+| <a name="input_disable_runner_autoupdate"></a> [disable\_runner\_autoupdate](#input\_disable\_runner\_autoupdate) | Disable the auto update of the github runner agent. Be-aware there is a grace period of 30 days, see also the [GitHub article](https://github.blog/changelog/2022-02-01-github-actions-self-hosted-runners-can-now-disable-automatic-updates/) | `bool` | `false` | no |
+| <a name="input_enable_cloudwatch_agent"></a> [enable\_cloudwatch\_agent](#input\_enable\_cloudwatch\_agent) | Enabling the cloudwatch agent on the ec2 runner instances, the runner contains default config. Configuration can be overridden via `cloudwatch_config`. | `bool` | `true` | no |
+| <a name="input_enable_ephemeral_runners"></a> [enable\_ephemeral\_runners](#input\_enable\_ephemeral\_runners) | Enable ephemeral runners, runners will only be used once. | `bool` | `false` | no |
+| <a name="input_enable_job_queued_check"></a> [enable\_job\_queued\_check](#input\_enable\_job\_queued\_check) | Only scale if the job event received by the scale up lambda is is in the state queued. By default enabled for non ephemeral runners and disabled for ephemeral. Set this variable to overwrite the default behavior. | `bool` | `null` | no |
+| <a name="input_enable_managed_runner_security_group"></a> [enable\_managed\_runner\_security\_group](#input\_enable\_managed\_runner\_security\_group) | Enabling the default managed security group creation. Unmanaged security groups can be specified via `runner_additional_security_group_ids`. | `bool` | `true` | no |
+| <a name="input_enable_organization_runners"></a> [enable\_organization\_runners](#input\_enable\_organization\_runners) | Register runners to organization, instead of repo level | `bool` | `false` | no |
+| <a name="input_enable_runner_detailed_monitoring"></a> [enable\_runner\_detailed\_monitoring](#input\_enable\_runner\_detailed\_monitoring) | Should detailed monitoring be enabled for the runner. Set this to true if you want to use detailed monitoring. See https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-cloudwatch-new.html for details. | `bool` | `false` | no |
+| <a name="input_enable_ssm_on_runners"></a> [enable\_ssm\_on\_runners](#input\_enable\_ssm\_on\_runners) | Enable to allow access the runner instances for debugging purposes via SSM. Note that this adds additional permissions to the runner instances. | `bool` | `false` | no |
+| <a name="input_enabled_userdata"></a> [enabled\_userdata](#input\_enabled\_userdata) | Should the userdata script be enabled for the runner. Set this to false if you are using your own prebuilt AMI. | `bool` | `true` | no |
+| <a name="input_environment"></a> [environment](#input\_environment) | A name that identifies the environment, used as prefix and for tagging. | `string` | `null` | no |
+| <a name="input_fifo_build_queue"></a> [fifo\_build\_queue](#input\_fifo\_build\_queue) | Enable a FIFO queue to remain the order of events received by the webhook. Suggest to set to true for repo level runners. | `bool` | `false` | no |
+| <a name="input_ghes_ssl_verify"></a> [ghes\_ssl\_verify](#input\_ghes\_ssl\_verify) | GitHub Enterprise SSL verification. Set to 'false' when custom certificate (chains) is used for GitHub Enterprise Server (insecure). | `bool` | `true` | no |
+| <a name="input_ghes_url"></a> [ghes\_url](#input\_ghes\_url) | GitHub Enterprise Server URL. Example: https://github.internal.co - DO NOT SET IF USING PUBLIC GITHUB | `string` | `null` | no |
+| <a name="input_github_app"></a> [github\_app](#input\_github\_app) | GitHub app parameters, see your github app. Ensure the key is the base64-encoded `.pem` file (the output of `base64 app.private-key.pem`, not the content of `private-key.pem`). | <pre>object({<br>    key_base64     = string<br>    id             = string<br>    webhook_secret = string<br>  })</pre> | n/a | yes |
+| <a name="input_idle_config"></a> [idle\_config](#input\_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. | <pre>list(object({<br>    cron      = string<br>    timeZone  = string<br>    idleCount = number<br>  }))</pre> | `[]` | no |
+| <a name="input_instance_allocation_strategy"></a> [instance\_allocation\_strategy](#input\_instance\_allocation\_strategy) | The allocation strategy for spot instances. AWS recommends to use `capacity-optimized` however the AWS default is `lowest-price`. | `string` | `"lowest-price"` | no |
+| <a name="input_instance_max_spot_price"></a> [instance\_max\_spot\_price](#input\_instance\_max\_spot\_price) | Max price price for spot intances per hour. This variable will be passed to the create fleet as max spot price for the fleet. | `string` | `null` | no |
+| <a name="input_instance_profile_path"></a> [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 |
+| <a name="input_instance_target_capacity_type"></a> [instance\_target\_capacity\_type](#input\_instance\_target\_capacity\_type) | Default lifecycle used for runner instances, can be either `spot` or `on-demand`. | `string` | `"spot"` | no |
+| <a name="input_instance_type"></a> [instance\_type](#input\_instance\_type) | [DEPRECATED] See instance\_types. | `string` | `null` | no |
+| <a name="input_instance_types"></a> [instance\_types](#input\_instance\_types) | List of instance types for the action runner. Defaults are based on runner\_os (amzn2 for linux and Windows Server Core for win). | `list(string)` | <pre>[<br>  "m5.large",<br>  "c5.large"<br>]</pre> | no |
+| <a name="input_job_queue_retention_in_seconds"></a> [job\_queue\_retention\_in\_seconds](#input\_job\_queue\_retention\_in\_seconds) | The number of seconds the job is held in the queue before it is purged | `number` | `86400` | no |
+| <a name="input_key_name"></a> [key\_name](#input\_key\_name) | Key pair name | `string` | `null` | no |
+| <a name="input_kms_key_arn"></a> [kms\_key\_arn](#input\_kms\_key\_arn) | Optional CMK Key ARN to be used for Parameter Store. This key must be in the current account. | `string` | `null` | no |
+| <a name="input_lambda_architecture"></a> [lambda\_architecture](#input\_lambda\_architecture) | AWS Lambda architecture. Lambda functions using Graviton processors ('arm64') tend to have better price/performance than 'x86\_64' functions. | `string` | `"x86_64"` | no |
+| <a name="input_lambda_principals"></a> [lambda\_principals](#input\_lambda\_principals) | (Optional) add extra principals to the role created for execution of the lambda, e.g. for local testing. | <pre>list(object({<br>    type        = string<br>    identifiers = list(string)<br>  }))</pre> | `[]` | no |
+| <a name="input_lambda_runtime"></a> [lambda\_runtime](#input\_lambda\_runtime) | AWS Lambda runtime. | `string` | `"nodejs16.x"` | no |
+| <a name="input_lambda_s3_bucket"></a> [lambda\_s3\_bucket](#input\_lambda\_s3\_bucket) | S3 bucket from which to specify lambda functions. This is an alternative to providing local files directly. | `any` | `null` | no |
+| <a name="input_lambda_security_group_ids"></a> [lambda\_security\_group\_ids](#input\_lambda\_security\_group\_ids) | List of security group IDs associated with the Lambda function. | `list(string)` | `[]` | no |
+| <a name="input_lambda_subnet_ids"></a> [lambda\_subnet\_ids](#input\_lambda\_subnet\_ids) | List of subnets in which the action runners will be launched, the subnets needs to be subnets in the `vpc_id`. | `list(string)` | `[]` | no |
+| <a name="input_log_level"></a> [log\_level](#input\_log\_level) | Logging level for lambda logging. Valid values are  'silly', 'trace', 'debug', 'info', 'warn', 'error', 'fatal'. | `string` | `"info"` | no |
+| <a name="input_log_type"></a> [log\_type](#input\_log\_type) | Logging format for lambda logging. Valid values are 'json', 'pretty', 'hidden'. | `string` | `"pretty"` | no |
+| <a name="input_logging_kms_key_id"></a> [logging\_kms\_key\_id](#input\_logging\_kms\_key\_id) | Specifies the kms key id to encrypt the logs with | `string` | `null` | no |
+| <a name="input_logging_retention_in_days"></a> [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 |
+| <a name="input_market_options"></a> [market\_options](#input\_market\_options) | DEPCRECATED: Replaced by `instance_target_capacity_type`. | `string` | `null` | 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_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 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.` | <pre>list(object({<br>    schedule_expression = string<br>    size                = number<br>  }))</pre> | `[]` | 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 |
+| <a name="input_pool_lambda_timeout"></a> [pool\_lambda\_timeout](#input\_pool\_lambda\_timeout) | Time out for the pool lambda lambda in seconds. | `number` | `60` | no |
+| <a name="input_pool_runner_owner"></a> [pool\_runner\_owner](#input\_pool\_runner\_owner) | The pool will deploy runners to the GitHub org ID, set this value to the org to which you want the runners deployed. Repo level is not supported. | `string` | `null` | no |
+| <a name="input_prefix"></a> [prefix](#input\_prefix) | The prefix used for naming resources | `string` | `"github-actions"` | no |
+| <a name="input_redrive_build_queue"></a> [redrive\_build\_queue](#input\_redrive\_build\_queue) | Set options to attach (optional) a dead letter queue to the build queue, the queue between the webhook and the scale up lambda. You have the following options. 1. Disable by setting, `enalbed' to false. 2. Enable by setting `enabled` to `true`, `maxReceiveCount` to a number of max retries.` | <pre>object({<br>    enabled         = bool<br>    maxReceiveCount = number<br>  })</pre> | <pre>{<br>  "enabled": false,<br>  "maxReceiveCount": null<br>}</pre> | no |
+| <a name="input_repository_white_list"></a> [repository\_white\_list](#input\_repository\_white\_list) | List of repositories allowed to use the github app | `list(string)` | `[]` | no |
+| <a name="input_role_path"></a> [role\_path](#input\_role\_path) | The path that will be added to role path for created roles, if not set the environment name will be used. | `string` | `null` | no |
+| <a name="input_role_permissions_boundary"></a> [role\_permissions\_boundary](#input\_role\_permissions\_boundary) | Permissions boundary that will be added to the created roles. | `string` | `null` | no |
+| <a name="input_runner_additional_security_group_ids"></a> [runner\_additional\_security\_group\_ids](#input\_runner\_additional\_security\_group\_ids) | (optional) List of additional security groups IDs to apply to the runner | `list(string)` | `[]` | no |
+| <a name="input_runner_allow_prerelease_binaries"></a> [runner\_allow\_prerelease\_binaries](#input\_runner\_allow\_prerelease\_binaries) | Allow the runners to update to prerelease binaries. | `bool` | `false` | no |
+| <a name="input_runner_architecture"></a> [runner\_architecture](#input\_runner\_architecture) | The platform architecture of the runner instance\_type. | `string` | `"x64"` | no |
+| <a name="input_runner_as_root"></a> [runner\_as\_root](#input\_runner\_as\_root) | Run the action runner under the root user. Variable `runner_run_as` will be ingored. | `bool` | `false` | no |
+| <a name="input_runner_binaries_s3_sse_configuration"></a> [runner\_binaries\_s3\_sse\_configuration](#input\_runner\_binaries\_s3\_sse\_configuration) | Map containing server-side encryption configuration for runner-binaries S3 bucket. | `any` | `{}` | no |
+| <a name="input_runner_binaries_syncer_lambda_timeout"></a> [runner\_binaries\_syncer\_lambda\_timeout](#input\_runner\_binaries\_syncer\_lambda\_timeout) | Time out of the binaries sync lambda in seconds. | `number` | `300` | no |
+| <a name="input_runner_binaries_syncer_lambda_zip"></a> [runner\_binaries\_syncer\_lambda\_zip](#input\_runner\_binaries\_syncer\_lambda\_zip) | File location of the binaries sync lambda zip file. | `string` | `null` | no |
+| <a name="input_runner_boot_time_in_minutes"></a> [runner\_boot\_time\_in\_minutes](#input\_runner\_boot\_time\_in\_minutes) | The minimum time for an EC2 runner to boot and register as a runner. | `number` | `5` | no |
+| <a name="input_runner_ec2_tags"></a> [runner\_ec2\_tags](#input\_runner\_ec2\_tags) | Map of tags that will be added to the launch template instance tag specificatons. | `map(string)` | `{}` | no |
+| <a name="input_runner_egress_rules"></a> [runner\_egress\_rules](#input\_runner\_egress\_rules) | List of egress rules for the GitHub runner instances. | <pre>list(object({<br>    cidr_blocks      = list(string)<br>    ipv6_cidr_blocks = list(string)<br>    prefix_list_ids  = list(string)<br>    from_port        = number<br>    protocol         = string<br>    security_groups  = list(string)<br>    self             = bool<br>    to_port          = number<br>    description      = string<br>  }))</pre> | <pre>[<br>  {<br>    "cidr_blocks": [<br>      "0.0.0.0/0"<br>    ],<br>    "description": null,<br>    "from_port": 0,<br>    "ipv6_cidr_blocks": [<br>      "::/0"<br>    ],<br>    "prefix_list_ids": null,<br>    "protocol": "-1",<br>    "security_groups": null,<br>    "self": null,<br>    "to_port": 0<br>  }<br>]</pre> | no |
+| <a name="input_runner_enable_workflow_job_labels_check"></a> [runner\_enable\_workflow\_job\_labels\_check](#input\_runner\_enable\_workflow\_job\_labels\_check) | If set to true all labels in the workflow job even are matched agaist the custom labels and GitHub labels (os, architecture and `self-hosted`). When the labels are not matching the event is dropped at the webhook. | `bool` | `false` | no |
+| <a name="input_runner_enable_workflow_job_labels_check_all"></a> [runner\_enable\_workflow\_job\_labels\_check\_all](#input\_runner\_enable\_workflow\_job\_labels\_check\_all) | If set to true all labels in the workflow job must match the GitHub labels (os, architecture and `self-hosted`). When false if __any__ label matches it will trigger the webhook. `runner_enable_workflow_job_labels_check` must be true for this to take effect. | `bool` | `true` | no |
+| <a name="input_runner_extra_labels"></a> [runner\_extra\_labels](#input\_runner\_extra\_labels) | Extra (custom) labels for the runners (GitHub). Separate each label by a comma. Labels checks on the webhook can be enforced by setting `enable_workflow_job_labels_check`. GitHub read-only labels should not be provided. | `string` | `""` | no |
+| <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_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_log_files"></a> [runner\_log\_files](#input\_runner\_log\_files) | (optional) Replaces the module default cloudwatch log config. See https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Agent-Configuration-File-Details.html for details. | <pre>list(object({<br>    log_group_name   = string<br>    prefix_log_group = bool<br>    file_path        = string<br>    log_stream_name  = string<br>  }))</pre> | `null` | no |
+| <a name="input_runner_metadata_options"></a> [runner\_metadata\_options](#input\_runner\_metadata\_options) | Metadata options for the ec2 runner instances. | `map(any)` | <pre>{<br>  "http_endpoint": "enabled",<br>  "http_put_response_hop_limit": 1,<br>  "http_tokens": "optional"<br>}</pre> | no |
+| <a name="input_runner_os"></a> [runner\_os](#input\_runner\_os) | The EC2 Operating System type to use for action runner instances (linux,windows). | `string` | `"linux"` | no |
+| <a name="input_runner_run_as"></a> [runner\_run\_as](#input\_runner\_run\_as) | Run the GitHub actions agent as user. | `string` | `"ec2-user"` | no |
+| <a name="input_runners_lambda_s3_key"></a> [runners\_lambda\_s3\_key](#input\_runners\_lambda\_s3\_key) | S3 key for runners lambda function. Required if using S3 bucket to specify lambdas. | `any` | `null` | no |
+| <a name="input_runners_lambda_s3_object_version"></a> [runners\_lambda\_s3\_object\_version](#input\_runners\_lambda\_s3\_object\_version) | S3 object version for runners lambda function. Useful if S3 versioning is enabled on source bucket. | `any` | `null` | no |
+| <a name="input_runners_lambda_zip"></a> [runners\_lambda\_zip](#input\_runners\_lambda\_zip) | File location of the lambda zip file for scaling runners. | `string` | `null` | no |
+| <a name="input_runners_maximum_count"></a> [runners\_maximum\_count](#input\_runners\_maximum\_count) | The maximum number of runners that will be created. | `number` | `3` | no |
+| <a name="input_runners_scale_down_lambda_timeout"></a> [runners\_scale\_down\_lambda\_timeout](#input\_runners\_scale\_down\_lambda\_timeout) | Time out for the scale down lambda in seconds. | `number` | `60` | no |
+| <a name="input_runners_scale_up_lambda_timeout"></a> [runners\_scale\_up\_lambda\_timeout](#input\_runners\_scale\_up\_lambda\_timeout) | Time out for the scale up lambda in seconds. | `number` | `30` | no |
+| <a name="input_scale_down_schedule_expression"></a> [scale\_down\_schedule\_expression](#input\_scale\_down\_schedule\_expression) | Scheduler expression to check every x for scale down. | `string` | `"cron(*/5 * * * ? *)"` | no |
+| <a name="input_scale_up_reserved_concurrent_executions"></a> [scale\_up\_reserved\_concurrent\_executions](#input\_scale\_up\_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 |
+| <a name="input_subnet_ids"></a> [subnet\_ids](#input\_subnet\_ids) | List of subnets in which the action runners will be launched, the subnets needs to be subnets in the `vpc_id`. | `list(string)` | n/a | yes |
+| <a name="input_syncer_lambda_s3_key"></a> [syncer\_lambda\_s3\_key](#input\_syncer\_lambda\_s3\_key) | S3 key for syncer lambda function. Required if using S3 bucket to specify lambdas. | `any` | `null` | no |
+| <a name="input_syncer_lambda_s3_object_version"></a> [syncer\_lambda\_s3\_object\_version](#input\_syncer\_lambda\_s3\_object\_version) | S3 object version for syncer lambda function. Useful if S3 versioning is enabled on source bucket. | `any` | `null` | no |
+| <a name="input_tags"></a> [tags](#input\_tags) | Map of tags that will be added to created resources. By default resources will be tagged with name and environment. | `map(string)` | `{}` | no |
+| <a name="input_userdata_post_install"></a> [userdata\_post\_install](#input\_userdata\_post\_install) | Script to be ran after the GitHub Actions runner is installed on the EC2 instances | `string` | `""` | no |
+| <a name="input_userdata_pre_install"></a> [userdata\_pre\_install](#input\_userdata\_pre\_install) | Script to be ran before the GitHub Actions runner is installed on the EC2 instances | `string` | `""` | no |
+| <a name="input_userdata_template"></a> [userdata\_template](#input\_userdata\_template) | Alternative user-data template, replacing the default template. By providing your own user\_data you have to take care of installing all required software, including the action runner. Variables userdata\_pre/post\_install are ignored. | `string` | `null` | no |
+| <a name="input_vpc_id"></a> [vpc\_id](#input\_vpc\_id) | The VPC for security groups of the action runners. | `string` | n/a | yes |
+| <a name="input_webhook_lambda_s3_key"></a> [webhook\_lambda\_s3\_key](#input\_webhook\_lambda\_s3\_key) | S3 key for webhook lambda function. Required if using S3 bucket to specify lambdas. | `any` | `null` | no |
+| <a name="input_webhook_lambda_s3_object_version"></a> [webhook\_lambda\_s3\_object\_version](#input\_webhook\_lambda\_s3\_object\_version) | S3 object version for webhook lambda function. Useful if S3 versioning is enabled on source bucket. | `any` | `null` | no |
+| <a name="input_webhook_lambda_timeout"></a> [webhook\_lambda\_timeout](#input\_webhook\_lambda\_timeout) | Time out of the webhook lambda in seconds. | `number` | `10` | no |
+| <a name="input_webhook_lambda_zip"></a> [webhook\_lambda\_zip](#input\_webhook\_lambda\_zip) | File location of the webhook lambda zip file. | `string` | `null` | no |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| <a name="output_binaries_syncer"></a> [binaries\_syncer](#output\_binaries\_syncer) | n/a |
+| <a name="output_queues"></a> [queues](#output\_queues) | SQS queues. |
+| <a name="output_runners"></a> [runners](#output\_runners) | n/a |
+| <a name="output_ssm_parameters"></a> [ssm\_parameters](#output\_ssm\_parameters) | n/a |
+| <a name="output_webhook"></a> [webhook](#output\_webhook) | n/a |
+<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
+
+## Contribution
+
+We welcome contribution, please checkout the [contribution guide](CONTRIBUTING.md). Be-aware we use [pre commit hooks](https://pre-commit.com/) to update the docs.
+
+## Philips Forest
+
+This module is part of the Philips Forest.
+
+```bash
+
+                                                     ___                   _
+                                                    / __\__  _ __ ___  ___| |_
+                                                   / _\/ _ \| '__/ _ \/ __| __|
+                                                  / / | (_) | | |  __/\__ \ |_
+                                                  \/   \___/|_|  \___||___/\__|
+
+                                                                 Infrastructure
+
+```
+
+Talk to the forestkeepers in the `runners`-channel on Slack.
+
+[![Slack](https://img.shields.io/badge/Slack-4A154B?style=for-the-badge&logo=slack&logoColor=white)](https://join.slack.com/t/philips-software/shared_invite/zt-xecw65v5-i1531hGP~mdVwgxLFx7ckg)

Файловите разлики са ограничени, защото са твърде много
+ 0 - 0
thirdparty/terraform-aws-github-runner/docs/architecture.drawio


Файловите разлики са ограничени, защото са твърде много
+ 2 - 0
thirdparty/terraform-aws-github-runner/docs/architecture.svg


Файловите разлики са ограничени, защото са твърде много
+ 2 - 0
thirdparty/terraform-aws-github-runner/docs/component-overview.svg


+ 88 - 0
thirdparty/terraform-aws-github-runner/docs/test-lambda-local.md

@@ -0,0 +1,88 @@
+# Lambda - Test locally
+
+This README provides guidance for testing the lambda locally / and or in AWS. This guide assumes you are familiar with AWS, lambda and Node. If not mentioned explicitly, comments provided should be executed from the root of the lambda package.
+
+## Testing in AWS
+
+Just navigate to the Lambda in the AWS Console and trigger a test event. Provide an event that matches the required input. For lambdas that does not require a specific event, just send any event.
+
+
+## Testing locally
+
+Testing locally can be done in two ways; using AWS SAM framework or run via a wrapper to simulate the event to invoke the lambda. Both setups require that the mandatory input environment variables be set, and AWS resources on which the lambda depends are available. We advise for testing the lambda locally to first create your own deployment of the whole module to AWS, this will simplify the setup of dependent AWS resources. For example, based on the de [default example](../../../../examples/default/).
+
+Local test setup instructions are available for the following lambda's:
+
+- [runner-binary-syncer](./moduele/../../modules/runner-binaries-syncer/lambdas/runner-binaries-syncer) - This lambda does not need any input, no event is required. Supported via SAM and local Node.
+
+### Extend deployment configuration
+
+Add the code below to your Terraform deployment to allow your principal to use the Lambda role and retrieve the lambda configuration. Update your Terraform deployment and apply the changes.
+
+```hcl
+data "aws_caller_identity" "current" {}
+
+module "runners" {
+  
+  ...
+
+  # Assume you have a profile with Admin privileges, allow you to switch to the Lambda role
+  lambda_principals = [{
+    type        = "AWS"
+    identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"]
+  }]
+
+}
+
+output "development" {
+  value = {
+    lambda_syncer = module.runners.binaries_syncer.lambda
+  }
+}```
+
+Once you have updated your Terraform deployment you need to read the lambda configuration into your environment. Run the commands below in your Terraform workspace folder.
+
+```bash
+LAMBDA_ENV=$(terraform output -json development | jq -r '.lambda_syncer.environment[].variables' | jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]")
+for x in $LAMBDA_ENV ; do echo setting $x; export $x; done
+```
+
+### Testing with SAM
+
+This setup requires AWS SAM CLI and Docker is installed locally. First update the AWS config (`~/.aws/config`) so you can use easily switch to the role used by the lambda.
+
+```properties
+[profile gh-development]
+source_profile=<OPTIONAL_SOURCE_PROFILE>
+region=<DEFAULT_REGION>
+role_arn=<ARN_CHECK_TF_OUTPUT>
+```
+
+Now you can set the profile and region as environment variables or pass as argument to SAM.
+
+```
+export AWS_REGION=<region>
+export AWS_PROFILE=gh-development
+```
+
+For SAM a `template.yml` defines the lambda for running locally. Thats all, now build your lambda with `yarn run dist` and then invoke the lambda with `sam local invoke`.
+
+
+### With Node
+
+Instead of using SAM you can use Node with `ts-node-dev` to test the code locally. The drawback is that you have to setup AWS credentials in your shell. Also, you are dependent on a tiny wrapper (`local.ts`), and your local Node version.
+
+The AWS SDK does not seem to handle environment variables for profiles, the only option to pass the role is via credentials. You can get credentials via STS for the role.
+
+```bash
+
+role=$(aws sts assume-role \
+    --role-arn "<ROLE>" \
+    --duration-seconds 3600 --role-session-name "dev")
+
+export AWS_ACCESS_KEY_ID=$(echo $role | jq -r .Credentials.AccessKeyId)
+export AWS_SECRET_ACCESS_KEY=$(echo $role | jq -r .Credentials.SecretAccessKey)
+export AWS_SESSION_TOKEN=$(echo $role | jq -r .Credentials.SessionToken)
+```
+
+Next set the region `export AWS_REGION=<region>`. Now you can run the lambda locally via `yarn run watch`.

+ 60 - 0
thirdparty/terraform-aws-github-runner/examples/arm64/.terraform.lock.hcl

@@ -0,0 +1,60 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/aws" {
+  version     = "4.15.1"
+  constraints = "~> 4.0, ~> 4.15"
+  hashes = [
+    "h1:KNkM4pOCRzbjlGoCxt4Yl4qGUESLQ2uKIOSHb+aiMlY=",
+    "zh:1d944144f8d613b8090c0c8391e4b205ca036086d70aceb4cdf664856fa8410c",
+    "zh:2a0ca16a6b12c0ac509f64512f80bd2ed6e7ea0ec369212efd4be3fa65e9773d",
+    "zh:3f9efdce4f1c320ffd061e8715e1d031deac1be0b959eaa60c25a274925653e4",
+    "zh:4cf82f3267b0c3e08be29b0345f711ab84ea1ea75f0e8ce81f5a2fe635ba67b4",
+    "zh:58474a0b7da438e1bcd53e87f10e28830836ff9b46cce5f09413c90952ae4f78",
+    "zh:6eb1be8afb0314b6b8424fe212b13beeb04f3f24692f0f3ee86c5153c7eb2e63",
+    "zh:8022da7d3b050d452ce6c679844e13729bdb4e1b3e75dcf68931af17a06b9277",
+    "zh:8e2683d00fff1df43440d6e7c04a2c1eb432c7d5dacff32fe8ce9045bc948fe6",
+    "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
+    "zh:b0c22d9a306e8ac2de57b5291a3d0a7a2c1713e33b7d076005662451afdc4d29",
+    "zh:ba6b7d7d91388b636145b133da6b4e32620cdc8046352e2dc8f3f0f81ff5d2e2",
+    "zh:d38a816eb60f4419d99303136a3bb61a0d2df3ca8a1dce2ced9b99bf23efa9f7",
+  ]
+}
+
+provider "registry.terraform.io/hashicorp/local" {
+  version = "2.2.3"
+  hashes = [
+    "h1:FvRIEgCmAezgZUqb2F+PZ9WnSSnR5zbEM2ZI+GLmbMk=",
+    "zh:04f0978bb3e052707b8e82e46780c371ac1c66b689b4a23bbc2f58865ab7d5c0",
+    "zh:6484f1b3e9e3771eb7cc8e8bab8b35f939a55d550b3f4fb2ab141a24269ee6aa",
+    "zh:78a56d59a013cb0f7eb1c92815d6eb5cf07f8b5f0ae20b96d049e73db915b238",
+    "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+    "zh:8aa9950f4c4db37239bcb62e19910c49e47043f6c8587e5b0396619923657797",
+    "zh:996beea85f9084a725ff0e6473a4594deb5266727c5f56e9c1c7c62ded6addbb",
+    "zh:9a7ef7a21f48fabfd145b2e2a4240ca57517ad155017e86a30860d7c0c109de3",
+    "zh:a63e70ac052aa25120113bcddd50c1f3cfe61f681a93a50cea5595a4b2cc3e1c",
+    "zh:a6e8d46f94108e049ad85dbed60354236dc0b9b5ec8eabe01c4580280a43d3b8",
+    "zh:bb112ce7efbfcfa0e65ed97fa245ef348e0fd5bfa5a7e4ab2091a9bd469f0a9e",
+    "zh:d7bec0da5c094c6955efed100f3fe22fca8866859f87c025be1760feb174d6d9",
+    "zh:fb9f271b72094d07cef8154cd3d50e9aa818a0ea39130bc193132ad7b23076fd",
+  ]
+}
+
+provider "registry.terraform.io/hashicorp/random" {
+  version = "3.2.0"
+  hashes = [
+    "h1:NvMyFNHHq65GUNyBGjLuLD4ABA6sTlRebZCIK5OtvFU=",
+    "zh:2960977ce9a7d6a7d3e934e75ec5814735626f95c186ad95a9102344a1a38ac1",
+    "zh:2fd012abfabe7076f3f2f402eeef4970e20574d20ffec57c162b02b6e848c32f",
+    "zh:4cd3234671cf01c913023418b227eb78b0659f2cd2e0b387be1f0bb607d29889",
+    "zh:52e695b4fa3fae735ffc901edff8183745f980923510a744db7616e8f10dc499",
+    "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+    "zh:848b4a294e5ba15192ee4bfd199c07f60a437d7572efcd2d89db036e1ebc0e6e",
+    "zh:9d49aa432a05748a9527e95448cebee1238c87c97c7e8dec694bfd709683f9c7",
+    "zh:b4ad4cf289d3f7408649b74b8639918833613f2a1f3cf51b51f4b2fdaa412dd2",
+    "zh:c1544c4b416096fb8d8dbf84c4488584a2844a30dd533b957e9e9e60a165f24e",
+    "zh:dc737d6b4591cad8c9a1d0b347e587e846d8d901789b29b4dd401b6cdf82c017",
+    "zh:f5645fd39f749dbbf847cbdc87ba0dbd141143f12917a6a8904faf8a9b64111e",
+    "zh:fdedf610e0d020878a8f1fedda8105e0c33a7e23c4792fca54460685552de308",
+  ]
+}

+ 31 - 0
thirdparty/terraform-aws-github-runner/examples/arm64/README.md

@@ -0,0 +1,31 @@
+# Action runners deployment with ARM64 architecture
+
+This module shows how to create GitHub action runners using AWS Graviton instances which have ARM64 architecture. Lambda release will be downloaded from GitHub.
+
+## Usages
+
+Steps for the full setup, such as creating a GitHub app can be found in the root module's [README](../../README.md). First download the Lambda releases from GitHub. Alternatively you can build the lambdas locally with Node or Docker, there is a simple build script in `<root>/.ci/build.sh`. In the `main.tf` you can simply remove the location of the lambda zip files, the default location will work in this case.
+
+> Ensure you have set the version in `lambdas-download/main.tf` for running the example. The version needs to be set to a GitHub release version, see https://github.com/philips-labs/terraform-aws-github-runner/releases
+
+```bash
+cd lambdas-download
+terraform init
+terraform apply
+cd ..
+```
+
+Before running Terraform, ensure the GitHub app is configured. See the [configuration details](../../README.md#usages) for more details.
+
+```bash
+terraform init
+terraform apply
+```
+
+You can receive the webhook details by running:
+
+```bash
+terraform output -raw webhook_secret
+```
+
+Be-aware some shells will print some end of line character `%`. 

+ 25 - 0
thirdparty/terraform-aws-github-runner/examples/arm64/lambdas-download/main.tf

@@ -0,0 +1,25 @@
+locals {
+  version = "<REPLACE_BY_GITHUB_RELEASE_VERSION>"
+}
+
+module "lambdas" {
+  source = "../../../modules/download-lambda"
+  lambdas = [
+    {
+      name = "webhook"
+      tag  = local.version
+    },
+    {
+      name = "runners"
+      tag  = local.version
+    },
+    {
+      name = "runner-binaries-syncer"
+      tag  = local.version
+    }
+  ]
+}
+
+output "files" {
+  value = module.lambdas.files
+}

+ 77 - 0
thirdparty/terraform-aws-github-runner/examples/arm64/main.tf

@@ -0,0 +1,77 @@
+locals {
+  environment = "default"
+  aws_region  = "eu-west-1"
+}
+
+resource "random_id" "random" {
+  byte_length = 20
+}
+
+
+################################################################################
+### Hybrid account
+################################################################################
+
+module "runners" {
+  source                          = "../../"
+  create_service_linked_role_spot = true
+  aws_region                      = local.aws_region
+  vpc_id                          = module.vpc.vpc_id
+  subnet_ids                      = module.vpc.private_subnets
+
+  prefix = local.environment
+  tags = {
+    Project = "ProjectX"
+  }
+
+  github_app = {
+    key_base64     = var.github_app_key_base64
+    id             = var.github_app_id
+    webhook_secret = random_id.random.hex
+  }
+
+  # Grab zip files via lambda_download, will automatically get the ARM64 build
+  webhook_lambda_zip                = "lambdas-download/webhook.zip"
+  runner_binaries_syncer_lambda_zip = "lambdas-download/runner-binaries-syncer.zip"
+  runners_lambda_zip                = "lambdas-download/runners.zip"
+
+  enable_organization_runners = false
+  # Runners will automatically get the "arm64" label
+  runner_extra_labels = "default,example"
+
+  # enable access to the runners via SSM
+  enable_ssm_on_runners = true
+
+  # use S3 or KMS SSE to runners S3 bucket
+  # runner_binaries_s3_sse_configuration = {
+  #   rule = {
+  #     apply_server_side_encryption_by_default = {
+  #       sse_algorithm = "AES256"
+  #     }
+  #   }
+  # }
+
+  # Uncommet idle config to have idle runners from 9 to 5 in time zone Amsterdam
+  # idle_config = [{
+  #   cron      = "* * 9-17 * * *"
+  #   timeZone  = "Europe/Amsterdam"
+  #   idleCount = 1
+  # }]
+
+  # Let the module manage the service linked role
+  # create_service_linked_role_spot = true
+
+  runner_architecture = "arm64"
+  # Ensure all instance types have ARM64 architecture (ie. AWS Graviton processors)
+  instance_types = ["t4g.large", "c6g.large"]
+
+  # override delay of events in seconds
+  delay_webhook_event   = 5
+  runners_maximum_count = 1
+
+  # set up a fifo queue to remain order
+  fifo_build_queue = true
+
+  # override scaling down
+  scale_down_schedule_expression = "cron(* * * * ? *)"
+}

+ 15 - 0
thirdparty/terraform-aws-github-runner/examples/arm64/outputs.tf

@@ -0,0 +1,15 @@
+output "runners" {
+  value = {
+    lambda_syncer_name = module.runners.binaries_syncer.lambda.function_name
+  }
+}
+
+output "webhook_endpoint" {
+  value = module.runners.webhook.endpoint
+}
+
+output "webhook_secret" {
+  sensitive = true
+  value     = random_id.random.hex
+}
+

+ 3 - 0
thirdparty/terraform-aws-github-runner/examples/arm64/providers.tf

@@ -0,0 +1,3 @@
+provider "aws" {
+  region = local.aws_region
+}

+ 4 - 0
thirdparty/terraform-aws-github-runner/examples/arm64/variables.tf

@@ -0,0 +1,4 @@
+
+variable "github_app_key_base64" {}
+
+variable "github_app_id" {}

+ 15 - 0
thirdparty/terraform-aws-github-runner/examples/arm64/versions.tf

@@ -0,0 +1,15 @@
+terraform {
+  required_providers {
+    aws = {
+      source  = "hashicorp/aws"
+      version = "~> 4.0"
+    }
+    local = {
+      source = "hashicorp/local"
+    }
+    random = {
+      source = "hashicorp/random"
+    }
+  }
+  required_version = ">= 0.14"
+}

+ 7 - 0
thirdparty/terraform-aws-github-runner/examples/arm64/vpc.tf

@@ -0,0 +1,7 @@
+module "vpc" {
+  source = "git::https://github.com/philips-software/terraform-aws-vpc.git?ref=2.2.0"
+
+  environment                = local.environment
+  aws_region                 = local.aws_region
+  create_private_hosted_zone = false
+}

+ 60 - 0
thirdparty/terraform-aws-github-runner/examples/default/.terraform.lock.hcl

@@ -0,0 +1,60 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/aws" {
+  version     = "4.15.1"
+  constraints = ">= 3.63.0, ~> 4.0"
+  hashes = [
+    "h1:KNkM4pOCRzbjlGoCxt4Yl4qGUESLQ2uKIOSHb+aiMlY=",
+    "zh:1d944144f8d613b8090c0c8391e4b205ca036086d70aceb4cdf664856fa8410c",
+    "zh:2a0ca16a6b12c0ac509f64512f80bd2ed6e7ea0ec369212efd4be3fa65e9773d",
+    "zh:3f9efdce4f1c320ffd061e8715e1d031deac1be0b959eaa60c25a274925653e4",
+    "zh:4cf82f3267b0c3e08be29b0345f711ab84ea1ea75f0e8ce81f5a2fe635ba67b4",
+    "zh:58474a0b7da438e1bcd53e87f10e28830836ff9b46cce5f09413c90952ae4f78",
+    "zh:6eb1be8afb0314b6b8424fe212b13beeb04f3f24692f0f3ee86c5153c7eb2e63",
+    "zh:8022da7d3b050d452ce6c679844e13729bdb4e1b3e75dcf68931af17a06b9277",
+    "zh:8e2683d00fff1df43440d6e7c04a2c1eb432c7d5dacff32fe8ce9045bc948fe6",
+    "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
+    "zh:b0c22d9a306e8ac2de57b5291a3d0a7a2c1713e33b7d076005662451afdc4d29",
+    "zh:ba6b7d7d91388b636145b133da6b4e32620cdc8046352e2dc8f3f0f81ff5d2e2",
+    "zh:d38a816eb60f4419d99303136a3bb61a0d2df3ca8a1dce2ced9b99bf23efa9f7",
+  ]
+}
+
+provider "registry.terraform.io/hashicorp/local" {
+  version = "2.2.3"
+  hashes = [
+    "h1:FvRIEgCmAezgZUqb2F+PZ9WnSSnR5zbEM2ZI+GLmbMk=",
+    "zh:04f0978bb3e052707b8e82e46780c371ac1c66b689b4a23bbc2f58865ab7d5c0",
+    "zh:6484f1b3e9e3771eb7cc8e8bab8b35f939a55d550b3f4fb2ab141a24269ee6aa",
+    "zh:78a56d59a013cb0f7eb1c92815d6eb5cf07f8b5f0ae20b96d049e73db915b238",
+    "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+    "zh:8aa9950f4c4db37239bcb62e19910c49e47043f6c8587e5b0396619923657797",
+    "zh:996beea85f9084a725ff0e6473a4594deb5266727c5f56e9c1c7c62ded6addbb",
+    "zh:9a7ef7a21f48fabfd145b2e2a4240ca57517ad155017e86a30860d7c0c109de3",
+    "zh:a63e70ac052aa25120113bcddd50c1f3cfe61f681a93a50cea5595a4b2cc3e1c",
+    "zh:a6e8d46f94108e049ad85dbed60354236dc0b9b5ec8eabe01c4580280a43d3b8",
+    "zh:bb112ce7efbfcfa0e65ed97fa245ef348e0fd5bfa5a7e4ab2091a9bd469f0a9e",
+    "zh:d7bec0da5c094c6955efed100f3fe22fca8866859f87c025be1760feb174d6d9",
+    "zh:fb9f271b72094d07cef8154cd3d50e9aa818a0ea39130bc193132ad7b23076fd",
+  ]
+}
+
+provider "registry.terraform.io/hashicorp/random" {
+  version = "3.2.0"
+  hashes = [
+    "h1:NvMyFNHHq65GUNyBGjLuLD4ABA6sTlRebZCIK5OtvFU=",
+    "zh:2960977ce9a7d6a7d3e934e75ec5814735626f95c186ad95a9102344a1a38ac1",
+    "zh:2fd012abfabe7076f3f2f402eeef4970e20574d20ffec57c162b02b6e848c32f",
+    "zh:4cd3234671cf01c913023418b227eb78b0659f2cd2e0b387be1f0bb607d29889",
+    "zh:52e695b4fa3fae735ffc901edff8183745f980923510a744db7616e8f10dc499",
+    "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+    "zh:848b4a294e5ba15192ee4bfd199c07f60a437d7572efcd2d89db036e1ebc0e6e",
+    "zh:9d49aa432a05748a9527e95448cebee1238c87c97c7e8dec694bfd709683f9c7",
+    "zh:b4ad4cf289d3f7408649b74b8639918833613f2a1f3cf51b51f4b2fdaa412dd2",
+    "zh:c1544c4b416096fb8d8dbf84c4488584a2844a30dd533b957e9e9e60a165f24e",
+    "zh:dc737d6b4591cad8c9a1d0b347e587e846d8d901789b29b4dd401b6cdf82c017",
+    "zh:f5645fd39f749dbbf847cbdc87ba0dbd141143f12917a6a8904faf8a9b64111e",
+    "zh:fdedf610e0d020878a8f1fedda8105e0c33a7e23c4792fca54460685552de308",
+  ]
+}

+ 31 - 0
thirdparty/terraform-aws-github-runner/examples/default/README.md

@@ -0,0 +1,31 @@
+# Action runners deployment default example
+
+This module shows how to create GitHub action runners. Lambda release will be downloaded from GitHub.
+
+## Usages
+
+Steps for the full setup, such as creating a GitHub app can be found in the root module's [README](../../README.md). First download the Lambda releases from GitHub. Alternatively you can build the lambdas locally with Node or Docker, there is a simple build script in `<root>/.ci/build.sh`. In the `main.tf` you can simply remove the location of the lambda zip files, the default location will work in this case.
+
+> Ensure you have set the version in `lambdas-download/main.tf` for running the example. The version needs to be set to a GitHub release version, see https://github.com/philips-labs/terraform-aws-github-runner/releases
+
+```bash
+cd lambdas-download
+terraform init
+terraform apply
+cd ..
+```
+
+Before running Terraform, ensure the GitHub app is configured. See the [configuration details](../../README.md#usages) for more details.
+
+```bash
+terraform init
+terraform apply
+```
+
+You can receive the webhook details by running:
+
+```bash
+terraform output -raw webhook_secret
+```
+
+Be-aware some shells will print some end of line character `%`. 

+ 25 - 0
thirdparty/terraform-aws-github-runner/examples/default/lambdas-download/main.tf

@@ -0,0 +1,25 @@
+locals {
+  version = "<REPLACE_BY_GITHUB_RELEASE_VERSION>"
+}
+
+module "lambdas" {
+  source = "../../../modules/download-lambda"
+  lambdas = [
+    {
+      name = "webhook"
+      tag  = local.version
+    },
+    {
+      name = "runners"
+      tag  = local.version
+    },
+    {
+      name = "runner-binaries-syncer"
+      tag  = local.version
+    }
+  ]
+}
+
+output "files" {
+  value = module.lambdas.files
+}

+ 84 - 0
thirdparty/terraform-aws-github-runner/examples/default/main.tf

@@ -0,0 +1,84 @@
+locals {
+  environment = "default"
+  aws_region  = "eu-west-1"
+}
+
+resource "random_id" "random" {
+  byte_length = 20
+}
+
+
+################################################################################
+### Hybrid account
+################################################################################
+
+module "runners" {
+  source                          = "../../"
+  create_service_linked_role_spot = true
+  aws_region                      = local.aws_region
+  vpc_id                          = module.vpc.vpc_id
+  subnet_ids                      = module.vpc.private_subnets
+
+  prefix = local.environment
+  tags = {
+    Project = "ProjectX"
+  }
+
+  github_app = {
+    key_base64     = var.github_app_key_base64
+    id             = var.github_app_id
+    webhook_secret = random_id.random.hex
+  }
+
+  # configure the block device mappings, default for Amazon Linux2
+  # block_device_mappings = [{
+  #   device_name           = "/dev/xvda"
+  #   delete_on_termination = true
+  #   volume_type           = "gp3"
+  #   volume_size           = 10
+  #   encrypted             = true
+  #   iops                  = null
+  # }]
+
+  # Grab zip files via lambda_download
+  webhook_lambda_zip                = "lambdas-download/webhook.zip"
+  runner_binaries_syncer_lambda_zip = "lambdas-download/runner-binaries-syncer.zip"
+  runners_lambda_zip                = "lambdas-download/runners.zip"
+
+  enable_organization_runners = false
+  runner_extra_labels         = "default,example"
+
+  # enable access to the runners via SSM
+  enable_ssm_on_runners = true
+
+  # use S3 or KMS SSE to runners S3 bucket
+  # runner_binaries_s3_sse_configuration = {
+  #   rule = {
+  #     apply_server_side_encryption_by_default = {
+  #       sse_algorithm = "AES256"
+  #     }
+  #   }
+  # }
+
+  # Uncommet idle config to have idle runners from 9 to 5 in time zone Amsterdam
+  # idle_config = [{
+  #   cron      = "* * 9-17 * * *"
+  #   timeZone  = "Europe/Amsterdam"
+  #   idleCount = 1
+  # }]
+
+  # Let the module manage the service linked role
+  # create_service_linked_role_spot = true
+
+  instance_types = ["m5.large", "c5.large"]
+
+  # override delay of events in seconds
+  delay_webhook_event   = 5
+  runners_maximum_count = 1
+
+  # set up a fifo queue to remain order
+  fifo_build_queue = true
+
+  # override scaling down
+  scale_down_schedule_expression = "cron(* * * * ? *)"
+}

+ 15 - 0
thirdparty/terraform-aws-github-runner/examples/default/outputs.tf

@@ -0,0 +1,15 @@
+output "runners" {
+  value = {
+    lambda_syncer_name = module.runners.binaries_syncer.lambda.function_name
+  }
+}
+
+output "webhook_endpoint" {
+  value = module.runners.webhook.endpoint
+}
+
+output "webhook_secret" {
+  sensitive = true
+  value     = random_id.random.hex
+}
+

+ 3 - 0
thirdparty/terraform-aws-github-runner/examples/default/providers.tf

@@ -0,0 +1,3 @@
+provider "aws" {
+  region = local.aws_region
+}

+ 4 - 0
thirdparty/terraform-aws-github-runner/examples/default/variables.tf

@@ -0,0 +1,4 @@
+
+variable "github_app_key_base64" {}
+
+variable "github_app_id" {}

+ 15 - 0
thirdparty/terraform-aws-github-runner/examples/default/versions.tf

@@ -0,0 +1,15 @@
+terraform {
+  required_providers {
+    aws = {
+      source  = "hashicorp/aws"
+      version = "~> 4.0"
+    }
+    local = {
+      source = "hashicorp/local"
+    }
+    random = {
+      source = "hashicorp/random"
+    }
+  }
+  required_version = ">= 1"
+}

+ 21 - 0
thirdparty/terraform-aws-github-runner/examples/default/vpc.tf

@@ -0,0 +1,21 @@
+module "vpc" {
+  source  = "terraform-aws-modules/vpc/aws"
+  version = "3.11.2"
+
+  name = "vpc-${local.environment}"
+  cidr = "10.0.0.0/16"
+
+  azs             = ["${local.aws_region}a", "${local.aws_region}b", "${local.aws_region}c"]
+  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
+  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
+
+  enable_dns_hostnames    = true
+  enable_nat_gateway      = true
+  map_public_ip_on_launch = false
+  single_nat_gateway      = true
+
+  tags = {
+    Environment = local.environment
+  }
+
+}

+ 60 - 0
thirdparty/terraform-aws-github-runner/examples/ephemeral/.terraform.lock.hcl

@@ -0,0 +1,60 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/aws" {
+  version     = "4.15.1"
+  constraints = ">= 3.63.0, ~> 4.0, ~> 4.15"
+  hashes = [
+    "h1:KNkM4pOCRzbjlGoCxt4Yl4qGUESLQ2uKIOSHb+aiMlY=",
+    "zh:1d944144f8d613b8090c0c8391e4b205ca036086d70aceb4cdf664856fa8410c",
+    "zh:2a0ca16a6b12c0ac509f64512f80bd2ed6e7ea0ec369212efd4be3fa65e9773d",
+    "zh:3f9efdce4f1c320ffd061e8715e1d031deac1be0b959eaa60c25a274925653e4",
+    "zh:4cf82f3267b0c3e08be29b0345f711ab84ea1ea75f0e8ce81f5a2fe635ba67b4",
+    "zh:58474a0b7da438e1bcd53e87f10e28830836ff9b46cce5f09413c90952ae4f78",
+    "zh:6eb1be8afb0314b6b8424fe212b13beeb04f3f24692f0f3ee86c5153c7eb2e63",
+    "zh:8022da7d3b050d452ce6c679844e13729bdb4e1b3e75dcf68931af17a06b9277",
+    "zh:8e2683d00fff1df43440d6e7c04a2c1eb432c7d5dacff32fe8ce9045bc948fe6",
+    "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
+    "zh:b0c22d9a306e8ac2de57b5291a3d0a7a2c1713e33b7d076005662451afdc4d29",
+    "zh:ba6b7d7d91388b636145b133da6b4e32620cdc8046352e2dc8f3f0f81ff5d2e2",
+    "zh:d38a816eb60f4419d99303136a3bb61a0d2df3ca8a1dce2ced9b99bf23efa9f7",
+  ]
+}
+
+provider "registry.terraform.io/hashicorp/local" {
+  version = "2.2.3"
+  hashes = [
+    "h1:FvRIEgCmAezgZUqb2F+PZ9WnSSnR5zbEM2ZI+GLmbMk=",
+    "zh:04f0978bb3e052707b8e82e46780c371ac1c66b689b4a23bbc2f58865ab7d5c0",
+    "zh:6484f1b3e9e3771eb7cc8e8bab8b35f939a55d550b3f4fb2ab141a24269ee6aa",
+    "zh:78a56d59a013cb0f7eb1c92815d6eb5cf07f8b5f0ae20b96d049e73db915b238",
+    "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+    "zh:8aa9950f4c4db37239bcb62e19910c49e47043f6c8587e5b0396619923657797",
+    "zh:996beea85f9084a725ff0e6473a4594deb5266727c5f56e9c1c7c62ded6addbb",
+    "zh:9a7ef7a21f48fabfd145b2e2a4240ca57517ad155017e86a30860d7c0c109de3",
+    "zh:a63e70ac052aa25120113bcddd50c1f3cfe61f681a93a50cea5595a4b2cc3e1c",
+    "zh:a6e8d46f94108e049ad85dbed60354236dc0b9b5ec8eabe01c4580280a43d3b8",
+    "zh:bb112ce7efbfcfa0e65ed97fa245ef348e0fd5bfa5a7e4ab2091a9bd469f0a9e",
+    "zh:d7bec0da5c094c6955efed100f3fe22fca8866859f87c025be1760feb174d6d9",
+    "zh:fb9f271b72094d07cef8154cd3d50e9aa818a0ea39130bc193132ad7b23076fd",
+  ]
+}
+
+provider "registry.terraform.io/hashicorp/random" {
+  version = "3.2.0"
+  hashes = [
+    "h1:NvMyFNHHq65GUNyBGjLuLD4ABA6sTlRebZCIK5OtvFU=",
+    "zh:2960977ce9a7d6a7d3e934e75ec5814735626f95c186ad95a9102344a1a38ac1",
+    "zh:2fd012abfabe7076f3f2f402eeef4970e20574d20ffec57c162b02b6e848c32f",
+    "zh:4cd3234671cf01c913023418b227eb78b0659f2cd2e0b387be1f0bb607d29889",
+    "zh:52e695b4fa3fae735ffc901edff8183745f980923510a744db7616e8f10dc499",
+    "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+    "zh:848b4a294e5ba15192ee4bfd199c07f60a437d7572efcd2d89db036e1ebc0e6e",
+    "zh:9d49aa432a05748a9527e95448cebee1238c87c97c7e8dec694bfd709683f9c7",
+    "zh:b4ad4cf289d3f7408649b74b8639918833613f2a1f3cf51b51f4b2fdaa412dd2",
+    "zh:c1544c4b416096fb8d8dbf84c4488584a2844a30dd533b957e9e9e60a165f24e",
+    "zh:dc737d6b4591cad8c9a1d0b347e587e846d8d901789b29b4dd401b6cdf82c017",
+    "zh:f5645fd39f749dbbf847cbdc87ba0dbd141143f12917a6a8904faf8a9b64111e",
+    "zh:fdedf610e0d020878a8f1fedda8105e0c33a7e23c4792fca54460685552de308",
+  ]
+}

+ 30 - 0
thirdparty/terraform-aws-github-runner/examples/ephemeral/README.md

@@ -0,0 +1,30 @@
+# Action runners deployment ephemeral example
+
+This example is based on the default setup, but shows how runners can be used with the ephemeral flag enabled. Once enabled, ephemeral runners will be used for one job only. Each job requires a fresh instance. This feature should be used in combination with the `workflow_job` event. See GitHub webhook endpoint configuration(link needed here). It is also suggested to use a pre-build AMI to minimize runner launch times.
+## Usages
+
+Steps for the full setup, such as creating a GitHub app can be found in the root module's [README](../../README.md). First download the Lambda releases from GitHub. Alternatively you can build the lambdas locally with Node or Docker, there is a simple build script in `<root>/.ci/build.sh`. In the `main.tf` you can simply remove the location of the lambda zip files, the default location will work in this case.
+
+> Ensure you have set the version in `lambdas-download/main.tf` for running the example. The version needs to be set to a GitHub release version, see https://github.com/philips-labs/terraform-aws-github-runner/releases
+
+```bash
+cd lambdas-download
+terraform init
+terraform apply
+cd ..
+```
+
+Before running Terraform, ensure the GitHub app is configured. See the [configuration details](../../README.md#usages) for more details.
+
+```bash
+terraform init
+terraform apply
+```
+
+You can receive the webhook details by running:
+
+```bash
+terraform output -raw webhook_secret
+```
+
+Be-aware some shells will print some end of line character `%`. 

+ 25 - 0
thirdparty/terraform-aws-github-runner/examples/ephemeral/lambdas-download/main.tf

@@ -0,0 +1,25 @@
+locals {
+  version = "<REPLACE_BY_GITHUB_RELEASE_VERSION>"
+}
+
+module "lambdas" {
+  source = "../../../modules/download-lambda"
+  lambdas = [
+    {
+      name = "webhook"
+      tag  = local.version
+    },
+    {
+      name = "runners"
+      tag  = local.version
+    },
+    {
+      name = "runner-binaries-syncer"
+      tag  = local.version
+    }
+  ]
+}
+
+output "files" {
+  value = module.lambdas.files
+}

+ 84 - 0
thirdparty/terraform-aws-github-runner/examples/ephemeral/main.tf

@@ -0,0 +1,84 @@
+locals {
+  environment = "ephemeral"
+  aws_region  = "eu-west-1"
+}
+
+resource "random_id" "random" {
+  byte_length = 20
+}
+
+data "aws_caller_identity" "current" {}
+
+module "runners" {
+  source                          = "../../"
+  create_service_linked_role_spot = true
+  aws_region                      = local.aws_region
+  vpc_id                          = module.vpc.vpc_id
+  subnet_ids                      = module.vpc.private_subnets
+
+  prefix = local.environment
+  tags = {
+    Project = "ProjectX"
+  }
+
+  github_app = {
+    key_base64     = var.github_app_key_base64
+    id             = var.github_app_id
+    webhook_secret = random_id.random.hex
+  }
+
+  # Grab the lambda packages from local directory. Must run /.ci/build.sh first
+  webhook_lambda_zip                = "../../lambda_output/webhook.zip"
+  runner_binaries_syncer_lambda_zip = "../../lambda_output/runner-binaries-syncer.zip"
+  runners_lambda_zip                = "../../lambda_output/runners.zip"
+
+  enable_organization_runners = true
+  runner_extra_labels         = "default,example"
+
+  # enable workflow labels check
+  # runner_enable_workflow_job_labels_check = true
+
+  # enable access to the runners via SSM
+  enable_ssm_on_runners = true
+
+  # Let the module manage the service linked role
+  # create_service_linked_role_spot = true
+
+  instance_types = ["m5.large", "c5.large"]
+
+  # override delay of events in seconds
+  delay_webhook_event = 0
+
+  # Ensure you set the number not too low, each build require a new instance
+  runners_maximum_count = 20
+
+  # override scaling down
+  scale_down_schedule_expression = "cron(* * * * ? *)"
+
+  enable_ephemeral_runners = true
+
+  # # Example of simple pool usages
+  # pool_runner_owner = "my-org"
+  # pool_config = [{
+  #   size                = 20
+  #   schedule_expression = "cron(* * * * ? *)"
+  # }]
+  #
+  #
+  enable_job_queued_check = true
+
+  # configure your pre-built AMI
+  # enabled_userdata = false
+  # ami_filter       = { name = ["github-runner-amzn2-x86_64-*"] }
+  # ami_owners       = [data.aws_caller_identity.current.account_id]
+
+  # Enable logging
+  log_level = "debug"
+
+  # Setup a dead letter queue, by default scale up lambda will kepp retrying to process event in case of scaling error.
+  # redrive_policy_build_queue = {
+  #   enabled             = true
+  #   maxReceiveCount     = 50 # 50 retries every 30 seconds => 25 minutes
+  #   deadLetterTargetArn = null
+  # }
+}

+ 15 - 0
thirdparty/terraform-aws-github-runner/examples/ephemeral/outputs.tf

@@ -0,0 +1,15 @@
+output "runners" {
+  value = {
+    lambda_syncer_name = module.runners.binaries_syncer.lambda.function_name
+  }
+}
+
+output "webhook_endpoint" {
+  value = module.runners.webhook.endpoint
+}
+
+output "webhook_secret" {
+  sensitive = true
+  value     = random_id.random.hex
+}
+

+ 3 - 0
thirdparty/terraform-aws-github-runner/examples/ephemeral/providers.tf

@@ -0,0 +1,3 @@
+provider "aws" {
+  region = local.aws_region
+}

+ 5 - 0
thirdparty/terraform-aws-github-runner/examples/ephemeral/variables.tf

@@ -0,0 +1,5 @@
+
+variable "github_app_key_base64" {}
+
+variable "github_app_id" {}
+

+ 15 - 0
thirdparty/terraform-aws-github-runner/examples/ephemeral/versions.tf

@@ -0,0 +1,15 @@
+terraform {
+  required_providers {
+    aws = {
+      source  = "hashicorp/aws"
+      version = "~> 4.0"
+    }
+    local = {
+      source = "hashicorp/local"
+    }
+    random = {
+      source = "hashicorp/random"
+    }
+  }
+  required_version = ">= 1"
+}

+ 21 - 0
thirdparty/terraform-aws-github-runner/examples/ephemeral/vpc.tf

@@ -0,0 +1,21 @@
+module "vpc" {
+  source  = "terraform-aws-modules/vpc/aws"
+  version = "3.11.2"
+
+  name = "vpc-${local.environment}"
+  cidr = "10.0.0.0/16"
+
+  azs             = ["${local.aws_region}a", "${local.aws_region}b", "${local.aws_region}c"]
+  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
+  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
+
+  enable_dns_hostnames    = true
+  enable_nat_gateway      = true
+  map_public_ip_on_launch = false
+  single_nat_gateway      = true
+
+  tags = {
+    Environment = local.environment
+  }
+
+}

+ 60 - 0
thirdparty/terraform-aws-github-runner/examples/permissions-boundary/.terraform.lock.hcl

@@ -0,0 +1,60 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/aws" {
+  version     = "4.12.1"
+  constraints = ">= 3.63.0, ~> 4.0"
+  hashes = [
+    "h1:YvwxXRDVzn9j6Gt7Vg8tCcyF/niapue5sxSUw1TH+9U=",
+    "zh:2b432dc3bf7e0987bf9dcad5d397c384890d12fcd95827bc4581ca2955fc623a",
+    "zh:2f79a448a4e5ad24a706ab634078d0ef159be3278eb24988b7d2185173f5dd8f",
+    "zh:5d70074c10cefb30d4104af54f912e58ffa1b6871277b0a5324c8f13000f5009",
+    "zh:63623743fb15d54787a96c9761b97a935ff396672e625730cb7a5c1971acf4b6",
+    "zh:8263f376e6db684667c10e28df8d8d188e02fd09ad58e1ad7075e363c389e24c",
+    "zh:8b5aa9fd1ddf1de0ab7d462891123405e5af04d7e4d1e4b03381634b3cae4884",
+    "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
+    "zh:d00b2d0b374ab92e934eb597668c5f3e415c4cf8335e6a52ab99949b8fcf57dd",
+    "zh:d0e037725aced6cacc2e0a1903b31083c64f8765fb1263e4f8f891745266b7fb",
+    "zh:e6e244123bc1df109db90bef0af2a875a0b3afb268f21c3e5bc34753657102ad",
+    "zh:ec6901ab8b99ae3df50340e9aa86ed3bac1369f5e1403c0362edd9944640fa22",
+    "zh:f6a4d0ce3bd3d4b81163c4ae75b66e50c10b935c60a63d7fb96df285c0eeca40",
+  ]
+}
+
+provider "registry.terraform.io/hashicorp/local" {
+  version = "2.2.2"
+  hashes = [
+    "h1:BVEZnjtpWxKPG9OOQh4dFa1z5pwMO/uuzYtu6AR2LyM=",
+    "zh:027e4873c69da214e2fed131666d5de92089732a11d096b68257da54d30b6f9d",
+    "zh:0ba2216e16cfb72538d76a4c4945b4567a76f7edbfef926b1c5a08d7bba2a043",
+    "zh:1fee8f6aae1833c27caa96e156cf99a681b6f085e476d7e1b77d285e21d182c1",
+    "zh:2e8a3e72e877003df1c390a231e0d8e827eba9f788606e643f8e061218750360",
+    "zh:719008f9e262aa1523a6f9132adbe9eee93c648c2981f8359ce41a40e6425433",
+    "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+    "zh:9a70fdbe6ef955c4919a4519caca116f34c19c7ddedd77990fbe4f80fe66dc84",
+    "zh:abc412423d670cbb6264827fa80e1ffdc4a74aff3f19ba6a239dd87b85b15bec",
+    "zh:ae953a62c94d2a2a0822e5717fafc54e454af57bd6ed02cd301b9786765c1dd3",
+    "zh:be0910bdf46698560f9e86f51a4ff795c62c02f8dc82b2b1dab77a0b3a93f61e",
+    "zh:e58f9083b7971919b95f553227adaa7abe864fce976f0166cf4d65fc17257ff2",
+    "zh:ff4f77cbdbb22cc98182821c7ef84dce16298ab0e997d5c7fae97247f7a4bcb0",
+  ]
+}
+
+provider "registry.terraform.io/hashicorp/random" {
+  version = "3.1.3"
+  hashes = [
+    "h1:LPSVX+oXKGaZmxgtaPf2USxoEsWK/pnhmm/5FKw+PtU=",
+    "zh:26e07aa32e403303fc212a4367b4d67188ac965c37a9812e07acee1470687a73",
+    "zh:27386f48e9c9d849fbb5a8828d461fde35e71f6b6c9fc235bc4ae8403eb9c92d",
+    "zh:5f4edda4c94240297bbd9b83618fd362348cadf6bf24ea65ea0e1844d7ccedc0",
+    "zh:646313a907126cd5e69f6a9fafe816e9154fccdc04541e06fed02bb3a8fa2d2e",
+    "zh:7349692932a5d462f8dee1500ab60401594dddb94e9aa6bf6c4c0bd53e91bbb8",
+    "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+    "zh:9034daba8d9b32b35930d168f363af04cecb153d5849a7e4a5966c97c5dc956e",
+    "zh:bb81dfca59ef5f949ef39f19ea4f4de25479907abc28cdaa36d12ecd7c0a9699",
+    "zh:bcf7806b99b4c248439ae02c8e21f77aff9fadbc019ce619b929eef09d1221bb",
+    "zh:d708e14d169e61f326535dd08eecd3811cd4942555a6f8efabc37dbff9c6fc61",
+    "zh:dc294e19a46e1cefb9e557a7b789c8dd8f319beca99b8c265181bc633dc434cc",
+    "zh:f9d758ee53c55dc016dd736427b6b0c3c8eb4d0dbbc785b6a3579b0ffedd9e42",
+  ]
+}

+ 35 - 0
thirdparty/terraform-aws-github-runner/examples/permissions-boundary/README.md

@@ -0,0 +1,35 @@
+# Action runners deployed with permissions boundary
+
+This module shows how to create GitHub action runners with permissions boundaries and paths used in role, policies, and instance profiles.
+
+## Usages
+
+Steps for the full setup, such as creating a GitHub app can be find the module [README](../../README.md). First create the deploy role and boundary policies. These steps require an admin user.
+
+> Ensure you have set the version in `lambdas-download/main.tf` for running the example. The version needs to be set to a GitHub release version, see https://github.com/philips-labs/terraform-aws-github-runner/releases
+
+
+```bash
+cd setup
+terraform init
+terraform apply
+cd ..
+```
+
+Now a new role and policies should be created. The output of the previous step is imported in this workspace to load the role and policy. The deployment of the runner module assumes the new role before creating all resources (https://www.terraform.io/docs/providers/aws/index.html#assume-role). Before running Terraform, ensure the GitHub app is configured.
+
+Download the lambda releases.
+
+```bash
+cd lambdas-download
+terraform init
+terraform apply
+cd ..
+```
+
+Now you can deploy the module.
+
+```bash
+terraform init
+terraform apply
+```

+ 25 - 0
thirdparty/terraform-aws-github-runner/examples/permissions-boundary/lambdas-download/main.tf

@@ -0,0 +1,25 @@
+locals {
+  version = "<REPLACE_BY_GITHUB_RELEASE_VERSION>"
+}
+
+module "lambdas" {
+  source = "../../../modules/download-lambda"
+  lambdas = [
+    {
+      name = "webhook"
+      tag  = local.version
+    },
+    {
+      name = "runners"
+      tag  = local.version
+    },
+    {
+      name = "runner-binaries-syncer"
+      tag  = local.version
+    }
+  ]
+}
+
+output "files" {
+  value = module.lambdas.files
+}

+ 60 - 0
thirdparty/terraform-aws-github-runner/examples/permissions-boundary/main.tf

@@ -0,0 +1,60 @@
+locals {
+  environment = "boundaries"
+  aws_region  = "eu-west-1"
+}
+
+resource "random_id" "random" {
+  byte_length = 20
+}
+
+data "terraform_remote_state" "iam" {
+  backend = "local"
+
+  config = {
+    path = "${path.module}/setup/terraform.tfstate"
+  }
+}
+
+resource "aws_kms_key" "github" {
+  is_enabled = true
+}
+
+resource "aws_kms_alias" "github" {
+  name          = "alias/github/action-runners"
+  target_key_id = aws_kms_key.github.key_id
+}
+
+module "runners" {
+  source = "../../"
+  providers = {
+    aws = aws.terraform_role
+  }
+
+  aws_region  = local.aws_region
+  vpc_id      = module.vpc.vpc_id
+  subnet_ids  = module.vpc.private_subnets
+  kms_key_arn = aws_kms_key.github.key_id
+
+  prefix = local.environment
+  tags = {
+    Project = "ProjectX"
+  }
+
+  github_app = {
+    key_base64     = var.github_app_key_base64
+    id             = var.github_app_id
+    client_id      = var.github_app_client_id
+    client_secret  = var.github_app_client_secret
+    webhook_secret = random_id.random.hex
+  }
+
+  webhook_lambda_zip                = "lambdas-download/webhook.zip"
+  runner_binaries_syncer_lambda_zip = "lambdas-download/runner-binaries-syncer.zip"
+  runners_lambda_zip                = "lambdas-download/runners.zip"
+  enable_organization_runners       = false
+  runner_extra_labels               = "default,example"
+
+  instance_profile_path     = "/runners/"
+  role_path                 = "/runners/"
+  role_permissions_boundary = data.terraform_remote_state.iam.outputs.boundary
+}

+ 12 - 0
thirdparty/terraform-aws-github-runner/examples/permissions-boundary/outputs.tf

@@ -0,0 +1,12 @@
+output "runners" {
+  value = {
+    lambda_syncer_name = module.runners.binaries_syncer.lambda.function_name
+  }
+}
+
+output "webhook" {
+  value = {
+    secret   = random_id.random.hex
+    endpoint = module.runners.webhook.endpoint
+  }
+}

+ 7 - 0
thirdparty/terraform-aws-github-runner/examples/permissions-boundary/providers.tf

@@ -0,0 +1,7 @@
+provider "aws" {
+  alias  = "terraform_role"
+  region = local.aws_region
+  assume_role {
+    role_arn = data.terraform_remote_state.iam.outputs.role
+  }
+}

+ 22 - 0
thirdparty/terraform-aws-github-runner/examples/permissions-boundary/setup/.terraform.lock.hcl

@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/aws" {
+  version     = "4.12.1"
+  constraints = "~> 4.0"
+  hashes = [
+    "h1:YvwxXRDVzn9j6Gt7Vg8tCcyF/niapue5sxSUw1TH+9U=",
+    "zh:2b432dc3bf7e0987bf9dcad5d397c384890d12fcd95827bc4581ca2955fc623a",
+    "zh:2f79a448a4e5ad24a706ab634078d0ef159be3278eb24988b7d2185173f5dd8f",
+    "zh:5d70074c10cefb30d4104af54f912e58ffa1b6871277b0a5324c8f13000f5009",
+    "zh:63623743fb15d54787a96c9761b97a935ff396672e625730cb7a5c1971acf4b6",
+    "zh:8263f376e6db684667c10e28df8d8d188e02fd09ad58e1ad7075e363c389e24c",
+    "zh:8b5aa9fd1ddf1de0ab7d462891123405e5af04d7e4d1e4b03381634b3cae4884",
+    "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
+    "zh:d00b2d0b374ab92e934eb597668c5f3e415c4cf8335e6a52ab99949b8fcf57dd",
+    "zh:d0e037725aced6cacc2e0a1903b31083c64f8765fb1263e4f8f891745266b7fb",
+    "zh:e6e244123bc1df109db90bef0af2a875a0b3afb268f21c3e5bc34753657102ad",
+    "zh:ec6901ab8b99ae3df50340e9aa86ed3bac1369f5e1403c0362edd9944640fa22",
+    "zh:f6a4d0ce3bd3d4b81163c4ae75b66e50c10b935c60a63d7fb96df285c0eeca40",
+  ]
+}

+ 15 - 0
thirdparty/terraform-aws-github-runner/examples/permissions-boundary/setup/main.tf

@@ -0,0 +1,15 @@
+data "aws_caller_identity" "current" {}
+
+module "iam" {
+  source = "../../../modules/setup-iam-permissions"
+
+  environment = "boundaries"
+  account_id  = data.aws_caller_identity.current.account_id
+
+  namespaces = {
+    boundary_namespace         = "boundaries"
+    role_namespace             = "runners"
+    policy_namespace           = "runners"
+    instance_profile_namespace = "runners"
+  }
+}

+ 7 - 0
thirdparty/terraform-aws-github-runner/examples/permissions-boundary/setup/outputs.tf

@@ -0,0 +1,7 @@
+output "role" {
+  value = module.iam.role
+}
+
+output "boundary" {
+  value = module.iam.boundary
+}

+ 3 - 0
thirdparty/terraform-aws-github-runner/examples/permissions-boundary/setup/providers.tf

@@ -0,0 +1,3 @@
+provider "aws" {
+  region = "eu-west-1"
+}

+ 9 - 0
thirdparty/terraform-aws-github-runner/examples/permissions-boundary/setup/versions.tf

@@ -0,0 +1,9 @@
+terraform {
+  required_providers {
+    aws = {
+      source  = "hashicorp/aws"
+      version = "~> 4.0"
+    }
+  }
+  required_version = ">= 1"
+}

+ 8 - 0
thirdparty/terraform-aws-github-runner/examples/permissions-boundary/variables.tf

@@ -0,0 +1,8 @@
+
+variable "github_app_key_base64" {}
+
+variable "github_app_id" {}
+
+variable "github_app_client_id" {}
+
+variable "github_app_client_secret" {}

+ 15 - 0
thirdparty/terraform-aws-github-runner/examples/permissions-boundary/versions.tf

@@ -0,0 +1,15 @@
+terraform {
+  required_providers {
+    aws = {
+      source  = "hashicorp/aws"
+      version = "~> 4.0"
+    }
+    local = {
+      source = "hashicorp/local"
+    }
+    random = {
+      source = "hashicorp/random"
+    }
+  }
+  required_version = ">= 1"
+}

+ 21 - 0
thirdparty/terraform-aws-github-runner/examples/permissions-boundary/vpc.tf

@@ -0,0 +1,21 @@
+module "vpc" {
+  source  = "terraform-aws-modules/vpc/aws"
+  version = "3.11.2"
+
+  name = "vpc-${local.environment}"
+  cidr = "10.0.0.0/16"
+
+  azs             = ["${local.aws_region}a", "${local.aws_region}b", "${local.aws_region}c"]
+  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
+  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
+
+  enable_dns_hostnames    = true
+  enable_nat_gateway      = true
+  map_public_ip_on_launch = false
+  single_nat_gateway      = true
+
+  tags = {
+    Environment = local.environment
+  }
+
+}

+ 60 - 0
thirdparty/terraform-aws-github-runner/examples/prebuilt/.terraform.lock.hcl

@@ -0,0 +1,60 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/aws" {
+  version     = "4.15.1"
+  constraints = ">= 3.63.0, ~> 4.0, ~> 4.15"
+  hashes = [
+    "h1:KNkM4pOCRzbjlGoCxt4Yl4qGUESLQ2uKIOSHb+aiMlY=",
+    "zh:1d944144f8d613b8090c0c8391e4b205ca036086d70aceb4cdf664856fa8410c",
+    "zh:2a0ca16a6b12c0ac509f64512f80bd2ed6e7ea0ec369212efd4be3fa65e9773d",
+    "zh:3f9efdce4f1c320ffd061e8715e1d031deac1be0b959eaa60c25a274925653e4",
+    "zh:4cf82f3267b0c3e08be29b0345f711ab84ea1ea75f0e8ce81f5a2fe635ba67b4",
+    "zh:58474a0b7da438e1bcd53e87f10e28830836ff9b46cce5f09413c90952ae4f78",
+    "zh:6eb1be8afb0314b6b8424fe212b13beeb04f3f24692f0f3ee86c5153c7eb2e63",
+    "zh:8022da7d3b050d452ce6c679844e13729bdb4e1b3e75dcf68931af17a06b9277",
+    "zh:8e2683d00fff1df43440d6e7c04a2c1eb432c7d5dacff32fe8ce9045bc948fe6",
+    "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
+    "zh:b0c22d9a306e8ac2de57b5291a3d0a7a2c1713e33b7d076005662451afdc4d29",
+    "zh:ba6b7d7d91388b636145b133da6b4e32620cdc8046352e2dc8f3f0f81ff5d2e2",
+    "zh:d38a816eb60f4419d99303136a3bb61a0d2df3ca8a1dce2ced9b99bf23efa9f7",
+  ]
+}
+
+provider "registry.terraform.io/hashicorp/local" {
+  version = "2.2.3"
+  hashes = [
+    "h1:FvRIEgCmAezgZUqb2F+PZ9WnSSnR5zbEM2ZI+GLmbMk=",
+    "zh:04f0978bb3e052707b8e82e46780c371ac1c66b689b4a23bbc2f58865ab7d5c0",
+    "zh:6484f1b3e9e3771eb7cc8e8bab8b35f939a55d550b3f4fb2ab141a24269ee6aa",
+    "zh:78a56d59a013cb0f7eb1c92815d6eb5cf07f8b5f0ae20b96d049e73db915b238",
+    "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+    "zh:8aa9950f4c4db37239bcb62e19910c49e47043f6c8587e5b0396619923657797",
+    "zh:996beea85f9084a725ff0e6473a4594deb5266727c5f56e9c1c7c62ded6addbb",
+    "zh:9a7ef7a21f48fabfd145b2e2a4240ca57517ad155017e86a30860d7c0c109de3",
+    "zh:a63e70ac052aa25120113bcddd50c1f3cfe61f681a93a50cea5595a4b2cc3e1c",
+    "zh:a6e8d46f94108e049ad85dbed60354236dc0b9b5ec8eabe01c4580280a43d3b8",
+    "zh:bb112ce7efbfcfa0e65ed97fa245ef348e0fd5bfa5a7e4ab2091a9bd469f0a9e",
+    "zh:d7bec0da5c094c6955efed100f3fe22fca8866859f87c025be1760feb174d6d9",
+    "zh:fb9f271b72094d07cef8154cd3d50e9aa818a0ea39130bc193132ad7b23076fd",
+  ]
+}
+
+provider "registry.terraform.io/hashicorp/random" {
+  version = "3.2.0"
+  hashes = [
+    "h1:NvMyFNHHq65GUNyBGjLuLD4ABA6sTlRebZCIK5OtvFU=",
+    "zh:2960977ce9a7d6a7d3e934e75ec5814735626f95c186ad95a9102344a1a38ac1",
+    "zh:2fd012abfabe7076f3f2f402eeef4970e20574d20ffec57c162b02b6e848c32f",
+    "zh:4cd3234671cf01c913023418b227eb78b0659f2cd2e0b387be1f0bb607d29889",
+    "zh:52e695b4fa3fae735ffc901edff8183745f980923510a744db7616e8f10dc499",
+    "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+    "zh:848b4a294e5ba15192ee4bfd199c07f60a437d7572efcd2d89db036e1ebc0e6e",
+    "zh:9d49aa432a05748a9527e95448cebee1238c87c97c7e8dec694bfd709683f9c7",
+    "zh:b4ad4cf289d3f7408649b74b8639918833613f2a1f3cf51b51f4b2fdaa412dd2",
+    "zh:c1544c4b416096fb8d8dbf84c4488584a2844a30dd533b957e9e9e60a165f24e",
+    "zh:dc737d6b4591cad8c9a1d0b347e587e846d8d901789b29b4dd401b6cdf82c017",
+    "zh:f5645fd39f749dbbf847cbdc87ba0dbd141143f12917a6a8904faf8a9b64111e",
+    "zh:fdedf610e0d020878a8f1fedda8105e0c33a7e23c4792fca54460685552de308",
+  ]
+}

+ 93 - 0
thirdparty/terraform-aws-github-runner/examples/prebuilt/README.md

@@ -0,0 +1,93 @@
+# Action runners deployment with prebuilt image
+
+This module shows how to create GitHub action runners using a prebuilt AMI for the runners
+
+## Usages
+
+Steps for the full setup, such as creating a GitHub app can be found in the root module's [README](../../README.md).
+
+## Variables
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| <a name="input_ami_filter"></a> [ami\_filter](#input\_ami\_filter) | The amis to search.  Use the default for the provided amazon linux image, `github-runner-windows-core-2019-*` for the provided widnows image | `string` | `github-runner-amzn2-x86_64-2021*` | no |
+| <a name="input_github_app_key_base64"></a> [github\_app\_key\_base64](#input\_github\_app\_key\_base64) | The base64 encoded private key you downloaded from GitHub when creating the app | `string` | | yes |
+| <a name="input_github_app_id"></a> [github\_app\_id](#input\_github\_app\_id) | The id of the app you created on GitHub | `string` | | yes |
+| <a name="input_region"></a> [region](#input\_region) | The target aws region | `string` | `eu-west-1` | no |
+| <a name="input_runner_os"></a> [runner\_os](#input\_runner\_os) | The os of the image, either `linux` or `windows` | `string` | `linux` | no |
+
+### Lambdas
+
+You can either download the released lambda code or build them locally yourself.
+
+First download the Lambda releases from GitHub. Ensure you have set the version in `lambdas-download/main.tf` for running the example. The version needs to be set to a GitHub release version, see https://github.com/philips-labs/terraform-aws-github-runner/releases
+
+```bash
+cd lambdas-download
+terraform init
+terraform apply
+cd ..
+```
+
+Alternatively you can build the lambdas locally with Node or Docker, there is a simple build script in `<root>/.ci/build.sh`. In the `main.tf` you need to specify the build location for all of the zip files.
+
+```hcl
+  webhook_lambda_zip                = "../../lambda_output/webhook.zip"
+  runner_binaries_syncer_lambda_zip = "../../lambda_output/runner-binaries-syncer.zip"
+  runners_lambda_zip                = "../../lambda_output/runners.zip"
+```
+
+### GitHub App Configuration
+
+Before running Terraform, ensure the GitHub app is configured. See the [configuration details](../../README.md#usages) for more details.
+
+### Packer Image
+
+You will need to build your image. This example deployment uses the image example in `/images/linux-amz2`. You must build this image with packer in your AWS account first. Once you have built this you need to provider your owner ID as a variable
+
+## Deploy
+
+To use your image in the terraform modules you will need to set some values on the module.
+
+Assuming you have built the `linux-amzn2` image which has a pre-defined AMI name in the following format `github-runner-amzn2-x86_64-YYYYMMDDhhmm` you can use the following values.
+
+```hcl
+
+module "runners" {
+  ...
+  # set the name of the ami to use
+  ami_filter        = { name = ["github-runner-amzn2-x86_64-2021*"] }
+  # provide the owner id of 
+  ami_owners        = ["<your owner id>"]
+
+  enabled_userdata = false
+  ...
+}
+```
+
+If your owner is the same as the account you are logging into then you can use `aws_caller_identity` to retrieve it dynamically.
+
+```hcl
+data "aws_caller_identity" "current" {}
+
+module "runners" {
+  ...
+  ami_owners       = [data.aws_caller_identity.current.account_id]
+  ...
+}
+```
+
+You can then deploy the terraform
+
+```bash
+terraform init
+terraform apply
+```
+
+You can receive the webhook details by running:
+
+```bash
+terraform output -raw webhook_secret
+```
+
+Be-aware some shells will print some end of line character `%`.

+ 25 - 0
thirdparty/terraform-aws-github-runner/examples/prebuilt/lambdas-download/main.tf

@@ -0,0 +1,25 @@
+locals {
+  version = "<REPLACE_BY_GITHUB_RELEASE_VERSION>"
+}
+
+module "lambdas" {
+  source = "../../../modules/download-lambda"
+  lambdas = [
+    {
+      name = "webhook"
+      tag  = local.version
+    },
+    {
+      name = "runners"
+      tag  = local.version
+    },
+    {
+      name = "runner-binaries-syncer"
+      tag  = local.version
+    }
+  ]
+}
+
+output "files" {
+  value = module.lambdas.files
+}

+ 47 - 0
thirdparty/terraform-aws-github-runner/examples/prebuilt/main.tf

@@ -0,0 +1,47 @@
+locals {
+  environment = "prebuilt"
+}
+
+resource "random_id" "random" {
+  byte_length = 20
+}
+
+data "aws_caller_identity" "current" {}
+
+module "runners" {
+  source                          = "../../"
+  create_service_linked_role_spot = true
+  aws_region                      = var.aws_region
+  vpc_id                          = module.vpc.vpc_id
+  subnet_ids                      = module.vpc.private_subnets
+
+  prefix = local.environment
+
+  github_app = {
+    key_base64     = var.github_app_key_base64
+    id             = var.github_app_id
+    webhook_secret = random_id.random.hex
+  }
+
+  webhook_lambda_zip                = "lambdas-download/webhook.zip"
+  runner_binaries_syncer_lambda_zip = "lambdas-download/runner-binaries-syncer.zip"
+  runners_lambda_zip                = "lambdas-download/runners.zip"
+
+  runner_extra_labels = "default,example"
+
+  runner_os = var.runner_os
+
+  # configure your pre-built AMI
+  enabled_userdata = false
+  ami_filter       = { name = [var.ami_name_filter] }
+  ami_owners       = [data.aws_caller_identity.current.account_id]
+
+  # enable access to the runners via SSM
+  enable_ssm_on_runners = true
+
+  # override delay of events in seconds
+  delay_webhook_event = 5
+
+  # override scaling down
+  scale_down_schedule_expression = "cron(* * * * ? *)"
+}

+ 15 - 0
thirdparty/terraform-aws-github-runner/examples/prebuilt/outputs.tf

@@ -0,0 +1,15 @@
+output "runners" {
+  value = {
+    lambda_syncer_name = module.runners.binaries_syncer.lambda.function_name
+  }
+}
+
+output "webhook_endpoint" {
+  value = module.runners.webhook.endpoint
+}
+
+output "webhook_secret" {
+  sensitive = true
+  value     = random_id.random.hex
+}
+

+ 3 - 0
thirdparty/terraform-aws-github-runner/examples/prebuilt/providers.tf

@@ -0,0 +1,3 @@
+provider "aws" {
+  region = var.aws_region
+}

+ 19 - 0
thirdparty/terraform-aws-github-runner/examples/prebuilt/variables.tf

@@ -0,0 +1,19 @@
+
+variable "github_app_key_base64" {}
+
+variable "github_app_id" {}
+
+variable "runner_os" {
+  type    = string
+  default = "linux"
+}
+
+variable "ami_name_filter" {
+  type    = string
+  default = "github-runner-amzn2-x86_64-*"
+}
+
+variable "aws_region" {
+  type    = string
+  default = "eu-west-1"
+}

+ 15 - 0
thirdparty/terraform-aws-github-runner/examples/prebuilt/versions.tf

@@ -0,0 +1,15 @@
+terraform {
+  required_providers {
+    aws = {
+      source  = "hashicorp/aws"
+      version = "~> 4.0"
+    }
+    local = {
+      source = "hashicorp/local"
+    }
+    random = {
+      source = "hashicorp/random"
+    }
+  }
+  required_version = ">= 1"
+}

+ 21 - 0
thirdparty/terraform-aws-github-runner/examples/prebuilt/vpc.tf

@@ -0,0 +1,21 @@
+module "vpc" {
+  source  = "terraform-aws-modules/vpc/aws"
+  version = "3.11.2"
+
+  name = "vpc-${local.environment}"
+  cidr = "10.0.0.0/16"
+
+  azs             = ["${var.aws_region}a", "${var.aws_region}b", "${var.aws_region}c"]
+  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
+  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
+
+  enable_dns_hostnames    = true
+  enable_nat_gateway      = true
+  map_public_ip_on_launch = false
+  single_nat_gateway      = true
+
+  tags = {
+    Environment = local.environment
+  }
+
+}

+ 60 - 0
thirdparty/terraform-aws-github-runner/examples/ubuntu/.terraform.lock.hcl

@@ -0,0 +1,60 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/aws" {
+  version     = "4.15.1"
+  constraints = ">= 3.63.0, ~> 4.0, ~> 4.15"
+  hashes = [
+    "h1:KNkM4pOCRzbjlGoCxt4Yl4qGUESLQ2uKIOSHb+aiMlY=",
+    "zh:1d944144f8d613b8090c0c8391e4b205ca036086d70aceb4cdf664856fa8410c",
+    "zh:2a0ca16a6b12c0ac509f64512f80bd2ed6e7ea0ec369212efd4be3fa65e9773d",
+    "zh:3f9efdce4f1c320ffd061e8715e1d031deac1be0b959eaa60c25a274925653e4",
+    "zh:4cf82f3267b0c3e08be29b0345f711ab84ea1ea75f0e8ce81f5a2fe635ba67b4",
+    "zh:58474a0b7da438e1bcd53e87f10e28830836ff9b46cce5f09413c90952ae4f78",
+    "zh:6eb1be8afb0314b6b8424fe212b13beeb04f3f24692f0f3ee86c5153c7eb2e63",
+    "zh:8022da7d3b050d452ce6c679844e13729bdb4e1b3e75dcf68931af17a06b9277",
+    "zh:8e2683d00fff1df43440d6e7c04a2c1eb432c7d5dacff32fe8ce9045bc948fe6",
+    "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
+    "zh:b0c22d9a306e8ac2de57b5291a3d0a7a2c1713e33b7d076005662451afdc4d29",
+    "zh:ba6b7d7d91388b636145b133da6b4e32620cdc8046352e2dc8f3f0f81ff5d2e2",
+    "zh:d38a816eb60f4419d99303136a3bb61a0d2df3ca8a1dce2ced9b99bf23efa9f7",
+  ]
+}
+
+provider "registry.terraform.io/hashicorp/local" {
+  version = "2.2.3"
+  hashes = [
+    "h1:FvRIEgCmAezgZUqb2F+PZ9WnSSnR5zbEM2ZI+GLmbMk=",
+    "zh:04f0978bb3e052707b8e82e46780c371ac1c66b689b4a23bbc2f58865ab7d5c0",
+    "zh:6484f1b3e9e3771eb7cc8e8bab8b35f939a55d550b3f4fb2ab141a24269ee6aa",
+    "zh:78a56d59a013cb0f7eb1c92815d6eb5cf07f8b5f0ae20b96d049e73db915b238",
+    "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+    "zh:8aa9950f4c4db37239bcb62e19910c49e47043f6c8587e5b0396619923657797",
+    "zh:996beea85f9084a725ff0e6473a4594deb5266727c5f56e9c1c7c62ded6addbb",
+    "zh:9a7ef7a21f48fabfd145b2e2a4240ca57517ad155017e86a30860d7c0c109de3",
+    "zh:a63e70ac052aa25120113bcddd50c1f3cfe61f681a93a50cea5595a4b2cc3e1c",
+    "zh:a6e8d46f94108e049ad85dbed60354236dc0b9b5ec8eabe01c4580280a43d3b8",
+    "zh:bb112ce7efbfcfa0e65ed97fa245ef348e0fd5bfa5a7e4ab2091a9bd469f0a9e",
+    "zh:d7bec0da5c094c6955efed100f3fe22fca8866859f87c025be1760feb174d6d9",
+    "zh:fb9f271b72094d07cef8154cd3d50e9aa818a0ea39130bc193132ad7b23076fd",
+  ]
+}
+
+provider "registry.terraform.io/hashicorp/random" {
+  version = "3.2.0"
+  hashes = [
+    "h1:NvMyFNHHq65GUNyBGjLuLD4ABA6sTlRebZCIK5OtvFU=",
+    "zh:2960977ce9a7d6a7d3e934e75ec5814735626f95c186ad95a9102344a1a38ac1",
+    "zh:2fd012abfabe7076f3f2f402eeef4970e20574d20ffec57c162b02b6e848c32f",
+    "zh:4cd3234671cf01c913023418b227eb78b0659f2cd2e0b387be1f0bb607d29889",
+    "zh:52e695b4fa3fae735ffc901edff8183745f980923510a744db7616e8f10dc499",
+    "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+    "zh:848b4a294e5ba15192ee4bfd199c07f60a437d7572efcd2d89db036e1ebc0e6e",
+    "zh:9d49aa432a05748a9527e95448cebee1238c87c97c7e8dec694bfd709683f9c7",
+    "zh:b4ad4cf289d3f7408649b74b8639918833613f2a1f3cf51b51f4b2fdaa412dd2",
+    "zh:c1544c4b416096fb8d8dbf84c4488584a2844a30dd533b957e9e9e60a165f24e",
+    "zh:dc737d6b4591cad8c9a1d0b347e587e846d8d901789b29b4dd401b6cdf82c017",
+    "zh:f5645fd39f749dbbf847cbdc87ba0dbd141143f12917a6a8904faf8a9b64111e",
+    "zh:fdedf610e0d020878a8f1fedda8105e0c33a7e23c4792fca54460685552de308",
+  ]
+}

+ 24 - 0
thirdparty/terraform-aws-github-runner/examples/ubuntu/README.md

@@ -0,0 +1,24 @@
+# Action runners deployment ubuntu example
+
+This module shows how to create GitHub action runners using an Ubuntu AMI. Lambda release will be downloaded from GitHub.
+
+## Usages
+
+Steps for the full setup, such as creating a GitHub app can be found in the root module's [README](../../README.md). First download the Lambda releases from GitHub. Alternatively you can build the lambdas locally with Node or Docker, there is a simple build script in `<root>/.ci/build.sh`. In the `main.tf` you can simply remove the location of the lambda zip files, the default location will work in this case.
+
+> Ensure you have set the version in `lambdas-download/main.tf` for running the example. The version needs to be set to a GitHub release version, see https://github.com/philips-labs/terraform-aws-github-runner/releases
+
+
+```bash
+cd lambdas-download
+terraform init
+terraform apply
+cd ..
+```
+
+Before running Terraform, ensure the GitHub app is configured.
+
+```bash
+terraform init
+terraform apply
+```

+ 25 - 0
thirdparty/terraform-aws-github-runner/examples/ubuntu/lambdas-download/main.tf

@@ -0,0 +1,25 @@
+locals {
+  version = "<REPLACE_BY_GITHUB_RELEASE_VERSION>"
+}
+
+module "lambdas" {
+  source = "../../../modules/download-lambda"
+  lambdas = [
+    {
+      name = "webhook"
+      tag  = local.version
+    },
+    {
+      name = "runners"
+      tag  = local.version
+    },
+    {
+      name = "runner-binaries-syncer"
+      tag  = local.version
+    }
+  ]
+}
+
+output "files" {
+  value = module.lambdas.files
+}

+ 102 - 0
thirdparty/terraform-aws-github-runner/examples/ubuntu/main.tf

@@ -0,0 +1,102 @@
+locals {
+  environment = "ubuntu"
+  aws_region  = "eu-west-1"
+}
+
+resource "random_id" "random" {
+  byte_length = 20
+}
+
+data "aws_caller_identity" "current" {}
+
+module "runners" {
+  source = "../../"
+
+  aws_region = local.aws_region
+  vpc_id     = module.vpc.vpc_id
+  subnet_ids = module.vpc.private_subnets
+
+  prefix = local.environment
+  tags = {
+    Project = "ProjectX"
+  }
+
+  github_app = {
+    key_base64     = var.github_app_key_base64
+    id             = var.github_app_id
+    webhook_secret = random_id.random.hex
+  }
+
+  # webhook_lambda_zip                = "lambdas-download/webhook.zip"
+  # runner_binaries_syncer_lambda_zip = "lambdas-download/runner-binaries-syncer.zip"
+  # runners_lambda_zip                = "lambdas-download/runners.zip"
+
+  enable_organization_runners = false
+  runner_extra_labels         = "ubuntu,example"
+
+  # enable access to the runners via SSM
+  enable_ssm_on_runners = true
+
+  runner_run_as = "ubuntu"
+
+  # AMI selection and userdata
+  #
+  # option 1. configure your pre-built AMI + userdata
+  userdata_template = "./templates/user-data.sh"
+  ami_owners        = ["099720109477"] # Canonical's Amazon account ID
+
+  ami_filter = {
+    name = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
+  }
+
+  # Custom build AMI, no custom userdata needed.
+  # option 2: Build custom AMI see ../../images/ubuntu-focal
+  #           disable lines above (option 1) and enable the ones below
+  # ami_filter = { name = ["github-runner-ubuntu-focal-amd64-*"] }
+  # ami_owners = [data.aws_caller_identity.current.account_id]
+
+
+  block_device_mappings = [{
+    # Set the block device name for Ubuntu root device
+    device_name           = "/dev/sda1"
+    delete_on_termination = true
+    volume_type           = "gp3"
+    volume_size           = 30
+    encrypted             = true
+    iops                  = null
+  }]
+
+  runner_log_files = [
+    {
+      "log_group_name" : "syslog",
+      "prefix_log_group" : true,
+      "file_path" : "/var/log/syslog",
+      "log_stream_name" : "{instance_id}"
+    },
+    {
+      "log_group_name" : "user_data",
+      "prefix_log_group" : true,
+      "file_path" : "/var/log/user-data.log",
+      "log_stream_name" : "{instance_id}/user_data"
+    },
+    {
+      "log_group_name" : "runner",
+      "prefix_log_group" : true,
+      "file_path" : "/opt/actions-runner/_diag/Runner_**.log",
+      "log_stream_name" : "{instance_id}/runner"
+    }
+  ]
+
+  # Uncomment to enable ephemeral runners
+  # delay_webhook_event      = 0
+  # enable_ephemeral_runners = true
+  # enabled_userdata         = false
+
+  # Uncommet idle config to have idle runners from 9 to 5 in time zone Amsterdam
+  # idle_config = [{
+  #   cron      = "* * 9-17 * * *"
+  #   timeZone  = "Europe/Amsterdam"
+  #   idleCount = 1
+  # }]
+
+}

+ 15 - 0
thirdparty/terraform-aws-github-runner/examples/ubuntu/outputs.tf

@@ -0,0 +1,15 @@
+output "runners" {
+  value = {
+    lambda_syncer_name = module.runners.binaries_syncer.lambda.function_name
+  }
+}
+
+output "webhook_endpoint" {
+  value = module.runners.webhook.endpoint
+}
+
+output "webhook_secret" {
+  sensitive = true
+  value     = random_id.random.hex
+}
+

+ 11 - 0
thirdparty/terraform-aws-github-runner/examples/ubuntu/providers.tf

@@ -0,0 +1,11 @@
+provider "aws" {
+  region = local.aws_region
+
+  // If you use roles with specific permissions please add your role
+  // assume_role {
+  //   role_arn = "arn:aws:iam::123456789012:role/MyAdminRole"
+  // }
+}
+
+provider "random" {
+}

+ 73 - 0
thirdparty/terraform-aws-github-runner/examples/ubuntu/templates/user-data.sh

@@ -0,0 +1,73 @@
+#!/bin/bash -x
+exec > >(tee /var/log/user-data.log | logger -t user-data -s 2>/dev/console) 2>&1
+
+${pre_install}
+
+# Install AWS CLI
+apt-get update
+DEBIAN_FRONTEND=noninteractive apt-get install -y \
+    awscli \
+    jq \
+    curl \
+    wget \
+    git \
+    uidmap \
+    build-essential \
+    unzip
+
+USER_NAME=runners
+useradd -m -s /bin/bash $USER_NAME
+USER_ID=$(id -ru $USER_NAME)
+
+# install and configure cloudwatch logging agent
+wget https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb
+dpkg -i -E ./amazon-cloudwatch-agent.deb
+amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c ssm:${ssm_key_cloudwatch_agent_config}
+
+# configure systemd for running service in users accounts
+cat >/etc/systemd/user@UID.service <<-EOF
+
+[Unit]
+Description=User Manager for UID %i
+After=user-runtime-dir@%i.service
+Wants=user-runtime-dir@%i.service
+
+[Service]
+LimitNOFILE=infinity
+LimitNPROC=infinity
+User=%i
+PAMName=systemd-user
+Type=notify
+
+[Install]
+WantedBy=default.target
+
+EOF
+
+echo export XDG_RUNTIME_DIR=/run/user/$USER_ID >>/home/$USER_NAME/.profile
+
+systemctl daemon-reload
+systemctl enable user@UID.service
+systemctl start user@UID.service
+
+curl -fsSL https://get.docker.com/rootless >>/opt/rootless.sh && chmod 755 /opt/rootless.sh
+su -l $USER_NAME -c /opt/rootless.sh
+echo export DOCKER_HOST=unix:///run/user/$USER_ID/docker.sock >>/home/$USER_NAME/.profile
+echo export PATH=/home/$USER_NAME/bin:$PATH >>/home/$USER_NAME/.profile
+
+# Run docker service by default
+loginctl enable-linger $USER_NAME
+su -l $USER_NAME -c "systemctl --user enable docker"
+
+${install_runner}
+
+# config runner for rootless docker
+cd /opt/actions-runner/
+echo DOCKER_HOST=unix:///run/user/$USER_ID/docker.sock >>.env
+echo PATH=/home/$USER_NAME/bin:$PATH >>.env
+
+${post_install}
+
+cd /opt/actions-runner
+
+${start_runner}

+ 4 - 0
thirdparty/terraform-aws-github-runner/examples/ubuntu/variables.tf

@@ -0,0 +1,4 @@
+
+variable "github_app_key_base64" {}
+
+variable "github_app_id" {}

+ 15 - 0
thirdparty/terraform-aws-github-runner/examples/ubuntu/versions.tf

@@ -0,0 +1,15 @@
+terraform {
+  required_providers {
+    aws = {
+      source  = "hashicorp/aws"
+      version = "~> 4.0"
+    }
+    local = {
+      source = "hashicorp/local"
+    }
+    random = {
+      source = "hashicorp/random"
+    }
+  }
+  required_version = ">= 1"
+}

+ 21 - 0
thirdparty/terraform-aws-github-runner/examples/ubuntu/vpc.tf

@@ -0,0 +1,21 @@
+module "vpc" {
+  source  = "terraform-aws-modules/vpc/aws"
+  version = "3.11.2"
+
+  name = "vpc-${local.environment}"
+  cidr = "10.0.0.0/16"
+
+  azs             = ["${local.aws_region}a", "${local.aws_region}b", "${local.aws_region}c"]
+  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
+  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
+
+  enable_dns_hostnames    = true
+  enable_nat_gateway      = true
+  map_public_ip_on_launch = false
+  single_nat_gateway      = true
+
+  tags = {
+    Environment = local.environment
+  }
+
+}

+ 60 - 0
thirdparty/terraform-aws-github-runner/examples/windows/.terraform.lock.hcl

@@ -0,0 +1,60 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/aws" {
+  version     = "4.15.1"
+  constraints = ">= 3.63.0, ~> 4.0, ~> 4.15"
+  hashes = [
+    "h1:KNkM4pOCRzbjlGoCxt4Yl4qGUESLQ2uKIOSHb+aiMlY=",
+    "zh:1d944144f8d613b8090c0c8391e4b205ca036086d70aceb4cdf664856fa8410c",
+    "zh:2a0ca16a6b12c0ac509f64512f80bd2ed6e7ea0ec369212efd4be3fa65e9773d",
+    "zh:3f9efdce4f1c320ffd061e8715e1d031deac1be0b959eaa60c25a274925653e4",
+    "zh:4cf82f3267b0c3e08be29b0345f711ab84ea1ea75f0e8ce81f5a2fe635ba67b4",
+    "zh:58474a0b7da438e1bcd53e87f10e28830836ff9b46cce5f09413c90952ae4f78",
+    "zh:6eb1be8afb0314b6b8424fe212b13beeb04f3f24692f0f3ee86c5153c7eb2e63",
+    "zh:8022da7d3b050d452ce6c679844e13729bdb4e1b3e75dcf68931af17a06b9277",
+    "zh:8e2683d00fff1df43440d6e7c04a2c1eb432c7d5dacff32fe8ce9045bc948fe6",
+    "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
+    "zh:b0c22d9a306e8ac2de57b5291a3d0a7a2c1713e33b7d076005662451afdc4d29",
+    "zh:ba6b7d7d91388b636145b133da6b4e32620cdc8046352e2dc8f3f0f81ff5d2e2",
+    "zh:d38a816eb60f4419d99303136a3bb61a0d2df3ca8a1dce2ced9b99bf23efa9f7",
+  ]
+}
+
+provider "registry.terraform.io/hashicorp/local" {
+  version = "2.2.3"
+  hashes = [
+    "h1:FvRIEgCmAezgZUqb2F+PZ9WnSSnR5zbEM2ZI+GLmbMk=",
+    "zh:04f0978bb3e052707b8e82e46780c371ac1c66b689b4a23bbc2f58865ab7d5c0",
+    "zh:6484f1b3e9e3771eb7cc8e8bab8b35f939a55d550b3f4fb2ab141a24269ee6aa",
+    "zh:78a56d59a013cb0f7eb1c92815d6eb5cf07f8b5f0ae20b96d049e73db915b238",
+    "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+    "zh:8aa9950f4c4db37239bcb62e19910c49e47043f6c8587e5b0396619923657797",
+    "zh:996beea85f9084a725ff0e6473a4594deb5266727c5f56e9c1c7c62ded6addbb",
+    "zh:9a7ef7a21f48fabfd145b2e2a4240ca57517ad155017e86a30860d7c0c109de3",
+    "zh:a63e70ac052aa25120113bcddd50c1f3cfe61f681a93a50cea5595a4b2cc3e1c",
+    "zh:a6e8d46f94108e049ad85dbed60354236dc0b9b5ec8eabe01c4580280a43d3b8",
+    "zh:bb112ce7efbfcfa0e65ed97fa245ef348e0fd5bfa5a7e4ab2091a9bd469f0a9e",
+    "zh:d7bec0da5c094c6955efed100f3fe22fca8866859f87c025be1760feb174d6d9",
+    "zh:fb9f271b72094d07cef8154cd3d50e9aa818a0ea39130bc193132ad7b23076fd",
+  ]
+}
+
+provider "registry.terraform.io/hashicorp/random" {
+  version = "3.2.0"
+  hashes = [
+    "h1:NvMyFNHHq65GUNyBGjLuLD4ABA6sTlRebZCIK5OtvFU=",
+    "zh:2960977ce9a7d6a7d3e934e75ec5814735626f95c186ad95a9102344a1a38ac1",
+    "zh:2fd012abfabe7076f3f2f402eeef4970e20574d20ffec57c162b02b6e848c32f",
+    "zh:4cd3234671cf01c913023418b227eb78b0659f2cd2e0b387be1f0bb607d29889",
+    "zh:52e695b4fa3fae735ffc901edff8183745f980923510a744db7616e8f10dc499",
+    "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+    "zh:848b4a294e5ba15192ee4bfd199c07f60a437d7572efcd2d89db036e1ebc0e6e",
+    "zh:9d49aa432a05748a9527e95448cebee1238c87c97c7e8dec694bfd709683f9c7",
+    "zh:b4ad4cf289d3f7408649b74b8639918833613f2a1f3cf51b51f4b2fdaa412dd2",
+    "zh:c1544c4b416096fb8d8dbf84c4488584a2844a30dd533b957e9e9e60a165f24e",
+    "zh:dc737d6b4591cad8c9a1d0b347e587e846d8d901789b29b4dd401b6cdf82c017",
+    "zh:f5645fd39f749dbbf847cbdc87ba0dbd141143f12917a6a8904faf8a9b64111e",
+    "zh:fdedf610e0d020878a8f1fedda8105e0c33a7e23c4792fca54460685552de308",
+  ]
+}

+ 26 - 0
thirdparty/terraform-aws-github-runner/examples/windows/README.md

@@ -0,0 +1,26 @@
+# Action runners deployment windows example
+
+This module shows how to create GitHub action runners using an Windows Runners. Lambda release will be downloaded from GitHub.
+
+## Usages
+
+Steps for the full setup, such as creating a GitHub app can be found in the root module's [README](../../README.md). First, download the Lambda releases from GitHub. Alternatively you can build the lambdas locally with Node or Docker, for which there is a build script available at `<root>/.ci/build.sh`. In the `main.tf` you can remove the location of the lambda zip files, the default location will work in this case.
+
+> Ensure you have set the version in `lambdas-download/main.tf` for running the example. The version needs to be set to a GitHub release version, see <https://github.com/philips-labs/terraform-aws-github-runner/releases>
+
+
+```pwsh
+cd lambdas-download
+terraform init
+terraform apply
+cd ..
+```
+
+Before running Terraform, ensure the GitHub app is configured.
+
+```bash
+terraform init
+terraform apply
+```
+
+_**Note**_: It can take upwards of ten minutes for a runner to start processing jobs, and about as long for logs to start showing up. It's recommend that scale the runners via a warm-up job and then keep them idled.

+ 25 - 0
thirdparty/terraform-aws-github-runner/examples/windows/lambdas-download/main.tf

@@ -0,0 +1,25 @@
+locals {
+  version = "<REPLACE_BY_GITHUB_RELEASE_VERSION>"
+}
+
+module "lambdas" {
+  source = "../../../modules/download-lambda"
+  lambdas = [
+    {
+      name = "webhook"
+      tag  = local.version
+    },
+    {
+      name = "runners"
+      tag  = local.version
+    },
+    {
+      name = "runner-binaries-syncer"
+      tag  = local.version
+    }
+  ]
+}
+
+output "files" {
+  value = module.lambdas.files
+}

+ 48 - 0
thirdparty/terraform-aws-github-runner/examples/windows/main.tf

@@ -0,0 +1,48 @@
+locals {
+  environment = "windows"
+  aws_region  = "eu-west-1"
+}
+
+resource "random_id" "random" {
+  byte_length = 20
+}
+
+module "runners" {
+  source = "../../"
+
+  aws_region = local.aws_region
+  vpc_id     = module.vpc.vpc_id
+  subnet_ids = module.vpc.private_subnets
+  prefix     = local.environment
+
+  github_app = {
+    key_base64     = var.github_app_key_base64
+    id             = var.github_app_id
+    webhook_secret = random_id.random.hex
+  }
+
+  # Grab the lambda packages from local directory. Must run /.ci/build.sh first
+  webhook_lambda_zip                = "../../lambda_output/webhook.zip"
+  runner_binaries_syncer_lambda_zip = "../../lambda_output/runner-binaries-syncer.zip"
+  runners_lambda_zip                = "../../lambda_output/runners.zip"
+
+  enable_organization_runners = false
+  # no need to add extra windows tag here as it is automatically added by GitHub
+  runner_extra_labels = "default,example"
+
+  # Set the OS to Windows
+  runner_os = "windows"
+  # we need to give the runner time to start because this is windows.
+  runner_boot_time_in_minutes = 20
+
+  # enable access to the runners via SSM
+  enable_ssm_on_runners = true
+
+  instance_types = ["m5.large", "c5.large"]
+
+  # override delay of events in seconds for testing
+  delay_webhook_event = 5
+
+  # override scaling down for testing
+  scale_down_schedule_expression = "cron(* * * * ? *)"
+}

+ 15 - 0
thirdparty/terraform-aws-github-runner/examples/windows/outputs.tf

@@ -0,0 +1,15 @@
+output "runners" {
+  value = {
+    lambda_syncer_name = module.runners.binaries_syncer.lambda.function_name
+  }
+}
+
+output "webhook_endpoint" {
+  value = module.runners.webhook.endpoint
+}
+
+output "webhook_secret" {
+  sensitive = true
+  value     = random_id.random.hex
+}
+

+ 3 - 0
thirdparty/terraform-aws-github-runner/examples/windows/providers.tf

@@ -0,0 +1,3 @@
+provider "aws" {
+  region = local.aws_region
+}

+ 4 - 0
thirdparty/terraform-aws-github-runner/examples/windows/variables.tf

@@ -0,0 +1,4 @@
+
+variable "github_app_key_base64" {}
+
+variable "github_app_id" {}

+ 15 - 0
thirdparty/terraform-aws-github-runner/examples/windows/versions.tf

@@ -0,0 +1,15 @@
+terraform {
+  required_providers {
+    aws = {
+      source  = "hashicorp/aws"
+      version = "~> 4.0"
+    }
+    local = {
+      source = "hashicorp/local"
+    }
+    random = {
+      source = "hashicorp/random"
+    }
+  }
+  required_version = ">= 1"
+}

+ 21 - 0
thirdparty/terraform-aws-github-runner/examples/windows/vpc.tf

@@ -0,0 +1,21 @@
+module "vpc" {
+  source  = "terraform-aws-modules/vpc/aws"
+  version = "3.11.2"
+
+  name = "vpc-${local.environment}"
+  cidr = "10.0.0.0/16"
+
+  azs             = ["${local.aws_region}a", "${local.aws_region}b", "${local.aws_region}c"]
+  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
+  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
+
+  enable_dns_hostnames    = true
+  enable_nat_gateway      = true
+  map_public_ip_on_launch = false
+  single_nat_gateway      = true
+
+  tags = {
+    Environment = local.environment
+  }
+
+}

+ 37 - 0
thirdparty/terraform-aws-github-runner/images/README.md

@@ -0,0 +1,37 @@
+# Prebuilt Images
+
+The images inside this folder are pre-built images designed to shorten the boot time of your runners and make using ephemeral runners a faster experience.
+
+These images share the same scripting as used in the user-data mechanism in `/modules/runners/templates/`. We use a `tempaltefile` mechanism to insert the relevant script fragments into the scripts used for provisioning the images.
+
+The examples in `linux-amzn2` and `windows-core-2019` also upload a `start-runner` script that uses the exact same startup process as used in the user-data mechanism. This means that the image created here does not need any extra scripts injected or changes to boot up and connect to GH.
+
+## Building your own
+
+To build these images you first need to install packer.
+You will also need an amazon account and to have provisioned your credentials for packer to consume.
+
+Assuming you are building the `linux-amzn2` image. Then run the following from within the `linux-amzn2` folder
+
+```bash
+packer init .
+packer validate .
+packer build github_agent.linux.pkr.hcl
+```
+
+Your image will then begin to build inside AWS and when finished you will be provided with complete AMI.
+
+## Using your image
+
+To use your image in the terraform modules you will need to set some values on the module.
+
+Assuming you have built the `linux-amzn2` image which has a pre-defined AMI name in the following format `github-runner-amzn2-x86_64-YYYYMMDDhhmm` you can use the following values.
+
+```hcl
+# set the name of the ami to use
+ami_filter        = { name = ["github-runner-amzn2-x86_64-2021*"] }
+# provide the owner id of 
+ami_owners        = ["<your owner id>"]
+
+enabled_userdata = false
+```

+ 8 - 0
thirdparty/terraform-aws-github-runner/images/install-runner.ps1

@@ -0,0 +1,8 @@
+#!/bin/bash -e
+
+user_name=ec2-user
+
+## This wrapper file re-uses scripts in the /modules/runners/templates directory
+## of this repo. These are the same that are used by the user_data functionality 
+## to bootstrap the instance if it is started from an existing AMI.
+${install_runner}

+ 8 - 0
thirdparty/terraform-aws-github-runner/images/install-runner.sh

@@ -0,0 +1,8 @@
+#!/bin/bash -e
+
+user_name=$(cat /tmp/install-user.txt)
+
+## This wrapper file re-uses scripts in the /modules/runners/templates directory
+## of this repo. These are the same that are used by the user_data functionality 
+## to bootstrap the instance if it is started from an existing AMI.
+${install_runner}

+ 174 - 0
thirdparty/terraform-aws-github-runner/images/linux-amzn2/github_agent.linux.pkr.hcl

@@ -0,0 +1,174 @@
+packer {
+  required_plugins {
+    amazon = {
+      version = ">= 0.0.2"
+      source  = "github.com/hashicorp/amazon"
+    }
+  }
+}
+
+variable "runner_version" {
+  description = "The version (no v prefix) of the runner software to install https://github.com/actions/runner/releases"
+  type        = string
+  default     = "2.286.1"
+}
+
+variable "region" {
+  description = "The region to build the image in"
+  type        = string
+  default     = "eu-west-1"
+}
+
+variable "security_group_id" {
+  description = "The ID of the security group Packer will associate with the builder to enable access"
+  type        = string
+  default     = null
+}
+
+variable "subnet_id" {
+  description = "If using VPC, the ID of the subnet, such as subnet-12345def, where Packer will launch the EC2 instance. This field is required if you are using an non-default VPC"
+  type        = string
+  default     = null
+}
+
+variable "associate_public_ip_address" {
+  description = "If using a non-default VPC, there is no public IP address assigned to the EC2 instance. If you specified a public subnet, you probably want to set this to true. Otherwise the EC2 instance won't have access to the internet"
+  type        = string
+  default     = null
+}
+
+variable "instance_type" {
+  description = "The instance type Packer will use for the builder"
+  type        = string
+  default     = "m3.medium"
+}
+
+variable "root_volume_size_gb" {
+  type    = number
+  default = 8
+}
+
+variable "ebs_delete_on_termination" {
+  description = "Indicates whether the EBS volume is deleted on instance termination."
+  type        = bool
+  default     = true
+}
+
+variable "global_tags" {
+  description = "Tags to apply to everything"
+  type        = map(string)
+  default     = {}
+}
+
+variable "ami_tags" {
+  description = "Tags to apply to the AMI"
+  type        = map(string)
+  default     = {}
+}
+
+variable "snapshot_tags" {
+  description = "Tags to apply to the snapshot"
+  type        = map(string)
+  default     = {}
+}
+
+variable "custom_shell_commands" {
+  description = "Additional commands to run on the EC2 instance, to customize the instance, like installing packages"
+  type        = list(string)
+  default     = []
+}
+
+source "amazon-ebs" "githubrunner" {
+  ami_name                    = "github-runner-amzn2-x86_64-${formatdate("YYYYMMDDhhmm", timestamp())}"
+  instance_type               = var.instance_type
+  region                      = var.region
+  security_group_id           = var.security_group_id
+  subnet_id                   = var.subnet_id
+  associate_public_ip_address = var.associate_public_ip_address
+  source_ami_filter {
+    filters = {
+      name                = "amzn2-ami-kernel-5.*-hvm-*-x86_64-gp2"
+      root-device-type    = "ebs"
+      virtualization-type = "hvm"
+    }
+    most_recent = true
+    owners      = ["137112412989"]
+  }
+  ssh_username = "ec2-user"
+  tags = merge(
+    var.global_tags,
+    var.ami_tags,
+    {
+      OS_Version    = "amzn2"
+      Release       = "Latest"
+      Base_AMI_Name = "{{ .SourceAMIName }}"
+  })
+  snapshot_tags = merge(
+    var.global_tags,
+    var.snapshot_tags,
+  )
+
+
+  launch_block_device_mappings {
+    device_name           = "/dev/xvda"
+    volume_size           = "${var.root_volume_size_gb}"
+    volume_type           = "gp3"
+    delete_on_termination = "${var.ebs_delete_on_termination}"
+  }
+}
+
+build {
+  name = "githubactions-runner"
+  sources = [
+    "source.amazon-ebs.githubrunner"
+  ]
+  provisioner "shell" {
+    environment_vars = []
+    inline = concat([
+      "sudo yum update -y",
+      "sudo yum install -y amazon-cloudwatch-agent curl jq git",
+      "sudo amazon-linux-extras install docker",
+      "sudo systemctl enable docker.service",
+      "sudo systemctl enable containerd.service",
+      "sudo service docker start",
+      "sudo usermod -a -G docker ec2-user",
+    ], var.custom_shell_commands)
+  }
+
+  provisioner "file" {
+    content = templatefile("../install-runner.sh", {
+      install_runner = templatefile("../../modules/runners/templates/install-runner.sh", {
+        ARM_PATCH                       = ""
+        S3_LOCATION_RUNNER_DISTRIBUTION = ""
+        RUNNER_ARCHITECTURE             = "x64"
+      })
+    })
+    destination = "/tmp/install-runner.sh"
+  }
+
+  provisioner "shell" {
+    environment_vars = [
+      "RUNNER_TARBALL_URL=https://github.com/actions/runner/releases/download/v${var.runner_version}/actions-runner-linux-x64-${var.runner_version}.tar.gz"
+    ]
+    inline = [
+      "sudo chmod +x /tmp/install-runner.sh",
+      "echo ec2-user > /tmp/install-user.txt",
+      "sudo RUNNER_ARCHITECTURE=x64 RUNNER_TARBALL_URL=$RUNNER_TARBALL_URL /tmp/install-runner.sh"
+    ]
+  }
+
+  provisioner "file" {
+    content = templatefile("../start-runner.sh", {
+      start_runner = templatefile("../../modules/runners/templates/start-runner.sh", {})
+    })
+    destination = "/tmp/start-runner.sh"
+  }
+
+  provisioner "shell" {
+    inline = [
+      "sudo mv /tmp/start-runner.sh /var/lib/cloud/scripts/per-boot/start-runner.sh",
+      "sudo chmod +x /var/lib/cloud/scripts/per-boot/start-runner.sh",
+    ]
+  }
+
+}

+ 3 - 0
thirdparty/terraform-aws-github-runner/images/start-runner.ps1

@@ -0,0 +1,3 @@
+Start-Transcript -Path "C:\runner-startup.log" -Append
+${start_runner}
+Stop-Transcript

+ 9 - 0
thirdparty/terraform-aws-github-runner/images/start-runner.sh

@@ -0,0 +1,9 @@
+#!/bin/bash -e
+exec > >(tee /var/log/runner-startup.log | logger -t user-data -s 2>/dev/console) 2>&1
+
+cd /opt/actions-runner
+
+## This wrapper file re-uses scripts in the /modules/runners/templates directory
+## of this repo. These are the same that are used by the user_data functionality 
+## to bootstrap the instance if it is started from an existing AMI.
+${start_runner}

+ 185 - 0
thirdparty/terraform-aws-github-runner/images/ubuntu-focal/github_agent.ubuntu.pkr.hcl

@@ -0,0 +1,185 @@
+packer {
+  required_plugins {
+    amazon = {
+      version = ">= 0.0.2"
+      source  = "github.com/hashicorp/amazon"
+    }
+  }
+}
+
+variable "runner_version" {
+  description = "The version (no v prefix) of the runner software to install https://github.com/actions/runner/releases"
+  type        = string
+  default     = "2.286.1"
+}
+
+variable "region" {
+  description = "The region to build the image in"
+  type        = string
+  default     = "eu-west-1"
+}
+
+variable "security_group_id" {
+  description = "The ID of the security group Packer will associate with the builder to enable access"
+  type        = string
+  default     = null
+}
+
+variable "subnet_id" {
+  description = "If using VPC, the ID of the subnet, such as subnet-12345def, where Packer will launch the EC2 instance. This field is required if you are using an non-default VPC"
+  type        = string
+  default     = null
+}
+
+variable "associate_public_ip_address" {
+  description = "If using a non-default VPC, there is no public IP address assigned to the EC2 instance. If you specified a public subnet, you probably want to set this to true. Otherwise the EC2 instance won't have access to the internet"
+  type        = string
+  default     = null
+}
+
+variable "instance_type" {
+  description = "The instance type Packer will use for the builder"
+  type        = string
+  default     = "t3.medium"
+}
+
+variable "root_volume_size_gb" {
+  type    = number
+  default = 8
+}
+
+variable "ebs_delete_on_termination" {
+  description = "Indicates whether the EBS volume is deleted on instance termination."
+  type        = bool
+  default     = true
+}
+
+variable "global_tags" {
+  description = "Tags to apply to everything"
+  type        = map(string)
+  default     = {}
+}
+
+variable "ami_tags" {
+  description = "Tags to apply to the AMI"
+  type        = map(string)
+  default     = {}
+}
+
+variable "snapshot_tags" {
+  description = "Tags to apply to the snapshot"
+  type        = map(string)
+  default     = {}
+}
+
+variable "custom_shell_commands" {
+  description = "Additional commands to run on the EC2 instance, to customize the instance, like installing packages"
+  type        = list(string)
+  default     = []
+}
+
+source "amazon-ebs" "githubrunner" {
+  ami_name                    = "github-runner-ubuntu-focal-amd64-${formatdate("YYYYMMDDhhmm", timestamp())}"
+  instance_type               = var.instance_type
+  region                      = var.region
+  security_group_id           = var.security_group_id
+  subnet_id                   = var.subnet_id
+  associate_public_ip_address = var.associate_public_ip_address
+
+  source_ami_filter {
+    filters = {
+      name                = "*ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"
+      root-device-type    = "ebs"
+      virtualization-type = "hvm"
+    }
+    most_recent = true
+    owners      = ["099720109477"]
+  }
+  ssh_username = "ubuntu"
+  tags = merge(
+    var.global_tags,
+    var.ami_tags,
+    {
+      OS_Version    = "ubuntu-focal"
+      Release       = "Latest"
+      Base_AMI_Name = "{{ .SourceAMIName }}"
+  })
+  snapshot_tags = merge(
+    var.global_tags,
+    var.snapshot_tags,
+  )
+
+  launch_block_device_mappings {
+    device_name           = "/dev/sda1"
+    volume_size           = "${var.root_volume_size_gb}"
+    volume_type           = "gp3"
+    delete_on_termination = "${var.ebs_delete_on_termination}"
+  }
+}
+
+build {
+  name = "githubactions-runner"
+  sources = [
+    "source.amazon-ebs.githubrunner"
+  ]
+  provisioner "shell" {
+    environment_vars = [
+      "DEBIAN_FRONTEND=noninteractive"
+    ]
+    inline = concat([
+      "sudo apt-get -y update",
+      "sudo apt-get -y install ca-certificates curl gnupg lsb-release",
+      "sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg",
+      "echo deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null",
+      "sudo apt-get -y update",
+      "sudo apt-get -y install docker-ce docker-ce-cli containerd.io jq git unzip",
+      "sudo systemctl enable containerd.service",
+      "sudo service docker start",
+      "sudo usermod -a -G docker ubuntu",
+      "sudo curl -f https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb -o amazon-cloudwatch-agent.deb",
+      "sudo dpkg -i amazon-cloudwatch-agent.deb",
+      "sudo systemctl restart amazon-cloudwatch-agent",
+      "sudo curl -f https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o awscliv2.zip",
+      "unzip awscliv2.zip",
+      "sudo ./aws/install",
+    ], var.custom_shell_commands)
+  }
+
+  provisioner "file" {
+    content = templatefile("../install-runner.sh", {
+      install_runner = templatefile("../../modules/runners/templates/install-runner.sh", {
+        ARM_PATCH                       = ""
+        S3_LOCATION_RUNNER_DISTRIBUTION = ""
+        RUNNER_ARCHITECTURE             = "x64"
+      })
+    })
+    destination = "/tmp/install-runner.sh"
+  }
+
+  provisioner "shell" {
+    environment_vars = [
+      "RUNNER_TARBALL_URL=https://github.com/actions/runner/releases/download/v${var.runner_version}/actions-runner-linux-x64-${var.runner_version}.tar.gz"
+    ]
+    inline = [
+      "sudo chmod +x /tmp/install-runner.sh",
+      "echo ubuntu | tee -a /tmp/install-user.txt",
+      "sudo RUNNER_ARCHITECTURE=x64 RUNNER_TARBALL_URL=$RUNNER_TARBALL_URL /tmp/install-runner.sh",
+      "echo ImageOS=ubuntu20 | tee -a /opt/actions-runner/.env"
+    ]
+  }
+
+  provisioner "file" {
+    content = templatefile("../start-runner.sh", {
+      start_runner = templatefile("../../modules/runners/templates/start-runner.sh", {})
+    })
+    destination = "/tmp/start-runner.sh"
+  }
+
+  provisioner "shell" {
+    inline = [
+      "sudo mv /tmp/start-runner.sh /var/lib/cloud/scripts/per-boot/start-runner.sh",
+      "sudo chmod +x /var/lib/cloud/scripts/per-boot/start-runner.sh",
+    ]
+  }
+
+}

Някои файлове не бяха показани, защото твърде много файлове са промени