Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions modules/meshstack/noop/backplane/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,38 @@
# No-Op Backplane
# NoOp Backplane — Self-Hosted Cloud Run Runner

This building block requires no backplane infrastructure. All inputs are supplied directly to the building block at run time — there is no cloud-side setup for platform teams to deploy.
This backplane provisions a self-hosted meshStack building block runner on Google Cloud Run.

## What it provisions

| Resource | Purpose |
|------------------------------------|-----------------------------------------------------------------------------------------------------|
| `tls_private_key` (RSA 4096) | Runner identity key pair — public key registered in meshStack, private key stored in Secret Manager |
| `meshstack_api_key` | meshStack credentials the runner uses to poll and update building block runs |
| `google_secret_manager_secret` × 3 | Stores the RSA private key, runner config YAML, and meshStack client secret |
| `google_cloud_run_v2_service` | Runs the meshStack runner container |
| `meshstack_building_block_runner` | Registers the runner in meshStack with `TERRAFORM` implementation type |

## Runner container mounts

The Cloud Run service mounts the following secrets into the container:

| Mount path | Content |
|------------------------------------|--------------------------------------------------------------------------------------------------------------------|
| `/app/runner-config.yml` | Rendered from `runner-config.yml` with `RUNNER_UUID`, `RUNNER_API_URL`, and `RUNNER_API_KEY_CLIENT_ID` substituted |
| `/app/runner-private.pem` | RSA 4096 private key (PEM) |
| `$MESHSTACK_CLIENT_SECRET` env var | meshStack API client secret |
Comment on lines +19 to +23

Adjust the mount paths in `main.tf` if your runner image expects a different layout.

## Prerequisites

- The `cloudrun.googleapis.com` and `secretmanager.googleapis.com` APIs must be enabled in `gcp_project_id`.
- The service account identified by `gcp_cloud_run_service_account_email` must exist before applying. The backplane grants it `roles/secretmanager.secretAccessor` on the created secrets.
- The meshStack provider is configured via the `meshstack_endpoint` variable. Supply admin credentials via `MESHSTACK_CLIENT_ID` and `MESHSTACK_CLIENT_SECRET` environment variables (or `TF_VAR_*` equivalents).

## Outputs

| Output | Description |
|-------------------------|-------------------------------------------------------------------------------------------------------|
| `runner_ref` | Wire into `meshstack_building_block_definition.version_spec.runner_ref` in `meshstack_integration.tf` |
| `cloud_run_service_url` | URL of the deployed Cloud Run service |
232 changes: 232 additions & 0 deletions modules/meshstack/noop/backplane/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
data "google_project" "this" {
project_id = var.gcp_project_id
}

locals {
resource_prefix = var.gcp_resource_name_prefix
cloud_run_service_account = "${data.google_project.this.number}-compute@developer.gserviceaccount.com"
}

resource "time_static" "runner_key_expiry" {}

resource "tls_private_key" "runner" {
algorithm = "RSA"
rsa_bits = 4096
}

resource "meshstack_api_key" "runner" {
metadata = {
owned_by_workspace = var.meshstack_workspace_identifier
}
spec = {
display_name = var.runner_display_name
permissions = [
"MANAGED_BUILDINGBLOCKRUNSOURCE_SAVE",
"MANAGED_BUILDINGBLOCKRUN_LIST",
"MANAGED_BUILDINGBLOCKRUN_SAVE"
]
expires_at = formatdate("YYYY-MM-DD", timeadd(time_static.runner_key_expiry.rfc3339, "168h"))
}
}

resource "google_secret_manager_secret" "runner_private_key" {
project = var.gcp_project_id
secret_id = "${local.resource_prefix}-private-key"

replication {
user_managed {
replicas {
location = var.gcp_region
}
}
}
}

resource "google_secret_manager_secret_version" "runner_private_key" {
secret = google_secret_manager_secret.runner_private_key.id
secret_data = tls_private_key.runner.private_key_pem_pkcs8
}

resource "google_secret_manager_secret" "runner_config" {
project = var.gcp_project_id
secret_id = "${local.resource_prefix}-config"
replication {
user_managed {
replicas {
location = var.gcp_region
}
}
}
}

resource "google_secret_manager_secret_version" "runner_config" {
secret = google_secret_manager_secret.runner_config.id
secret_data = templatefile("${path.module}/runner-config.yml", {
RUNNER_UUID = meshstack_building_block_runner.this.metadata.uuid
RUNNER_API_URL = var.meshstack_endpoint
RUNNER_API_KEY_CLIENT_ID = meshstack_api_key.runner.status.client_id
})
}

resource "google_secret_manager_secret" "client_secret" {
project = var.gcp_project_id
secret_id = "${local.resource_prefix}-client-secret"
replication {
user_managed {
replicas {
location = var.gcp_region
}
}
}
}

resource "google_secret_manager_secret_version" "client_secret" {
secret = google_secret_manager_secret.client_secret.id
secret_data = meshstack_api_key.runner.status.client_secret
}

resource "google_secret_manager_secret_iam_member" "runner_private_key_accessor" {
project = var.gcp_project_id
secret_id = google_secret_manager_secret.runner_private_key.secret_id
role = "roles/secretmanager.secretAccessor"
member = "serviceAccount:${local.cloud_run_service_account}"
}

resource "google_secret_manager_secret_iam_member" "runner_config_accessor" {
project = var.gcp_project_id
secret_id = google_secret_manager_secret.runner_config.secret_id
role = "roles/secretmanager.secretAccessor"
member = "serviceAccount:${local.cloud_run_service_account}"
}

resource "google_secret_manager_secret_iam_member" "client_secret_accessor" {
project = var.gcp_project_id
secret_id = google_secret_manager_secret.client_secret.secret_id
role = "roles/secretmanager.secretAccessor"
member = "serviceAccount:${local.cloud_run_service_account}"
}

resource "google_cloud_run_v2_service" "runner" {
project = var.gcp_project_id
name = local.resource_prefix
location = var.gcp_region
deletion_protection = false

template {
service_account = local.cloud_run_service_account

containers {
image = var.gcp_runner_image

resources {
limits = {
cpu = "2"
# 512MiB did crash for the noop BB at pre-run script level, so did 1024:
# GCP Error message: Memory limit of 1024 MiB exceeded with 1074 MiB used. Consider increasing the memory limit,
# 2048 seems to work fine so far.
memory = "2048Mi"
}
}

env {
name = "RUNNER_CONFIG_FILE"
value = "/config/runner-config.yml"
}

env {
name = "RUNNER_PRIVATE_KEY_FILE"
value = "/keys/runner-private.pem"
}

env {
name = "RUNNER_API_CLIENT_SECRET"
value_source {
secret_key_ref {
secret = google_secret_manager_secret.client_secret.secret_id
version = "latest"
}
}
}

volume_mounts {
name = "runner-config"
mount_path = "/config"
}

volume_mounts {
name = "runner-private-key"
mount_path = "/keys"
}

startup_probe {
http_get {
path = "/healthz"
port = 8080
}
initial_delay_seconds = 5
period_seconds = 5
failure_threshold = 3
}

liveness_probe {
http_get {
path = "/healthz"
port = 8080
}
period_seconds = 30
failure_threshold = 3
}
}

volumes {
name = "runner-config"
secret {
secret = google_secret_manager_secret.runner_config.secret_id
items {
version = "latest"
path = "runner-config.yml"
}
}
}

volumes {
name = "runner-private-key"
secret {
secret = google_secret_manager_secret.runner_private_key.secret_id
items {
version = "latest"
path = "runner-private.pem"
}
}
}

}

depends_on = [
google_secret_manager_secret_iam_member.runner_private_key_accessor,
google_secret_manager_secret_iam_member.runner_config_accessor,
google_secret_manager_secret_iam_member.client_secret_accessor,
google_secret_manager_secret_version.runner_private_key,
google_secret_manager_secret_version.runner_config,
google_secret_manager_secret_version.client_secret,
]
}

resource "meshstack_building_block_runner" "this" {
metadata = {
owned_by_workspace = var.meshstack_workspace_identifier
}
spec = {
display_name = var.runner_display_name
implementation_type = "TERRAFORM"
public_key = tls_private_key.runner.public_key_pem
restriction = "PRIVATE"
}
}

/**
provider "meshstack" {
endpoint = "https://federation.dev.meshcloud.io"
apikey = "761ca118-5801-424b-b839-1ea3b8866f57"
apisecret = "nyZG2oduo58aUWzvFtDYksuVGrZV25xK"
**/
Comment on lines +227 to +232
9 changes: 9 additions & 0 deletions modules/meshstack/noop/backplane/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
output "runner_ref" {
description = "meshStack building block runner reference. Wire into meshstack_building_block_definition.version_spec.runner_ref."
value = meshstack_building_block_runner.this.ref
}

output "cloud_run_service_url" {
description = "URL of the deployed Cloud Run runner service."
value = google_cloud_run_v2_service.runner.uri
}
8 changes: 8 additions & 0 deletions modules/meshstack/noop/backplane/provider.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
provider "google" {
project = var.gcp_project_id
region = var.gcp_region
}

provider "meshstack" {
endpoint = var.meshstack_endpoint
}
28 changes: 28 additions & 0 deletions modules/meshstack/noop/backplane/runner-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Unique identifier of this runner, as registered in meshStack.
runnerUuid: ${RUNNER_UUID}

# Maximum total runtime (in minutes) for a single Building Block run before it is aborted.
timeoutMins: 60

# Maximum time (in minutes) to wait for a workspace operation (e.g. checkout, sync) to complete.
wsTimeoutMins: 5

# Maximum time (in minutes) allowed for the runner to initialize before a run starts.
initTimeoutMins: 3

# Directory inside the container where Terraform working directories are created.
workingDir: /tmp/runner/wd

# Directory inside the container where Terraform binaries are downloaded and cached.
tfInstallDir: /tmp/runner/tfbin

# Connection settings for the meshStack API this runner polls for work.
api:
# Base URL of the meshStack federation API.
url: ${RUNNER_API_URL}
# OAuth2 client ID used by the runner to authenticate against meshStack.
clientId: ${RUNNER_API_KEY_CLIENT_ID}
# OAuth2 client secret is injected via the RUNNER_API_CLIENT_SECRET environment variable (see docker run command).

# When true, SSH host key verification is skipped for Git operations. Keep false in production.
insecureHostKeys: false
38 changes: 38 additions & 0 deletions modules/meshstack/noop/backplane/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
variable "meshstack_workspace_identifier" {
type = string
description = "Identifier of the meshStack workspace that will own the runner and API key."
}

variable "meshstack_endpoint" {
type = string
description = "Base URL of the meshStack API (e.g. https://federation.example.meshcloud.io). Used by both the Terraform provider and the runner config."
}

variable "runner_display_name" {
type = string
default = "meshstack-noop-tf-runner"
description = "Display name for the meshStack building block runner and API key."
}

variable "gcp_project_id" {
type = string
description = "GCP project ID where Cloud Run and Secret Manager resources are deployed."
}

variable "gcp_region" {
type = string
default = "europe-west1"
description = "GCP region for the Cloud Run service."
}

variable "gcp_runner_image" {
type = string
description = "Container image URI for the meshStack runner."
default = "docker.io/meshcloud/tf-block-runner:main"
}

variable "gcp_resource_name_prefix" {
type = string
default = "meshstack-runner"
description = "Prefix for GCP resource names (Cloud Run service, Secret Manager secrets). Must be lowercase letters, numbers, and hyphens only."
}
22 changes: 22 additions & 0 deletions modules/meshstack/noop/backplane/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
terraform {
required_version = ">= 1.12.0"

required_providers {
tls = {
source = "hashicorp/tls"
version = "~> 4.0"
}
google = {
source = "hashicorp/google"
version = "~> 7.0"
}
meshstack = {
source = "meshcloud/meshstack"
version = "~> 0.21.0"
}
time = {
source = "hashicorp/time"
version = "~> 0.12"
}
}
}
Loading
Loading