Skip to content

Commit

Permalink
feat: add gh oidc module (#32)
Browse files Browse the repository at this point in the history
* feat: add gh oidc module

* add example

* add test

* fmt

* add meta

* fix resource names, drop issuer uri input
  • Loading branch information
bharathkkb authored Sep 20, 2021
1 parent d9a6589 commit 1f10847
Show file tree
Hide file tree
Showing 15 changed files with 1,361 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
# Make will use bash instead of sh
SHELL := /usr/bin/env bash

DOCKER_TAG_VERSION_DEVELOPER_TOOLS := 1.0
DOCKER_TAG_VERSION_DEVELOPER_TOOLS := 1.1
DOCKER_IMAGE_DEVELOPER_TOOLS := cft/developer-tools
REGISTRY_URL := gcr.io/cloud-foundation-cicd

Expand Down
22 changes: 21 additions & 1 deletion build/int.cloudbuild.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,29 @@ steps:
- id: destroy
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
args: ['/bin/bash', '-c', 'source /usr/local/bin/task_helper_functions.sh && kitchen_do destroy']
- id: create-oidc
waitFor:
- prepare
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
args: ['/bin/bash', '-c', 'cd test/integration && RUN_STAGE=init go test -v -run TestOIDCSimple ./... -p 1']
- id: converge-oidc
waitFor:
- create-oidc
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
args: ['/bin/bash', '-c', 'cd test/integration && RUN_STAGE=apply go test -v -run TestOIDCSimple ./... -p 1']
- id: verify-oidc
waitFor:
- converge-oidc
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
args: ['/bin/bash', '-c', 'cd test/integration && RUN_STAGE=verify go test -v -run TestOIDCSimple ./... -p 1']
- id: destroy-oidc
waitFor:
- verify-oidc
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
args: ['/bin/bash', '-c', 'cd test/integration && RUN_STAGE=teardown go test -v -run TestOIDCSimple ./... -p 1']
tags:
- 'ci'
- 'integration'
substitutions:
_DOCKER_IMAGE_DEVELOPER_TOOLS: 'cft/developer-tools'
_DOCKER_TAG_VERSION_DEVELOPER_TOOLS: '1.0'
_DOCKER_TAG_VERSION_DEVELOPER_TOOLS: '1.1'
22 changes: 22 additions & 0 deletions examples/oidc-simple/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# OIDC Simple Example

## Overview

This example showcases how to configure [Workload Identity Federation](https://cloud.google.com/iam/docs/workload-identity-federation) using the [gh-oidc module](../../modules/gh-oidc/README.md) for a sample Service Account.

<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| project\_id | The project id to create WIF pool and example SA | `string` | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| pool\_name | Pool name |
| provider\_name | Provider name |
| sa\_email | Example SA email |

<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
40 changes: 40 additions & 0 deletions examples/oidc-simple/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


resource "google_service_account" "sa" {
project = var.project_id
account_id = "test-storage-sa"
}

resource "google_project_iam_member" "project" {
project = var.project_id
role = "roles/storage.admin"
member = "serviceAccount:${google_service_account.sa.email}"
}

module "oidc" {
source = "../../modules/gh-oidc"
project_id = var.project_id
pool_id = "example-pool"
provider_id = "example-gh-provider"
sa_mapping = {
(google_service_account.sa.account_id) = {
sa_name = google_service_account.sa.name
attribute = "attribute.repository/user/repo"
}
}
}
30 changes: 30 additions & 0 deletions examples/oidc-simple/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

output "pool_name" {
description = "Pool name"
value = module.oidc.pool_name
}

output "provider_name" {
description = "Provider name"
value = module.oidc.provider_name
}

output "sa_email" {
description = "Example SA email"
value = google_service_account.sa.email
}
24 changes: 24 additions & 0 deletions examples/oidc-simple/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


provider "google" {
version = "~> 3.16"
}

provider "google-beta" {
version = "~> 3.16"
}
20 changes: 20 additions & 0 deletions examples/oidc-simple/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

variable "project_id" {
type = string
description = "The project id to create WIF pool and example SA"
}
110 changes: 110 additions & 0 deletions modules/gh-oidc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
## GitHub OIDC

This module handles the opinionated creation of infrastructure necessary to configure [Workload Identity pools](https://cloud.google.com/iam/docs/workload-identity-federation#pools) and [providers](https://cloud.google.com/iam/docs/workload-identity-federation#providers) for authenticating to GCP using GitHub Actions OIDC tokens.

This includes:

- Creation of a Workload Identity pool
- Configuring a Workload Identity provider
- Granting external identities necessary IAM roles on Service Accounts

### Example Usage

```terraform
module "gh_oidc" {
source = "terraform-google-modules/github-actions-runners/google//modules/gh-oidc"
project_id = var.project_id
pool_id = "example-pool"
provider_id = "example-gh-provider"
sa_mapping = {
"foo-service-account" = {
sa_name = "[email protected]"
attribute = "attribute.repository/user/repo"
}
}
}
```

Below are some examples:

### [OIDC Simple](../../examples/oidc-simple/README.md)

This example shows how to use this module along with a Service Account to access storage buckets.

### GitHub Workflow

Once provisioned, you can use the [oidc-auth-google-cloud](https://github.com/sethvargo/oidc-auth-google-cloud) Action in a workflow as shown below

```yaml
# Example workflow
# .github/workflows/example.yml

name: 'example oidc'
on:
push:
branches:
- 'main'
jobs:
run:
name: 'example to list bucket contents'
permissions:
id-token: write
contents: read
runs-on: 'ubuntu-latest'
steps:
- id: 'auth'
uses: 'sethvargo/oidc-auth-google-cloud@main'
with:
workload_identity_provider: ${{ secrets.PROVIDER_NAME }} # this is the output provider_name from the TF module
service_account: ${{ secrets.SA_EMAIL }} # this is a SA email configured using the TF module with access to YOUR-GCS-BUCKET
- id: 'list buckets contents'
run: |-
curl https://storage.googleapis.com/storage/v1/b/YOUR-GCS-BUCKET/o \
--header "Authorization: Bearer ${{ steps.auth.outputs.access_token }}"
```
<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Inputs
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| allowed\_audiences | Workload Identity Pool Provider allowed audiences. Currently, GitHub only allows sigstore | `list(string)` | <pre>[<br> "sigstore"<br>]</pre> | no |
| attribute\_condition | Workload Identity Pool Provider attribute condition expression. [More info](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/iam_workload_identity_pool_provider#attribute_condition) | `string` | `null` | no |
| attribute\_mapping | Workload Identity Pool Provider attribute mapping. [More info](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/iam_workload_identity_pool_provider#attribute_mapping) | `map(any)` | <pre>{<br> "attribute.actor": "assertion.actor",<br> "attribute.aud": "assertion.aud",<br> "attribute.repository": "assertion.repository",<br> "google.subject": "assertion.sub"<br>}</pre> | no |
| pool\_description | Workload Identity Pool description | `string` | `"Workload Identity Pool managed by Terraform"` | no |
| pool\_display\_name | Workload Identity Pool display name | `string` | `null` | no |
| pool\_id | Workload Identity Pool ID | `string` | n/a | yes |
| project\_id | The project id to create Workload Identity Pool | `string` | n/a | yes |
| provider\_description | Workload Identity Pool Provider description | `string` | `"Workload Identity Pool Provider managed by Terraform"` | no |
| provider\_display\_name | Workload Identity Pool Provider display name | `string` | `null` | no |
| provider\_id | Workload Identity Pool Provider id | `string` | n/a | yes |
| sa\_mapping | Service Account emails and corresponding WIF provider attributes. If attribute is set to `*` all identities in the pool are granted access to SAs. | <pre>map(object({<br> sa_name = string<br> attribute = string<br> }))</pre> | `{}` | no |

## Outputs

| Name | Description |
|------|-------------|
| pool\_name | Pool name |
| provider\_name | Provider name |

<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->

## Requirements

Before this module can be used on a project, you must ensure that the following pre-requisites are fulfilled:

1. Required APIs are activated

```
"iam.googleapis.com",
"cloudresourcemanager.googleapis.com",
"iamcredentials.googleapis.com",
"sts.googleapis.com",
```

1. Service Account used to deploy this module has the following roles

```
roles/iam.workloadIdentityPoolAdmin
roles/iam.serviceAccountAdmin
```
46 changes: 46 additions & 0 deletions modules/gh-oidc/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

resource "google_iam_workload_identity_pool" "main" {
provider = google-beta
project = var.project_id
workload_identity_pool_id = var.pool_id
display_name = var.pool_display_name
description = var.pool_description
disabled = false
}

resource "google_iam_workload_identity_pool_provider" "main" {
provider = google-beta
project = var.project_id
workload_identity_pool_id = google_iam_workload_identity_pool.main.workload_identity_pool_id
workload_identity_pool_provider_id = var.provider_id
display_name = var.provider_display_name
description = var.provider_description
attribute_condition = var.attribute_condition
attribute_mapping = var.attribute_mapping
oidc {
allowed_audiences = var.allowed_audiences
issuer_uri = "https://vstoken.actions.githubusercontent.com"
}
}

resource "google_service_account_iam_member" "wif-sa" {
for_each = var.sa_mapping
service_account_id = each.value.sa_name
role = "roles/iam.workloadIdentityUser"
member = "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.main.name}/${each.value.attribute}"
}
25 changes: 25 additions & 0 deletions modules/gh-oidc/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

output "pool_name" {
description = "Pool name"
value = google_iam_workload_identity_pool.main.name
}

output "provider_name" {
description = "Provider name"
value = google_iam_workload_identity_pool_provider.main.name
}
Loading

0 comments on commit 1f10847

Please sign in to comment.