Git Product home page Git Product logo

terraform-cloud-dynamic-credentials's Introduction

Terraform Cloud GCP Dynamic Credentials

Code in this repository allows dynamic, short-lived GCP service account credentials to be generated and used from within Terraform Cloud. This enables the use of GCP service accounts without manually generating, downloading, and uploading service account keys into Terraform Cloud as variables.

Security Model

The code in the Google cloud function takes the following security-focused constraints into account when authenticating a request from a client:

  1. Validates the supplied token against the Terraform Cloud API
  2. Ensures the supplied token belongs to a Terraform service account
    1. No user, team, or organization-supplied tokens will be permitted
  3. Queries the Terraform Cloud runs API to ensure the current run is in a state of planning or applying
    1. This ensures Terraform tokens from prior runs cannot be used
  4. Looks up the parent workspace of the supplied run ID and obtains its organization
  5. Ensures a statically-mapped GCP credential in the function's configuration matches explictly to an organization and workspace

Components

There are two necessary components: code for a Google Cloud Function and Terraform resources to call the function and set the access token in the Google Terraform provider.

Code

In the func/ folder is code for a Google Cloud Function written to receive HTTP requests. This function takes a configuration value which maps Terraform Cloud workspaces to service accounts. It expects to receive a JSON payload containing two values:

  1. Terraform Cloud Run ID belonging to the run from which it was called
  2. Terraform Cloud API token

A sample JSON body can be found below:

{
    "TFC_TOKEN": "9zCfoobarHTuu0A.atlasv1.48swmoQ1DMasdfghjklzExZk0q0QzIguuIaekI0HbjjOY5dXFkkoJV1pbazquux",
    "RUN_ID": "run-RbEqJ7cfoobarfiL"
}

An example response from the Cloud Function resembles the following:

{
   "status": "success",
   "token": "ya29.c.b0AXv0zTO..."
}

The function performs the following steps using the token and run ID it receives in the request body:

  1. Validates the supplied token against the Terraform Cloud API
  2. Ensures the token belongs to a TFC service account
  3. Queries the Terraform Cloud API for the parent workspace of the calling run
  4. Looks up the parent organization of the workspace
  5. Checks its configuration for a service account mapped to a TFC workspace
  6. Obtains a GCP service account token for the mapped credential with a lifetime of 1 hour

The returned token can subsequently be used when configuring the Google Terraform provider using the access_token attribute, which may then be used to deploy resources using the IAM permissions of the GCP service account.

Configuration

The Google Cloud Function requires a service account with the Service Account Token Creator (roles/iam.serviceAccountTokenCreator) role bound to each service account for which short-lived tokens will be created. Please review the documentation to grant IAM to a service account in the Google Cloud documentation here.

Once the Cloud Function's service account has the correct IAM grants to create tokens for service accounts, the function must be configured with a JSON object which maps a service account to a Terraform Cloud workspace. This JSON object should be the value of the SA_MAPPING_CONFIG environment variable. The JSON object must use the following structure:

{
  "terraform_cloud_org/workspace": "[email protected]",
  "my-org/dynamic-creds-workspace": "[email protected]"
}

To enable verbose logging in the Cloud Function, you may optionally set the environment variable DEBUG=true.

Deployment

Prerequisites

The following services will need to be enabled in the project where the Cloud Function is to be deployed:

  • iamcredentials.googleapis.com (required to generate service account tokens)
  • cloudfunctions.googleapis.com
  • cloudbuild.googleapis.com (required for functions)
  • logging.googleapis.com (required for functions)

This can be done in a one-liner command in a Bash-like shell with the following example:

PROJECT=<your-project-id> for SERVICE in logging.googleapis.com iamcredentials.googleapis.com cloudfunctions.googleapis.com cloudbuild.googleapis.com; do gcloud services enable $SERVICE --project $PROJECT; done

Create a GCP Service Account to use with this function following the documentation or with the below example gcloud command:

gcloud iam service-accounts create <function-service-account> --project <your-project-id>

Once you have a service account for your function, the function's SA will need Service Account Token Creator IAM role (roles/iam.serviceAccountTokenCreator) granted on every service account for which it will generate tokens. See Configuration above.

This function can be deployed with the following gcloud command:

gcloud functions deploy generate_token \
  --project <your-project-id> \
  --service-account <[email protected]> \
  --runtime python39 \
  --trigger-http \
  --allow-unauthenticated 

The above command deploys the cloud function without requiring authentication. This is due to the TFC token validation steps outlined above, and to avoid requiring manually generated service account credentials. If you require authentication of requests to this function, please read Using IAM to Authorize Access.

Note: If you have a Domain Restricted Sharing organization policy enabled in your organization, you will need to override this policy to the Google-managed default on the project where the function is to be deployed. This can be done at deployment-time and subsequently reverted thereafter.

Terraform

See the example for an demo of how one can call the deployed Cloud Function.

How It Works

Terraform Cloud sets two critical environments variables in its runtime environment for runs:

  • ATLAS_TOKEN: the token belonging to the service account tied to the lifecycle of the run
  • TFC_RUN_ID: A unique identifier for the currently executing run

You must make a remote web call to the deployed token generator Cloud Function endpoint. An example call is in the tf/get_gcp_token.sh script. In essence, it's a simple curl command with a JSON payload which provides the aforementioned values from the environment.

The cloud function returns a JSON response with a short-lived GCP access token belonging to a service account from the function's service account mapping config.

Using the external data resource, call the curl bash script:

data "external" "curl_command" {
  program = ["bash", "get_gcp_token.sh"]
}

Then instantiate the google provider using the dynamically generated token:

provider "google" {
  access_token = data.external.curl_command.result.token
}

License

Apache v2.0

Disclaimer

This is not an official Google product.

terraform-cloud-dynamic-credentials's People

Contributors

angstwad avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.