From ff5730041c9e120a0764fe784de1f473b25d3396 Mon Sep 17 00:00:00 2001 From: David Costa Date: Mon, 4 Dec 2023 12:14:21 +0000 Subject: [PATCH] docs: modify secure-env-vars example to use a custom entrypoint --- .../.github/workflows/docker-gcp-secrets.yaml | 53 ------------------- .../workflows/docker-github-secrets.yaml | 46 ---------------- examples/secure-env-vars/Dockerfile | 9 ---- examples/secure-env-vars/README.md | 19 ++++--- examples/secure-env-vars/cloudbuild.yaml | 23 -------- .../custom-entrypoint.sh.tftpl | 43 +++++++++++++++ examples/secure-env-vars/main.tf | 31 ++++++++--- examples/secure-env-vars/server-atlantis.yaml | 7 +++ 8 files changed, 86 insertions(+), 145 deletions(-) delete mode 100644 examples/secure-env-vars/.github/workflows/docker-gcp-secrets.yaml delete mode 100644 examples/secure-env-vars/.github/workflows/docker-github-secrets.yaml delete mode 100644 examples/secure-env-vars/Dockerfile delete mode 100644 examples/secure-env-vars/cloudbuild.yaml create mode 100644 examples/secure-env-vars/custom-entrypoint.sh.tftpl create mode 100644 examples/secure-env-vars/server-atlantis.yaml diff --git a/examples/secure-env-vars/.github/workflows/docker-gcp-secrets.yaml b/examples/secure-env-vars/.github/workflows/docker-gcp-secrets.yaml deleted file mode 100644 index 5576f2e..0000000 --- a/examples/secure-env-vars/.github/workflows/docker-gcp-secrets.yaml +++ /dev/null @@ -1,53 +0,0 @@ -name: Release -on: - push: - branches: - - main - -jobs: - docker-release: - name: Tagged Docker release to Google Artifact Registry - runs-on: ubuntu-latest - - permissions: - contents: 'read' - id-token: 'write' - - steps: - - uses: "actions/checkout@v3" - - - id: "auth" - name: "Authenticate to Google Cloud" - uses: "google-github-actions/auth@v0" - with: - token_format: access_token - workload_identity_provider: "projects//locations/global/workloadIdentityPools//providers/" - service_account: "@.iam.gserviceaccount.com" - access_token_lifetime: 300s - - - id: "secrets" - uses: "google-github-actions/get-secretmanager-secrets@v1" - with: - secrets: |- - atlantis_gh_user:/ - atlantis_gh_token:/ - atlantis_gh_webhook_secret:/ - - - name: Login to Artifact Registry - uses: docker/login-action@v1 - with: - registry: europe-docker.pkg.dev/ - username: oauth2accesstoken - password: ${{ steps.auth.outputs.access_token }} - - - id: docker-push-tagged - name: Tag Atlantis Docker image and push to Google Artifact Registry - uses: docker/build-push-action@v2 - with: - push: true - build-args: | - ATLANTIS_GH_USER=${{ steps.secrets.outputs.atlantis_gh_user }} - ATLANTIS_GH_TOKEN=${{ steps.secrets.outputs.atlantis_gh_token }} - ATLANTIS_GH_WEBHOOK_SECRET=${{ steps.secrets.outputs.atlantis_gh_webhook_secret }} - tags: | - -docker.pkg.dev///: diff --git a/examples/secure-env-vars/.github/workflows/docker-github-secrets.yaml b/examples/secure-env-vars/.github/workflows/docker-github-secrets.yaml deleted file mode 100644 index 55d2b33..0000000 --- a/examples/secure-env-vars/.github/workflows/docker-github-secrets.yaml +++ /dev/null @@ -1,46 +0,0 @@ -name: Release -on: - push: - branches: - - main - -jobs: - docker-release: - name: Tagged Docker release to Google Artifact Registry - runs-on: ubuntu-latest - - permissions: - contents: 'read' - id-token: 'write' - - steps: - - uses: "actions/checkout@v3" - - - id: "auth" - name: "Authenticate to Google Cloud" - uses: "google-github-actions/auth@v0" - with: - token_format: access_token - workload_identity_provider: "projects//locations/global/workloadIdentityPools//providers/" - service_account: "@.iam.gserviceaccount.com" - access_token_lifetime: 300s - - - name: Login to Artifact Registry - uses: docker/login-action@v1 - with: - registry: europe-docker.pkg.dev/ - username: oauth2accesstoken - password: ${{ steps.auth.outputs.access_token }} - - - id: docker-push-tagged - name: Tag Atlantis Docker image and push to Google Artifact Registry - uses: docker/build-push-action@v2 - with: - push: true - build-args: | - ATLANTIS_GH_USER=${{ secrets.ATLANTIS_GH_USER }} - ATLANTIS_GH_TOKEN=${{ secrets.ATLANTIS_GH_TOKEN }} - ATLANTIS_GH_WEBHOOK_SECRET=${{ secrets.ATLANTIS_GH_WEBHOOK_SECRET }} - tags: | - -docker.pkg.dev///: - diff --git a/examples/secure-env-vars/Dockerfile b/examples/secure-env-vars/Dockerfile deleted file mode 100644 index 5b3a00d..0000000 --- a/examples/secure-env-vars/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -FROM ghcr.io/runatlantis/atlantis:latest - -ARG ATLANTIS_GH_USER -ARG ATLANTIS_GH_TOKEN -ARG ATLANTIS_GH_WEBHOOK_SECRET - -ENV ATLANTIS_GH_USER $ATLANTIS_GH_USER -ENV ATLANTIS_GH_TOKEN $ATLANTIS_GH_TOKEN -ENV ATLANTIS_GH_WEBHOOK_SECRET $ATLANTIS_GH_WEBHOOK_SECRET diff --git a/examples/secure-env-vars/README.md b/examples/secure-env-vars/README.md index c688de9..94b8cd0 100644 --- a/examples/secure-env-vars/README.md +++ b/examples/secure-env-vars/README.md @@ -2,9 +2,11 @@ This guide explains how to secure environment variables when using the Atlantis module on Google Cloud Platform. For more information on using this module, see the [`basic example`](https://github.com/bschaatsbergen/atlantis-on-gcp-vm/tree/master/examples/basic). +Additionally, this example uses a GitHub App for authentication, and a custom image entrypoint to set environment variables at container startup time. + - [Prerequisites](#prerequisites) - [How to deploy](#how-to-deploy) - - [Important](#Important) + - [Important](#important) - [Setting sensitive environment variables](#setting-sensitive-environment-variables) - [Setting non sensitive environment variables](#setting-non-sensitive-environment-variables) @@ -12,8 +14,12 @@ This guide explains how to secure environment variables when using the Atlantis You should already have the following resources: -- An Artifact or Container Registry in Google Cloud. -- A CI/CD system with a secret manager integration (such as GitHub, Gitlab, Jenkins, or Cloud Build). +- Google network, subnetwork and a Cloud NAT +- Service account, [specifics can be found here](../../README.md#service-account) +- Domain, [specifics can be found here](../../README.md#dns-record) +- The secrets for the GitHub app id, secret, and webhook secret. + +If you prefer an example that includes the above resources, see [`complete example`](https://github.com/bschaatsbergen/atlantis-on-gcp-vm/tree/master/examples/complete) ## How to deploy @@ -29,11 +35,8 @@ Atlantis allows you to configure everything using environment variables. However ### Setting sensitive environment variables -Use a wrapper Atlantis Docker image to set environment variables that contain sensitive values. See the following examples for more details: - -- [**Cloud Build**: pull secrets from Google Secret Manager](https://github.com/bschaatsbergen/atlantis-on-gcp-vm/tree/master/examples/secure-env-vars/cloudbuild.yaml) -- [**GitHub Actions**: pull secrets from Google Secret Manager](https://github.com/bschaatsbergen/atlantis-on-gcp-vm/tree/master/examples/secure-env-vars/.github/workflows/docker-gcp-secrets.yaml) -- [**GitHub Actions**: use GitHub secrets](https://github.com/bschaatsbergen/atlantis-on-gcp-vm/tree/master/examples/secure-env-vars/.github/workflows/docker-github-secrets.yaml) +You can export sensitive values in the [`custom-entrypoint.sh.tftpl`](custom-entrypoint.sh.tftpl) script, which will be executed as the container entrypoint. +This strategy allow us to use the base Atlantis image, and to export environment variables that do not appear in the Console (e.g. ATLANTIS_GH_WEBHOOK_SECRET). ### Setting non-sensitive environment variables diff --git a/examples/secure-env-vars/cloudbuild.yaml b/examples/secure-env-vars/cloudbuild.yaml deleted file mode 100644 index 83a1dc5..0000000 --- a/examples/secure-env-vars/cloudbuild.yaml +++ /dev/null @@ -1,23 +0,0 @@ -steps: - - name: "gcr.io/cloud-builders/docker" - entrypoint: "bash" - args: - [ - "-c", - "docker build -t ${_IMAGE} . --build-arg ATLANTIS_GH_USER=$$ATLANTIS_GH_USER --build-arg ATLANTIS_GH_TOKEN=$$ATLANTIS_GH_TOKEN --build-arg ATLANTIS_GH_WEBHOOK_SECRET=$$ATLANTIS_GH_WEBHOOK_SECRET", - ] - dir: "atlantis/gcp-secrets" - secretEnv: - ["ATLANTIS_GH_USER", "ATLANTIS_GH_TOKEN", "ATLANTIS_GH_WEBHOOK_SECRET"] -availableSecrets: - secretManager: - - versionName: projects/$PROJECT_ID/secrets/atlantis-gh-user/versions/latest - env: "ATLANTIS_GH_USER" - - versionName: projects/$PROJECT_ID/secrets/atlantis-gh-token/versions/latest - env: "ATLANTIS_GH_TOKEN" - - versionName: projects/$PROJECT_ID/secrets/atlantis-gh-webhook-secret/versions/latest - env: "ATLANTIS_GH_WEBHOOK_SECRET" - -images: ["${_IMAGE}"] -substitutions: - _IMAGE: "europe-docker.pkg.dev///:" diff --git a/examples/secure-env-vars/custom-entrypoint.sh.tftpl b/examples/secure-env-vars/custom-entrypoint.sh.tftpl new file mode 100644 index 0000000..352efa9 --- /dev/null +++ b/examples/secure-env-vars/custom-entrypoint.sh.tftpl @@ -0,0 +1,43 @@ +#!/bin/bash + +set -e + +mkdir -p ${mount_folder} +chown 100 ${mount_folder} +cat <<'EOF' > "${mount_folder}/${entrypoint_filename}" +#!/bin/bash + +set -e + +ARCH="x86_64" +apk --no-cache upgrade && apk --no-cache add \ + curl \ + python3 \ + py3-crcmod \ + py3-openssl \ + bash \ + libc6-compat \ + openssh-client \ + git \ + gnupg \ + && curl -O https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-${cloud_sdk_version}-linux-$${ARCH}.tar.gz && \ + tar xzf google-cloud-cli-${cloud_sdk_version}-linux-$${ARCH}.tar.gz && \ + rm google-cloud-cli-${cloud_sdk_version}-linux-$${ARCH}.tar.gz + +export PATH=$PATH:/google-cloud-sdk/bin +gcloud config set core/disable_usage_reporting true +gcloud config set component_manager/disable_update_check true +gcloud config set metrics/environment github_docker_image +gcloud --version + +gcloud secrets versions access latest --secret="${app_key_secret_name}" > "${key_file_path}" && chmod 400 "${key_file_path}" && chown 100 "${key_file_path}" + +export ATLANTIS_GH_APP_ID=$(gcloud secrets versions access latest --secret="${app_id_secret_name}") +export ATLANTIS_GH_APP_KEY_FILE="${key_file_path}" +export ATLANTIS_GH_WEBHOOK_SECRET=$(gcloud secrets versions access latest --secret="${webhook_secret_secret_name}") + +# Call original atlantis entrypoint, passing along all arguments +docker-entrypoint.sh "$@" +EOF + +chmod 0755 "${mount_folder}/${entrypoint_filename}" diff --git a/examples/secure-env-vars/main.tf b/examples/secure-env-vars/main.tf index 9011c2e..cd5f247 100644 --- a/examples/secure-env-vars/main.tf +++ b/examples/secure-env-vars/main.tf @@ -4,11 +4,16 @@ locals { subnetwork = "" region = "" zone = "" - image = "" domain = "" managed_zone = "" github_repo_allow_list = "github.com/example/*" + + secret_names = { + app_id = "" + app_key = "" + webhook = "" + } } # Create a service account and attach the required Cloud Logging permissions to it. @@ -33,7 +38,6 @@ resource "google_project_iam_member" "atlantis_metric_writer" { module "atlantis" { source = "bschaatsbergen/atlantis/gce" name = "atlantis" - image = local.image # Your wrapper Atlantis Docker image network = local.network subnetwork = local.subnetwork region = local.region @@ -42,14 +46,29 @@ module "atlantis" { email = google_service_account.atlantis.email scopes = ["cloud-platform"] } - # Declare the non-sensitive environment variables here - # The sensitive environment variables are set in the Dockerfile! + env_vars = { - ATLANTIS_REPO_ALLOWLIST = local.github_repo_allow_list - ATLANTIS_ATLANTIS_URL = "https://${local.domain}" + ATLANTIS_REPO_ALLOWLIST = local.github_repo_allow_list + ATLANTIS_ATLANTIS_URL = "https://${local.domain}" + ATLANTIS_REPO_CONFIG_JSON = jsonencode(yamldecode(file("${path.module}/server-atlantis.yaml"))) + ATLANTIS_WRITE_GIT_CREDS = "true" } domain = local.domain project = local.project_id + + image = "ghcr.io/runatlantis/atlantis:latest" + command = ["/home/atlantis/custom-entrypoint.sh"] + args = ["server"] + + startup_script = templatefile("${path.module}/custom-entrypoint.sh.tftpl", { + cloud_sdk_version = "455.0.0" + app_key_secret_name = local.secret_names.app_key + app_id_secret_name = local.secret_names.app_id + webhook_secret_secret_name = local.secret_names.webhook + key_file_path = "/home/atlantis/gh_app_key.pem" + mount_folder = "/mnt/disks/gce-containers-mounts/gce-persistent-disks/atlantis-disk-0" + entrypoint_filename = "custom-entrypoint.sh" + }) } # As your DNS records might be managed at another registrar's site, we create the DNS record outside of the module. diff --git a/examples/secure-env-vars/server-atlantis.yaml b/examples/secure-env-vars/server-atlantis.yaml new file mode 100644 index 0000000..2005c3a --- /dev/null +++ b/examples/secure-env-vars/server-atlantis.yaml @@ -0,0 +1,7 @@ +repos: +- id: /.*/ + apply_requirements: [mergeable] + allowed_overrides: [apply_requirements, workflow] + allow_custom_workflows: true + delete_source_branch_on_merge: true + \ No newline at end of file