diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 0d1f68d..05d9536 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -42,19 +42,38 @@ jobs: username: 'oauth2accesstoken' password: '${{ steps.auth.outputs.access_token }}' + - id: 'id_token' + uses: google-github-actions/auth@v2 + with: + workload_identity_provider: ${{ secrets.GCLOUD_OIDC_POOL }} + service_account: ${{ secrets.GSA }} + id_token_audience: "vault/ci" + token_format: 'id_token' + id_token_include_email: true + + - name: Install vault + env: + VAULT_VERSION: 1.18.3 + run: | + wget -q https://releases.hashicorp.com/vault/${VAULT_VERSION}/vault_${VAULT_VERSION}_linux_amd64.zip + unzip vault_${VAULT_VERSION}_linux_amd64.zip + sudo mv vault /usr/bin/ + - name: terraform apply - run: ./ci/tf.sh env: TF_VAR_project: ${{ secrets.GCLOUD_PROJECT }} TF_VAR_region: ${{ secrets.GCLOUD_REGION }} + VAULT_ADDR: ${{ secrets.VAULT_ADDR }} + run: ./scripts/run.sh ci "${{ steps.id_token.outputs.id_token }}" > terraform.log 2>&1 - - name: Upload logs as artifacts + - name: Upload terraform log if: ${{ always() }} uses: actions/upload-artifact@v4 with: - name: terraform.log - path: /tmp/terraform.log + name: terraform.log-${{ github.sha }} + path: ./terraform.log + overwrite: true - name: cleanup if: ${{ always() }} - run: rm /tmp/terraform.log + run: rm terraform.log diff --git a/00-main.tf b/00-main.tf index 63d6dd9..6789c94 100644 --- a/00-main.tf +++ b/00-main.tf @@ -54,17 +54,3 @@ module "vault" { provider "vault" { address = module.vault.vault-url } - -resource "google_artifact_registry_repository_iam_member" "member" { - project = module.vault.repo[0].project - location = module.vault.repo[0].location - repository = module.vault.repo[0].name - role = "roles/artifactregistry.writer" - member = "serviceAccount:${local.ci_gsa}" -} - -resource "google_storage_bucket_iam_member" "member" { - bucket = module.vault.key_bucket - role = "roles/storage.objectViewer" - member = "serviceAccount:${local.ci_gsa}" -} diff --git a/00-secrets.tf b/00-secrets.tf index 4ce8a66..a54d71a 100644 --- a/00-secrets.tf +++ b/00-secrets.tf @@ -1,5 +1,5 @@ resource "vault_mount" "kv_v1" { - path = "kv-v1" + path = "secret" type = "kv" options = { diff --git a/01-policies.tf b/01-policies.tf index 1ccddcd..101c229 100644 --- a/01-policies.tf +++ b/01-policies.tf @@ -1,11 +1,15 @@ -# allow GCP auth access to paths in the GSA's project -# https://developer.hashicorp.com/vault/api-docs/auth/gcp#sample-payload-5 -resource "vault_policy" "project-read-kv" { - name = "kv-v1-per-project" +locals { + policy_files = fileset("policies", "*.hcl") +} + +data "local_file" "policy_docs" { + for_each = local.policy_files + filename = "policies/${each.value}" +} + +resource "vault_policy" "policies" { + for_each = data.local_file.policy_docs - policy = <<-EOT - path "kv-v1/{{identity.entity.metadata.project_id}}/*" { - capabilities = ["create", "read", "update", "delete", "list"] - } - EOT + name = basename(replace(each.value.filename, ".hcl", "")) + policy = each.value.content } diff --git a/02-auth.tf b/02-auth-gcp.tf similarity index 91% rename from 02-auth.tf rename to 02-auth-gcp.tf index d2c464b..39892a2 100644 --- a/02-auth.tf +++ b/02-auth-gcp.tf @@ -12,7 +12,7 @@ resource "vault_gcp_auth_backend_role" "ghat" { token_ttl = 300 token_max_ttl = 600 token_policies = [ - vault_policy.project-read-kv.name + vault_policy.policies["gcp-kv1.hcl"].name ] add_group_aliases = true } diff --git a/02-auth-jwt.tf b/02-auth-jwt.tf new file mode 100644 index 0000000..3a41fa7 --- /dev/null +++ b/02-auth-jwt.tf @@ -0,0 +1,39 @@ +resource "vault_jwt_auth_backend" "gsuite" { + path = "jwt" + oidc_discovery_url = "https://accounts.google.com" + bound_issuer = "https://accounts.google.com" + default_role = "default" +} + +resource "vault_jwt_auth_backend_role" "admin" { + backend = vault_jwt_auth_backend.gsuite.path + role_type = "jwt" + role_name = "admin" + user_claim = "email" + bound_audiences = [ + "32555940559.apps.googleusercontent.com" + ] + bound_claims = { + email = "joe@libops.io" + } + token_policies = [ + vault_policy.policies["admin.hcl"].name, + vault_policy.policies["ci.hcl"].name + ] +} + +resource "vault_jwt_auth_backend_role" "ci" { + backend = vault_jwt_auth_backend.gsuite.path + role_type = "jwt" + role_name = "ci" + user_claim = "email" + bound_audiences = [ + "vault/ci" + ] + bound_claims = { + email = local.ci_gsa + } + token_policies = [ + vault_policy.policies["ci.hcl"].name + ] +} diff --git a/policies/admin.hcl b/policies/admin.hcl new file mode 100644 index 0000000..75f1f52 --- /dev/null +++ b/policies/admin.hcl @@ -0,0 +1,3 @@ +path "secret/*" { + capabilities = ["create", "read", "update", "delete", "list"] +} diff --git a/policies/ci.hcl b/policies/ci.hcl new file mode 100644 index 0000000..d0d733a --- /dev/null +++ b/policies/ci.hcl @@ -0,0 +1,19 @@ +path "auth/token/create" { + capabilities = ["update"] +} + +path "auth/*" { + capabilities = ["create", "read", "update", "delete", "list"] +} + +path "sys/policies/acl/*" { + capabilities = ["create", "read", "update", "delete", "list"] +} + +path "sys/auth/*" { + capabilities = ["create", "read", "update", "delete", "list"] +} + +path "sys/mounts/*" { + capabilities = ["create", "read", "update", "delete", "list"] +} diff --git a/policies/gcp-kv1.hcl b/policies/gcp-kv1.hcl new file mode 100644 index 0000000..70463e0 --- /dev/null +++ b/policies/gcp-kv1.hcl @@ -0,0 +1,3 @@ +path "secret/{{identity.entity.metadata.project_id}}/*" { + capabilities = ["create", "read", "update", "delete", "list"] +} diff --git a/ci/tf.sh b/scripts/root.sh similarity index 95% rename from ci/tf.sh rename to scripts/root.sh index e86b7cf..cec065c 100755 --- a/ci/tf.sh +++ b/scripts/root.sh @@ -30,4 +30,4 @@ export VAULT_TOKEN="$(cat root-token)" rm root-token root-token.enc root-token.dc # Now we can apply all of the terraform with a valid Vault token -terraform apply -auto-approve >> /tmp/terraform.log 2>&1 +terraform apply -auto-approve diff --git a/scripts/run.sh b/scripts/run.sh new file mode 100755 index 0000000..bca5ee4 --- /dev/null +++ b/scripts/run.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +set -euo pipefail + +ROLE="${1:-admin}" +ID_TOKEN="${2:-$(gcloud auth print-identity-token)}" + +export VAULT_TOKEN=$(vault write -format=json "auth/jwt/login" \ + role="$ROLE" \ + jwt="$ID_TOKEN" \ +| jq -r .auth.client_token) + +terraform init -upgrade +if [ "$ROLE" = "ci" ]; then + terraform apply -auto-approve +else + terraform apply +fi