GCP Setup for Cloud Storage Buckets
This page is for the GCP admin setting up the Workload Identity method of a bucket connection. Run these commands once, then hand the result (a WIF audience string) to your teammates to paste into Mycorr.
You don't need any of this for the default Sign in with Google method, which reads a bucket with the user's own Google access.
Mycorr uses Workload Identity Federation (WIF): users sign in with Google, and Mycorr exchanges the user's Google id-token against your WIF provider for a short-lived federated token that reads the bucket directly. No service-account keys and no service-account impersonation. What the federated token can read comes entirely from the IAM bindings you set below.
The user's Google identity is the trust anchor; Mycorr never holds a long-lived customer secret.
What Mycorr signs as
Google is the OIDC issuer. The id-token Mycorr presents looks like:
{
"iss": "https://accounts.google.com",
"sub": "108234567890123456789",
"email": "you@yourcompany.com",
"email_verified": true,
"hd": "yourcompany.com",
"aud": "<Mycorr OAuth client_id>",
"exp": ...
}
Your WIF provider validates the signature against Google's JWKS, checks
the aud against --allowed-audiences, and evaluates your
--attribute-condition against the mapped claims.
Setup
Prerequisites
- A GCP project with Cloud Storage, IAM, and Security Token Service APIs enabled.
- A GCS bucket.
gcloudauthenticated withiam.workloadIdentityPoolAdminandstorage.admin.- Mycorr users sign in with Workspace Google accounts. Personal
@gmail.comaccounts have nohdclaim and will fail the default org-domain condition (usually what you want).
Step 1 — Set variables
export PROJECT=your-gcp-project
export BUCKET=your-bucket-name
export MYCORR_HOST=https://space.mycorr.app
gcloud config set project $PROJECT
PROJECT_NUM=$(gcloud projects describe $PROJECT --format='value(projectNumber)')
# Mycorr's allowed-audience — the bare OAuth client_id Google sets as
# the `aud` claim on user-OAuth id-tokens. Stable per Mycorr deployment.
# (Mycorr also shows this value inline on the connection form.)
MYCORR_AUDIENCE=$(curl -s $MYCORR_HOST/server/api/public/federation/config | jq -r .allowed_audience)
# The user (or domain) you want to authorize.
USER_EMAIL=you@yourcompany.com
USER_DOMAIN=${USER_EMAIL#*@}
Step 2 — Create the Workload Identity Pool + Provider
gcloud iam workload-identity-pools create mycorr-pool \
--location=global --project=$PROJECT
gcloud iam workload-identity-pools providers create-oidc mycorr-issuer \
--workload-identity-pool=mycorr-pool --location=global --project=$PROJECT \
--issuer-uri="https://accounts.google.com" \
--allowed-audiences="$MYCORR_AUDIENCE" \
--attribute-mapping="google.subject=assertion.sub,attribute.email=assertion.email,attribute.org=assertion.hd" \
--attribute-condition="attribute.email == '$USER_EMAIL'"
# Or trust every user in your Workspace domain — swap the last flag:
# --attribute-condition="attribute.org == '$USER_DOMAIN'"
The three flags doing real work:
--issuer-uri=https://accounts.google.com— Google is the OIDC issuer; GCP fetches Google's JWKS to verify token signatures.--allowed-audiences=$MYCORR_AUDIENCE— required. Without it, STS only accepts tokens whoseaudequals the provider resource name.--attribute-condition=...— the security gate. Email-pinned for one user, orattribute.orgfor whole-org trust.
Step 3 — Grant the federated principalSet read on your bucket
Bucket-scoped (recommended):
PREFIX="principalSet://iam.googleapis.com/projects/$PROJECT_NUM/locations/global/workloadIdentityPools/mycorr-pool"
# Anyone in your Workspace domain:
PRINCIPAL_SET="$PREFIX/attribute.org/$USER_DOMAIN"
# Or a specific user:
# PRINCIPAL_SET="$PREFIX/attribute.email/$USER_EMAIL"
gcloud storage buckets add-iam-policy-binding gs://$BUCKET \
--member="$PRINCIPAL_SET" --role=roles/storage.objectViewer
Project-scoped: grant both bucketViewer (to enable buckets.list)
and objectViewer at the project level:
gcloud projects add-iam-policy-binding $PROJECT \
--member="$PRINCIPAL_SET" --role=roles/storage.bucketViewer
gcloud projects add-iam-policy-binding $PROJECT \
--member="$PRINCIPAL_SET" --role=roles/storage.objectViewer
Step 4 — Hand the audience string to the Mycorr user
echo "//iam.googleapis.com/projects/$PROJECT_NUM/locations/global/workloadIdentityPools/mycorr-pool/providers/mycorr-issuer"
What the Mycorr user does in the app
- Connections → Add connection, pick the bucket type, and set Method to Workload Identity.
- Access scope: Single bucket (and the bucket name) or Entire project.
- Click Sign in with Google and approve.
- Paste the audience string from Step 4 into WIF audience. (Copy
Mycorr client ID shows the value used for
--allowed-audiences, for cross-checking.) - Click Test & save.
Revoking access
# Remove the principalSet binding (other resources unaffected):
gcloud storage buckets remove-iam-policy-binding gs://$BUCKET \
--member="$PRINCIPAL_SET" --role=roles/storage.objectViewer
# Tighten the condition (kicks off any user no longer matching):
gcloud iam workload-identity-pools providers update-oidc mycorr-issuer \
--workload-identity-pool=mycorr-pool --location=global \
--attribute-condition="attribute.email == 'specific-user@$USER_DOMAIN'"
# Nuclear — delete the provider (all Mycorr federation against it stops
# on next refresh):
gcloud iam workload-identity-pools providers delete mycorr-issuer \
--workload-identity-pool=mycorr-pool --location=global
In-flight 1-hour federated tokens stay valid until expiry; deleting the provider cuts off new exchanges immediately.
Troubleshooting
| What the user sees | Likely cause | Fix |
|---|---|---|
| "linked google_saved_connection_id not found — sign in to Google again" | The user hasn't signed in, or removed the Google connection | Click Sign in with Google again on the connection |
| A server error when testing the connection | The STS exchange was refused: the audience doesn't match (--allowed-audiences must be the bare client ID), or the user's email / hd fails --attribute-condition | Re-check Steps 2 and 4, and the provider's condition |
"Permission denied by cloud storage. Grant roles/storage.objectViewer…" | The principalSet has no read on the bucket, or lacks bucketViewer for project scope | Re-check Step 3 |
| "Bucket or path not found…" | Wrong bucket name, or the federated identity can't see it | Check the name and the bucket binding |
ALREADY_EXISTS creating the WIF pool / provider | GCP soft-deletes for 30 days | Use undelete + update-oidc, or pick a new name |
Audit logging
The federated principal encodes the user's stable sub in
principalSubject. Cross-reference against your IdP / Workspace directory.
resource.type="gcs_bucket"
resource.labels.bucket_name="$BUCKET"
protoPayload.authenticationInfo.principalSubject=~"workloadIdentityPools/mycorr-pool"
Note on OAuth scopes
The Google consent screen asks for openid, email, profile and the
read-only Cloud Storage scope (devstorage.read_only). One sign-in serves
both connection methods, so switching between them never asks again.
Workload Identity doesn't use the Cloud Storage scope: it exchanges the
openid id-token for its own federated token.
With Workload Identity, what Mycorr can read is bounded by your IAM:
the federated principalSet is granted only storage.objectViewer
(+ bucketViewer for project scope), read-only on the bucket. The sign-in
proves who the user is; your IAM bindings decide what they can read.