Configure GCP Server TLS Policies

The gcp:networksecurity/serverTlsPolicy:ServerTlsPolicy resource, part of the Pulumi GCP provider, defines how servers authenticate incoming TLS connections: certificate provisioning, client validation requirements, and mTLS enforcement. This guide focuses on three capabilities: server certificate provisioning from external providers, mTLS client validation modes, and trust config integration.

Server TLS policies reference external certificate providers, gRPC endpoints, and Certificate Manager trust configs. The policy itself has no effect until attached to a target HTTPS proxy or endpoint config selector. The examples are intentionally small. Combine them with your own load balancer or proxy configuration.

Provision server certificates from a gRPC endpoint

Load balancers need to present certificates during TLS handshakes. When certificates are managed externally, the policy fetches them from a gRPC endpoint.

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

const _default = new gcp.networksecurity.ServerTlsPolicy("default", {
    name: "my-server-tls-policy",
    labels: {
        foo: "bar",
    },
    description: "my description",
    location: "global",
    allowOpen: false,
    serverCertificate: {
        grpcEndpoint: {
            targetUri: "unix:mypath",
        },
    },
});
import pulumi
import pulumi_gcp as gcp

default = gcp.networksecurity.ServerTlsPolicy("default",
    name="my-server-tls-policy",
    labels={
        "foo": "bar",
    },
    description="my description",
    location="global",
    allow_open=False,
    server_certificate={
        "grpc_endpoint": {
            "target_uri": "unix:mypath",
        },
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := networksecurity.NewServerTlsPolicy(ctx, "default", &networksecurity.ServerTlsPolicyArgs{
			Name: pulumi.String("my-server-tls-policy"),
			Labels: pulumi.StringMap{
				"foo": pulumi.String("bar"),
			},
			Description: pulumi.String("my description"),
			Location:    pulumi.String("global"),
			AllowOpen:   pulumi.Bool(false),
			ServerCertificate: &networksecurity.ServerTlsPolicyServerCertificateArgs{
				GrpcEndpoint: &networksecurity.ServerTlsPolicyServerCertificateGrpcEndpointArgs{
					TargetUri: pulumi.String("unix:mypath"),
				},
			},
		})
		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.NetworkSecurity.ServerTlsPolicy("default", new()
    {
        Name = "my-server-tls-policy",
        Labels = 
        {
            { "foo", "bar" },
        },
        Description = "my description",
        Location = "global",
        AllowOpen = false,
        ServerCertificate = new Gcp.NetworkSecurity.Inputs.ServerTlsPolicyServerCertificateArgs
        {
            GrpcEndpoint = new Gcp.NetworkSecurity.Inputs.ServerTlsPolicyServerCertificateGrpcEndpointArgs
            {
                TargetUri = "unix:mypath",
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.networksecurity.ServerTlsPolicy;
import com.pulumi.gcp.networksecurity.ServerTlsPolicyArgs;
import com.pulumi.gcp.networksecurity.inputs.ServerTlsPolicyServerCertificateArgs;
import com.pulumi.gcp.networksecurity.inputs.ServerTlsPolicyServerCertificateGrpcEndpointArgs;
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 ServerTlsPolicy("default", ServerTlsPolicyArgs.builder()
            .name("my-server-tls-policy")
            .labels(Map.of("foo", "bar"))
            .description("my description")
            .location("global")
            .allowOpen(false)
            .serverCertificate(ServerTlsPolicyServerCertificateArgs.builder()
                .grpcEndpoint(ServerTlsPolicyServerCertificateGrpcEndpointArgs.builder()
                    .targetUri("unix:mypath")
                    .build())
                .build())
            .build());

    }
}
resources:
  default:
    type: gcp:networksecurity:ServerTlsPolicy
    properties:
      name: my-server-tls-policy
      labels:
        foo: bar
      description: my description
      location: global
      allowOpen: 'false'
      serverCertificate:
        grpcEndpoint:
          targetUri: unix:mypath

The serverCertificate block tells the policy where to fetch certificates at runtime. The grpcEndpoint.targetUri points to a certificate provider service. Setting allowOpen to false ensures the server rejects plain text connections.

Validate client certificates with mTLS and SPIFFE

Mutual TLS requires both server and client to present certificates. Service mesh architectures often use SPIFFE for workload identity.

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

const _default = new gcp.networksecurity.ServerTlsPolicy("default", {
    name: "my-server-tls-policy",
    labels: {
        foo: "bar",
    },
    description: "my description",
    allowOpen: false,
    serverCertificate: {
        certificateProviderInstance: {
            pluginInstance: "google_cloud_private_spiffe",
        },
    },
    mtlsPolicy: {
        clientValidationCas: [{
            grpcEndpoint: {
                targetUri: "unix:mypath",
            },
        }],
    },
});
import pulumi
import pulumi_gcp as gcp

default = gcp.networksecurity.ServerTlsPolicy("default",
    name="my-server-tls-policy",
    labels={
        "foo": "bar",
    },
    description="my description",
    allow_open=False,
    server_certificate={
        "certificate_provider_instance": {
            "plugin_instance": "google_cloud_private_spiffe",
        },
    },
    mtls_policy={
        "client_validation_cas": [{
            "grpc_endpoint": {
                "target_uri": "unix:mypath",
            },
        }],
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := networksecurity.NewServerTlsPolicy(ctx, "default", &networksecurity.ServerTlsPolicyArgs{
			Name: pulumi.String("my-server-tls-policy"),
			Labels: pulumi.StringMap{
				"foo": pulumi.String("bar"),
			},
			Description: pulumi.String("my description"),
			AllowOpen:   pulumi.Bool(false),
			ServerCertificate: &networksecurity.ServerTlsPolicyServerCertificateArgs{
				CertificateProviderInstance: &networksecurity.ServerTlsPolicyServerCertificateCertificateProviderInstanceArgs{
					PluginInstance: pulumi.String("google_cloud_private_spiffe"),
				},
			},
			MtlsPolicy: &networksecurity.ServerTlsPolicyMtlsPolicyArgs{
				ClientValidationCas: networksecurity.ServerTlsPolicyMtlsPolicyClientValidationCaArray{
					&networksecurity.ServerTlsPolicyMtlsPolicyClientValidationCaArgs{
						GrpcEndpoint: &networksecurity.ServerTlsPolicyMtlsPolicyClientValidationCaGrpcEndpointArgs{
							TargetUri: pulumi.String("unix:mypath"),
						},
					},
				},
			},
		})
		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.NetworkSecurity.ServerTlsPolicy("default", new()
    {
        Name = "my-server-tls-policy",
        Labels = 
        {
            { "foo", "bar" },
        },
        Description = "my description",
        AllowOpen = false,
        ServerCertificate = new Gcp.NetworkSecurity.Inputs.ServerTlsPolicyServerCertificateArgs
        {
            CertificateProviderInstance = new Gcp.NetworkSecurity.Inputs.ServerTlsPolicyServerCertificateCertificateProviderInstanceArgs
            {
                PluginInstance = "google_cloud_private_spiffe",
            },
        },
        MtlsPolicy = new Gcp.NetworkSecurity.Inputs.ServerTlsPolicyMtlsPolicyArgs
        {
            ClientValidationCas = new[]
            {
                new Gcp.NetworkSecurity.Inputs.ServerTlsPolicyMtlsPolicyClientValidationCaArgs
                {
                    GrpcEndpoint = new Gcp.NetworkSecurity.Inputs.ServerTlsPolicyMtlsPolicyClientValidationCaGrpcEndpointArgs
                    {
                        TargetUri = "unix:mypath",
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.networksecurity.ServerTlsPolicy;
import com.pulumi.gcp.networksecurity.ServerTlsPolicyArgs;
import com.pulumi.gcp.networksecurity.inputs.ServerTlsPolicyServerCertificateArgs;
import com.pulumi.gcp.networksecurity.inputs.ServerTlsPolicyServerCertificateCertificateProviderInstanceArgs;
import com.pulumi.gcp.networksecurity.inputs.ServerTlsPolicyMtlsPolicyArgs;
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 ServerTlsPolicy("default", ServerTlsPolicyArgs.builder()
            .name("my-server-tls-policy")
            .labels(Map.of("foo", "bar"))
            .description("my description")
            .allowOpen(false)
            .serverCertificate(ServerTlsPolicyServerCertificateArgs.builder()
                .certificateProviderInstance(ServerTlsPolicyServerCertificateCertificateProviderInstanceArgs.builder()
                    .pluginInstance("google_cloud_private_spiffe")
                    .build())
                .build())
            .mtlsPolicy(ServerTlsPolicyMtlsPolicyArgs.builder()
                .clientValidationCas(ServerTlsPolicyMtlsPolicyClientValidationCaArgs.builder()
                    .grpcEndpoint(ServerTlsPolicyMtlsPolicyClientValidationCaGrpcEndpointArgs.builder()
                        .targetUri("unix:mypath")
                        .build())
                    .build())
                .build())
            .build());

    }
}
resources:
  default:
    type: gcp:networksecurity:ServerTlsPolicy
    properties:
      name: my-server-tls-policy
      labels:
        foo: bar
      description: my description
      allowOpen: 'false'
      serverCertificate:
        certificateProviderInstance:
          pluginInstance: google_cloud_private_spiffe
      mtlsPolicy:
        clientValidationCas:
          - grpcEndpoint:
              targetUri: unix:mypath

The serverCertificate block provisions server identity using the google_cloud_private_spiffe plugin. The mtlsPolicy.clientValidationCas block specifies where to fetch client CA certificates for validation. This configuration enforces mutual authentication: both parties must present valid certificates.

Allow invalid or missing client certificates

During migration to mTLS, you may need to accept connections from clients without valid certificates.

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

const _default = new gcp.networksecurity.ServerTlsPolicy("default", {
    name: "my-server-tls-policy",
    labels: {
        foo: "bar",
    },
    description: "my description",
    location: "global",
    allowOpen: false,
    mtlsPolicy: {
        clientValidationMode: "ALLOW_INVALID_OR_MISSING_CLIENT_CERT",
    },
});
import pulumi
import pulumi_gcp as gcp

default = gcp.networksecurity.ServerTlsPolicy("default",
    name="my-server-tls-policy",
    labels={
        "foo": "bar",
    },
    description="my description",
    location="global",
    allow_open=False,
    mtls_policy={
        "client_validation_mode": "ALLOW_INVALID_OR_MISSING_CLIENT_CERT",
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := networksecurity.NewServerTlsPolicy(ctx, "default", &networksecurity.ServerTlsPolicyArgs{
			Name: pulumi.String("my-server-tls-policy"),
			Labels: pulumi.StringMap{
				"foo": pulumi.String("bar"),
			},
			Description: pulumi.String("my description"),
			Location:    pulumi.String("global"),
			AllowOpen:   pulumi.Bool(false),
			MtlsPolicy: &networksecurity.ServerTlsPolicyMtlsPolicyArgs{
				ClientValidationMode: pulumi.String("ALLOW_INVALID_OR_MISSING_CLIENT_CERT"),
			},
		})
		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.NetworkSecurity.ServerTlsPolicy("default", new()
    {
        Name = "my-server-tls-policy",
        Labels = 
        {
            { "foo", "bar" },
        },
        Description = "my description",
        Location = "global",
        AllowOpen = false,
        MtlsPolicy = new Gcp.NetworkSecurity.Inputs.ServerTlsPolicyMtlsPolicyArgs
        {
            ClientValidationMode = "ALLOW_INVALID_OR_MISSING_CLIENT_CERT",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.networksecurity.ServerTlsPolicy;
import com.pulumi.gcp.networksecurity.ServerTlsPolicyArgs;
import com.pulumi.gcp.networksecurity.inputs.ServerTlsPolicyMtlsPolicyArgs;
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 ServerTlsPolicy("default", ServerTlsPolicyArgs.builder()
            .name("my-server-tls-policy")
            .labels(Map.of("foo", "bar"))
            .description("my description")
            .location("global")
            .allowOpen(false)
            .mtlsPolicy(ServerTlsPolicyMtlsPolicyArgs.builder()
                .clientValidationMode("ALLOW_INVALID_OR_MISSING_CLIENT_CERT")
                .build())
            .build());

    }
}
resources:
  default:
    type: gcp:networksecurity:ServerTlsPolicy
    properties:
      name: my-server-tls-policy
      labels:
        foo: bar
      description: my description
      location: global
      allowOpen: 'false'
      mtlsPolicy:
        clientValidationMode: ALLOW_INVALID_OR_MISSING_CLIENT_CERT

The clientValidationMode property controls how strictly the server validates client certificates. ALLOW_INVALID_OR_MISSING_CLIENT_CERT accepts connections even when clients don’t present certificates or present invalid ones. This mode supports gradual mTLS adoption.

Validate client certificates against a trust config

Production mTLS deployments validate client certificates against a trust store containing root and intermediate CAs.

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

const project = gcp.organizations.getProject({});
const defaultTrustConfig = new gcp.certificatemanager.TrustConfig("default", {
    name: "my-trust-config",
    description: "sample trust config description",
    location: "global",
    trustStores: [{
        trustAnchors: [{
            pemCertificate: std.file({
                input: "test-fixtures/ca_cert.pem",
            }).then(invoke => invoke.result),
        }],
        intermediateCas: [{
            pemCertificate: std.file({
                input: "test-fixtures/ca_cert.pem",
            }).then(invoke => invoke.result),
        }],
    }],
    labels: {
        foo: "bar",
    },
});
const _default = new gcp.networksecurity.ServerTlsPolicy("default", {
    name: "my-server-tls-policy",
    description: "my description",
    location: "global",
    allowOpen: false,
    mtlsPolicy: {
        clientValidationMode: "REJECT_INVALID",
        clientValidationTrustConfig: pulumi.all([project, defaultTrustConfig.name]).apply(([project, name]) => `projects/${project.number}/locations/global/trustConfigs/${name}`),
    },
    labels: {
        foo: "bar",
    },
});
import pulumi
import pulumi_gcp as gcp
import pulumi_std as std

project = gcp.organizations.get_project()
default_trust_config = gcp.certificatemanager.TrustConfig("default",
    name="my-trust-config",
    description="sample trust config description",
    location="global",
    trust_stores=[{
        "trust_anchors": [{
            "pem_certificate": std.file(input="test-fixtures/ca_cert.pem").result,
        }],
        "intermediate_cas": [{
            "pem_certificate": std.file(input="test-fixtures/ca_cert.pem").result,
        }],
    }],
    labels={
        "foo": "bar",
    })
default = gcp.networksecurity.ServerTlsPolicy("default",
    name="my-server-tls-policy",
    description="my description",
    location="global",
    allow_open=False,
    mtls_policy={
        "client_validation_mode": "REJECT_INVALID",
        "client_validation_trust_config": default_trust_config.name.apply(lambda name: f"projects/{project.number}/locations/global/trustConfigs/{name}"),
    },
    labels={
        "foo": "bar",
    })
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/certificatemanager"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/networksecurity"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
	"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 {
		project, err := organizations.LookupProject(ctx, &organizations.LookupProjectArgs{}, nil)
		if err != nil {
			return err
		}
		invokeFile, err := std.File(ctx, &std.FileArgs{
			Input: "test-fixtures/ca_cert.pem",
		}, nil)
		if err != nil {
			return err
		}
		invokeFile1, err := std.File(ctx, &std.FileArgs{
			Input: "test-fixtures/ca_cert.pem",
		}, nil)
		if err != nil {
			return err
		}
		defaultTrustConfig, err := certificatemanager.NewTrustConfig(ctx, "default", &certificatemanager.TrustConfigArgs{
			Name:        pulumi.String("my-trust-config"),
			Description: pulumi.String("sample trust config description"),
			Location:    pulumi.String("global"),
			TrustStores: certificatemanager.TrustConfigTrustStoreArray{
				&certificatemanager.TrustConfigTrustStoreArgs{
					TrustAnchors: certificatemanager.TrustConfigTrustStoreTrustAnchorArray{
						&certificatemanager.TrustConfigTrustStoreTrustAnchorArgs{
							PemCertificate: pulumi.String(invokeFile.Result),
						},
					},
					IntermediateCas: certificatemanager.TrustConfigTrustStoreIntermediateCaArray{
						&certificatemanager.TrustConfigTrustStoreIntermediateCaArgs{
							PemCertificate: pulumi.String(invokeFile1.Result),
						},
					},
				},
			},
			Labels: pulumi.StringMap{
				"foo": pulumi.String("bar"),
			},
		})
		if err != nil {
			return err
		}
		_, err = networksecurity.NewServerTlsPolicy(ctx, "default", &networksecurity.ServerTlsPolicyArgs{
			Name:        pulumi.String("my-server-tls-policy"),
			Description: pulumi.String("my description"),
			Location:    pulumi.String("global"),
			AllowOpen:   pulumi.Bool(false),
			MtlsPolicy: &networksecurity.ServerTlsPolicyMtlsPolicyArgs{
				ClientValidationMode: pulumi.String("REJECT_INVALID"),
				ClientValidationTrustConfig: defaultTrustConfig.Name.ApplyT(func(name string) (string, error) {
					return fmt.Sprintf("projects/%v/locations/global/trustConfigs/%v", project.Number, name), nil
				}).(pulumi.StringOutput),
			},
			Labels: pulumi.StringMap{
				"foo": pulumi.String("bar"),
			},
		})
		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 project = Gcp.Organizations.GetProject.Invoke();

    var defaultTrustConfig = new Gcp.CertificateManager.TrustConfig("default", new()
    {
        Name = "my-trust-config",
        Description = "sample trust config description",
        Location = "global",
        TrustStores = new[]
        {
            new Gcp.CertificateManager.Inputs.TrustConfigTrustStoreArgs
            {
                TrustAnchors = new[]
                {
                    new Gcp.CertificateManager.Inputs.TrustConfigTrustStoreTrustAnchorArgs
                    {
                        PemCertificate = Std.File.Invoke(new()
                        {
                            Input = "test-fixtures/ca_cert.pem",
                        }).Apply(invoke => invoke.Result),
                    },
                },
                IntermediateCas = new[]
                {
                    new Gcp.CertificateManager.Inputs.TrustConfigTrustStoreIntermediateCaArgs
                    {
                        PemCertificate = Std.File.Invoke(new()
                        {
                            Input = "test-fixtures/ca_cert.pem",
                        }).Apply(invoke => invoke.Result),
                    },
                },
            },
        },
        Labels = 
        {
            { "foo", "bar" },
        },
    });

    var @default = new Gcp.NetworkSecurity.ServerTlsPolicy("default", new()
    {
        Name = "my-server-tls-policy",
        Description = "my description",
        Location = "global",
        AllowOpen = false,
        MtlsPolicy = new Gcp.NetworkSecurity.Inputs.ServerTlsPolicyMtlsPolicyArgs
        {
            ClientValidationMode = "REJECT_INVALID",
            ClientValidationTrustConfig = Output.Tuple(project, defaultTrustConfig.Name).Apply(values =>
            {
                var project = values.Item1;
                var name = values.Item2;
                return $"projects/{project.Apply(getProjectResult => getProjectResult.Number)}/locations/global/trustConfigs/{name}";
            }),
        },
        Labels = 
        {
            { "foo", "bar" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetProjectArgs;
import com.pulumi.gcp.certificatemanager.TrustConfig;
import com.pulumi.gcp.certificatemanager.TrustConfigArgs;
import com.pulumi.gcp.certificatemanager.inputs.TrustConfigTrustStoreArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.FileArgs;
import com.pulumi.gcp.networksecurity.ServerTlsPolicy;
import com.pulumi.gcp.networksecurity.ServerTlsPolicyArgs;
import com.pulumi.gcp.networksecurity.inputs.ServerTlsPolicyMtlsPolicyArgs;
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) {
        final var project = OrganizationsFunctions.getProject(GetProjectArgs.builder()
            .build());

        var defaultTrustConfig = new TrustConfig("defaultTrustConfig", TrustConfigArgs.builder()
            .name("my-trust-config")
            .description("sample trust config description")
            .location("global")
            .trustStores(TrustConfigTrustStoreArgs.builder()
                .trustAnchors(TrustConfigTrustStoreTrustAnchorArgs.builder()
                    .pemCertificate(StdFunctions.file(FileArgs.builder()
                        .input("test-fixtures/ca_cert.pem")
                        .build()).result())
                    .build())
                .intermediateCas(TrustConfigTrustStoreIntermediateCaArgs.builder()
                    .pemCertificate(StdFunctions.file(FileArgs.builder()
                        .input("test-fixtures/ca_cert.pem")
                        .build()).result())
                    .build())
                .build())
            .labels(Map.of("foo", "bar"))
            .build());

        var default_ = new ServerTlsPolicy("default", ServerTlsPolicyArgs.builder()
            .name("my-server-tls-policy")
            .description("my description")
            .location("global")
            .allowOpen(false)
            .mtlsPolicy(ServerTlsPolicyMtlsPolicyArgs.builder()
                .clientValidationMode("REJECT_INVALID")
                .clientValidationTrustConfig(defaultTrustConfig.name().applyValue(_name -> String.format("projects/%s/locations/global/trustConfigs/%s", project.number(),_name)))
                .build())
            .labels(Map.of("foo", "bar"))
            .build());

    }
}
resources:
  default:
    type: gcp:networksecurity:ServerTlsPolicy
    properties:
      name: my-server-tls-policy
      description: my description
      location: global
      allowOpen: 'false'
      mtlsPolicy:
        clientValidationMode: REJECT_INVALID
        clientValidationTrustConfig: projects/${project.number}/locations/global/trustConfigs/${defaultTrustConfig.name}
      labels:
        foo: bar
  defaultTrustConfig:
    type: gcp:certificatemanager:TrustConfig
    name: default
    properties:
      name: my-trust-config
      description: sample trust config description
      location: global
      trustStores:
        - trustAnchors:
            - pemCertificate:
                fn::invoke:
                  function: std:file
                  arguments:
                    input: test-fixtures/ca_cert.pem
                  return: result
          intermediateCas:
            - pemCertificate:
                fn::invoke:
                  function: std:file
                  arguments:
                    input: test-fixtures/ca_cert.pem
                  return: result
      labels:
        foo: bar
variables:
  project:
    fn::invoke:
      function: gcp:organizations:getProject
      arguments: {}

The clientValidationTrustConfig property references a Certificate Manager TrustConfig resource that defines trusted CAs. Setting clientValidationMode to REJECT_INVALID enforces strict validation: connections fail if the client certificate isn’t signed by a trusted CA. This builds on basic mTLS by adding centralized trust management.

Beyond these examples

These snippets focus on specific server TLS policy features: server certificate provisioning, mTLS client validation modes, and trust config integration. They’re intentionally minimal rather than complete load balancer configurations.

The examples reference pre-existing infrastructure such as gRPC certificate provider endpoints, Certificate Manager TrustConfig resources, SPIFFE plugin configuration, and target HTTPS proxies or endpoint config selectors for policy attachment. They focus on policy configuration rather than provisioning the surrounding infrastructure.

To keep things focused, common server TLS patterns are omitted, including:

  • Policy attachment to load balancers or proxies
  • Certificate rotation and renewal
  • Traffic Director-specific configuration
  • Plain text connection handling (allowOpen variations)

These omissions are intentional: the goal is to illustrate how each server TLS feature is wired, not provide drop-in load balancer modules. See the ServerTlsPolicy resource reference for all available configuration options.

Let's configure GCP Server TLS Policies

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Configuration & Attachment
Why isn't my ServerTlsPolicy taking effect?
ServerTlsPolicy doesn’t affect configuration until attached to a target HTTPS proxy or endpoint config selector resource.
Load Balancer Compatibility
What are the differences between Traffic Director and external HTTPS load balancer policies?
For external HTTPS load balancers, mtlsPolicy is required and allowOpen must be set to false. For Traffic Director, mtlsPolicy can be empty and allowOpen can be true to allow plaintext connections.
What's allowOpen and when should I use it?
allowOpen allows plaintext connections alongside encrypted traffic. Use it when upgrading deployments to TLS with mixed TLS and non-TLS traffic on port 80. This field only applies to Traffic Director policies and must be false for external HTTPS load balancers.
mTLS & Certificate Configuration
How do I configure mTLS?
Configure mTLS using either mtlsPolicy (for peer validation certificates) or serverCertificate (for client identity provisioning). The presence of serverCertificate dictates mTLS. For certificate validation, use mtlsPolicy with clientValidationMode and clientValidationTrustConfig pointing to a TrustConfig resource.
Resource Properties & Lifecycle
What properties can't I change after creation?
The name and project properties are immutable and cannot be changed after the ServerTlsPolicy is created.
What's the default location for ServerTlsPolicy?
The default location is global.

Using a different cloud?

Explore security guides for other cloud providers: