From 6d7a4803dda4083743c7cbc1bd21b3e6a6760383 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Sat, 13 Jul 2024 17:11:08 +0200 Subject: [PATCH] create the start-release lambda --- terraform/releases/.terraform.lock.hcl | 60 ++++++------- terraform/releases/_terraform.tf | 2 +- terraform/releases/impl/main.tf | 2 +- terraform/releases/impl/outputs.tf | 4 + .../releases/lambdas/start-release/index.py | 86 +++++++++++++++++++ terraform/releases/start-release.tf | 47 ++++++++++ terraform/shared/modules/lambda/main.tf | 5 +- 7 files changed, 172 insertions(+), 34 deletions(-) create mode 100644 terraform/releases/lambdas/start-release/index.py create mode 100644 terraform/releases/start-release.tf diff --git a/terraform/releases/.terraform.lock.hcl b/terraform/releases/.terraform.lock.hcl index 6d0eebd20..db23c7a19 100644 --- a/terraform/releases/.terraform.lock.hcl +++ b/terraform/releases/.terraform.lock.hcl @@ -2,44 +2,44 @@ # Manual edits may be lost in future updates. provider "registry.terraform.io/hashicorp/aws" { - version = "4.61.0" - constraints = "~> 4.20" + version = "5.58.0" + constraints = ">= 4.20.0, ~> 5.58, < 6.0.0" hashes = [ - "h1:qyBawxoNN6EpiiX5h5ZG5P2dHsBeA5Z67xESl2c1HRk=", - "zh:051e2588410b7448a5c4c30d668948dd6fdfa8037700bfc00fb228986ccbf3a5", - "zh:082fbcf9706b48d0880ba552a11c29527e228dadd6d83668d0789abda24e5922", - "zh:0e0e72f214fb24f4f9c601cab088a2d8e00ec3327c451bc753911951d773214a", - "zh:3af6d38ca733ca66cce15c6a5735ded7c18348ad26040ebd9a59778b2cd9cf6c", - "zh:404898bc2258bbb9527fa06c72cb927ca011fd9bc3f4b90931c0912652c3f9e9", - "zh:4f617653b0f17a7708bc896f029c4ab0b677a1a1c987bd77166acad1d82db469", - "zh:5dbe393355ac137aa3fd329e3d24871f27012d3ba93d714485b55820df240349", - "zh:6067c2127eb5c879227aca671f101de6dcba909d0d8d15d5711480351962a248", + "h1:6vsFc7SmmlElqg3k0X6azrO0yarM7UPCUF4XsAYryjA=", + "zh:15e9be54a8febe8e560362b10967cb60b680ca3f78fe207d7209b76e076f59d3", + "zh:240f6899a2cec259aa2729ce031f6af2b453f90a8b59118bb2571c54acc65db8", + "zh:2b6e8e2ab1a3dce1001503dba6086a128bb2a71652b0d0b3b107db665b7d6881", + "zh:579b0ed95247a0bd8bfb3fac7fb767547dde76026c578f4f184b5743af5e32cc", + "zh:6adcd10fd12be0be9eb78a89e745a5b77ae0d8b3522cd782456a71178aad8ccb", + "zh:7f829cef82f0a02faa97d0fbe1417a40b73fc5142e883b12eebc5b71015efac9", + "zh:81977f001998c9096f7b59710996e159774a9313c1bc03db3beb81c3e016ebef", "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", - "zh:a939f94461f91aa3b7ec7096271e2714309bd917fe9a03e02f68afb556d65e0f", - "zh:b21227b9082e5fafe8b7c415dc6a99c0d82da05492457377a5fe7d4acaed80e2", - "zh:b8d9f09ed5fc8c654b768b7bee1237eaf1e2287c898249e740695055fb0fe072", - "zh:d360e1e185b148ff6b1d0ed4f7d574e08f2391697ab43df62085b04a1a5b1284", - "zh:da962da17ddda744911cb1e92b983fa3874d73a28f3ee72faa9ddb6680a63774", - "zh:e2f1c4f5ebeb4fd7ef690178168a4c529025b54a91bb7a087dcea48e0b82737a", + "zh:a5d98ac6fab6e6c85164ca7dd38f94a1e44bd70c0e8354c61f7fbabf698957cd", + "zh:c27fa4fed50f6f83ca911bef04f05d635a7b7a01a89dc8fc5d66a277588f08df", + "zh:d4042bdf86ca6dc10e0cca91c4fcc592b12572d26185b3d37bbbb9e2026ac68b", + "zh:d536482cf4ace0d49a2a86c931150921649beae59337d0c02a785879fe943cf3", + "zh:e205f8243274a621fb9ef2b5e2c71e84c1670be1d23697739439f5a831fa620f", + "zh:eb76ce0c77fd76c47f57122c91c4fcf0f72c01423538ed7833eaa7eeaae2edf6", + "zh:ffe04e494af6cc7348ceb8d85f4c1d5a847a44510827b4496513c810a4d9196d", ] } provider "registry.terraform.io/hashicorp/external" { - version = "2.3.1" + version = "2.3.3" constraints = "~> 2.3.1" hashes = [ - "h1:gznGscVJ0USxy4CdihpjRKPsKvyGr/zqPvBoFLJTQDc=", - "zh:001e2886dc81fc98cf17cf34c0d53cb2dae1e869464792576e11b0f34ee92f54", - "zh:2eeac58dd75b1abdf91945ac4284c9ccb2bfb17fa9bdb5f5d408148ff553b3ee", - "zh:2fc39079ba61411a737df2908942e6970cb67ed2f4fb19090cd44ce2082903dd", - "zh:472a71c624952cff7aa98a7b967f6c7bb53153dbd2b8f356ceb286e6743bb4e2", - "zh:4cff06d31272aac8bc35e9b7faec42cf4554cbcbae1092eaab6ab7f643c215d9", + "h1:H+3QlVPs/7CDa3I4KU/a23wYeGeJxeBlgvR7bfK1t1w=", + "zh:03d81462f9578ec91ce8e26f887e34151eda0e100f57e9772dbea86363588239", + "zh:37ec2a20f6a3ec3a0fd95d3f3de26da6cb9534b30488bc45723e118a0911c0d8", + "zh:4eb5b119179539f2749ce9de0e1b9629d025990f062f4f4dddc161562bb89d37", + "zh:5a31bb58414f41bee5e09b939012df5b88654120b0238a89dfd6691ba197619a", + "zh:6221a05e52a6a2d4f520ffe7cbc741f4f6080e0855061b0ed54e8be4a84eb9b7", "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:7ed16ccd2049fa089616b98c0bd57219f407958f318f3c697843e2397ddf70df", - "zh:842696362c92bf2645eb85c739410fd51376be6c488733efae44f4ce688da50e", - "zh:8985129f2eccfd7f1841ce06f3bf2bbede6352ec9e9f926fbaa6b1a05313b326", - "zh:a5f0602d8ec991a5411ef42f872aa90f6347e93886ce67905c53cfea37278e05", - "zh:bf4ab82cbe5256dcef16949973bf6aa1a98c2c73a98d6a44ee7bc40809d002b8", - "zh:e70770be62aa70198fa899526d671643ff99eecf265bf1a50e798fc3480bd417", + "zh:8bb068496b4679bef625e4710d9f3432e301c3a56602271f04e60eadf7f8a94c", + "zh:94742aa5378bab626ce34f79bcef6a373e4f86ea7a8b762e9f71270a899e0d00", + "zh:a485831b5a525cd8f40e8982fa37da40ff70b1ae092c8b755fcde123f0b1238d", + "zh:a647ff16d071eabcabd87ea8183eb90a775a0294ddd735d742075d62fff09193", + "zh:b74710c5954aaa3faf262c18d36a8c2407862d9f842c63e7fa92fa4de3d29df6", + "zh:fa73d83edc92af2e551857594c2232ba6a9e3603ad34b0a5940865202c08d8d7", ] } diff --git a/terraform/releases/_terraform.tf b/terraform/releases/_terraform.tf index fe78c8a14..83256808e 100644 --- a/terraform/releases/_terraform.tf +++ b/terraform/releases/_terraform.tf @@ -6,7 +6,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = "~> 4.20" + version = "~> 5.58" } external = { source = "hashicorp/external" diff --git a/terraform/releases/impl/main.tf b/terraform/releases/impl/main.tf index d53c54d1d..3963a11e2 100644 --- a/terraform/releases/impl/main.tf +++ b/terraform/releases/impl/main.tf @@ -2,7 +2,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = "~> 4.20" + version = "~> 5.58" configuration_aliases = [aws.east1] } } diff --git a/terraform/releases/impl/outputs.tf b/terraform/releases/impl/outputs.tf index c5c36b342..7c5c4d730 100644 --- a/terraform/releases/impl/outputs.tf +++ b/terraform/releases/impl/outputs.tf @@ -1,3 +1,7 @@ output "promote_release_role_id" { value = aws_iam_role.promote_release.unique_id } + +output "codebuild_project_arn" { + value = aws_codebuild_project.promote_release.arn +} diff --git a/terraform/releases/lambdas/start-release/index.py b/terraform/releases/lambdas/start-release/index.py new file mode 100644 index 000000000..2f267935c --- /dev/null +++ b/terraform/releases/lambdas/start-release/index.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 + +# We want to grant folks on the release team the ability to start publishing +# releases, but simply granting them permission to start the CodeBuild job +# grants way too many privileges. For example, it would allow them to bypass +# startup checks, override the commit being released, or worse override the +# command being executed by CodeBuild to exfiltrate secrets. +# +# To solve the problem, this script accepts a limited set of actions allowed to +# be executed, and invokes CodeBuild with the right environment variables. This +# means we can safely grant the release team access to this function. + +import boto3 +import time + + +codebuild = boto3.client("codebuild") + + +def handler(event, context): + match event["action"]: + case "update-rust-branches": + # The channel for updating branches is not actually used by + # promote-release, but we have to pass it anyway. + return run_build("promote-branches", "prod", "nightly") + + case "publish-rust-dev-nightly": + return run_build("promote-release", "dev", "nightly") + + case "publish-rust-dev-beta": + return run_build("promote-release", "dev", "beta") + + case "publish-rust-dev-stable": + return run_build( + "promote-release", + "dev", + "stable", + { + "PROMOTE_RELEASE_BLOG_REPOSITORY": "rust-lang/blog.rust-lang.org", + "PROMOTE_RELEASE_BLOG_SCHEDULED_RELEASE_DATE": event["date"], + }, + ) + + case "publish-rust-dev-stable-rebuild": + return run_build( + "promote-release", + "dev", + "stable", + { + "PROMOTE_RELEASE_BYPASS_STARTUP_CHECKS": "1", + }, + ) + + case "publish-rust-prod-stable": + return run_build("promote-release", "prod", "stable") + + case action: + raise RuntimeError(f"unsupported action: {action}") + + +def run_build(action, env, channel, extra_vars=None): + vars = { + "PROMOTE_RELEASE_ACTION": action, + "PROMOTE_RELEASE_CHANNEL": channel, + } + if extra_vars is not None: + vars.update(extra_vars) + + build = codebuild.start_build( + projectName=f"promote-release--{env}", + environmentVariablesOverride=[ + {"name": name, "value": value, "type": "PLAINTEXT"} + for name, value in vars.items() + ], + )["build"] + + # Continue fetching information about the build + while "streamName" not in build["logs"]: + time.sleep(1) + build = codebuild.batch_get_builds(ids=[build["id"]])["builds"][0] + + return { + "build_id": build["id"], + "logs_group": build["logs"]["groupName"], + "logs_link": build["logs"]["deepLink"], + } diff --git a/terraform/releases/start-release.tf b/terraform/releases/start-release.tf new file mode 100644 index 000000000..607b6b7fc --- /dev/null +++ b/terraform/releases/start-release.tf @@ -0,0 +1,47 @@ +resource "aws_iam_role" "start_release" { + name = "start-release-lambda" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Action = "sts:AssumeRole" + Principal = { + Service = "lambda.amazonaws.com" + } + } + ] + }) + + inline_policy { + name = "permissions" + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Action = [ + "codebuild:StartBuild", + "codebuild:BatchGetBuilds", + ] + Resource = [ + module.dev.codebuild_project_arn, + module.prod.codebuild_project_arn, + ] + } + ] + }) + } +} + +module "lambda_start_release" { + source = "../shared/modules/lambda" + + name = "start-release" + source_dir = "lambdas/start-release" + handler = "index.handler" + runtime = "python3.12" + role_arn = aws_iam_role.start_release.arn + timeout_seconds = 900 # 15 minutes +} diff --git a/terraform/shared/modules/lambda/main.tf b/terraform/shared/modules/lambda/main.tf index ec598729f..ad3ecd6db 100644 --- a/terraform/shared/modules/lambda/main.tf +++ b/terraform/shared/modules/lambda/main.tf @@ -1,8 +1,9 @@ terraform { required_providers { aws = { - source = "hashicorp/aws" - version = "~> 4.20" + source = "hashicorp/aws" + // Allow both 4.x and 5.x while we upgrade everything to 5.x. + version = ">= 4.20, < 6" } } }