The gcp:certificatemanager/certificate:Certificate resource, part of the Pulumi GCP provider, defines TLS certificates for Google Cloud load balancers and services: their provisioning method, domain coverage, and geographic scope. This guide focuses on four capabilities: Google-managed certificates with DNS authorization, self-managed certificate uploads, private CA integration, and regional and client authentication scopes.
Certificates require DNS control for domain validation, may reference Certificate Authority Service pools for private CA issuance, or require PEM-encoded certificate files for self-managed uploads. The examples are intentionally small. Combine them with your own load balancers, DNS configuration, and certificate management workflows.
Provision Google-managed certificates with DNS authorization
Most teams start with Google-managed certificates that handle provisioning and renewal automatically. DNS authorization proves domain ownership by creating validation records that Google checks before issuing certificates.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const instance = new gcp.certificatemanager.DnsAuthorization("instance", {
name: "dns-auth",
description: "The default dnss",
domain: "subdomain.hashicorptest.com",
});
const instance2 = new gcp.certificatemanager.DnsAuthorization("instance2", {
name: "dns-auth2",
description: "The default dnss",
domain: "subdomain2.hashicorptest.com",
});
const _default = new gcp.certificatemanager.Certificate("default", {
name: "dns-cert",
description: "The default cert",
scope: "EDGE_CACHE",
labels: {
env: "test",
},
managed: {
domains: [
instance.domain,
instance2.domain,
],
dnsAuthorizations: [
instance.id,
instance2.id,
],
},
});
import pulumi
import pulumi_gcp as gcp
instance = gcp.certificatemanager.DnsAuthorization("instance",
name="dns-auth",
description="The default dnss",
domain="subdomain.hashicorptest.com")
instance2 = gcp.certificatemanager.DnsAuthorization("instance2",
name="dns-auth2",
description="The default dnss",
domain="subdomain2.hashicorptest.com")
default = gcp.certificatemanager.Certificate("default",
name="dns-cert",
description="The default cert",
scope="EDGE_CACHE",
labels={
"env": "test",
},
managed={
"domains": [
instance.domain,
instance2.domain,
],
"dns_authorizations": [
instance.id,
instance2.id,
],
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/certificatemanager"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
instance, err := certificatemanager.NewDnsAuthorization(ctx, "instance", &certificatemanager.DnsAuthorizationArgs{
Name: pulumi.String("dns-auth"),
Description: pulumi.String("The default dnss"),
Domain: pulumi.String("subdomain.hashicorptest.com"),
})
if err != nil {
return err
}
instance2, err := certificatemanager.NewDnsAuthorization(ctx, "instance2", &certificatemanager.DnsAuthorizationArgs{
Name: pulumi.String("dns-auth2"),
Description: pulumi.String("The default dnss"),
Domain: pulumi.String("subdomain2.hashicorptest.com"),
})
if err != nil {
return err
}
_, err = certificatemanager.NewCertificate(ctx, "default", &certificatemanager.CertificateArgs{
Name: pulumi.String("dns-cert"),
Description: pulumi.String("The default cert"),
Scope: pulumi.String("EDGE_CACHE"),
Labels: pulumi.StringMap{
"env": pulumi.String("test"),
},
Managed: &certificatemanager.CertificateManagedArgs{
Domains: pulumi.StringArray{
instance.Domain,
instance2.Domain,
},
DnsAuthorizations: pulumi.StringArray{
instance.ID(),
instance2.ID(),
},
},
})
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 instance = new Gcp.CertificateManager.DnsAuthorization("instance", new()
{
Name = "dns-auth",
Description = "The default dnss",
Domain = "subdomain.hashicorptest.com",
});
var instance2 = new Gcp.CertificateManager.DnsAuthorization("instance2", new()
{
Name = "dns-auth2",
Description = "The default dnss",
Domain = "subdomain2.hashicorptest.com",
});
var @default = new Gcp.CertificateManager.Certificate("default", new()
{
Name = "dns-cert",
Description = "The default cert",
Scope = "EDGE_CACHE",
Labels =
{
{ "env", "test" },
},
Managed = new Gcp.CertificateManager.Inputs.CertificateManagedArgs
{
Domains = new[]
{
instance.Domain,
instance2.Domain,
},
DnsAuthorizations = new[]
{
instance.Id,
instance2.Id,
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.certificatemanager.DnsAuthorization;
import com.pulumi.gcp.certificatemanager.DnsAuthorizationArgs;
import com.pulumi.gcp.certificatemanager.Certificate;
import com.pulumi.gcp.certificatemanager.CertificateArgs;
import com.pulumi.gcp.certificatemanager.inputs.CertificateManagedArgs;
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 instance = new DnsAuthorization("instance", DnsAuthorizationArgs.builder()
.name("dns-auth")
.description("The default dnss")
.domain("subdomain.hashicorptest.com")
.build());
var instance2 = new DnsAuthorization("instance2", DnsAuthorizationArgs.builder()
.name("dns-auth2")
.description("The default dnss")
.domain("subdomain2.hashicorptest.com")
.build());
var default_ = new Certificate("default", CertificateArgs.builder()
.name("dns-cert")
.description("The default cert")
.scope("EDGE_CACHE")
.labels(Map.of("env", "test"))
.managed(CertificateManagedArgs.builder()
.domains(
instance.domain(),
instance2.domain())
.dnsAuthorizations(
instance.id(),
instance2.id())
.build())
.build());
}
}
resources:
default:
type: gcp:certificatemanager:Certificate
properties:
name: dns-cert
description: The default cert
scope: EDGE_CACHE
labels:
env: test
managed:
domains:
- ${instance.domain}
- ${instance2.domain}
dnsAuthorizations:
- ${instance.id}
- ${instance2.id}
instance:
type: gcp:certificatemanager:DnsAuthorization
properties:
name: dns-auth
description: The default dnss
domain: subdomain.hashicorptest.com
instance2:
type: gcp:certificatemanager:DnsAuthorization
properties:
name: dns-auth2
description: The default dnss
domain: subdomain2.hashicorptest.com
The managed block configures automatic certificate provisioning. The domains property lists the domains to cover, and dnsAuthorizations references DnsAuthorization resources that define the DNS validation records. The scope property controls where the certificate is served; EDGE_CACHE serves from edge locations for lower latency. Google handles renewal automatically as long as DNS authorization remains valid.
Upload self-managed certificates for regional use
Applications that already have certificates from external CAs or need specific certificate properties can upload PEM-encoded files directly.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
import * as std from "@pulumi/std";
const _default = new gcp.certificatemanager.Certificate("default", {
name: "self-managed-cert",
description: "Regional cert",
location: "us-central1",
selfManaged: {
pemCertificate: std.file({
input: "test-fixtures/cert.pem",
}).then(invoke => invoke.result),
pemPrivateKey: std.file({
input: "test-fixtures/private-key.pem",
}).then(invoke => invoke.result),
},
});
import pulumi
import pulumi_gcp as gcp
import pulumi_std as std
default = gcp.certificatemanager.Certificate("default",
name="self-managed-cert",
description="Regional cert",
location="us-central1",
self_managed={
"pem_certificate": std.file(input="test-fixtures/cert.pem").result,
"pem_private_key": std.file(input="test-fixtures/private-key.pem").result,
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/certificatemanager"
"github.com/pulumi/pulumi-std/sdk/go/std"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
invokeFile, err := std.File(ctx, &std.FileArgs{
Input: "test-fixtures/cert.pem",
}, nil)
if err != nil {
return err
}
invokeFile1, err := std.File(ctx, &std.FileArgs{
Input: "test-fixtures/private-key.pem",
}, nil)
if err != nil {
return err
}
_, err = certificatemanager.NewCertificate(ctx, "default", &certificatemanager.CertificateArgs{
Name: pulumi.String("self-managed-cert"),
Description: pulumi.String("Regional cert"),
Location: pulumi.String("us-central1"),
SelfManaged: &certificatemanager.CertificateSelfManagedArgs{
PemCertificate: pulumi.String(invokeFile.Result),
PemPrivateKey: pulumi.String(invokeFile1.Result),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
using Std = Pulumi.Std;
return await Deployment.RunAsync(() =>
{
var @default = new Gcp.CertificateManager.Certificate("default", new()
{
Name = "self-managed-cert",
Description = "Regional cert",
Location = "us-central1",
SelfManaged = new Gcp.CertificateManager.Inputs.CertificateSelfManagedArgs
{
PemCertificate = Std.File.Invoke(new()
{
Input = "test-fixtures/cert.pem",
}).Apply(invoke => invoke.Result),
PemPrivateKey = Std.File.Invoke(new()
{
Input = "test-fixtures/private-key.pem",
}).Apply(invoke => invoke.Result),
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.certificatemanager.Certificate;
import com.pulumi.gcp.certificatemanager.CertificateArgs;
import com.pulumi.gcp.certificatemanager.inputs.CertificateSelfManagedArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.FileArgs;
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 Certificate("default", CertificateArgs.builder()
.name("self-managed-cert")
.description("Regional cert")
.location("us-central1")
.selfManaged(CertificateSelfManagedArgs.builder()
.pemCertificate(StdFunctions.file(FileArgs.builder()
.input("test-fixtures/cert.pem")
.build()).result())
.pemPrivateKey(StdFunctions.file(FileArgs.builder()
.input("test-fixtures/private-key.pem")
.build()).result())
.build())
.build());
}
}
resources:
default:
type: gcp:certificatemanager:Certificate
properties:
name: self-managed-cert
description: Regional cert
location: us-central1
selfManaged:
pemCertificate:
fn::invoke:
function: std:file
arguments:
input: test-fixtures/cert.pem
return: result
pemPrivateKey:
fn::invoke:
function: std:file
arguments:
input: test-fixtures/private-key.pem
return: result
The selfManaged block accepts PEM-encoded certificate and private key data. The location property restricts the certificate to a specific region rather than serving globally. Unlike managed certificates, you’re responsible for renewing self-managed certificates before they expire.
Issue certificates from private Certificate Authority
Organizations with private Certificate Authority Service (CAS) pools can configure Certificate Manager to issue certificates from their internal CA infrastructure.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const pool = new gcp.certificateauthority.CaPool("pool", {
name: "ca-pool",
location: "us-central1",
tier: "ENTERPRISE",
});
const caAuthority = new gcp.certificateauthority.Authority("ca_authority", {
location: "us-central1",
pool: pool.name,
certificateAuthorityId: "ca-authority",
config: {
subjectConfig: {
subject: {
organization: "HashiCorp",
commonName: "my-certificate-authority",
},
subjectAltName: {
dnsNames: ["hashicorp.com"],
},
},
x509Config: {
caOptions: {
isCa: true,
},
keyUsage: {
baseKeyUsage: {
certSign: true,
crlSign: true,
},
extendedKeyUsage: {
serverAuth: true,
},
},
},
},
keySpec: {
algorithm: "RSA_PKCS1_4096_SHA256",
},
deletionProtection: false,
skipGracePeriod: true,
ignoreActiveCertificatesOnDeletion: true,
});
// creating certificate_issuance_config to use it in the managed certificate
const issuanceconfig = new gcp.certificatemanager.CertificateIssuanceConfig("issuanceconfig", {
name: "issuance-config",
description: "sample description for the certificate issuanceConfigs",
certificateAuthorityConfig: {
certificateAuthorityServiceConfig: {
caPool: pool.id,
},
},
lifetime: "1814400s",
rotationWindowPercentage: 34,
keyAlgorithm: "ECDSA_P256",
}, {
dependsOn: [caAuthority],
});
const _default = new gcp.certificatemanager.Certificate("default", {
name: "issuance-config-cert",
description: "The default cert",
scope: "EDGE_CACHE",
managed: {
domains: ["terraform.subdomain1.com"],
issuanceConfig: issuanceconfig.id,
},
});
import pulumi
import pulumi_gcp as gcp
pool = gcp.certificateauthority.CaPool("pool",
name="ca-pool",
location="us-central1",
tier="ENTERPRISE")
ca_authority = gcp.certificateauthority.Authority("ca_authority",
location="us-central1",
pool=pool.name,
certificate_authority_id="ca-authority",
config={
"subject_config": {
"subject": {
"organization": "HashiCorp",
"common_name": "my-certificate-authority",
},
"subject_alt_name": {
"dns_names": ["hashicorp.com"],
},
},
"x509_config": {
"ca_options": {
"is_ca": True,
},
"key_usage": {
"base_key_usage": {
"cert_sign": True,
"crl_sign": True,
},
"extended_key_usage": {
"server_auth": True,
},
},
},
},
key_spec={
"algorithm": "RSA_PKCS1_4096_SHA256",
},
deletion_protection=False,
skip_grace_period=True,
ignore_active_certificates_on_deletion=True)
# creating certificate_issuance_config to use it in the managed certificate
issuanceconfig = gcp.certificatemanager.CertificateIssuanceConfig("issuanceconfig",
name="issuance-config",
description="sample description for the certificate issuanceConfigs",
certificate_authority_config={
"certificate_authority_service_config": {
"ca_pool": pool.id,
},
},
lifetime="1814400s",
rotation_window_percentage=34,
key_algorithm="ECDSA_P256",
opts = pulumi.ResourceOptions(depends_on=[ca_authority]))
default = gcp.certificatemanager.Certificate("default",
name="issuance-config-cert",
description="The default cert",
scope="EDGE_CACHE",
managed={
"domains": ["terraform.subdomain1.com"],
"issuance_config": issuanceconfig.id,
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/certificateauthority"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/certificatemanager"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
pool, err := certificateauthority.NewCaPool(ctx, "pool", &certificateauthority.CaPoolArgs{
Name: pulumi.String("ca-pool"),
Location: pulumi.String("us-central1"),
Tier: pulumi.String("ENTERPRISE"),
})
if err != nil {
return err
}
caAuthority, err := certificateauthority.NewAuthority(ctx, "ca_authority", &certificateauthority.AuthorityArgs{
Location: pulumi.String("us-central1"),
Pool: pool.Name,
CertificateAuthorityId: pulumi.String("ca-authority"),
Config: &certificateauthority.AuthorityConfigArgs{
SubjectConfig: &certificateauthority.AuthorityConfigSubjectConfigArgs{
Subject: &certificateauthority.AuthorityConfigSubjectConfigSubjectArgs{
Organization: pulumi.String("HashiCorp"),
CommonName: pulumi.String("my-certificate-authority"),
},
SubjectAltName: &certificateauthority.AuthorityConfigSubjectConfigSubjectAltNameArgs{
DnsNames: pulumi.StringArray{
pulumi.String("hashicorp.com"),
},
},
},
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{
ServerAuth: pulumi.Bool(true),
},
},
},
},
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
}
// creating certificate_issuance_config to use it in the managed certificate
issuanceconfig, err := certificatemanager.NewCertificateIssuanceConfig(ctx, "issuanceconfig", &certificatemanager.CertificateIssuanceConfigArgs{
Name: pulumi.String("issuance-config"),
Description: pulumi.String("sample description for the certificate issuanceConfigs"),
CertificateAuthorityConfig: &certificatemanager.CertificateIssuanceConfigCertificateAuthorityConfigArgs{
CertificateAuthorityServiceConfig: &certificatemanager.CertificateIssuanceConfigCertificateAuthorityConfigCertificateAuthorityServiceConfigArgs{
CaPool: pool.ID(),
},
},
Lifetime: pulumi.String("1814400s"),
RotationWindowPercentage: pulumi.Int(34),
KeyAlgorithm: pulumi.String("ECDSA_P256"),
}, pulumi.DependsOn([]pulumi.Resource{
caAuthority,
}))
if err != nil {
return err
}
_, err = certificatemanager.NewCertificate(ctx, "default", &certificatemanager.CertificateArgs{
Name: pulumi.String("issuance-config-cert"),
Description: pulumi.String("The default cert"),
Scope: pulumi.String("EDGE_CACHE"),
Managed: &certificatemanager.CertificateManagedArgs{
Domains: pulumi.StringArray{
pulumi.String("terraform.subdomain1.com"),
},
IssuanceConfig: issuanceconfig.ID(),
},
})
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 pool = new Gcp.CertificateAuthority.CaPool("pool", new()
{
Name = "ca-pool",
Location = "us-central1",
Tier = "ENTERPRISE",
});
var caAuthority = new Gcp.CertificateAuthority.Authority("ca_authority", new()
{
Location = "us-central1",
Pool = pool.Name,
CertificateAuthorityId = "ca-authority",
Config = new Gcp.CertificateAuthority.Inputs.AuthorityConfigArgs
{
SubjectConfig = new Gcp.CertificateAuthority.Inputs.AuthorityConfigSubjectConfigArgs
{
Subject = new Gcp.CertificateAuthority.Inputs.AuthorityConfigSubjectConfigSubjectArgs
{
Organization = "HashiCorp",
CommonName = "my-certificate-authority",
},
SubjectAltName = new Gcp.CertificateAuthority.Inputs.AuthorityConfigSubjectConfigSubjectAltNameArgs
{
DnsNames = new[]
{
"hashicorp.com",
},
},
},
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 = new Gcp.CertificateAuthority.Inputs.AuthorityConfigX509ConfigKeyUsageExtendedKeyUsageArgs
{
ServerAuth = true,
},
},
},
},
KeySpec = new Gcp.CertificateAuthority.Inputs.AuthorityKeySpecArgs
{
Algorithm = "RSA_PKCS1_4096_SHA256",
},
DeletionProtection = false,
SkipGracePeriod = true,
IgnoreActiveCertificatesOnDeletion = true,
});
// creating certificate_issuance_config to use it in the managed certificate
var issuanceconfig = new Gcp.CertificateManager.CertificateIssuanceConfig("issuanceconfig", new()
{
Name = "issuance-config",
Description = "sample description for the certificate issuanceConfigs",
CertificateAuthorityConfig = new Gcp.CertificateManager.Inputs.CertificateIssuanceConfigCertificateAuthorityConfigArgs
{
CertificateAuthorityServiceConfig = new Gcp.CertificateManager.Inputs.CertificateIssuanceConfigCertificateAuthorityConfigCertificateAuthorityServiceConfigArgs
{
CaPool = pool.Id,
},
},
Lifetime = "1814400s",
RotationWindowPercentage = 34,
KeyAlgorithm = "ECDSA_P256",
}, new CustomResourceOptions
{
DependsOn =
{
caAuthority,
},
});
var @default = new Gcp.CertificateManager.Certificate("default", new()
{
Name = "issuance-config-cert",
Description = "The default cert",
Scope = "EDGE_CACHE",
Managed = new Gcp.CertificateManager.Inputs.CertificateManagedArgs
{
Domains = new[]
{
"terraform.subdomain1.com",
},
IssuanceConfig = issuanceconfig.Id,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.certificateauthority.CaPool;
import com.pulumi.gcp.certificateauthority.CaPoolArgs;
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.AuthorityConfigSubjectConfigSubjectAltNameArgs;
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.certificatemanager.CertificateIssuanceConfig;
import com.pulumi.gcp.certificatemanager.CertificateIssuanceConfigArgs;
import com.pulumi.gcp.certificatemanager.inputs.CertificateIssuanceConfigCertificateAuthorityConfigArgs;
import com.pulumi.gcp.certificatemanager.inputs.CertificateIssuanceConfigCertificateAuthorityConfigCertificateAuthorityServiceConfigArgs;
import com.pulumi.gcp.certificatemanager.Certificate;
import com.pulumi.gcp.certificatemanager.CertificateArgs;
import com.pulumi.gcp.certificatemanager.inputs.CertificateManagedArgs;
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 pool = new CaPool("pool", CaPoolArgs.builder()
.name("ca-pool")
.location("us-central1")
.tier("ENTERPRISE")
.build());
var caAuthority = new Authority("caAuthority", AuthorityArgs.builder()
.location("us-central1")
.pool(pool.name())
.certificateAuthorityId("ca-authority")
.config(AuthorityConfigArgs.builder()
.subjectConfig(AuthorityConfigSubjectConfigArgs.builder()
.subject(AuthorityConfigSubjectConfigSubjectArgs.builder()
.organization("HashiCorp")
.commonName("my-certificate-authority")
.build())
.subjectAltName(AuthorityConfigSubjectConfigSubjectAltNameArgs.builder()
.dnsNames("hashicorp.com")
.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()
.serverAuth(true)
.build())
.build())
.build())
.build())
.keySpec(AuthorityKeySpecArgs.builder()
.algorithm("RSA_PKCS1_4096_SHA256")
.build())
.deletionProtection(false)
.skipGracePeriod(true)
.ignoreActiveCertificatesOnDeletion(true)
.build());
// creating certificate_issuance_config to use it in the managed certificate
var issuanceconfig = new CertificateIssuanceConfig("issuanceconfig", CertificateIssuanceConfigArgs.builder()
.name("issuance-config")
.description("sample description for the certificate issuanceConfigs")
.certificateAuthorityConfig(CertificateIssuanceConfigCertificateAuthorityConfigArgs.builder()
.certificateAuthorityServiceConfig(CertificateIssuanceConfigCertificateAuthorityConfigCertificateAuthorityServiceConfigArgs.builder()
.caPool(pool.id())
.build())
.build())
.lifetime("1814400s")
.rotationWindowPercentage(34)
.keyAlgorithm("ECDSA_P256")
.build(), CustomResourceOptions.builder()
.dependsOn(caAuthority)
.build());
var default_ = new Certificate("default", CertificateArgs.builder()
.name("issuance-config-cert")
.description("The default cert")
.scope("EDGE_CACHE")
.managed(CertificateManagedArgs.builder()
.domains("terraform.subdomain1.com")
.issuanceConfig(issuanceconfig.id())
.build())
.build());
}
}
resources:
default:
type: gcp:certificatemanager:Certificate
properties:
name: issuance-config-cert
description: The default cert
scope: EDGE_CACHE
managed:
domains:
- terraform.subdomain1.com
issuanceConfig: ${issuanceconfig.id}
# creating certificate_issuance_config to use it in the managed certificate
issuanceconfig:
type: gcp:certificatemanager:CertificateIssuanceConfig
properties:
name: issuance-config
description: sample description for the certificate issuanceConfigs
certificateAuthorityConfig:
certificateAuthorityServiceConfig:
caPool: ${pool.id}
lifetime: 1814400s
rotationWindowPercentage: 34
keyAlgorithm: ECDSA_P256
options:
dependsOn:
- ${caAuthority}
pool:
type: gcp:certificateauthority:CaPool
properties:
name: ca-pool
location: us-central1
tier: ENTERPRISE
caAuthority:
type: gcp:certificateauthority:Authority
name: ca_authority
properties:
location: us-central1
pool: ${pool.name}
certificateAuthorityId: ca-authority
config:
subjectConfig:
subject:
organization: HashiCorp
commonName: my-certificate-authority
subjectAltName:
dnsNames:
- hashicorp.com
x509Config:
caOptions:
isCa: true
keyUsage:
baseKeyUsage:
certSign: true
crlSign: true
extendedKeyUsage:
serverAuth: true
keySpec:
algorithm: RSA_PKCS1_4096_SHA256
deletionProtection: false
skipGracePeriod: true
ignoreActiveCertificatesOnDeletion: true
The issuanceConfig property references a CertificateIssuanceConfig resource that connects to your CA pool. Certificate Manager requests certificates from your private CA instead of a public CA. The lifetime and rotationWindowPercentage properties control certificate validity and automatic rotation timing.
Deploy regional certificates with DNS authorization
Regional certificates serve traffic from specific GCP regions rather than globally, useful for applications with regional load balancers or compliance requirements.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const instance = new gcp.certificatemanager.DnsAuthorization("instance", {
name: "dns-auth",
location: "us-central1",
description: "The default dnss",
domain: "subdomain.hashicorptest.com",
});
const _default = new gcp.certificatemanager.Certificate("default", {
name: "dns-cert",
description: "regional managed certs",
location: "us-central1",
managed: {
domains: [instance.domain],
dnsAuthorizations: [instance.id],
},
});
import pulumi
import pulumi_gcp as gcp
instance = gcp.certificatemanager.DnsAuthorization("instance",
name="dns-auth",
location="us-central1",
description="The default dnss",
domain="subdomain.hashicorptest.com")
default = gcp.certificatemanager.Certificate("default",
name="dns-cert",
description="regional managed certs",
location="us-central1",
managed={
"domains": [instance.domain],
"dns_authorizations": [instance.id],
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/certificatemanager"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
instance, err := certificatemanager.NewDnsAuthorization(ctx, "instance", &certificatemanager.DnsAuthorizationArgs{
Name: pulumi.String("dns-auth"),
Location: pulumi.String("us-central1"),
Description: pulumi.String("The default dnss"),
Domain: pulumi.String("subdomain.hashicorptest.com"),
})
if err != nil {
return err
}
_, err = certificatemanager.NewCertificate(ctx, "default", &certificatemanager.CertificateArgs{
Name: pulumi.String("dns-cert"),
Description: pulumi.String("regional managed certs"),
Location: pulumi.String("us-central1"),
Managed: &certificatemanager.CertificateManagedArgs{
Domains: pulumi.StringArray{
instance.Domain,
},
DnsAuthorizations: pulumi.StringArray{
instance.ID(),
},
},
})
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 instance = new Gcp.CertificateManager.DnsAuthorization("instance", new()
{
Name = "dns-auth",
Location = "us-central1",
Description = "The default dnss",
Domain = "subdomain.hashicorptest.com",
});
var @default = new Gcp.CertificateManager.Certificate("default", new()
{
Name = "dns-cert",
Description = "regional managed certs",
Location = "us-central1",
Managed = new Gcp.CertificateManager.Inputs.CertificateManagedArgs
{
Domains = new[]
{
instance.Domain,
},
DnsAuthorizations = new[]
{
instance.Id,
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.certificatemanager.DnsAuthorization;
import com.pulumi.gcp.certificatemanager.DnsAuthorizationArgs;
import com.pulumi.gcp.certificatemanager.Certificate;
import com.pulumi.gcp.certificatemanager.CertificateArgs;
import com.pulumi.gcp.certificatemanager.inputs.CertificateManagedArgs;
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 instance = new DnsAuthorization("instance", DnsAuthorizationArgs.builder()
.name("dns-auth")
.location("us-central1")
.description("The default dnss")
.domain("subdomain.hashicorptest.com")
.build());
var default_ = new Certificate("default", CertificateArgs.builder()
.name("dns-cert")
.description("regional managed certs")
.location("us-central1")
.managed(CertificateManagedArgs.builder()
.domains(instance.domain())
.dnsAuthorizations(instance.id())
.build())
.build());
}
}
resources:
default:
type: gcp:certificatemanager:Certificate
properties:
name: dns-cert
description: regional managed certs
location: us-central1
managed:
domains:
- ${instance.domain}
dnsAuthorizations:
- ${instance.id}
instance:
type: gcp:certificatemanager:DnsAuthorization
properties:
name: dns-auth
location: us-central1
description: The default dnss
domain: subdomain.hashicorptest.com
The location property restricts both the certificate and its DNS authorization to a specific region. Regional certificates work with regional load balancers and can help meet data residency requirements. The DnsAuthorization must be in the same region as the certificate.
Configure client authentication certificates for mTLS
Backend mutual TLS (mTLS) requires load balancers to present client certificates when connecting to backend services that verify client identity.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
import * as std from "@pulumi/std";
const _default = new gcp.certificatemanager.Certificate("default", {
name: "client-auth-cert",
description: "Global cert",
scope: "CLIENT_AUTH",
selfManaged: {
pemCertificate: std.file({
input: "test-fixtures/cert.pem",
}).then(invoke => invoke.result),
pemPrivateKey: std.file({
input: "test-fixtures/private-key.pem",
}).then(invoke => invoke.result),
},
});
import pulumi
import pulumi_gcp as gcp
import pulumi_std as std
default = gcp.certificatemanager.Certificate("default",
name="client-auth-cert",
description="Global cert",
scope="CLIENT_AUTH",
self_managed={
"pem_certificate": std.file(input="test-fixtures/cert.pem").result,
"pem_private_key": std.file(input="test-fixtures/private-key.pem").result,
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/certificatemanager"
"github.com/pulumi/pulumi-std/sdk/go/std"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
invokeFile, err := std.File(ctx, &std.FileArgs{
Input: "test-fixtures/cert.pem",
}, nil)
if err != nil {
return err
}
invokeFile1, err := std.File(ctx, &std.FileArgs{
Input: "test-fixtures/private-key.pem",
}, nil)
if err != nil {
return err
}
_, err = certificatemanager.NewCertificate(ctx, "default", &certificatemanager.CertificateArgs{
Name: pulumi.String("client-auth-cert"),
Description: pulumi.String("Global cert"),
Scope: pulumi.String("CLIENT_AUTH"),
SelfManaged: &certificatemanager.CertificateSelfManagedArgs{
PemCertificate: pulumi.String(invokeFile.Result),
PemPrivateKey: pulumi.String(invokeFile1.Result),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
using Std = Pulumi.Std;
return await Deployment.RunAsync(() =>
{
var @default = new Gcp.CertificateManager.Certificate("default", new()
{
Name = "client-auth-cert",
Description = "Global cert",
Scope = "CLIENT_AUTH",
SelfManaged = new Gcp.CertificateManager.Inputs.CertificateSelfManagedArgs
{
PemCertificate = Std.File.Invoke(new()
{
Input = "test-fixtures/cert.pem",
}).Apply(invoke => invoke.Result),
PemPrivateKey = Std.File.Invoke(new()
{
Input = "test-fixtures/private-key.pem",
}).Apply(invoke => invoke.Result),
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.certificatemanager.Certificate;
import com.pulumi.gcp.certificatemanager.CertificateArgs;
import com.pulumi.gcp.certificatemanager.inputs.CertificateSelfManagedArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.FileArgs;
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 Certificate("default", CertificateArgs.builder()
.name("client-auth-cert")
.description("Global cert")
.scope("CLIENT_AUTH")
.selfManaged(CertificateSelfManagedArgs.builder()
.pemCertificate(StdFunctions.file(FileArgs.builder()
.input("test-fixtures/cert.pem")
.build()).result())
.pemPrivateKey(StdFunctions.file(FileArgs.builder()
.input("test-fixtures/private-key.pem")
.build()).result())
.build())
.build());
}
}
resources:
default:
type: gcp:certificatemanager:Certificate
properties:
name: client-auth-cert
description: Global cert
scope: CLIENT_AUTH
selfManaged:
pemCertificate:
fn::invoke:
function: std:file
arguments:
input: test-fixtures/cert.pem
return: result
pemPrivateKey:
fn::invoke:
function: std:file
arguments:
input: test-fixtures/private-key.pem
return: result
The scope property set to CLIENT_AUTH designates this certificate for load balancer-to-backend authentication rather than client-to-load-balancer. The load balancer presents this certificate when connecting to backends configured for mTLS. Backend services must be configured to require and validate client certificates.
Beyond these examples
These snippets focus on specific certificate-level features: Google-managed and self-managed certificate types, DNS authorization and private CA issuance, and global, regional, and client authentication scopes. They’re intentionally minimal rather than full TLS configurations.
The examples may reference pre-existing infrastructure such as DNS control for domain validation, Certificate Authority Service pools for private CA examples, and PEM certificate and private key files for self-managed examples. They focus on configuring the certificate rather than provisioning the surrounding infrastructure.
To keep things focused, common certificate patterns are omitted, including:
- Certificate rotation and renewal monitoring
- Load balancer attachment and SSL policy configuration
- Certificate map creation for multi-domain routing
- Wildcard certificate configuration
These omissions are intentional: the goal is to illustrate how each certificate feature is wired, not provide drop-in TLS modules. See the Certificate Manager Certificate resource reference for all available configuration options.
Let's create GCP Certificate Manager Certificates
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Certificate Types & Management
managed with domains and either dnsAuthorizations or issuanceConfig. Self-managed certificates are uploaded by you using selfManaged with pemCertificate and pemPrivateKey, and you’re responsible for renewing them before expiration.managed property with domains and either dnsAuthorizations (for DNS validation) or issuanceConfig (for Certificate Authority integration). Certificate Manager will automatically provision and renew the certificate.selfManaged property with pemCertificate and pemPrivateKey containing your certificate and private key data. You’re responsible for updating the certificate before it expires.You have four scope options:
- DEFAULT - Served from core Google datacenters (use if unsure)
- EDGE_CACHE - Served from Edge Points of Presence for lower latency
- ALL_REGIONS - Served from all GCP regions (requires global certificates)
- CLIENT_AUTH - Used for backend mTLS when load balancer presents cert to backend
Configuration & Constraints
name, location, scope, managed, and selfManaged. Changing any of these requires recreating the certificate.[a-zA-Z][a-zA-Z0-9_-]*. The first character must be a letter, and subsequent characters can be letters, digits, dashes, or underscores.labels field is non-authoritative and only manages labels present in your configuration. Other clients and services may add additional labels. Use the effectiveLabels output to see all labels actually present on the resource.Regional & Global Deployment
location (e.g., us-central1). Global certificates are deployed across Google’s network by omitting location or setting it to global.location or set it to global when using ALL_REGIONS scope.