Skip to main content

GCP Certificate Authority Service

The GCP Certificate Authority Service (CAS) upstream authority integrates the Trust Domain Server with Google Cloud Certificate Authority Service. Instead of operating as a self-signed root CA, the Trust Domain Server obtains its intermediate CA certificate from GCP CAS, chaining the SPIFFE trust bundle to a corporate PKI root.

How it works

On startup (or after a CA rotation), the Trust Domain Server generates a fresh RSA-2048 key pair and submits a certificate signing request (CSR) to the configured CA pool. When caID is set, the Trust Domain Server first checks that the configured CA is reachable and logs a warning if the CA is not in an ENABLED state. GCP CAS issues a pathLen=0 intermediate CA certificate, which the Trust Domain Server uses to sign workload SVIDs. The GCP CAS root is published to agents as an upstream root in the SPIFFE trust bundle, and the intermediate certificate chain is delivered alongside issued SVIDs.

How to Deploy

Step 1 — Set Up GCP IAM

Create a GCP service account and grant it the following IAM permissions on the CA pool resource:

OperationPermissionPredefined role
Issue certificatesprivateca.certificates.createroles/privateca.certificateRequester
Startup CA-state check (when caID is set)privateca.certificateAuthorities.getroles/privateca.auditor

roles/privateca.certificateRequester grants only privateca.certificates.create and is the minimum required for certificate issuance. If caID is set and the service account lacks privateca.certificateAuthorities.get, the startup CA-state check is skipped with a warning and the Trust Domain Server starts normally. Issuance is unaffected.

The check is only advisory when the permission itself is missing. Other failures are hard errors. For example, if caID names a CA that does not exist in the pool, the Trust Domain Server logs an error, keeps its previously active authority, and the new configuration does not take effect.

To grant the minimum permissions for issuance only:

gcloud privateca pools add-iam-policy-binding CA_POOL \
--location LOCATION \
--project PROJECT_ID \
--member "serviceAccount:SA_EMAIL" \
--role roles/privateca.certificateRequester

To also enable the startup CA-state check (recommended when caID is set):

gcloud privateca pools add-iam-policy-binding CA_POOL \
--location LOCATION \
--project PROJECT_ID \
--member "serviceAccount:SA_EMAIL" \
--role roles/privateca.auditor

Alternatively, grant privateca.certificateAuthorities.get directly via a custom role to avoid the broader read permissions included in roles/privateca.auditor.

For GKE deployments, use Workload Identity Federation to bind the Trust Domain Server's Kubernetes service account to the GCP service account:

gcloud iam service-accounts add-iam-policy-binding SA_EMAIL \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE/KSA_NAME]"

Then annotate the Kubernetes service account:

kubectl annotate serviceaccount KSA_NAME \
--namespace NAMESPACE \
iam.gke.io/gcp-service-account=SA_EMAIL

Step 2 — Update cluster configuration

The CA pool and at least one enabled CA within it must already exist before configuring the upstream authority. The CA pool must be Enterprise-tier. DevOps-tier pools cannot issue CA certificates.

section: UpstreamAuthority
schema: v1
spec:
extensions:
gcpCas:
projectID: "my-project"
location: "us-central1"
caPool: "my-ca-pool"
caID: "my-root-ca"

Apply it using spirlctl:

spirlctl config set trust-domain-deployment --id <deployment-id> upstream-authority.yaml

Or using Terraform:

resource "spirl_trust_domain_deployment_config" "upstream_authority" {
trust_domain_deployment_id = spirl_trust_domain_deployment.example.id
sections = {
UpstreamAuthority = <<-YAML
section: UpstreamAuthority
schema: v1
spec:
extensions:
gcpCas:
projectID: "my-project"
location: "us-central1"
caPool: "my-ca-pool"
caID: "my-root-ca"
YAML
}
}

Once a configuration document passes validation and is stored, the Defakto control plane syncs it to your Trust Domain Servers automatically. No server or agent restart is required.

Configuration Reference

FieldRequiredDefaultDescription
projectIDYesGCP project ID where the CA pool resides.
locationYesGCP region of the CA pool (e.g. us-central1, us-east1).
caPoolYesName of the CA pool. Must be Enterprise-tier.
caIDNoID of a specific CA within the pool to use for issuance. If omitted, GCP CAS selects any available enabled CA from the pool automatically.
credentialsFileNoApplication Default CredentialsPath to a service account key JSON file. If omitted, ADC is used (recommended for GKE with Workload Identity).
supplementalBundlePathNoPath to a PEM file containing additional root certificates to include in the SPIFFE trust bundle alongside the upstream root returned by GCP CAS. Useful when bridging multiple PKI hierarchies or adding cross-signed roots.

Step 3 — Verify

On startup, the Trust Domain Server logs Submitting CSR to GCP Certificate Authority Service when it requests the intermediate CA certificate, followed by Prepared region key set once the key set is ready. The SPIFFE trust bundle published to agents will include the GCP CAS root as an upstream root.

Verify the trust bundle using:

spirlctl trust-bundle get --cluster-id <cluster-id>

The output should include the GCP CAS root in the X.509 authorities section.

Migration

To migrate from the default self-signed CA to GCP Certificate Authority Service:

  1. Apply the UpstreamAuthority Managed Config with the gcpCas extension.
  2. The Trust Domain Server picks up the new configuration automatically. At the next CA rotation, it fetches a new intermediate CA certificate from GCP CAS and begins issuing SVIDs chained to it.
  3. Agents automatically receive the updated trust bundle (including the new upstream root) on their next bundle refresh.
  4. SVIDs signed with the old self-signed CA remain valid until they expire.

Relying parties that trust only the old self-signed root will fail to verify new SVIDs. Update relying party trust stores before or during migration.

Security Considerations

  • Intermediate CA, not root. The Trust Domain Server holds a pathLen=0 intermediate CA certificate. It cannot issue intermediate CAs, only leaf SVIDs.
  • CA TTL. Short CA TTLs limit the window of exposure if the Trust Domain Server is compromised. The Trust Domain Server renews the intermediate CA automatically before expiry.
  • Cloud Audit Logs. Every certificate issuance call to GCP CAS is logged in Cloud Audit Logs.
  • Workload Identity. Use GKE Workload Identity Federation rather than a static service account key file so credentials rotate automatically.
  • Enterprise-tier required. DevOps-tier CA pools do not support issuing CA certificates and cannot be used with this integration.