diff --git a/examples/secured-env-vars/.github/workflows/docker-gcp-secrets.yaml b/examples/secured-env-vars/.github/workflows/docker-gcp-secrets.yaml deleted file mode 100644 index 5576f2e..0000000 --- a/examples/secured-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/secured-env-vars/.github/workflows/docker-github-secrets.yaml b/examples/secured-env-vars/.github/workflows/docker-github-secrets.yaml deleted file mode 100644 index 55d2b33..0000000 --- a/examples/secured-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/secured-env-vars/Dockerfile b/examples/secured-env-vars/Dockerfile index 5b3a00d..6016e22 100644 --- a/examples/secured-env-vars/Dockerfile +++ b/examples/secured-env-vars/Dockerfile @@ -1,9 +1,12 @@ +FROM binxio/gcp-get-secret:latest + FROM ghcr.io/runatlantis/atlantis:latest +COPY --from=0 /gcp-get-secret /usr/local/bin/ -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 +# gcp-get-secret will replace the environment variables values +# with the value in the Google Secret Manager secret before exec'ing +# the atlantis entrypoint. +# +# See https://github.com/binxio/gcp-get-secret +ENTRYPOINT ["/usr/local/bin/gcp-get-secret", "docker-entrypoint.sh"] \ No newline at end of file diff --git a/examples/secured-env-vars/README.md b/examples/secured-env-vars/README.md index 71bc673..d874302 100644 --- a/examples/secured-env-vars/README.md +++ b/examples/secured-env-vars/README.md @@ -1,38 +1,61 @@ # Securing sensitive environment variables -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). +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`](../basic/README.md). -## Prerequisites +## build your own image +To retrieve sensitive values from the Google Secret manager you need to: -You should already have the following resources: +- enable artifact registry in your Google Cloud Project +- build your own image using the [gcp-get-secret](https://github.com/binxio/gcp-get-secret) as entrypoint +- store your secrets in Google Secret Manager. +- set variable values to point to the secret manager secret URL -- 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). +## Enable artifact registry +To enable artifact registry, type: -## How to deploy +```shell +gcloud services enable artifactregistry.googleapis.com -To deploy the Atlantis module, see [`Dockerfile`](https://github.com/bschaatsbergen/atlantis-on-gcp-vm/tree/master/examples/secured-env-vars/Dockerfile) and the [`main.tf`](https://github.com/bschaatsbergen/atlantis-on-gcp-vm/tree/master/examples/secured-env-vars/main.tf). - -## Configuring Atlantis - -Atlantis allows you to configure everything using environment variables. However, these variables may contain sensitive values, and are therefore visible in the Google Cloud console when deploying a container. To protect these values, follow the steps below. - -### Setting sensitive environment variables +gcloud artifacts repositories \ + create atlantis \ + --repository-format=docker \ + --location=europe \ + --description="Atlantis gcp-get-secret" +``` -Use a wrapper Atlantis Docker image to set environment variables that contain sensitive values. See the following examples for more details: +## build the image +The build the atlantis image, type the following commands: -- [**Cloud Build**: pull secrets from Google Secret Manager](https://github.com/bschaatsbergen/atlantis-on-gcp-vm/tree/master/examples/secured-env-vars/cloudbuild.yaml) -- [**GitHub Actions**: pull secrets from Google Secret Manager](https://github.com/bschaatsbergen/atlantis-on-gcp-vm/tree/master/examples/secured-env-vars/.github/workflows/docker-gcp-secrets.yaml) -- [**GitHub Actions**: use GitHub secrets](https://github.com/bschaatsbergen/atlantis-on-gcp-vm/tree/master/examples/secured-env-vars/.github/workflows/docker-github-secrets.yaml) +```shell +REPOSITORY=europe-docker.pkg.dev/$(gcloud config get-value project)/atlantis:latest +docker build -t $REPOSITORY -f Dockerfile . +docker push $REPOSITORY +echo "INFO: set the terraform variable image to \"$REPOSITORY\"" >&2 +``` -### Setting non-sensitive environment variables +## Store the secrets in Google Secret Manager +Add the secrets into the secret manager, using the following script: + +```bash +for SECRET in ATLANTIS_GH_USER ATLANTIS_GH_TOKEN ATLANTIS_GH_WEBHOOK_SECRET; do + NAME=$(sed -e 's/_/-/g' | tr '[:upper:]' '[:lower:]') + + read "Value for $SECRET:" VALUE + gcloud secrets create $NAME + gcloud secrets versions add --secret $NAME --datafile <(echo -n "$VALUE") + echo "INFO: stored $SECRET as $NAME" >&2 +done +``` +## set variable values to point to the secret manager secret URL Use the `var.env_vars` variable to set non-sensitive environment variables. ```hcl env_vars = { - ATLANTIS_EXAMPLE = "example" + ATLANTIS_GH_USER = "gcp:///atlantis-gh-user" + ATLANTIS_GH_TOKEN = "gcp:///atlantis-gh-token" + ATLANTIS_GH_WEBHOOK_SECRET = "gcp:///atlantis-gh-webhook-secret" + ... other ... } ``` - -> **Important**: Do **not** specify the same environment variable in both the env_vars and the Dockerfile, as this will cause the deployment to fail. +This will retrieve the value for the environments variables from the Google Secret Manager on startup of Atlantis. diff --git a/examples/secured-env-vars/cloudbuild.yaml b/examples/secured-env-vars/cloudbuild.yaml deleted file mode 100644 index 83a1dc5..0000000 --- a/examples/secured-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/secured-env-vars/main.tf b/examples/secured-env-vars/main.tf index 233726b..2f31756 100644 --- a/examples/secured-env-vars/main.tf +++ b/examples/secured-env-vars/main.tf @@ -4,18 +4,20 @@ resource "google_service_account" "atlantis" { display_name = "Service Account for Atlantis" } -resource "google_project_iam_member" "atlantis_log_writer" { - role = "roles/logging.logWriter" - member = "serviceAccount:${google_service_account.atlantis.email}" - project = "" -} -resource "google_project_iam_member" "atlantis_metric_writer" { - role = "roles/monitoring.metricWriter" +resource "google_project_iam_member" "atlantis" { + for_each = set([ + "roles/logging.logWriter", + "roles/monitoring.metricWriter", + "roles/secretmanager.secretAccessor", + "roles/artifactregistry.reader", + ]) + role = each.value member = "serviceAccount:${google_service_account.atlantis.email}" project = "" } + # As your DNS records might be managed at another registrar's site, we create the DNS record outside of the module. # This record is mandatory in order to provision the managed SSL certificate successfully. resource "google_dns_record_set" "default" { @@ -41,11 +43,14 @@ module "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 = "github.com//*" ATLANTIS_ATLANTIS_URL = "https://" + # the sensitive value will contain an URL in the form of + # gcp:///. See https://github.com/binxio/gcp-get-secret + ATLANTIS_GH_USER = "gcp:///atlantis-gh-user" + ATLANTIS_GH_TOKEN = "gcp:///atlantis-gh-token" + ATLANTIS_GH_WEBHOOK_SECRET = "gcp:///atlantis-gh-webhook-secret" } domain = "" }