diff --git a/README.md b/README.md
index 8cde215df0..3eec26ec7e 100644
--- a/README.md
+++ b/README.md
@@ -86,10 +86,12 @@ Join our discord community via [this invite link](https://discord.gg/bxgXW8jJGh)
|------|--------|---------|
| [ami\_housekeeper](#module\_ami\_housekeeper) | ./modules/ami-housekeeper | n/a |
| [instance\_termination\_watcher](#module\_instance\_termination\_watcher) | ./modules/termination-watcher | n/a |
+| [rotating\_random](#module\_rotating\_random) | ./modules/rotating-random | n/a |
| [runner\_binaries](#module\_runner\_binaries) | ./modules/runner-binaries-syncer | n/a |
| [runners](#module\_runners) | ./modules/runners | n/a |
| [ssm](#module\_ssm) | ./modules/ssm | n/a |
| [webhook](#module\_webhook) | ./modules/webhook | n/a |
+| [webhook\_github\_app](#module\_webhook\_github\_app) | ./modules/webhook-github-app | n/a |
## Resources
@@ -140,8 +142,8 @@ Join our discord community via [this invite link](https://discord.gg/bxgXW8jJGh)
| [enable\_userdata](#input\_enable\_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 |
| [eventbridge](#input\_eventbridge) | Enable the use of EventBridge by the module. By enabling this feature events will be put on the EventBridge by the webhook instead of directly dispatching to queues for scaling.
`enable`: Enable the EventBridge feature.
`accept_events`: List can be used to only allow specific events to be putted on the EventBridge. By default all events, empty list will be be interpreted as all events. |
object({
enable = optional(bool, true)
accept_events = optional(list(string), null)
}) | `{}` | no |
| [ghes\_ssl\_verify](#input\_ghes\_ssl\_verify) | GitHub Enterprise SSL verification. Set to 'false' when custom certificate (chains) is used for GitHub Enterprise Server (insecure). | `bool` | `true` | no |
-| [ghes\_url](#input\_ghes\_url) | GitHub Enterprise Server URL. Example: https://github.internal.co - DO NOT SET IF USING PUBLIC GITHUB - github.com. However if you are using Github Enterprise Cloud with data-residency (ghe.com), set the endpoint here. Example - https://companyname.ghe.com | `string` | `null` | no |
-| [github\_app](#input\_github\_app) | GitHub app parameters, see your github app. Ensure the key is the base64-encoded `.pem` file (the output of `base64 app.private-key.pem`, not the content of `private-key.pem`). | object({
key_base64 = string
id = string
webhook_secret = string
}) | n/a | yes |
+| [ghes\_url](#input\_ghes\_url) | GitHub Enterprise Server URL. Example: https://github.internal.co - DO NOT SET IF USING PUBLIC GITHUB. However if you are using Github Enterprise Cloud with data-residency (ghe.com), set the endpoint here. Example - https://companyname.ghe.com | `string` | `null` | no |
+| [github\_app](#input\_github\_app) | GitHub app parameters, see your github app. Ensure the key is the base64-encoded `.pem` file (the output of `base64 app.private-key.pem`, not the content of `private-key.pem`)."object({
key_base64 = string
id = string
webhook_secret = optional(string)
webhook_secret_rotation_days = optional(number, 30)
}) | n/a | yes |
| [idle\_config](#input\_idle\_config) | List of time periods, defined as a cron expression, to keep a minimum amount of runners active instead of scaling down to 0. By defining this list you can ensure that in time periods that match the cron expression within 5 seconds a runner is kept idle. | list(object({
cron = string
timeZone = string
idleCount = number
evictionStrategy = optional(string, "oldest_first")
})) | `[]` | no |
| [instance\_allocation\_strategy](#input\_instance\_allocation\_strategy) | The allocation strategy for spot instances. AWS recommends using `price-capacity-optimized` however the AWS default is `lowest-price`. | `string` | `"lowest-price"` | no |
| [instance\_max\_spot\_price](#input\_instance\_max\_spot\_price) | Max price price for spot instances per hour. This variable will be passed to the create fleet as max spot price for the fleet. | `string` | `null` | no |
diff --git a/docs/configuration.md b/docs/configuration.md
index c7f53121ed..2c66340003 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -14,6 +14,7 @@ To be able to support a number of use-cases, the module has quite a lot of confi
- 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.
- Disable default labels for the runners (os, architecture and `self-hosted`) can achieve by setting `runner_disable_default_labels` = true. If enabled, the runner will only have the extra labels provided in `runner_extra_labels`. In case you on own start script is used, this configuration parameter needs to be parsed via SSM.
+- Managed vs self-managed webhook secret. The module can manage the webhook secret for you. In that case simply do not provide a value for `github_app.webhook_secret`. If you want to manage the secret yourself, provide a value for `github_app.webhook_secret`. The secret will be managed and a rotation is triggered once running terraform apply again after `github_app.webhook_secret_rotation_days` days. **Important note**: THe managed webhook secret depends on a local-exec (bash) to update the secret in GitNub. It will also update the webhook url.
## AWS SSM Parameters
diff --git a/docs/getting-started.md b/docs/getting-started.md
index cfd8f7b88b..37872d7eb7 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -85,7 +85,7 @@ module "github-runner" {
github_app = {
key_base64 = "base64string"
id = "1"
- webhook_secret = "webhook_secret"
+ webhook_secret = "webhook_secret" # optional, if not set the module will manage the secret.
}
webhook_lambda_zip = "lambdas-download/webhook.zip"
@@ -109,7 +109,7 @@ The lambda for syncing the GitHub distribution to S3 is triggered via CloudWatch
### Setup the webhook / GitHub App (part 2)
At this point you have two options. Either create a separate webhook (enterprise,
-org, or repo), or create a webhook in the App.
+org, or repo), or create a webhook in the App. In case you have not provided a Webhook secret the module will create one and update the GitHub app with both the secret and the webhook url.
#### Option 1: Webhook
diff --git a/examples/default/.terraform.lock.hcl b/examples/default/.terraform.lock.hcl
index 045fb7350a..c236658c15 100644
--- a/examples/default/.terraform.lock.hcl
+++ b/examples/default/.terraform.lock.hcl
@@ -83,3 +83,23 @@ provider "registry.terraform.io/hashicorp/random" {
"zh:eff58323099f1bd9a0bec7cb04f717e7f1b2774c7d612bf7581797e1622613a0",
]
}
+
+provider "registry.terraform.io/hashicorp/time" {
+ version = "0.12.1"
+ constraints = "~> 0.7"
+ hashes = [
+ "h1:JzYsPugN8Fb7C4NlfLoFu7BBPuRVT2/fCOdCaxshveI=",
+ "zh:090023137df8effe8804e81c65f636dadf8f9d35b79c3afff282d39367ba44b2",
+ "zh:26f1e458358ba55f6558613f1427dcfa6ae2be5119b722d0b3adb27cd001efea",
+ "zh:272ccc73a03384b72b964918c7afeb22c2e6be22460d92b150aaf28f29a7d511",
+ "zh:438b8c74f5ed62fe921bd1078abe628a6675e44912933100ea4fa26863e340e9",
+ "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+ "zh:85c8bd8eefc4afc33445de2ee7fbf33a7807bc34eb3734b8eefa4e98e4cddf38",
+ "zh:98bbe309c9ff5b2352de6a047e0ec6c7e3764b4ed3dfd370839c4be2fbfff869",
+ "zh:9c7bf8c56da1b124e0e2f3210a1915e778bab2be924481af684695b52672891e",
+ "zh:d2200f7f6ab8ecb8373cda796b864ad4867f5c255cff9d3b032f666e4c78f625",
+ "zh:d8c7926feaddfdc08d5ebb41b03445166df8c125417b28d64712dccd9feef136",
+ "zh:e2412a192fc340c61b373d6c20c9d805d7d3dee6c720c34db23c2a8ff0abd71b",
+ "zh:e6ac6bba391afe728a099df344dbd6481425b06d61697522017b8f7a59957d44",
+ ]
+}
diff --git a/examples/default/README.md b/examples/default/README.md
index 771b2c7bab..463d54482a 100644
--- a/examples/default/README.md
+++ b/examples/default/README.md
@@ -40,9 +40,7 @@ terraform output -raw webhook_secret
## Providers
-| Name | Version |
-|------|---------|
-| [random](#provider\_random) | 3.6.3 |
+No providers.
## Modules
@@ -50,13 +48,10 @@ terraform output -raw webhook_secret
|------|--------|---------|
| [base](#module\_base) | ../base | n/a |
| [runners](#module\_runners) | ../../ | n/a |
-| [webhook\_github\_app](#module\_webhook\_github\_app) | ../../modules/webhook-github-app | n/a |
## Resources
-| Name | Type |
-|------|------|
-| [random_id.random](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource |
+No resources.
## Inputs
@@ -72,5 +67,4 @@ terraform output -raw webhook_secret
|------|-------------|
| [runners](#output\_runners) | n/a |
| [webhook\_endpoint](#output\_webhook\_endpoint) | n/a |
-| [webhook\_secret](#output\_webhook\_secret) | n/a |
diff --git a/examples/default/main.tf b/examples/default/main.tf
index 42608fae40..7ff2a97ac9 100644
--- a/examples/default/main.tf
+++ b/examples/default/main.tf
@@ -3,10 +3,6 @@ locals {
aws_region = var.aws_region
}
-resource "random_id" "random" {
- byte_length = 20
-}
-
module "base" {
source = "../base"
@@ -27,9 +23,9 @@ module "runners" {
}
github_app = {
- key_base64 = var.github_app.key_base64
- id = var.github_app.id
- webhook_secret = random_id.random.hex
+ 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
@@ -143,18 +139,6 @@ module "runners" {
# kms_key_arn = aws_kms_key.github.arn
}
-module "webhook_github_app" {
- source = "../../modules/webhook-github-app"
- depends_on = [module.runners]
-
- github_app = {
- key_base64 = var.github_app.key_base64
- id = var.github_app.id
- webhook_secret = random_id.random.hex
- }
- webhook_endpoint = module.runners.webhook.endpoint
-}
-
# enable CMK instead of aws managed key for encryptions
# resource "aws_kms_key" "github" {
# is_enabled = true
diff --git a/examples/default/outputs.tf b/examples/default/outputs.tf
index c50214f566..2709fc69b3 100644
--- a/examples/default/outputs.tf
+++ b/examples/default/outputs.tf
@@ -7,9 +7,3 @@ output "runners" {
output "webhook_endpoint" {
value = module.runners.webhook.endpoint
}
-
-output "webhook_secret" {
- sensitive = true
- value = random_id.random.hex
-}
-
diff --git a/main.tf b/main.tf
index 3f3c9808b4..19e5c61036 100644
--- a/main.tf
+++ b/main.tf
@@ -12,6 +12,17 @@ locals {
runner_labels = (var.runner_disable_default_labels == false) ? sort(concat(local.default_runner_labels, var.runner_extra_labels)) : var.runner_extra_labels
ssm_root_path = var.ssm_paths.use_prefix ? "/${var.ssm_paths.root}/${var.prefix}" : "/${var.ssm_paths.root}"
+
+ github_app = merge(var.github_app, {
+ webhook_secret = var.github_app.webhook_secret != null ? var.github_app.webhook_secret : module.rotating_random[0].random.hex
+ })
+}
+
+module "rotating_random" {
+ count = var.github_app.webhook_secret == null ? 1 : 0
+ source = "./modules/rotating-random"
+
+ rotation_days = var.github_app.webhook_secret_rotation_days
}
resource "random_string" "random" {
@@ -91,10 +102,18 @@ module "ssm" {
kms_key_arn = var.kms_key_arn
path_prefix = "${local.ssm_root_path}/${var.ssm_paths.app}"
- github_app = var.github_app
+ github_app = local.github_app
tags = local.tags
}
+module "webhook_github_app" {
+ count = var.github_app.webhook_secret == null ? 1 : 0
+ source = "./modules/webhook-github-app"
+
+ github_app = local.github_app
+ webhook_endpoint = "${module.webhook.gateway.api_endpoint}/${module.webhook.endpoint_relative_path}"
+}
+
module "webhook" {
source = "./modules/webhook"
diff --git a/modules/multi-runner/README.md b/modules/multi-runner/README.md
index de8811bc49..88cd5de7f4 100644
--- a/modules/multi-runner/README.md
+++ b/modules/multi-runner/README.md
@@ -95,10 +95,12 @@ module "multi-runner" {
|------|--------|---------|
| [ami\_housekeeper](#module\_ami\_housekeeper) | ../ami-housekeeper | n/a |
| [instance\_termination\_watcher](#module\_instance\_termination\_watcher) | ../termination-watcher | n/a |
+| [rotating\_random](#module\_rotating\_random) | ./../rotating-random | n/a |
| [runner\_binaries](#module\_runner\_binaries) | ../runner-binaries-syncer | n/a |
| [runners](#module\_runners) | ../runners | n/a |
| [ssm](#module\_ssm) | ../ssm | n/a |
| [webhook](#module\_webhook) | ../webhook | n/a |
+| [webhook\_github\_app](#module\_webhook\_github\_app) | ./../webhook-github-app | n/a |
## Resources
@@ -130,8 +132,8 @@ module "multi-runner" {
| [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 |
| [eventbridge](#input\_eventbridge) | Enable the use of EventBridge by the module. By enabling this feature events will be put on the EventBridge by the webhook instead of directly dispatching to queues for scaling. | object({
enable = optional(bool, true)
accept_events = optional(list(string), [])
}) | `{}` | no |
| [ghes\_ssl\_verify](#input\_ghes\_ssl\_verify) | GitHub Enterprise SSL verification. Set to 'false' when custom certificate (chains) is used for GitHub Enterprise Server (insecure). | `bool` | `true` | no |
-| [ghes\_url](#input\_ghes\_url) | GitHub Enterprise Server URL. Example: https://github.internal.co - DO NOT SET IF USING PUBLIC GITHUB.However if you are using Github Enterprise Cloud with data-residency (ghe.com), set the endpoint here. Example - https://companyname.ghe.com| `string` | `null` | no |
-| [github\_app](#input\_github\_app) | GitHub app parameters, see your github app. Ensure the key is the base64-encoded `.pem` file (the output of `base64 app.private-key.pem`, not the content of `private-key.pem`). | object({
key_base64 = string
id = string
webhook_secret = string
}) | n/a | yes |
+| [ghes\_url](#input\_ghes\_url) | GitHub Enterprise Server URL. Example: https://github.internal.co - DO NOT SET IF USING PUBLIC GITHUB. .However if you are using Github Enterprise Cloud with data-residency (ghe.com), set the endpoint here. Example - https://companyname.ghe.com\| | `string` | `null` | no |
+| [github\_app](#input\_github\_app) | GitHub app parameters, see your github app. Ensure the key is the base64-encoded `.pem` file (the output of `base64 app.private-key.pem`, not the content of `private-key.pem`)."object({
key_base64 = string
id = string
webhook_secret = optional(string)
webhook_secret_rotation_days = optional(number, 30)
}) | n/a | yes |
| [instance\_profile\_path](#input\_instance\_profile\_path) | The path that will be added to the instance\_profile, if not set the environment name will be used. | `string` | `null` | no |
| [instance\_termination\_watcher](#input\_instance\_termination\_watcher) | Configuration for the spot termination watcher lambda function. This feature is Beta, changes will not trigger a major release as long in beta.object({
enable = optional(bool, false)
features = optional(object({
enable_spot_termination_handler = optional(bool, true)
enable_spot_termination_notification_watcher = optional(bool, true)
}), {})
memory_size = optional(number, null)
s3_key = optional(string, null)
s3_object_version = optional(string, null)
timeout = optional(number, null)
zip = optional(string, null)
}) | `{}` | no |
| [key\_name](#input\_key\_name) | Key pair name | `string` | `null` | no |
diff --git a/modules/multi-runner/main.tf b/modules/multi-runner/main.tf
index 22ec0df3ba..ecdf79eb9a 100644
--- a/modules/multi-runner/main.tf
+++ b/modules/multi-runner/main.tf
@@ -16,6 +16,17 @@ locals {
unique_os_and_arch = { for i, v in local.tmp_distinct_list_unique_os_and_arch : "${v.os_type}_${v.architecture}" => v }
ssm_root_path = "/${var.ssm_paths.root}/${var.prefix}"
+
+ github_app = merge(var.github_app, {
+ webhook_secret = var.github_app.webhook_secret != null ? var.github_app.webhook_secret : module.rotating_random[0].random.hex
+ })
+}
+
+module "rotating_random" {
+ count = var.github_app.webhook_secret == null ? 1 : 0
+ source = "./../rotating-random"
+
+ rotation_days = var.github_app.webhook_secret_rotation_days
}
resource "random_string" "random" {
diff --git a/modules/multi-runner/ssm.tf b/modules/multi-runner/ssm.tf
index 6b2591f465..ae914e7471 100644
--- a/modules/multi-runner/ssm.tf
+++ b/modules/multi-runner/ssm.tf
@@ -3,6 +3,6 @@ module "ssm" {
kms_key_arn = var.kms_key_arn
path_prefix = "${local.ssm_root_path}/${var.ssm_paths.app}"
- github_app = var.github_app
+ github_app = local.github_app
tags = local.tags
}
diff --git a/modules/multi-runner/variables.tf b/modules/multi-runner/variables.tf
index 8e4897985b..5b636b5b72 100644
--- a/modules/multi-runner/variables.tf
+++ b/modules/multi-runner/variables.tf
@@ -1,9 +1,15 @@
variable "github_app" {
- description = "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`)."
+ description = <object({
key_base64 = map(string)
id = map(string)
}) | n/a | yes |
| [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. | list(object({
cron = string
timeZone = string
idleCount = number
evictionStrategy = optional(string, "oldest_first")
})) | `[]` | no |
| [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 |
diff --git a/outputs.tf b/outputs.tf
index 699867ec2e..403402e495 100644
--- a/outputs.tf
+++ b/outputs.tf
@@ -47,7 +47,6 @@ output "ssm_parameters" {
value = module.ssm.parameters
}
-
output "queues" {
description = "SQS queues."
value = {
diff --git a/variables.tf b/variables.tf
index 85c675d58a..68dff756f9 100644
--- a/variables.tf
+++ b/variables.tf
@@ -32,11 +32,17 @@ variable "enable_organization_runners" {
}
variable "github_app" {
- description = "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`)."
+ description = <