Configure GCP Certificate Authority

The gcp:certificateauthority/authority:Authority resource, part of the Pulumi GCP provider, defines a Certificate Authority within a CA pool: its identity, key material, certificate constraints, and distribution endpoints. This guide focuses on four capabilities: self-signed root CA creation, subordinate CA hierarchy, 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 hierarchical PKI. The examples are intentionally small. Combine them with your own CA pools, KMS keys, and certificate policies.

Create a self-signed root CA with organization identity

Most PKI deployments begin with a root CA that establishes organizational identity and issues certificates for internal services or subordinate CAs.

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 (
	"fmt"

	"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 and certificate properties. The subjectConfig sets the distinguished name (organization and commonName), while x509Config controls certificate behavior. Setting isCa to true marks this as a CA certificate, and the keyUsage block enables certSign and crlSign, allowing the CA to issue and revoke certificates. The lifetime property sets certificate validity (here, 10 years), and keySpec defines the signing algorithm. The pool property references an existing CA pool that must be created separately.

Chain a subordinate CA under a root CA

Organizations often delegate certificate issuance to subordinate CAs, limiting the blast radius if a CA key is compromised and enabling different policies per department.

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 (
	"fmt"

	"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 chains 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 property in caOptions prevents this subordinate from issuing further subordinate CAs, creating a two-level hierarchy. Subordinate CAs require activation before they can issue certificates, either through automatic activation by the parent or by providing a signed certificate via pemCaCertificate.

Use Cloud KMS keys for CA signing operations

Regulated environments often require CA private keys to remain in hardware security modules. Cloud KMS integration allows CA signing without exporting keys.

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 specific Cloud KMS key version instead of generating a new key. The CA service account needs signerVerifier and viewer roles on the KMS key, configured via IAM bindings. The nameConstraints block restricts which domains, IP ranges, email addresses, and URIs this CA can issue certificates for, using permitted and excluded lists. The dependsOn property ensures IAM bindings complete before creating the CA.

Publish CA certificates and CRLs to custom URLs

Certificate clients need to download CA certificates and check revocation lists. Custom URLs let you host these artifacts on your own infrastructure.

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 (
	"fmt"

	"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 overrides default GCS URLs with custom HTTP endpoints. The aiaIssuingCertificateUrls property lists where clients can download the CA certificate, while crlAccessUrls points to certificate revocation lists. These URLs appear in issued certificates, directing clients to your infrastructure for certificate validation.

Beyond these examples

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

The examples reference pre-existing infrastructure such as CA pools (pool property references existing pool) 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 managed certificate storage
  • Staged CA creation (desiredState property)
  • Third-party issuer activation (pemCaCertificate for subordinates)
  • Label management and lifecycle controls

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. It’s recommended to keep this true until you’re ready to delete.
What's the difference between skipGracePeriod and normal deletion?
Normal deletion includes a 30-day grace period where undeletion is possible. Setting skipGracePeriod to true deletes the CA immediately with no recovery option. Defaults to false.
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. Defaults to false.
What properties can't be changed after creation?
These properties are immutable: certificateAuthorityId, config, keySpec, location, pool, project, gcsBucket, lifetime, and type.
CA Types & Hierarchy
How do I create a subordinate Certificate Authority?
Set type to SUBORDINATE and configure subordinateConfig with the parent CA’s name. The subordinate example shows this with subordinateConfig.certificateAuthority pointing to the root CA’s name.
Why can't my subordinate CA issue certificates?
Subordinate CAs must be activated before they can issue certificates. For third-party issuers, provide the signed CA certificate via pemCaCertificate.
How do I create a staged root CA?
Set desiredState to STAGED when creating the CA. Possible states are ENABLED, DISABLED, and STAGED.
Key Management
How do I use my own Cloud KMS key for the Certificate Authority?
Set keySpec.cloudKmsKeyVersion to the full KMS key version resource name. Grant the Private CA service account roles/cloudkms.signerVerifier and roles/viewer on the key. Use dependsOn to ensure IAM bindings are created before the CA.
Configuration
What format should I use for the lifetime property?
Use a duration string in seconds with up to nine fractional digits, terminated by s. Examples show ${10 * 365 * 24 * 3600}s for a 10-year lifetime.
What should I know about the gcsBucket property?
Specify only the bucket name without gs:// prefix or .googleapis.com suffix (e.g., my-bucket). If not specified, a managed bucket is created automatically. This property is immutable.
How do labels work with this resource?
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.
Advanced Features
Can I specify custom CRL and AIA URLs?
Yes, configure userDefinedAccessUrls with crlAccessUrls and aiaIssuingCertificateUrls arrays to specify custom URLs for accessing CA content.
How do I set a custom Subject Key Identifier?
Configure config.subjectKeyId.keyId with your custom key ID value. The custom SKI example shows this with a hex string like 4cf3372289b1d411b999dbb9ebcd44744b6b2fca.

Using a different cloud?

Explore security guides for other cloud providers: