Configure AWS KMS Custom Key Stores

The aws:kms/customKeyStore:CustomKeyStore resource, part of the Pulumi AWS provider, connects AWS KMS to external cryptographic hardware or key management systems. This guide focuses on two capabilities: CloudHSM cluster integration and external key store connectivity through VPC or public endpoints.

Custom key stores require either a CloudHSM cluster or an external XKS proxy deployment with appropriate network connectivity. The examples are intentionally small. Combine them with your own HSM clusters, VPC infrastructure, or external key management systems.

Connect KMS to a CloudHSM cluster

Organizations with strict key management requirements often use CloudHSM to maintain physical control over cryptographic operations.

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

When you create a CloudHSM-backed custom key store, KMS delegates cryptographic operations to your HSM cluster. The cloudHsmClusterId identifies your cluster, keyStorePassword authenticates KMS to the cluster, and trustAnchorCertificate establishes trust. KMS keys created in this store have their key material generated and stored in your HSM hardware.

Connect to an external key manager via VPC endpoint

Some organizations maintain their own key management infrastructure and need KMS to delegate operations to external systems over private networking.

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 tells KMS to use an external proxy rather than CloudHSM. The xksProxyConnectivity value of VPC_ENDPOINT_SERVICE routes traffic through a VPC endpoint service, keeping communication private. The xksProxyAuthenticationCredential block provides access credentials, while xksProxyUriEndpoint and xksProxyUriPath define where KMS sends cryptographic requests.

Connect to an external key manager via public endpoint

When external key management systems are accessible over the internet, KMS can connect through public endpoints without VPC infrastructure.

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 and omits xksProxyVpcEndpointServiceName. KMS connects directly to the public DNS name specified in xksProxyUriEndpoint. The external proxy must be internet-accessible and secured with TLS.

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 complete 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 deployments. They focus on connecting KMS to external systems rather than provisioning the underlying infrastructure.

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

  • Key store lifecycle management (connecting, disconnecting, deleting)
  • Credential rotation for XKS authentication
  • TLS certificate validation for proxy endpoints
  • Error handling and connection monitoring

These omissions are intentional: the goal is to illustrate how each connectivity model 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

Configuration & Types
What types of custom key stores are available?
You can create two types: AWS_CLOUDHSM (the default) and EXTERNAL_KEY_STORE. If you don’t specify customKeyStoreType, AWS defaults to AWS_CLOUDHSM.
What's required to create a CloudHSM custom key store?
You need three things: cloudHsmClusterId, keyStorePassword, and trustAnchorCertificate (loaded from a file).
What's required to create an external key store?
You need xksProxyAuthenticationCredential (with access key ID and secret), xksProxyConnectivity, xksProxyUriEndpoint, and xksProxyUriPath.
Immutability & Limitations
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 Setup
What's the difference between VPC and public connectivity for external key stores?
VPC connectivity (VPC_ENDPOINT_SERVICE) uses xksProxyVpcEndpointServiceName for private access through a VPC endpoint. Public connectivity (PUBLIC_ENDPOINT) accesses the proxy over the internet without VPC configuration.
How do I authenticate to an external key store proxy?
Configure xksProxyAuthenticationCredential with accessKeyId and rawSecretAccessKey for authentication.
Can I use the same custom key store across multiple regions?
No, custom key stores are regional resources. The region property determines where the key store is managed, defaulting to your provider’s region.

Using a different cloud?

Explore security guides for other cloud providers: