Configure GCP Certificate Authority

The gcp:certificateauthority/authority:Authority resource, part of the Pulumi GCP provider, defines a Certificate Authority within Google Cloud’s Certificate Authority Service: its identity, key material, trust hierarchy, and certificate issuance constraints. This guide focuses on four capabilities: self-signed root CA creation, subordinate CA hierarchies, Cloud KMS key integration, and custom certificate distribution URLs.

Certificate Authorities belong to CA pools and may reference Cloud KMS keys or parent CAs for subordinate configurations. The examples are intentionally small. Combine them with your own CA pools, KMS keys, and certificate issuance workflows.

Create a self-signed root CA with organization identity

Most PKI deployments begin with a root Certificate Authority that establishes the trust anchor for issuing certificates.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const _default = new gcp.certificateauthority.Authority("default", {
    pool: "ca-pool",
    certificateAuthorityId: "my-certificate-authority",
    location: "us-central1",
    deletionProtection: true,
    config: {
        subjectConfig: {
            subject: {
                organization: "ACME",
                commonName: "my-certificate-authority",
            },
        },
        x509Config: {
            caOptions: {
                isCa: true,
            },
            keyUsage: {
                baseKeyUsage: {
                    certSign: true,
                    crlSign: true,
                },
                extendedKeyUsage: {},
            },
        },
    },
    lifetime: `${10 * 365 * 24 * 3600}s`,
    keySpec: {
        algorithm: "RSA_PKCS1_4096_SHA256",
    },
});
import pulumi
import pulumi_gcp as gcp

default = gcp.certificateauthority.Authority("default",
    pool="ca-pool",
    certificate_authority_id="my-certificate-authority",
    location="us-central1",
    deletion_protection=True,
    config={
        "subject_config": {
            "subject": {
                "organization": "ACME",
                "common_name": "my-certificate-authority",
            },
        },
        "x509_config": {
            "ca_options": {
                "is_ca": True,
            },
            "key_usage": {
                "base_key_usage": {
                    "cert_sign": True,
                    "crl_sign": True,
                },
                "extended_key_usage": {},
            },
        },
    },
    lifetime=f"{10 * 365 * 24 * 3600}s",
    key_spec={
        "algorithm": "RSA_PKCS1_4096_SHA256",
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/certificateauthority"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := certificateauthority.NewAuthority(ctx, "default", &certificateauthority.AuthorityArgs{
			Pool:                   pulumi.String("ca-pool"),
			CertificateAuthorityId: pulumi.String("my-certificate-authority"),
			Location:               pulumi.String("us-central1"),
			DeletionProtection:     pulumi.Bool(true),
			Config: &certificateauthority.AuthorityConfigArgs{
				SubjectConfig: &certificateauthority.AuthorityConfigSubjectConfigArgs{
					Subject: &certificateauthority.AuthorityConfigSubjectConfigSubjectArgs{
						Organization: pulumi.String("ACME"),
						CommonName:   pulumi.String("my-certificate-authority"),
					},
				},
				X509Config: &certificateauthority.AuthorityConfigX509ConfigArgs{
					CaOptions: &certificateauthority.AuthorityConfigX509ConfigCaOptionsArgs{
						IsCa: pulumi.Bool(true),
					},
					KeyUsage: &certificateauthority.AuthorityConfigX509ConfigKeyUsageArgs{
						BaseKeyUsage: &certificateauthority.AuthorityConfigX509ConfigKeyUsageBaseKeyUsageArgs{
							CertSign: pulumi.Bool(true),
							CrlSign:  pulumi.Bool(true),
						},
						ExtendedKeyUsage: &certificateauthority.AuthorityConfigX509ConfigKeyUsageExtendedKeyUsageArgs{},
					},
				},
			},
			Lifetime: pulumi.Sprintf("%vs", 10*365*24*3600),
			KeySpec: &certificateauthority.AuthorityKeySpecArgs{
				Algorithm: pulumi.String("RSA_PKCS1_4096_SHA256"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var @default = new Gcp.CertificateAuthority.Authority("default", new()
    {
        Pool = "ca-pool",
        CertificateAuthorityId = "my-certificate-authority",
        Location = "us-central1",
        DeletionProtection = true,
        Config = new Gcp.CertificateAuthority.Inputs.AuthorityConfigArgs
        {
            SubjectConfig = new Gcp.CertificateAuthority.Inputs.AuthorityConfigSubjectConfigArgs
            {
                Subject = new Gcp.CertificateAuthority.Inputs.AuthorityConfigSubjectConfigSubjectArgs
                {
                    Organization = "ACME",
                    CommonName = "my-certificate-authority",
                },
            },
            X509Config = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigArgs
            {
                CaOptions = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigCaOptionsArgs
                {
                    IsCa = true,
                },
                KeyUsage = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigKeyUsageArgs
                {
                    BaseKeyUsage = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigKeyUsageBaseKeyUsageArgs
                    {
                        CertSign = true,
                        CrlSign = true,
                    },
                    ExtendedKeyUsage = null,
                },
            },
        },
        Lifetime = $"{10 * 365 * 24 * 3600}s",
        KeySpec = new Gcp.CertificateAuthority.Inputs.AuthorityKeySpecArgs
        {
            Algorithm = "RSA_PKCS1_4096_SHA256",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.certificateauthority.Authority;
import com.pulumi.gcp.certificateauthority.AuthorityArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigSubjectConfigArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigSubjectConfigSubjectArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigX509ConfigArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigX509ConfigCaOptionsArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigX509ConfigKeyUsageArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigX509ConfigKeyUsageBaseKeyUsageArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigX509ConfigKeyUsageExtendedKeyUsageArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityKeySpecArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var default_ = new Authority("default", AuthorityArgs.builder()
            .pool("ca-pool")
            .certificateAuthorityId("my-certificate-authority")
            .location("us-central1")
            .deletionProtection(true)
            .config(AuthorityConfigArgs.builder()
                .subjectConfig(AuthorityConfigSubjectConfigArgs.builder()
                    .subject(AuthorityConfigSubjectConfigSubjectArgs.builder()
                        .organization("ACME")
                        .commonName("my-certificate-authority")
                        .build())
                    .build())
                .x509Config(AuthorityConfigX509ConfigArgs.builder()
                    .caOptions(AuthorityConfigX509ConfigCaOptionsArgs.builder()
                        .isCa(true)
                        .build())
                    .keyUsage(AuthorityConfigX509ConfigKeyUsageArgs.builder()
                        .baseKeyUsage(AuthorityConfigX509ConfigKeyUsageBaseKeyUsageArgs.builder()
                            .certSign(true)
                            .crlSign(true)
                            .build())
                        .extendedKeyUsage(AuthorityConfigX509ConfigKeyUsageExtendedKeyUsageArgs.builder()
                            .build())
                        .build())
                    .build())
                .build())
            .lifetime(String.format("%ss", 10 * 365 * 24 * 3600))
            .keySpec(AuthorityKeySpecArgs.builder()
                .algorithm("RSA_PKCS1_4096_SHA256")
                .build())
            .build());

    }
}

The config block defines the CA’s identity through subjectConfig (organization and commonName) and its capabilities through x509Config. Setting isCa to true marks this as a CA certificate, while certSign and crlSign in keyUsage allow it to sign certificates and revocation lists. The keySpec determines the signing algorithm, and lifetime sets how long the CA certificate remains valid. This CA can now issue certificates within its pool.

Chain a subordinate CA under a root CA

Organizations often delegate certificate issuance to subordinate CAs that operate under a root CA’s authority, creating a trust hierarchy.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const root_ca = new gcp.certificateauthority.Authority("root-ca", {
    pool: "ca-pool",
    certificateAuthorityId: "my-certificate-authority-root",
    location: "us-central1",
    config: {
        subjectConfig: {
            subject: {
                organization: "ACME",
                commonName: "my-certificate-authority",
            },
        },
        x509Config: {
            caOptions: {
                isCa: true,
            },
            keyUsage: {
                baseKeyUsage: {
                    certSign: true,
                    crlSign: true,
                },
                extendedKeyUsage: {},
            },
        },
    },
    keySpec: {
        algorithm: "RSA_PKCS1_4096_SHA256",
    },
    deletionProtection: false,
    skipGracePeriod: true,
    ignoreActiveCertificatesOnDeletion: true,
});
const _default = new gcp.certificateauthority.Authority("default", {
    pool: "ca-pool",
    certificateAuthorityId: "my-certificate-authority-sub",
    location: "us-central1",
    deletionProtection: true,
    subordinateConfig: {
        certificateAuthority: root_ca.name,
    },
    config: {
        subjectConfig: {
            subject: {
                organization: "ACME",
                commonName: "my-subordinate-authority",
            },
        },
        x509Config: {
            caOptions: {
                isCa: true,
                zeroMaxIssuerPathLength: true,
            },
            keyUsage: {
                baseKeyUsage: {
                    certSign: true,
                    crlSign: true,
                },
                extendedKeyUsage: {},
            },
        },
    },
    lifetime: `${5 * 365 * 24 * 3600}s`,
    keySpec: {
        algorithm: "RSA_PKCS1_2048_SHA256",
    },
    type: "SUBORDINATE",
});
import pulumi
import pulumi_gcp as gcp

root_ca = gcp.certificateauthority.Authority("root-ca",
    pool="ca-pool",
    certificate_authority_id="my-certificate-authority-root",
    location="us-central1",
    config={
        "subject_config": {
            "subject": {
                "organization": "ACME",
                "common_name": "my-certificate-authority",
            },
        },
        "x509_config": {
            "ca_options": {
                "is_ca": True,
            },
            "key_usage": {
                "base_key_usage": {
                    "cert_sign": True,
                    "crl_sign": True,
                },
                "extended_key_usage": {},
            },
        },
    },
    key_spec={
        "algorithm": "RSA_PKCS1_4096_SHA256",
    },
    deletion_protection=False,
    skip_grace_period=True,
    ignore_active_certificates_on_deletion=True)
default = gcp.certificateauthority.Authority("default",
    pool="ca-pool",
    certificate_authority_id="my-certificate-authority-sub",
    location="us-central1",
    deletion_protection=True,
    subordinate_config={
        "certificate_authority": root_ca.name,
    },
    config={
        "subject_config": {
            "subject": {
                "organization": "ACME",
                "common_name": "my-subordinate-authority",
            },
        },
        "x509_config": {
            "ca_options": {
                "is_ca": True,
                "zero_max_issuer_path_length": True,
            },
            "key_usage": {
                "base_key_usage": {
                    "cert_sign": True,
                    "crl_sign": True,
                },
                "extended_key_usage": {},
            },
        },
    },
    lifetime=f"{5 * 365 * 24 * 3600}s",
    key_spec={
        "algorithm": "RSA_PKCS1_2048_SHA256",
    },
    type="SUBORDINATE")
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/certificateauthority"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		root_ca, err := certificateauthority.NewAuthority(ctx, "root-ca", &certificateauthority.AuthorityArgs{
			Pool:                   pulumi.String("ca-pool"),
			CertificateAuthorityId: pulumi.String("my-certificate-authority-root"),
			Location:               pulumi.String("us-central1"),
			Config: &certificateauthority.AuthorityConfigArgs{
				SubjectConfig: &certificateauthority.AuthorityConfigSubjectConfigArgs{
					Subject: &certificateauthority.AuthorityConfigSubjectConfigSubjectArgs{
						Organization: pulumi.String("ACME"),
						CommonName:   pulumi.String("my-certificate-authority"),
					},
				},
				X509Config: &certificateauthority.AuthorityConfigX509ConfigArgs{
					CaOptions: &certificateauthority.AuthorityConfigX509ConfigCaOptionsArgs{
						IsCa: pulumi.Bool(true),
					},
					KeyUsage: &certificateauthority.AuthorityConfigX509ConfigKeyUsageArgs{
						BaseKeyUsage: &certificateauthority.AuthorityConfigX509ConfigKeyUsageBaseKeyUsageArgs{
							CertSign: pulumi.Bool(true),
							CrlSign:  pulumi.Bool(true),
						},
						ExtendedKeyUsage: &certificateauthority.AuthorityConfigX509ConfigKeyUsageExtendedKeyUsageArgs{},
					},
				},
			},
			KeySpec: &certificateauthority.AuthorityKeySpecArgs{
				Algorithm: pulumi.String("RSA_PKCS1_4096_SHA256"),
			},
			DeletionProtection:                 pulumi.Bool(false),
			SkipGracePeriod:                    pulumi.Bool(true),
			IgnoreActiveCertificatesOnDeletion: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		_, err = certificateauthority.NewAuthority(ctx, "default", &certificateauthority.AuthorityArgs{
			Pool:                   pulumi.String("ca-pool"),
			CertificateAuthorityId: pulumi.String("my-certificate-authority-sub"),
			Location:               pulumi.String("us-central1"),
			DeletionProtection:     pulumi.Bool(true),
			SubordinateConfig: &certificateauthority.AuthoritySubordinateConfigArgs{
				CertificateAuthority: root_ca.Name,
			},
			Config: &certificateauthority.AuthorityConfigArgs{
				SubjectConfig: &certificateauthority.AuthorityConfigSubjectConfigArgs{
					Subject: &certificateauthority.AuthorityConfigSubjectConfigSubjectArgs{
						Organization: pulumi.String("ACME"),
						CommonName:   pulumi.String("my-subordinate-authority"),
					},
				},
				X509Config: &certificateauthority.AuthorityConfigX509ConfigArgs{
					CaOptions: &certificateauthority.AuthorityConfigX509ConfigCaOptionsArgs{
						IsCa:                    pulumi.Bool(true),
						ZeroMaxIssuerPathLength: pulumi.Bool(true),
					},
					KeyUsage: &certificateauthority.AuthorityConfigX509ConfigKeyUsageArgs{
						BaseKeyUsage: &certificateauthority.AuthorityConfigX509ConfigKeyUsageBaseKeyUsageArgs{
							CertSign: pulumi.Bool(true),
							CrlSign:  pulumi.Bool(true),
						},
						ExtendedKeyUsage: &certificateauthority.AuthorityConfigX509ConfigKeyUsageExtendedKeyUsageArgs{},
					},
				},
			},
			Lifetime: pulumi.Sprintf("%vs", 5*365*24*3600),
			KeySpec: &certificateauthority.AuthorityKeySpecArgs{
				Algorithm: pulumi.String("RSA_PKCS1_2048_SHA256"),
			},
			Type: pulumi.String("SUBORDINATE"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var root_ca = new Gcp.CertificateAuthority.Authority("root-ca", new()
    {
        Pool = "ca-pool",
        CertificateAuthorityId = "my-certificate-authority-root",
        Location = "us-central1",
        Config = new Gcp.CertificateAuthority.Inputs.AuthorityConfigArgs
        {
            SubjectConfig = new Gcp.CertificateAuthority.Inputs.AuthorityConfigSubjectConfigArgs
            {
                Subject = new Gcp.CertificateAuthority.Inputs.AuthorityConfigSubjectConfigSubjectArgs
                {
                    Organization = "ACME",
                    CommonName = "my-certificate-authority",
                },
            },
            X509Config = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigArgs
            {
                CaOptions = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigCaOptionsArgs
                {
                    IsCa = true,
                },
                KeyUsage = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigKeyUsageArgs
                {
                    BaseKeyUsage = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigKeyUsageBaseKeyUsageArgs
                    {
                        CertSign = true,
                        CrlSign = true,
                    },
                    ExtendedKeyUsage = null,
                },
            },
        },
        KeySpec = new Gcp.CertificateAuthority.Inputs.AuthorityKeySpecArgs
        {
            Algorithm = "RSA_PKCS1_4096_SHA256",
        },
        DeletionProtection = false,
        SkipGracePeriod = true,
        IgnoreActiveCertificatesOnDeletion = true,
    });

    var @default = new Gcp.CertificateAuthority.Authority("default", new()
    {
        Pool = "ca-pool",
        CertificateAuthorityId = "my-certificate-authority-sub",
        Location = "us-central1",
        DeletionProtection = true,
        SubordinateConfig = new Gcp.CertificateAuthority.Inputs.AuthoritySubordinateConfigArgs
        {
            CertificateAuthority = root_ca.Name,
        },
        Config = new Gcp.CertificateAuthority.Inputs.AuthorityConfigArgs
        {
            SubjectConfig = new Gcp.CertificateAuthority.Inputs.AuthorityConfigSubjectConfigArgs
            {
                Subject = new Gcp.CertificateAuthority.Inputs.AuthorityConfigSubjectConfigSubjectArgs
                {
                    Organization = "ACME",
                    CommonName = "my-subordinate-authority",
                },
            },
            X509Config = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigArgs
            {
                CaOptions = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigCaOptionsArgs
                {
                    IsCa = true,
                    ZeroMaxIssuerPathLength = true,
                },
                KeyUsage = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigKeyUsageArgs
                {
                    BaseKeyUsage = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigKeyUsageBaseKeyUsageArgs
                    {
                        CertSign = true,
                        CrlSign = true,
                    },
                    ExtendedKeyUsage = null,
                },
            },
        },
        Lifetime = $"{5 * 365 * 24 * 3600}s",
        KeySpec = new Gcp.CertificateAuthority.Inputs.AuthorityKeySpecArgs
        {
            Algorithm = "RSA_PKCS1_2048_SHA256",
        },
        Type = "SUBORDINATE",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.certificateauthority.Authority;
import com.pulumi.gcp.certificateauthority.AuthorityArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigSubjectConfigArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigSubjectConfigSubjectArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigX509ConfigArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigX509ConfigCaOptionsArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigX509ConfigKeyUsageArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigX509ConfigKeyUsageBaseKeyUsageArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigX509ConfigKeyUsageExtendedKeyUsageArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityKeySpecArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthoritySubordinateConfigArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var root_ca = new Authority("root-ca", AuthorityArgs.builder()
            .pool("ca-pool")
            .certificateAuthorityId("my-certificate-authority-root")
            .location("us-central1")
            .config(AuthorityConfigArgs.builder()
                .subjectConfig(AuthorityConfigSubjectConfigArgs.builder()
                    .subject(AuthorityConfigSubjectConfigSubjectArgs.builder()
                        .organization("ACME")
                        .commonName("my-certificate-authority")
                        .build())
                    .build())
                .x509Config(AuthorityConfigX509ConfigArgs.builder()
                    .caOptions(AuthorityConfigX509ConfigCaOptionsArgs.builder()
                        .isCa(true)
                        .build())
                    .keyUsage(AuthorityConfigX509ConfigKeyUsageArgs.builder()
                        .baseKeyUsage(AuthorityConfigX509ConfigKeyUsageBaseKeyUsageArgs.builder()
                            .certSign(true)
                            .crlSign(true)
                            .build())
                        .extendedKeyUsage(AuthorityConfigX509ConfigKeyUsageExtendedKeyUsageArgs.builder()
                            .build())
                        .build())
                    .build())
                .build())
            .keySpec(AuthorityKeySpecArgs.builder()
                .algorithm("RSA_PKCS1_4096_SHA256")
                .build())
            .deletionProtection(false)
            .skipGracePeriod(true)
            .ignoreActiveCertificatesOnDeletion(true)
            .build());

        var default_ = new Authority("default", AuthorityArgs.builder()
            .pool("ca-pool")
            .certificateAuthorityId("my-certificate-authority-sub")
            .location("us-central1")
            .deletionProtection(true)
            .subordinateConfig(AuthoritySubordinateConfigArgs.builder()
                .certificateAuthority(root_ca.name())
                .build())
            .config(AuthorityConfigArgs.builder()
                .subjectConfig(AuthorityConfigSubjectConfigArgs.builder()
                    .subject(AuthorityConfigSubjectConfigSubjectArgs.builder()
                        .organization("ACME")
                        .commonName("my-subordinate-authority")
                        .build())
                    .build())
                .x509Config(AuthorityConfigX509ConfigArgs.builder()
                    .caOptions(AuthorityConfigX509ConfigCaOptionsArgs.builder()
                        .isCa(true)
                        .zeroMaxIssuerPathLength(true)
                        .build())
                    .keyUsage(AuthorityConfigX509ConfigKeyUsageArgs.builder()
                        .baseKeyUsage(AuthorityConfigX509ConfigKeyUsageBaseKeyUsageArgs.builder()
                            .certSign(true)
                            .crlSign(true)
                            .build())
                        .extendedKeyUsage(AuthorityConfigX509ConfigKeyUsageExtendedKeyUsageArgs.builder()
                            .build())
                        .build())
                    .build())
                .build())
            .lifetime(String.format("%ss", 5 * 365 * 24 * 3600))
            .keySpec(AuthorityKeySpecArgs.builder()
                .algorithm("RSA_PKCS1_2048_SHA256")
                .build())
            .type("SUBORDINATE")
            .build());

    }
}

The subordinateConfig property links this CA to a parent by referencing the root CA’s name. Setting type to SUBORDINATE changes the CA’s role in the hierarchy. The zeroMaxIssuerPathLength constraint prevents this subordinate from creating its own subordinates. Subordinate CAs must be activated before they can issue certificates; the root CA signs the subordinate’s certificate during activation.

Use Cloud KMS keys for CA signing operations

Security-sensitive deployments often require CA private keys to remain in hardware security modules rather than being managed by the service.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const privatecaSa = new gcp.projects.ServiceIdentity("privateca_sa", {service: "privateca.googleapis.com"});
const privatecaSaKeyuserSignerverifier = new gcp.kms.CryptoKeyIAMMember("privateca_sa_keyuser_signerverifier", {
    cryptoKeyId: "projects/keys-project/locations/us-central1/keyRings/key-ring/cryptoKeys/crypto-key",
    role: "roles/cloudkms.signerVerifier",
    member: privatecaSa.member,
});
const privatecaSaKeyuserViewer = new gcp.kms.CryptoKeyIAMMember("privateca_sa_keyuser_viewer", {
    cryptoKeyId: "projects/keys-project/locations/us-central1/keyRings/key-ring/cryptoKeys/crypto-key",
    role: "roles/viewer",
    member: privatecaSa.member,
});
const _default = new gcp.certificateauthority.Authority("default", {
    pool: "ca-pool",
    certificateAuthorityId: "my-certificate-authority",
    location: "us-central1",
    deletionProtection: true,
    keySpec: {
        cloudKmsKeyVersion: "projects/keys-project/locations/us-central1/keyRings/key-ring/cryptoKeys/crypto-key/cryptoKeyVersions/1",
    },
    config: {
        subjectConfig: {
            subject: {
                organization: "Example, Org.",
                commonName: "Example Authority",
            },
        },
        x509Config: {
            caOptions: {
                isCa: true,
            },
            keyUsage: {
                baseKeyUsage: {
                    certSign: true,
                    crlSign: true,
                },
                extendedKeyUsage: {},
            },
            nameConstraints: {
                critical: true,
                permittedDnsNames: ["*.example.com"],
                excludedDnsNames: ["*.deny.example.com"],
                permittedIpRanges: ["10.0.0.0/8"],
                excludedIpRanges: ["10.1.1.0/24"],
                permittedEmailAddresses: [".example.com"],
                excludedEmailAddresses: [".deny.example.com"],
                permittedUris: [".example.com"],
                excludedUris: [".deny.example.com"],
            },
        },
    },
}, {
    dependsOn: [
        privatecaSaKeyuserSignerverifier,
        privatecaSaKeyuserViewer,
    ],
});
import pulumi
import pulumi_gcp as gcp

privateca_sa = gcp.projects.ServiceIdentity("privateca_sa", service="privateca.googleapis.com")
privateca_sa_keyuser_signerverifier = gcp.kms.CryptoKeyIAMMember("privateca_sa_keyuser_signerverifier",
    crypto_key_id="projects/keys-project/locations/us-central1/keyRings/key-ring/cryptoKeys/crypto-key",
    role="roles/cloudkms.signerVerifier",
    member=privateca_sa.member)
privateca_sa_keyuser_viewer = gcp.kms.CryptoKeyIAMMember("privateca_sa_keyuser_viewer",
    crypto_key_id="projects/keys-project/locations/us-central1/keyRings/key-ring/cryptoKeys/crypto-key",
    role="roles/viewer",
    member=privateca_sa.member)
default = gcp.certificateauthority.Authority("default",
    pool="ca-pool",
    certificate_authority_id="my-certificate-authority",
    location="us-central1",
    deletion_protection=True,
    key_spec={
        "cloud_kms_key_version": "projects/keys-project/locations/us-central1/keyRings/key-ring/cryptoKeys/crypto-key/cryptoKeyVersions/1",
    },
    config={
        "subject_config": {
            "subject": {
                "organization": "Example, Org.",
                "common_name": "Example Authority",
            },
        },
        "x509_config": {
            "ca_options": {
                "is_ca": True,
            },
            "key_usage": {
                "base_key_usage": {
                    "cert_sign": True,
                    "crl_sign": True,
                },
                "extended_key_usage": {},
            },
            "name_constraints": {
                "critical": True,
                "permitted_dns_names": ["*.example.com"],
                "excluded_dns_names": ["*.deny.example.com"],
                "permitted_ip_ranges": ["10.0.0.0/8"],
                "excluded_ip_ranges": ["10.1.1.0/24"],
                "permitted_email_addresses": [".example.com"],
                "excluded_email_addresses": [".deny.example.com"],
                "permitted_uris": [".example.com"],
                "excluded_uris": [".deny.example.com"],
            },
        },
    },
    opts = pulumi.ResourceOptions(depends_on=[
            privateca_sa_keyuser_signerverifier,
            privateca_sa_keyuser_viewer,
        ]))
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/certificateauthority"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/kms"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/projects"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		privatecaSa, err := projects.NewServiceIdentity(ctx, "privateca_sa", &projects.ServiceIdentityArgs{
			Service: pulumi.String("privateca.googleapis.com"),
		})
		if err != nil {
			return err
		}
		privatecaSaKeyuserSignerverifier, err := kms.NewCryptoKeyIAMMember(ctx, "privateca_sa_keyuser_signerverifier", &kms.CryptoKeyIAMMemberArgs{
			CryptoKeyId: pulumi.String("projects/keys-project/locations/us-central1/keyRings/key-ring/cryptoKeys/crypto-key"),
			Role:        pulumi.String("roles/cloudkms.signerVerifier"),
			Member:      privatecaSa.Member,
		})
		if err != nil {
			return err
		}
		privatecaSaKeyuserViewer, err := kms.NewCryptoKeyIAMMember(ctx, "privateca_sa_keyuser_viewer", &kms.CryptoKeyIAMMemberArgs{
			CryptoKeyId: pulumi.String("projects/keys-project/locations/us-central1/keyRings/key-ring/cryptoKeys/crypto-key"),
			Role:        pulumi.String("roles/viewer"),
			Member:      privatecaSa.Member,
		})
		if err != nil {
			return err
		}
		_, err = certificateauthority.NewAuthority(ctx, "default", &certificateauthority.AuthorityArgs{
			Pool:                   pulumi.String("ca-pool"),
			CertificateAuthorityId: pulumi.String("my-certificate-authority"),
			Location:               pulumi.String("us-central1"),
			DeletionProtection:     pulumi.Bool(true),
			KeySpec: &certificateauthority.AuthorityKeySpecArgs{
				CloudKmsKeyVersion: pulumi.String("projects/keys-project/locations/us-central1/keyRings/key-ring/cryptoKeys/crypto-key/cryptoKeyVersions/1"),
			},
			Config: &certificateauthority.AuthorityConfigArgs{
				SubjectConfig: &certificateauthority.AuthorityConfigSubjectConfigArgs{
					Subject: &certificateauthority.AuthorityConfigSubjectConfigSubjectArgs{
						Organization: pulumi.String("Example, Org."),
						CommonName:   pulumi.String("Example Authority"),
					},
				},
				X509Config: &certificateauthority.AuthorityConfigX509ConfigArgs{
					CaOptions: &certificateauthority.AuthorityConfigX509ConfigCaOptionsArgs{
						IsCa: pulumi.Bool(true),
					},
					KeyUsage: &certificateauthority.AuthorityConfigX509ConfigKeyUsageArgs{
						BaseKeyUsage: &certificateauthority.AuthorityConfigX509ConfigKeyUsageBaseKeyUsageArgs{
							CertSign: pulumi.Bool(true),
							CrlSign:  pulumi.Bool(true),
						},
						ExtendedKeyUsage: &certificateauthority.AuthorityConfigX509ConfigKeyUsageExtendedKeyUsageArgs{},
					},
					NameConstraints: &certificateauthority.AuthorityConfigX509ConfigNameConstraintsArgs{
						Critical: pulumi.Bool(true),
						PermittedDnsNames: pulumi.StringArray{
							pulumi.String("*.example.com"),
						},
						ExcludedDnsNames: pulumi.StringArray{
							pulumi.String("*.deny.example.com"),
						},
						PermittedIpRanges: pulumi.StringArray{
							pulumi.String("10.0.0.0/8"),
						},
						ExcludedIpRanges: pulumi.StringArray{
							pulumi.String("10.1.1.0/24"),
						},
						PermittedEmailAddresses: pulumi.StringArray{
							pulumi.String(".example.com"),
						},
						ExcludedEmailAddresses: pulumi.StringArray{
							pulumi.String(".deny.example.com"),
						},
						PermittedUris: pulumi.StringArray{
							pulumi.String(".example.com"),
						},
						ExcludedUris: pulumi.StringArray{
							pulumi.String(".deny.example.com"),
						},
					},
				},
			},
		}, pulumi.DependsOn([]pulumi.Resource{
			privatecaSaKeyuserSignerverifier,
			privatecaSaKeyuserViewer,
		}))
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var privatecaSa = new Gcp.Projects.ServiceIdentity("privateca_sa", new()
    {
        Service = "privateca.googleapis.com",
    });

    var privatecaSaKeyuserSignerverifier = new Gcp.Kms.CryptoKeyIAMMember("privateca_sa_keyuser_signerverifier", new()
    {
        CryptoKeyId = "projects/keys-project/locations/us-central1/keyRings/key-ring/cryptoKeys/crypto-key",
        Role = "roles/cloudkms.signerVerifier",
        Member = privatecaSa.Member,
    });

    var privatecaSaKeyuserViewer = new Gcp.Kms.CryptoKeyIAMMember("privateca_sa_keyuser_viewer", new()
    {
        CryptoKeyId = "projects/keys-project/locations/us-central1/keyRings/key-ring/cryptoKeys/crypto-key",
        Role = "roles/viewer",
        Member = privatecaSa.Member,
    });

    var @default = new Gcp.CertificateAuthority.Authority("default", new()
    {
        Pool = "ca-pool",
        CertificateAuthorityId = "my-certificate-authority",
        Location = "us-central1",
        DeletionProtection = true,
        KeySpec = new Gcp.CertificateAuthority.Inputs.AuthorityKeySpecArgs
        {
            CloudKmsKeyVersion = "projects/keys-project/locations/us-central1/keyRings/key-ring/cryptoKeys/crypto-key/cryptoKeyVersions/1",
        },
        Config = new Gcp.CertificateAuthority.Inputs.AuthorityConfigArgs
        {
            SubjectConfig = new Gcp.CertificateAuthority.Inputs.AuthorityConfigSubjectConfigArgs
            {
                Subject = new Gcp.CertificateAuthority.Inputs.AuthorityConfigSubjectConfigSubjectArgs
                {
                    Organization = "Example, Org.",
                    CommonName = "Example Authority",
                },
            },
            X509Config = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigArgs
            {
                CaOptions = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigCaOptionsArgs
                {
                    IsCa = true,
                },
                KeyUsage = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigKeyUsageArgs
                {
                    BaseKeyUsage = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigKeyUsageBaseKeyUsageArgs
                    {
                        CertSign = true,
                        CrlSign = true,
                    },
                    ExtendedKeyUsage = null,
                },
                NameConstraints = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigNameConstraintsArgs
                {
                    Critical = true,
                    PermittedDnsNames = new[]
                    {
                        "*.example.com",
                    },
                    ExcludedDnsNames = new[]
                    {
                        "*.deny.example.com",
                    },
                    PermittedIpRanges = new[]
                    {
                        "10.0.0.0/8",
                    },
                    ExcludedIpRanges = new[]
                    {
                        "10.1.1.0/24",
                    },
                    PermittedEmailAddresses = new[]
                    {
                        ".example.com",
                    },
                    ExcludedEmailAddresses = new[]
                    {
                        ".deny.example.com",
                    },
                    PermittedUris = new[]
                    {
                        ".example.com",
                    },
                    ExcludedUris = new[]
                    {
                        ".deny.example.com",
                    },
                },
            },
        },
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            privatecaSaKeyuserSignerverifier,
            privatecaSaKeyuserViewer,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.projects.ServiceIdentity;
import com.pulumi.gcp.projects.ServiceIdentityArgs;
import com.pulumi.gcp.kms.CryptoKeyIAMMember;
import com.pulumi.gcp.kms.CryptoKeyIAMMemberArgs;
import com.pulumi.gcp.certificateauthority.Authority;
import com.pulumi.gcp.certificateauthority.AuthorityArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityKeySpecArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigSubjectConfigArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigSubjectConfigSubjectArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigX509ConfigArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigX509ConfigCaOptionsArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigX509ConfigKeyUsageArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigX509ConfigKeyUsageBaseKeyUsageArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigX509ConfigKeyUsageExtendedKeyUsageArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigX509ConfigNameConstraintsArgs;
import com.pulumi.resources.CustomResourceOptions;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var privatecaSa = new ServiceIdentity("privatecaSa", ServiceIdentityArgs.builder()
            .service("privateca.googleapis.com")
            .build());

        var privatecaSaKeyuserSignerverifier = new CryptoKeyIAMMember("privatecaSaKeyuserSignerverifier", CryptoKeyIAMMemberArgs.builder()
            .cryptoKeyId("projects/keys-project/locations/us-central1/keyRings/key-ring/cryptoKeys/crypto-key")
            .role("roles/cloudkms.signerVerifier")
            .member(privatecaSa.member())
            .build());

        var privatecaSaKeyuserViewer = new CryptoKeyIAMMember("privatecaSaKeyuserViewer", CryptoKeyIAMMemberArgs.builder()
            .cryptoKeyId("projects/keys-project/locations/us-central1/keyRings/key-ring/cryptoKeys/crypto-key")
            .role("roles/viewer")
            .member(privatecaSa.member())
            .build());

        var default_ = new Authority("default", AuthorityArgs.builder()
            .pool("ca-pool")
            .certificateAuthorityId("my-certificate-authority")
            .location("us-central1")
            .deletionProtection(true)
            .keySpec(AuthorityKeySpecArgs.builder()
                .cloudKmsKeyVersion("projects/keys-project/locations/us-central1/keyRings/key-ring/cryptoKeys/crypto-key/cryptoKeyVersions/1")
                .build())
            .config(AuthorityConfigArgs.builder()
                .subjectConfig(AuthorityConfigSubjectConfigArgs.builder()
                    .subject(AuthorityConfigSubjectConfigSubjectArgs.builder()
                        .organization("Example, Org.")
                        .commonName("Example Authority")
                        .build())
                    .build())
                .x509Config(AuthorityConfigX509ConfigArgs.builder()
                    .caOptions(AuthorityConfigX509ConfigCaOptionsArgs.builder()
                        .isCa(true)
                        .build())
                    .keyUsage(AuthorityConfigX509ConfigKeyUsageArgs.builder()
                        .baseKeyUsage(AuthorityConfigX509ConfigKeyUsageBaseKeyUsageArgs.builder()
                            .certSign(true)
                            .crlSign(true)
                            .build())
                        .extendedKeyUsage(AuthorityConfigX509ConfigKeyUsageExtendedKeyUsageArgs.builder()
                            .build())
                        .build())
                    .nameConstraints(AuthorityConfigX509ConfigNameConstraintsArgs.builder()
                        .critical(true)
                        .permittedDnsNames("*.example.com")
                        .excludedDnsNames("*.deny.example.com")
                        .permittedIpRanges("10.0.0.0/8")
                        .excludedIpRanges("10.1.1.0/24")
                        .permittedEmailAddresses(".example.com")
                        .excludedEmailAddresses(".deny.example.com")
                        .permittedUris(".example.com")
                        .excludedUris(".deny.example.com")
                        .build())
                    .build())
                .build())
            .build(), CustomResourceOptions.builder()
                .dependsOn(                
                    privatecaSaKeyuserSignerverifier,
                    privatecaSaKeyuserViewer)
                .build());

    }
}
resources:
  privatecaSa:
    type: gcp:projects:ServiceIdentity
    name: privateca_sa
    properties:
      service: privateca.googleapis.com
  privatecaSaKeyuserSignerverifier:
    type: gcp:kms:CryptoKeyIAMMember
    name: privateca_sa_keyuser_signerverifier
    properties:
      cryptoKeyId: projects/keys-project/locations/us-central1/keyRings/key-ring/cryptoKeys/crypto-key
      role: roles/cloudkms.signerVerifier
      member: ${privatecaSa.member}
  privatecaSaKeyuserViewer:
    type: gcp:kms:CryptoKeyIAMMember
    name: privateca_sa_keyuser_viewer
    properties:
      cryptoKeyId: projects/keys-project/locations/us-central1/keyRings/key-ring/cryptoKeys/crypto-key
      role: roles/viewer
      member: ${privatecaSa.member}
  default:
    type: gcp:certificateauthority:Authority
    properties:
      pool: ca-pool
      certificateAuthorityId: my-certificate-authority
      location: us-central1
      deletionProtection: true
      keySpec:
        cloudKmsKeyVersion: projects/keys-project/locations/us-central1/keyRings/key-ring/cryptoKeys/crypto-key/cryptoKeyVersions/1
      config:
        subjectConfig:
          subject:
            organization: Example, Org.
            commonName: Example Authority
        x509Config:
          caOptions:
            isCa: true
          keyUsage:
            baseKeyUsage:
              certSign: true
              crlSign: true
            extendedKeyUsage: {}
          nameConstraints:
            critical: true
            permittedDnsNames:
              - '*.example.com'
            excludedDnsNames:
              - '*.deny.example.com'
            permittedIpRanges:
              - 10.0.0.0/8
            excludedIpRanges:
              - 10.1.1.0/24
            permittedEmailAddresses:
              - .example.com
            excludedEmailAddresses:
              - .deny.example.com
            permittedUris:
              - .example.com
            excludedUris:
              - .deny.example.com
    options:
      dependsOn:
        - ${privatecaSaKeyuserSignerverifier}
        - ${privatecaSaKeyuserViewer}

The cloudKmsKeyVersion property in keySpec points to a Cloud KMS key that performs all signing operations. The CA never has direct access to the private key; it sends signing requests to Cloud KMS. The nameConstraints block restricts which domains, IP ranges, email addresses, and URIs this CA can issue certificates for, with separate permitted and excluded lists for each type. The dependsOn ensures IAM permissions are in place before the CA attempts to use the key.

Publish CA certificates and CRLs to custom URLs

Certificate validation often requires clients to download CA certificates and certificate revocation lists from specific URLs.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const _default = new gcp.certificateauthority.Authority("default", {
    pool: "ca-pool",
    certificateAuthorityId: "my-certificate-authority",
    location: "us-central1",
    deletionProtection: true,
    config: {
        subjectConfig: {
            subject: {
                organization: "ACME",
                commonName: "my-certificate-authority",
            },
        },
        x509Config: {
            caOptions: {
                isCa: true,
            },
            keyUsage: {
                baseKeyUsage: {
                    certSign: true,
                    crlSign: true,
                },
                extendedKeyUsage: {},
            },
        },
    },
    lifetime: `${10 * 365 * 24 * 3600}s`,
    keySpec: {
        algorithm: "RSA_PKCS1_4096_SHA256",
    },
    userDefinedAccessUrls: {
        aiaIssuingCertificateUrls: [
            "http://example.com/ca.crt",
            "http://example.com/anotherca.crt",
        ],
        crlAccessUrls: [
            "http://example.com/crl1.crt",
            "http://example.com/crl2.crt",
        ],
    },
});
import pulumi
import pulumi_gcp as gcp

default = gcp.certificateauthority.Authority("default",
    pool="ca-pool",
    certificate_authority_id="my-certificate-authority",
    location="us-central1",
    deletion_protection=True,
    config={
        "subject_config": {
            "subject": {
                "organization": "ACME",
                "common_name": "my-certificate-authority",
            },
        },
        "x509_config": {
            "ca_options": {
                "is_ca": True,
            },
            "key_usage": {
                "base_key_usage": {
                    "cert_sign": True,
                    "crl_sign": True,
                },
                "extended_key_usage": {},
            },
        },
    },
    lifetime=f"{10 * 365 * 24 * 3600}s",
    key_spec={
        "algorithm": "RSA_PKCS1_4096_SHA256",
    },
    user_defined_access_urls={
        "aia_issuing_certificate_urls": [
            "http://example.com/ca.crt",
            "http://example.com/anotherca.crt",
        ],
        "crl_access_urls": [
            "http://example.com/crl1.crt",
            "http://example.com/crl2.crt",
        ],
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/certificateauthority"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := certificateauthority.NewAuthority(ctx, "default", &certificateauthority.AuthorityArgs{
			Pool:                   pulumi.String("ca-pool"),
			CertificateAuthorityId: pulumi.String("my-certificate-authority"),
			Location:               pulumi.String("us-central1"),
			DeletionProtection:     pulumi.Bool(true),
			Config: &certificateauthority.AuthorityConfigArgs{
				SubjectConfig: &certificateauthority.AuthorityConfigSubjectConfigArgs{
					Subject: &certificateauthority.AuthorityConfigSubjectConfigSubjectArgs{
						Organization: pulumi.String("ACME"),
						CommonName:   pulumi.String("my-certificate-authority"),
					},
				},
				X509Config: &certificateauthority.AuthorityConfigX509ConfigArgs{
					CaOptions: &certificateauthority.AuthorityConfigX509ConfigCaOptionsArgs{
						IsCa: pulumi.Bool(true),
					},
					KeyUsage: &certificateauthority.AuthorityConfigX509ConfigKeyUsageArgs{
						BaseKeyUsage: &certificateauthority.AuthorityConfigX509ConfigKeyUsageBaseKeyUsageArgs{
							CertSign: pulumi.Bool(true),
							CrlSign:  pulumi.Bool(true),
						},
						ExtendedKeyUsage: &certificateauthority.AuthorityConfigX509ConfigKeyUsageExtendedKeyUsageArgs{},
					},
				},
			},
			Lifetime: pulumi.Sprintf("%vs", 10*365*24*3600),
			KeySpec: &certificateauthority.AuthorityKeySpecArgs{
				Algorithm: pulumi.String("RSA_PKCS1_4096_SHA256"),
			},
			UserDefinedAccessUrls: &certificateauthority.AuthorityUserDefinedAccessUrlsArgs{
				AiaIssuingCertificateUrls: pulumi.StringArray{
					pulumi.String("http://example.com/ca.crt"),
					pulumi.String("http://example.com/anotherca.crt"),
				},
				CrlAccessUrls: pulumi.StringArray{
					pulumi.String("http://example.com/crl1.crt"),
					pulumi.String("http://example.com/crl2.crt"),
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var @default = new Gcp.CertificateAuthority.Authority("default", new()
    {
        Pool = "ca-pool",
        CertificateAuthorityId = "my-certificate-authority",
        Location = "us-central1",
        DeletionProtection = true,
        Config = new Gcp.CertificateAuthority.Inputs.AuthorityConfigArgs
        {
            SubjectConfig = new Gcp.CertificateAuthority.Inputs.AuthorityConfigSubjectConfigArgs
            {
                Subject = new Gcp.CertificateAuthority.Inputs.AuthorityConfigSubjectConfigSubjectArgs
                {
                    Organization = "ACME",
                    CommonName = "my-certificate-authority",
                },
            },
            X509Config = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigArgs
            {
                CaOptions = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigCaOptionsArgs
                {
                    IsCa = true,
                },
                KeyUsage = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigKeyUsageArgs
                {
                    BaseKeyUsage = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigKeyUsageBaseKeyUsageArgs
                    {
                        CertSign = true,
                        CrlSign = true,
                    },
                    ExtendedKeyUsage = null,
                },
            },
        },
        Lifetime = $"{10 * 365 * 24 * 3600}s",
        KeySpec = new Gcp.CertificateAuthority.Inputs.AuthorityKeySpecArgs
        {
            Algorithm = "RSA_PKCS1_4096_SHA256",
        },
        UserDefinedAccessUrls = new Gcp.CertificateAuthority.Inputs.AuthorityUserDefinedAccessUrlsArgs
        {
            AiaIssuingCertificateUrls = new[]
            {
                "http://example.com/ca.crt",
                "http://example.com/anotherca.crt",
            },
            CrlAccessUrls = new[]
            {
                "http://example.com/crl1.crt",
                "http://example.com/crl2.crt",
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.certificateauthority.Authority;
import com.pulumi.gcp.certificateauthority.AuthorityArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigSubjectConfigArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigSubjectConfigSubjectArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigX509ConfigArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigX509ConfigCaOptionsArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigX509ConfigKeyUsageArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigX509ConfigKeyUsageBaseKeyUsageArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityConfigX509ConfigKeyUsageExtendedKeyUsageArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityKeySpecArgs;
import com.pulumi.gcp.certificateauthority.inputs.AuthorityUserDefinedAccessUrlsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var default_ = new Authority("default", AuthorityArgs.builder()
            .pool("ca-pool")
            .certificateAuthorityId("my-certificate-authority")
            .location("us-central1")
            .deletionProtection(true)
            .config(AuthorityConfigArgs.builder()
                .subjectConfig(AuthorityConfigSubjectConfigArgs.builder()
                    .subject(AuthorityConfigSubjectConfigSubjectArgs.builder()
                        .organization("ACME")
                        .commonName("my-certificate-authority")
                        .build())
                    .build())
                .x509Config(AuthorityConfigX509ConfigArgs.builder()
                    .caOptions(AuthorityConfigX509ConfigCaOptionsArgs.builder()
                        .isCa(true)
                        .build())
                    .keyUsage(AuthorityConfigX509ConfigKeyUsageArgs.builder()
                        .baseKeyUsage(AuthorityConfigX509ConfigKeyUsageBaseKeyUsageArgs.builder()
                            .certSign(true)
                            .crlSign(true)
                            .build())
                        .extendedKeyUsage(AuthorityConfigX509ConfigKeyUsageExtendedKeyUsageArgs.builder()
                            .build())
                        .build())
                    .build())
                .build())
            .lifetime(String.format("%ss", 10 * 365 * 24 * 3600))
            .keySpec(AuthorityKeySpecArgs.builder()
                .algorithm("RSA_PKCS1_4096_SHA256")
                .build())
            .userDefinedAccessUrls(AuthorityUserDefinedAccessUrlsArgs.builder()
                .aiaIssuingCertificateUrls(                
                    "http://example.com/ca.crt",
                    "http://example.com/anotherca.crt")
                .crlAccessUrls(                
                    "http://example.com/crl1.crt",
                    "http://example.com/crl2.crt")
                .build())
            .build());

    }
}

The userDefinedAccessUrls block specifies where clients can retrieve the CA certificate (aiaIssuingCertificateUrls) and revocation lists (crlAccessUrls). These URLs appear in issued certificates, directing clients to your infrastructure instead of Google-managed endpoints. You’re responsible for hosting the artifacts at these locations.

Beyond these examples

These snippets focus on specific CA-level features: self-signed and subordinate CA hierarchies, Cloud KMS key integration and name constraints, and custom certificate distribution URLs. They’re intentionally minimal rather than full PKI deployments.

The examples may reference pre-existing infrastructure such as CA pools (referenced by pool property) and Cloud KMS keys and IAM bindings (for BYO key example). They focus on configuring the CA rather than provisioning everything around it.

To keep things focused, common CA patterns are omitted, including:

  • GCS bucket configuration for CA artifacts (gcsBucket)
  • CA state management (desiredState, STAGED CAs)
  • Third-party issuer activation (pemCaCertificate)
  • Deletion controls (skipGracePeriod, ignoreActiveCertificatesOnDeletion)

These omissions are intentional: the goal is to illustrate how each CA feature is wired, not provide drop-in PKI modules. See the Certificate Authority resource reference for all available configuration options.

Let's configure GCP Certificate Authority

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Deletion & Lifecycle
Why can't I delete my Certificate Authority?
You must explicitly set deletionProtection to false and run pulumi up to write it to state before destroying the CA. By default, deletion protection prevents accidental CA deletion.
How do I delete a Certificate Authority immediately without the grace period?
Set skipGracePeriod to true. This bypasses the 30-day grace period where undeletion would normally be allowed. Use with caution as there’s no recovery option.
Can I delete a CA that has active certificates?
By default, no. Set ignoreActiveCertificatesOnDeletion to true to allow deletion even with unrevoked or unexpired certificates. Use with care.
CA Types & Activation
What's the difference between SELF_SIGNED and SUBORDINATE Certificate Authorities?
SELF_SIGNED CAs (the default) sign their own certificates and can issue certificates immediately. SUBORDINATE CAs are signed by a parent CA and must be activated before they can issue certificates.
How do I create a subordinate Certificate Authority?
Set type to SUBORDINATE and configure subordinateConfig with a reference to the parent CA (e.g., certificateAuthority: rootCa.name).
How do I activate a subordinate CA with a third-party issuer?
Provide the signed CA certificate in the pemCaCertificate field. This certificate is issued from the subordinate CA’s CSR by the third-party issuer.
Can I create a staged root CA?
Yes, set desiredState to STAGED when creating the CA. This creates a root CA in staged state rather than enabled.
Configuration & Immutability
What properties can't be changed after creating a Certificate Authority?
These properties are immutable and require resource replacement if changed: certificateAuthorityId, config, keySpec, location, pool, project, gcsBucket, lifetime, and type.
Why aren't my labels showing up correctly?
The labels field is non-authoritative and only manages labels in your configuration. Use effectiveLabels to see all labels present on the resource, including those set by other clients.
Key Management
How do I use my own Cloud KMS key for the Certificate Authority?
Set keySpec.cloudKmsKeyVersion to your KMS key version path (e.g., projects/.../cryptoKeys/.../cryptoKeyVersions/1). Ensure the Private CA service account has roles/cloudkms.signerVerifier and roles/viewer on the key, using dependsOn to enforce IAM binding order.
Can I specify a custom Subject Key Identifier?
Yes, configure config.subjectKeyId.keyId with your custom key ID (e.g., 4cf3372289b1d411b999dbb9ebcd44744b6b2fca).
Advanced Features
How do I customize the URLs for CA certificates and CRLs?
Use userDefinedAccessUrls to specify custom aiaIssuingCertificateUrls and crlAccessUrls. These override the default GCP-managed URLs.

Using a different cloud?

Explore security guides for other cloud providers: