Configure AWS KMS Custom Key Stores

The aws:kms/customKeyStore:CustomKeyStore resource, part of the Pulumi AWS provider, defines a KMS custom key store that delegates cryptographic operations to CloudHSM clusters or external key management systems. This guide focuses on two capabilities: CloudHSM cluster integration and external key store connectivity via VPC or public endpoints.

Custom key stores require either CloudHSM clusters with trust anchor certificates or external XKS proxy endpoints with authentication credentials. The examples are intentionally small. Combine them with your own key management infrastructure and security policies.

Connect KMS to a CloudHSM cluster

Organizations with strict key management requirements use CloudHSM to maintain physical control over cryptographic operations, bridging KMS APIs with CloudHSM hardware.

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

const test = new aws.kms.CustomKeyStore("test", {
    cloudHsmClusterId: cloudHsmClusterId,
    customKeyStoreName: "kms-custom-key-store-test",
    keyStorePassword: "noplaintextpasswords1",
    trustAnchorCertificate: std.file({
        input: "anchor-certificate.crt",
    }).then(invoke => invoke.result),
});
import pulumi
import pulumi_aws as aws
import pulumi_std as std

test = aws.kms.CustomKeyStore("test",
    cloud_hsm_cluster_id=cloud_hsm_cluster_id,
    custom_key_store_name="kms-custom-key-store-test",
    key_store_password="noplaintextpasswords1",
    trust_anchor_certificate=std.file(input="anchor-certificate.crt").result)
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/kms"
	"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: "anchor-certificate.crt",
		}, nil)
		if err != nil {
			return err
		}
		_, err = kms.NewCustomKeyStore(ctx, "test", &kms.CustomKeyStoreArgs{
			CloudHsmClusterId:      pulumi.Any(cloudHsmClusterId),
			CustomKeyStoreName:     pulumi.String("kms-custom-key-store-test"),
			KeyStorePassword:       pulumi.String("noplaintextpasswords1"),
			TrustAnchorCertificate: pulumi.String(invokeFile.Result),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
using Std = Pulumi.Std;

return await Deployment.RunAsync(() => 
{
    var test = new Aws.Kms.CustomKeyStore("test", new()
    {
        CloudHsmClusterId = cloudHsmClusterId,
        CustomKeyStoreName = "kms-custom-key-store-test",
        KeyStorePassword = "noplaintextpasswords1",
        TrustAnchorCertificate = Std.File.Invoke(new()
        {
            Input = "anchor-certificate.crt",
        }).Apply(invoke => invoke.Result),
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.kms.CustomKeyStore;
import com.pulumi.aws.kms.CustomKeyStoreArgs;
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 test = new CustomKeyStore("test", CustomKeyStoreArgs.builder()
            .cloudHsmClusterId(cloudHsmClusterId)
            .customKeyStoreName("kms-custom-key-store-test")
            .keyStorePassword("noplaintextpasswords1")
            .trustAnchorCertificate(StdFunctions.file(FileArgs.builder()
                .input("anchor-certificate.crt")
                .build()).result())
            .build());

    }
}
resources:
  test:
    type: aws:kms:CustomKeyStore
    properties:
      cloudHsmClusterId: ${cloudHsmClusterId}
      customKeyStoreName: kms-custom-key-store-test
      keyStorePassword: noplaintextpasswords1
      trustAnchorCertificate:
        fn::invoke:
          function: std:file
          arguments:
            input: anchor-certificate.crt
          return: result

The cloudHsmClusterId property links the custom key store to your CloudHSM cluster. The trustAnchorCertificate property provides the cluster’s certificate chain, establishing trust between KMS and CloudHSM. The keyStorePassword authenticates KMS to the cluster’s crypto user account.

Connect to an external key manager via VPC endpoint

Some organizations maintain key management systems outside AWS and need KMS to delegate operations over private network connections.

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

const example = new aws.kms.CustomKeyStore("example", {
    customKeyStoreName: "example-vpc-xks",
    customKeyStoreType: "EXTERNAL_KEY_STORE",
    xksProxyAuthenticationCredential: {
        accessKeyId: ephemeralAccessKeyId,
        rawSecretAccessKey: ephemeralSecretAccessKey,
    },
    xksProxyConnectivity: "VPC_ENDPOINT_SERVICE",
    xksProxyUriEndpoint: "https://myproxy-private.xks.example.com",
    xksProxyUriPath: "/kms/xks/v1",
    xksProxyVpcEndpointServiceName: "com.amazonaws.vpce.us-east-1.vpce-svc-example",
});
import pulumi
import pulumi_aws as aws

example = aws.kms.CustomKeyStore("example",
    custom_key_store_name="example-vpc-xks",
    custom_key_store_type="EXTERNAL_KEY_STORE",
    xks_proxy_authentication_credential={
        "access_key_id": ephemeral_access_key_id,
        "raw_secret_access_key": ephemeral_secret_access_key,
    },
    xks_proxy_connectivity="VPC_ENDPOINT_SERVICE",
    xks_proxy_uri_endpoint="https://myproxy-private.xks.example.com",
    xks_proxy_uri_path="/kms/xks/v1",
    xks_proxy_vpc_endpoint_service_name="com.amazonaws.vpce.us-east-1.vpce-svc-example")
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/kms"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := kms.NewCustomKeyStore(ctx, "example", &kms.CustomKeyStoreArgs{
			CustomKeyStoreName: pulumi.String("example-vpc-xks"),
			CustomKeyStoreType: pulumi.String("EXTERNAL_KEY_STORE"),
			XksProxyAuthenticationCredential: &kms.CustomKeyStoreXksProxyAuthenticationCredentialArgs{
				AccessKeyId:        pulumi.Any(ephemeralAccessKeyId),
				RawSecretAccessKey: pulumi.Any(ephemeralSecretAccessKey),
			},
			XksProxyConnectivity:           pulumi.String("VPC_ENDPOINT_SERVICE"),
			XksProxyUriEndpoint:            pulumi.String("https://myproxy-private.xks.example.com"),
			XksProxyUriPath:                pulumi.String("/kms/xks/v1"),
			XksProxyVpcEndpointServiceName: pulumi.String("com.amazonaws.vpce.us-east-1.vpce-svc-example"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.Kms.CustomKeyStore("example", new()
    {
        CustomKeyStoreName = "example-vpc-xks",
        CustomKeyStoreType = "EXTERNAL_KEY_STORE",
        XksProxyAuthenticationCredential = new Aws.Kms.Inputs.CustomKeyStoreXksProxyAuthenticationCredentialArgs
        {
            AccessKeyId = ephemeralAccessKeyId,
            RawSecretAccessKey = ephemeralSecretAccessKey,
        },
        XksProxyConnectivity = "VPC_ENDPOINT_SERVICE",
        XksProxyUriEndpoint = "https://myproxy-private.xks.example.com",
        XksProxyUriPath = "/kms/xks/v1",
        XksProxyVpcEndpointServiceName = "com.amazonaws.vpce.us-east-1.vpce-svc-example",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.kms.CustomKeyStore;
import com.pulumi.aws.kms.CustomKeyStoreArgs;
import com.pulumi.aws.kms.inputs.CustomKeyStoreXksProxyAuthenticationCredentialArgs;
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 example = new CustomKeyStore("example", CustomKeyStoreArgs.builder()
            .customKeyStoreName("example-vpc-xks")
            .customKeyStoreType("EXTERNAL_KEY_STORE")
            .xksProxyAuthenticationCredential(CustomKeyStoreXksProxyAuthenticationCredentialArgs.builder()
                .accessKeyId(ephemeralAccessKeyId)
                .rawSecretAccessKey(ephemeralSecretAccessKey)
                .build())
            .xksProxyConnectivity("VPC_ENDPOINT_SERVICE")
            .xksProxyUriEndpoint("https://myproxy-private.xks.example.com")
            .xksProxyUriPath("/kms/xks/v1")
            .xksProxyVpcEndpointServiceName("com.amazonaws.vpce.us-east-1.vpce-svc-example")
            .build());

    }
}
resources:
  example:
    type: aws:kms:CustomKeyStore
    properties:
      customKeyStoreName: example-vpc-xks
      customKeyStoreType: EXTERNAL_KEY_STORE
      xksProxyAuthenticationCredential:
        accessKeyId: ${ephemeralAccessKeyId}
        rawSecretAccessKey: ${ephemeralSecretAccessKey}
      xksProxyConnectivity: VPC_ENDPOINT_SERVICE
      xksProxyUriEndpoint: https://myproxy-private.xks.example.com
      xksProxyUriPath: /kms/xks/v1
      xksProxyVpcEndpointServiceName: com.amazonaws.vpce.us-east-1.vpce-svc-example

The customKeyStoreType property set to EXTERNAL_KEY_STORE enables integration with third-party key managers. The xksProxyConnectivity property set to VPC_ENDPOINT_SERVICE routes traffic through a private VPC endpoint service. The xksProxyAuthenticationCredential property provides access credentials for the external proxy, while xksProxyUriEndpoint and xksProxyUriPath define the proxy’s location and API path.

Connect to an external key manager via public endpoint

When private connectivity isn’t required, external key stores can communicate with key management systems over public internet endpoints.

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

const example = new aws.kms.CustomKeyStore("example", {
    customKeyStoreName: "example-public-xks",
    customKeyStoreType: "EXTERNAL_KEY_STORE",
    xksProxyAuthenticationCredential: {
        accessKeyId: ephemeralAccessKeyId,
        rawSecretAccessKey: ephemeralSecretAccessKey,
    },
    xksProxyConnectivity: "PUBLIC_ENDPOINT",
    xksProxyUriEndpoint: "https://myproxy.xks.example.com",
    xksProxyUriPath: "/kms/xks/v1",
});
import pulumi
import pulumi_aws as aws

example = aws.kms.CustomKeyStore("example",
    custom_key_store_name="example-public-xks",
    custom_key_store_type="EXTERNAL_KEY_STORE",
    xks_proxy_authentication_credential={
        "access_key_id": ephemeral_access_key_id,
        "raw_secret_access_key": ephemeral_secret_access_key,
    },
    xks_proxy_connectivity="PUBLIC_ENDPOINT",
    xks_proxy_uri_endpoint="https://myproxy.xks.example.com",
    xks_proxy_uri_path="/kms/xks/v1")
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/kms"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := kms.NewCustomKeyStore(ctx, "example", &kms.CustomKeyStoreArgs{
			CustomKeyStoreName: pulumi.String("example-public-xks"),
			CustomKeyStoreType: pulumi.String("EXTERNAL_KEY_STORE"),
			XksProxyAuthenticationCredential: &kms.CustomKeyStoreXksProxyAuthenticationCredentialArgs{
				AccessKeyId:        pulumi.Any(ephemeralAccessKeyId),
				RawSecretAccessKey: pulumi.Any(ephemeralSecretAccessKey),
			},
			XksProxyConnectivity: pulumi.String("PUBLIC_ENDPOINT"),
			XksProxyUriEndpoint:  pulumi.String("https://myproxy.xks.example.com"),
			XksProxyUriPath:      pulumi.String("/kms/xks/v1"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.Kms.CustomKeyStore("example", new()
    {
        CustomKeyStoreName = "example-public-xks",
        CustomKeyStoreType = "EXTERNAL_KEY_STORE",
        XksProxyAuthenticationCredential = new Aws.Kms.Inputs.CustomKeyStoreXksProxyAuthenticationCredentialArgs
        {
            AccessKeyId = ephemeralAccessKeyId,
            RawSecretAccessKey = ephemeralSecretAccessKey,
        },
        XksProxyConnectivity = "PUBLIC_ENDPOINT",
        XksProxyUriEndpoint = "https://myproxy.xks.example.com",
        XksProxyUriPath = "/kms/xks/v1",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.kms.CustomKeyStore;
import com.pulumi.aws.kms.CustomKeyStoreArgs;
import com.pulumi.aws.kms.inputs.CustomKeyStoreXksProxyAuthenticationCredentialArgs;
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 example = new CustomKeyStore("example", CustomKeyStoreArgs.builder()
            .customKeyStoreName("example-public-xks")
            .customKeyStoreType("EXTERNAL_KEY_STORE")
            .xksProxyAuthenticationCredential(CustomKeyStoreXksProxyAuthenticationCredentialArgs.builder()
                .accessKeyId(ephemeralAccessKeyId)
                .rawSecretAccessKey(ephemeralSecretAccessKey)
                .build())
            .xksProxyConnectivity("PUBLIC_ENDPOINT")
            .xksProxyUriEndpoint("https://myproxy.xks.example.com")
            .xksProxyUriPath("/kms/xks/v1")
            .build());

    }
}
resources:
  example:
    type: aws:kms:CustomKeyStore
    properties:
      customKeyStoreName: example-public-xks
      customKeyStoreType: EXTERNAL_KEY_STORE
      xksProxyAuthenticationCredential:
        accessKeyId: ${ephemeralAccessKeyId}
        rawSecretAccessKey: ${ephemeralSecretAccessKey}
      xksProxyConnectivity: PUBLIC_ENDPOINT
      xksProxyUriEndpoint: https://myproxy.xks.example.com
      xksProxyUriPath: /kms/xks/v1

This configuration mirrors the VPC example but sets xksProxyConnectivity to PUBLIC_ENDPOINT, routing traffic over the public internet instead of through a VPC endpoint service. The xksProxyVpcEndpointServiceName property is omitted since no private connectivity is needed.

Beyond these examples

These snippets focus on specific custom key store features: CloudHSM integration and external key store connectivity (VPC and public). They’re intentionally minimal rather than full key management solutions.

The examples reference pre-existing infrastructure such as CloudHSM clusters with trust anchor certificates, VPC endpoint services for private connectivity, and external XKS proxy endpoints. They focus on configuring the custom key store rather than provisioning the underlying key management infrastructure.

To keep things focused, common custom key store patterns are omitted, including:

  • Custom key store lifecycle management (connect/disconnect operations)
  • Key creation within custom key stores
  • Rotation and backup strategies
  • Authentication credential rotation

These omissions are intentional: the goal is to illustrate how each custom key store type is wired, not provide drop-in key management modules. See the KMS Custom Key Store resource reference for all available configuration options.

Let's configure AWS KMS Custom Key Stores

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Key Store Types & Configuration
What's the difference between CloudHSM and External Key Store types?
CloudHSM (AWS_CLOUDHSM) uses AWS CloudHSM clusters and requires cloudHsmClusterId, keyStorePassword, and trustAnchorCertificate. External Key Store (EXTERNAL_KEY_STORE) connects to external key management systems and requires xksProxyAuthenticationCredential, xksProxyConnectivity, xksProxyUriEndpoint, and xksProxyUriPath.
What's the default key store type if I don't specify one?
AWS defaults to AWS_CLOUDHSM if customKeyStoreType is omitted.
How do I create a CloudHSM-backed custom key store?
Set customKeyStoreType to AWS_CLOUDHSM (or omit it for the default), then provide cloudHsmClusterId, keyStorePassword, and trustAnchorCertificate.
Immutability & Lifecycle
What properties can't be changed after creation?
Three properties are immutable: customKeyStoreType, cloudHsmClusterId, and trustAnchorCertificate. Changing any of these requires replacing the resource.
External Key Store Connectivity
How do I connect an external key store through a VPC endpoint?
Set xksProxyConnectivity to VPC_ENDPOINT_SERVICE and provide xksProxyVpcEndpointServiceName along with the standard external key store properties (xksProxyAuthenticationCredential, xksProxyUriEndpoint, xksProxyUriPath).
How do I connect an external key store through a public endpoint?
Set xksProxyConnectivity to PUBLIC_ENDPOINT and provide xksProxyAuthenticationCredential, xksProxyUriEndpoint, and xksProxyUriPath. No VPC endpoint service name is needed.
What's the difference between VPC and public endpoint connectivity for external key stores?
VPC endpoint connectivity (VPC_ENDPOINT_SERVICE) routes traffic through a private VPC endpoint service and requires xksProxyVpcEndpointServiceName. Public endpoint connectivity (PUBLIC_ENDPOINT) connects directly over the internet without VPC configuration.

Using a different cloud?

Explore security guides for other cloud providers: