Identity-Federation

26 April 2023

Github Actions is a powerful tool to automate your deployments. However, when it comes to accessing cloud resources, we need a secure way to authenticate on cloud providers. This is now easily configurable with OpenID connect on Github Actions and Identity Federation on GCP. In this article, we’ll learn how to set up Workload Identity Federation on GCP (manually and with terraform), and how to use it in Github Actions.

Overview of the keyless authentication feature

To access or deploy resources on Google Cloud with Github Actions, pipelines must contain authentication credentials. In order to control which rights you want to grant for these pipelines, you must first create a service account on GCP and grant it the correct permissions for your project. Then you will use this service account to access your GCP project from Github Actions pipelines.

The deprecated way of doing this was to export a JSON credential file for your service account into a Github Actions. How was this a problem? First, exporting a credential file exposes it to a leak, therefore someone with malicious intent could use it to access your resources. Second, managing Github Actions secrets can be painful and you might easily get lost on which secret is used for which purpose. Third, if the credentials of the service account were to be deleted or deactivated on GCP, it would block all the pipelines using this credential file.

Now, there is a more secure and maintainable way of authenticating with OpenID Connect using Workload Identity Federation on GCP. This allows matching an OIDC token from GitHub to a cloud access token with permissions in the cloud platform.

github_gcp_oidc

Image from GCP article

When starting a pipeline using this new authentication mode, Github Actions presents an OIDC JWT token to the Cloud Provider with specific claims related to the target service account but also to the repository, organization, or branch name it should be able to access.

The cloud provider validates the claims and returns a cloud access token with only permissions related to the service account.

Then, your Github Actions pipeline is able to access and deploy resources directly in your cloud platform using this cloud access token.

Let’s see how it’s configured!


OIDC setup

Workload Identity Federation needs to be configured in order to exchange the tokens we talked about in the first section. Let’s create a GCP workload identity pool and a workload identity provider. It is possible to set it up directly with gcloud cli but also with terraform.

Setup with gcloud CLI


First, set up the workload identity pool and the provider.

gcloud iam workload-identity-pools create "github-identity-pool" \
  --project="$PROJECT_ID" \
  --location="global" \
  --display-name="Github identity pool"
gcloud iam workload-identity-pools providers create-oidc “github-identity-provider”  \
   --location="global"  \
   --project="$PROJECT_ID" \
   --workload-identity-pool="github-identity-pool"  \
   --display-name="Github identity pool provider"  \
   --attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.aud=assertion.aud,attribute.repository_owner=assertion.repository_owner" \
   --issuer-uri="https://token.actions.githubusercontent.com"   

Then, you need to allow the workload identity provider to impersonate the service account. After that your Github Actions will be able to access the GCP resources; we’ll see how to use it in Github Actions in the next section.

gcloud iam service-accounts add-iam-policy-binding "github_actions_sa@$PROJECT_ID.iam.gserviceaccount.com" \
  --project="$PROJECT_ID" \
  --role="roles/iam.workloadIdentityUser" \
  --member="principalSet://iam.googleapis.com/github-identity-pool/attribute.repository/my-org/my-repo"

Setup with terraform using gh-oidc module

If the GCP service account you want to impersonate with your Github Actions is not already there, you can create it.

module "github_actions_sa" {
  source  = "terraform-google-modules/service-accounts/google"
  version = "~> 4.0"

  project_id = var.project_id

  names        = ["github_actions_sa"]
  display_name = "Github Actions SA for GCP - Managed by Terraform"

  project_roles = …
}

Then, use the gh-oidc terraform module that configures the workload identity provider and pool at the same time. It also automatically adds the roles/iam.workloadIdentityUser binding to your desired service accounts.

module "gh_oidc" {
  source         = "terraform-google-modules/github-actions-runners/google//modules/gh-oidc"
  project_id     = var.project_id
  pool_id        = "github-identity-pool"
  provider_id    = "github-identity-provider"
  sa_mapping     = {
    "my_service_account" = {
      sa_name   = "projects/my-project/serviceAccounts/${module.github_actions_sa.email}"
      attribute = "attribute.repository/user/repo"
    }
  }
}

Now, let’s see how we can authenticate your GitHub pipelines using the Github Actions auth!


Usage in Github Actions

Using identity federation in GitHub pipelines requires the usage of the auth Github Actions. Every step related to GCP in the job will then use these credentials to authenticate.

Note: gsutil does not support identity federation yet.

jobs:
  my-job:
    name: apply
    runs-on: ubuntu-latest
    permissions:
      contents: 'read'
      id-token: 'write'

    steps:
      - name: Authenticate to Google Cloud
        id: auth
        uses: google-github-actions/auth@v0
        with:
          workload_identity_provider: 'projects/<project-number>/locations/global/workloadIdentityPools/github-identity-pool/providers/github-identity-provider'
          service_account: 'github_actions_sa@${ PROJECT_ID }.iam.gserviceaccount.com'
          token_format: 'access_token'
          access_token_lifetime: '300s'

      - name: Set up Cloud SDK
        uses: google-github-actions/setup-gcloud@v0

      …

The auth action creates a secret in your job environment with the temporary authentication token. Therefore, the auth result is not passed to the other jobs in the CI, you will need to authenticate again in another job.

Conclusion

Now you are all set to access your GCP projects resources with your Github Actions pipelines! You can use it to manage the access of all your Github Actions pipelines to your GCP project, with different identity service accounts with specific permissions. Do not forget to allow only the necessary permissions to your GCP projects and resources, as well as your GitHub repositories. You can also restrain the access to your GCP service account from Github Action only to the master or main branch, this prevents PRs from accessing GCP resources 😊

If you want to learn more about DevOps security practices, you can check our article about DevSecOps tools or our Padok security offers!