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:

# 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 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:

{
  "dependencies": {
    "yaml": ">=2.9.1"
  }
}

Install the dependency and generate trust_store.yaml:

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 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.

S
Description
A set of scripts that show the use of Workload Identity Federation using X.509 federation provider.
Readme
336 KiB
0 Stars 1 Watchers 0 Forks
Languages
Shell 49.3%
Python 35.3%
JavaScript 13.1%
HTML 2.3%