Skip to content

Commit

Permalink
feat: Add option to let the module manage the webhook secret
Browse files Browse the repository at this point in the history
  • Loading branch information
npalm committed Jan 28, 2025
1 parent a71f1d8 commit ad304f8
Show file tree
Hide file tree
Showing 17 changed files with 124 additions and 38 deletions.
1 change: 1 addition & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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

Expand Down
20 changes: 20 additions & 0 deletions examples/default/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 3 additions & 19 deletions examples/default/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@ locals {
aws_region = var.aws_region
}

resource "random_id" "random" {
byte_length = 20
}

module "base" {
source = "../base"

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
6 changes: 0 additions & 6 deletions examples/default/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,3 @@ output "runners" {
output "webhook_endpoint" {
value = module.runners.webhook.endpoint
}

output "webhook_secret" {
sensitive = true
value = random_id.random.hex
}

21 changes: 20 additions & 1 deletion main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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" {
Expand Down Expand Up @@ -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"

Expand Down
11 changes: 11 additions & 0 deletions modules/multi-runner/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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" {
Expand Down
2 changes: 1 addition & 1 deletion modules/multi-runner/ssm.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
14 changes: 10 additions & 4 deletions modules/multi-runner/variables.tf
Original file line number Diff line number Diff line change
@@ -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 = <<EOF
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`)."
If `webhook_secret` is not set, a random secret will be generated and stored in SSM. The secret is used to validate the webhook events. If you want to use your own secret, set the `webhook_secret` parameter.
When the secret is managed by the module, it will be rotated every `webhook_secret_rotation_days` days.
EOF
type = object({
key_base64 = string
id = string
webhook_secret = string
key_base64 = string
id = string
webhook_secret = optional(string)
webhook_secret_rotation_days = optional(number, 30)
})
}

Expand Down
8 changes: 8 additions & 0 deletions modules/multi-runner/webhook.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
module "webhook_github_app" {
count = var.github_app.webhook_secret == null ? 1 : 0
source = "./../webhook-github-app"

github_app = local.github_app
webhook_endpoint = "${module.webhook.gateway.api_endpoint}/${module.webhook.endpoint_relative_path}"
}

module "webhook" {
source = "../webhook"
prefix = var.prefix
Expand Down
6 changes: 6 additions & 0 deletions modules/rotating-random/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Module - Rotating Random

> This module is treated as internal module, breaking changes will not trigger a major release bump.

<!-- BEGIN_TF_DOCS -->
<!-- END_TF_DOCS -->
10 changes: 10 additions & 0 deletions modules/rotating-random/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
resource "time_rotating" "rotation_days" {
rotation_days = var.rotation_days
}

resource "random_id" "random" {
byte_length = 20
keepers = {
rotation = time_rotating.rotation_days.id
}
}
3 changes: 3 additions & 0 deletions modules/rotating-random/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
output "random" {
value = random_id.random
}
5 changes: 5 additions & 0 deletions modules/rotating-random/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
variable "rotation_days" {
description = "Number of days before rotating the random."
type = number
default = 30
}
14 changes: 14 additions & 0 deletions modules/rotating-random/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
terraform {
required_version = ">= 1.3.0"

required_providers {
random = {
source = "hashicorp/random"
version = "~> 3"
}
time = {
source = "hashicorp/time"
version = "~> 0.12"
}
}
}
1 change: 0 additions & 1 deletion outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ output "ssm_parameters" {
value = module.ssm.parameters
}


output "queues" {
description = "SQS queues."
value = {
Expand Down
14 changes: 10 additions & 4 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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 = <<EOF
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`)."

If `webhook_secret` is not set, a random secret will be generated and stored in SSM. The secret is used to validate the webhook events. If you want to use your own secret, set the `webhook_secret` parameter.
When the secret is managed by the module, it will be rotated every `webhook_secret_rotation_days` days.
EOF
type = object({
key_base64 = string
id = string
webhook_secret = string
key_base64 = string
id = string
webhook_secret = optional(string)
webhook_secret_rotation_days = optional(number, 30)
})
}

Expand Down

0 comments on commit ad304f8

Please sign in to comment.