# How to replace JSON key with X.509 WiF This short guide provides step by step instructions how to replace a JSON key with a Workload Identity Federation (WiF) X.509 certificate. ## Prerequisites - `openssl` 3.x - Node.js with `npm` - `gcloud` authenticated as an administrator of the target project ## Configuration The scripts read the names of the resources from `env.sh`. Replace the example values with your own before running them. Run all scripts from the repository directory. `env.sh`: ```bash # Project PROJECT_ID=my-project PROJECT_NUMBER=123456789012 # Workload identity pool and provider POOL_ID=my-pool POOL_DISPLAY_NAME="My Pool" PROVIDER_ID=my-x509 # Service account SA_EMAIL="sa-test@${PROJECT_ID}.iam.gserviceaccount.com" # Storage bucket BUCKET=my-project-wif-test BUCKET_LOCATION=europe-central2 ``` ## About the shell scripts The `.sh` files are meant as references for copying and pasting the commands one by one, so that each step can be inspected and adapted. Running them directly with `bash` also works. > **Note:** The scripts are not idempotent. Running a whole script with `bash` a second time may fail, because the resources created by the first run already exist, for example the workload identity pool, the provider, the service account, the bucket and the `wif-test` gcloud configuration. ## 1. Create the certificates `make_certs.sh` performs the following steps: 1. Creates a root CA certificate and key (`ca_cert.pem`, `ca_key.pem`). 2. Creates an issuing CA certificate and key (`issuing_ca_cert.pem`, `issuing_ca_key.pem`), signed by the root CA. 3. Creates a client certificate and key (`client_cert.pem`, `client_key.pem`), signed by the issuing CA. Its subject CN (`test-client`) becomes the WiF subject. ```bash bash make_certs.sh ``` ## 2. Create the trust store `make_trust_store.mjs` creates `trust_store.yaml`, a YAML file that holds the root CA as the trust anchor and the issuing CA as an intermediate CA. It uses the `yaml` npm package, declared in `package.json`: ```json { "dependencies": { "yaml": ">=2.9.1" } } ``` Install the dependency and generate `trust_store.yaml`: ```bash npm install node make_trust_store.mjs ``` The PEM files must contain only the certificate block. A trailing newline after `-----END CERTIFICATE-----` makes gcloud fail with `Certificate is not in PEM format`, which is why the script trims it. ## 3. Create the pool, provider and credentials `make_wif.sh` performs the following steps: 1. Creates the workload identity pool and the X.509 provider. 2. Creates a service account. 3. Allows the client certificate subject to impersonate the service account. 4. Grants the service account read access to the project. 5. Writes `cred.json`. 6. Creates a storage bucket and grants the service account read and write access to its objects. 7. Enables Data Access audit logs for Cloud Storage. 8. Creates a separate gcloud configuration and logs in with `cred.json`. 9. Checks the access to the project and the bucket, including an upload and a download of a file. 10. Switches back to the original gcloud configuration. 11. Makes the `public/` managed folder of the bucket publicly readable. 12. Lists the audit log of the service account operations. 13. Optionally switches back to the service account configuration. ```bash bash make_wif.sh ``` 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 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.