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 FREEFrequently Asked Questions
Deletion & Lifecycle
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.skipGracePeriod to true deletes the CA immediately with no recovery option. Defaults to false.ignoreActiveCertificatesOnDeletion to true to allow deletion even with unrevoked or unexpired certificates. Use with care. Defaults to false.certificateAuthorityId, config, keySpec, location, pool, project, gcsBucket, lifetime, and type.CA Types & Hierarchy
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.pemCaCertificate.desiredState to STAGED when creating the CA. Possible states are ENABLED, DISABLED, and STAGED.Key Management
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
s. Examples show ${10 * 365 * 24 * 3600}s for a 10-year lifetime.gs:// prefix or .googleapis.com suffix (e.g., my-bucket). If not specified, a managed bucket is created automatically. This property is immutable.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
userDefinedAccessUrls with crlAccessUrls and aiaIssuingCertificateUrls arrays to specify custom URLs for accessing CA content.config.subjectKeyId.keyId with your custom key ID value. The custom SKI example shows this with a hex string like 4cf3372289b1d411b999dbb9ebcd44744b6b2fca.