diff --git a/README.md b/README.md index fe9178e..7d75a95 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,32 @@ The PEM files must contain only the certificate block. A trailing newline after ## 3. Create the pool, provider and credentials -The script creates the workload identity pool, the X.509 provider and a service account. It allows the client certificate subject to impersonate the service account, grants the service account read access to the project, creates a storage bucket with read and write access to its objects for the service account, and writes `cred.json`. It then logs in with `cred.json` and checks the access. +The script creates the workload identity pool, the X.509 provider and a service account. It allows the client certificate subject to impersonate the service account, grants the service account read access to the project, creates a storage bucket with read and write access to its objects for the service account, enables Data Access audit logs for Cloud Storage, and writes `cred.json`. It then logs in with `cred.json` in a separate gcloud configuration, checks the access, uploads and downloads a file, and lists the audit log of the service account operations. + +Data Access audit logs are enabled for the whole project, not per bucket, by editing the project IAM policy. `add_audit_config.mjs` adds the `auditConfigs` section to the policy file fetched by gcloud. The policy must be fetched as YAML, because a different default gcloud output format makes `set-iam-policy` reject the file. + +`add_audit_config.mjs`: + +```javascript +#!/usr/bin/env node +import { readFileSync, writeFileSync } from "node:fs"; +import YAML from "yaml"; + +const policy = YAML.parse(readFileSync("iam_policy.yaml", "utf8")); + +// Replace the Cloud Storage entry, if any, and keep the other audit configs. +policy.auditConfigs = (policy.auditConfigs ?? []).filter( + (c) => c.service !== "storage.googleapis.com", +); +policy.auditConfigs.push({ + service: "storage.googleapis.com", + auditLogConfigs: [{ logType: "DATA_READ" }, { logType: "DATA_WRITE" }], +}); + +writeFileSync("iam_policy.yaml", YAML.stringify(policy, { indentSeq: false })); +``` + +`make_wif.sh`: ```bash # Create a workload identity pool and a X.509 provider @@ -154,6 +179,14 @@ gcloud projects add-iam-policy-binding my-project \ --member="serviceAccount:sa-test@my-project.iam.gserviceaccount.com" \ --role=roles/browser +# Create credentials configuration files +gcloud iam workload-identity-pools create-cred-config \ + projects/123456789012/locations/global/workloadIdentityPools/my-pool/providers/my-x509 \ + --service-account=sa-test@my-project.iam.gserviceaccount.com \ + --credential-cert-path=client_cert.pem \ + --credential-cert-private-key-path=client_key.pem \ + --output-file=cred.json + # Create a storage bucket gcloud storage buckets create gs://my-project-wif-test \ --project=my-project \ @@ -165,17 +198,20 @@ gcloud storage buckets add-iam-policy-binding gs://my-project-wif-test \ --member="serviceAccount:sa-test@my-project.iam.gserviceaccount.com" \ --role=roles/storage.objectUser -# Create credentials configuration files -gcloud iam workload-identity-pools create-cred-config \ - projects/123456789012/locations/global/workloadIdentityPools/my-pool/providers/my-x509 \ - --service-account=sa-test@my-project.iam.gserviceaccount.com \ - --credential-cert-path=client_cert.pem \ - --credential-cert-private-key-path=client_key.pem \ - --output-file=cred.json +# Enable Data Access audit logs for Cloud Storage (project-wide, not per bucket) +gcloud projects get-iam-policy my-project --format=yaml > iam_policy.yaml +node add_audit_config.mjs +gcloud projects set-iam-policy my-project iam_policy.yaml + +# Create a new gcloud configuration for the workload identity federation test +gcloud config configurations create wif-test # Authenticate gcloud with the credentials configuration file gcloud auth login --cred-file=cred.json +# Set the project to my-project +gcloud config set project my-project + # Test the authentication by listing the project details gcloud auth list gcloud projects describe my-project @@ -183,13 +219,30 @@ gcloud projects get-iam-policy my-project \ --flatten="bindings[].members" \ --format="table(bindings.role, bindings.members)" -# Then, switch back to your original account -gcloud config set account admin@example.com +# Test the bucket access by uploading and downloading a file +gcloud storage ls gs://my-project-wif-test +gcloud storage cp README.md gs://my-project-wif-test/README.md +gcloud storage ls gs://my-project-wif-test +gcloud storage cp gs://my-project-wif-test/README.md README.downloaded.md +cmp README.md README.downloaded.md -# and again switch back to the service account using the credentials configuration file -gcloud config set account sa-test@my-project.iam.gserviceaccount.com +# Then, switch back to your original account +gcloud config configurations activate default + +# List the audit log of the operations made by the service account +gcloud logging read \ + 'protoPayload.authenticationInfo.principalEmail="sa-test@my-project.iam.gserviceaccount.com"' \ + --project=my-project \ + --freshness=1h \ + --order=asc \ + --format="table(timestamp, protoPayload.serviceName, protoPayload.methodName)" + +# and again switch back to the service account +gcloud config configurations activate wif-test ``` +The audit log lists only Cloud Storage operations of the service account. Resource Manager calls such as `projects describe` are not covered by the Data Access configuration. + ## Result `cred.json` is a credentials configuration file that references the client certificate and private key. It contains no secret itself, but `client_key.pem` does and must be protected like a JSON key.