The aws:acmpca/certificateAuthority:CertificateAuthority resource, part of the Pulumi AWS provider, provisions AWS Certificate Manager Private Certificate Authorities that issue and manage private certificates for internal applications. This guide focuses on three capabilities: subordinate CA creation, short-lived certificate mode, and CRL distribution to S3.
Private CAs require a root CA to sign their certificate signing request before they can issue certificates. CRL distribution requires S3 buckets with appropriate service permissions. The examples are intentionally small. Combine them with your own CA hierarchy and certificate installation workflow.
Create a subordinate CA with standard settings
Most private CA deployments start with a subordinate CA that will be signed by a root CA.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.acmpca.CertificateAuthority("example", {
certificateAuthorityConfiguration: {
keyAlgorithm: "RSA_4096",
signingAlgorithm: "SHA512WITHRSA",
subject: {
commonName: "example.com",
},
},
permanentDeletionTimeInDays: 7,
});
import pulumi
import pulumi_aws as aws
example = aws.acmpca.CertificateAuthority("example",
certificate_authority_configuration={
"key_algorithm": "RSA_4096",
"signing_algorithm": "SHA512WITHRSA",
"subject": {
"common_name": "example.com",
},
},
permanent_deletion_time_in_days=7)
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/acmpca"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := acmpca.NewCertificateAuthority(ctx, "example", &acmpca.CertificateAuthorityArgs{
CertificateAuthorityConfiguration: &acmpca.CertificateAuthorityCertificateAuthorityConfigurationArgs{
KeyAlgorithm: pulumi.String("RSA_4096"),
SigningAlgorithm: pulumi.String("SHA512WITHRSA"),
Subject: &acmpca.CertificateAuthorityCertificateAuthorityConfigurationSubjectArgs{
CommonName: pulumi.String("example.com"),
},
},
PermanentDeletionTimeInDays: pulumi.Int(7),
})
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.Acmpca.CertificateAuthority("example", new()
{
CertificateAuthorityConfiguration = new Aws.Acmpca.Inputs.CertificateAuthorityCertificateAuthorityConfigurationArgs
{
KeyAlgorithm = "RSA_4096",
SigningAlgorithm = "SHA512WITHRSA",
Subject = new Aws.Acmpca.Inputs.CertificateAuthorityCertificateAuthorityConfigurationSubjectArgs
{
CommonName = "example.com",
},
},
PermanentDeletionTimeInDays = 7,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.acmpca.CertificateAuthority;
import com.pulumi.aws.acmpca.CertificateAuthorityArgs;
import com.pulumi.aws.acmpca.inputs.CertificateAuthorityCertificateAuthorityConfigurationArgs;
import com.pulumi.aws.acmpca.inputs.CertificateAuthorityCertificateAuthorityConfigurationSubjectArgs;
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 CertificateAuthority("example", CertificateAuthorityArgs.builder()
.certificateAuthorityConfiguration(CertificateAuthorityCertificateAuthorityConfigurationArgs.builder()
.keyAlgorithm("RSA_4096")
.signingAlgorithm("SHA512WITHRSA")
.subject(CertificateAuthorityCertificateAuthorityConfigurationSubjectArgs.builder()
.commonName("example.com")
.build())
.build())
.permanentDeletionTimeInDays(7)
.build());
}
}
resources:
example:
type: aws:acmpca:CertificateAuthority
properties:
certificateAuthorityConfiguration:
keyAlgorithm: RSA_4096
signingAlgorithm: SHA512WITHRSA
subject:
commonName: example.com
permanentDeletionTimeInDays: 7
When you create the CA, it enters PENDING_CERTIFICATE status. The certificateAuthorityConfiguration defines the cryptographic algorithms and subject information. The certificateSigningRequest output contains a CSR that you must sign with your root CA and install using the CertificateAuthorityCertificate resource before the CA can issue certificates. The permanentDeletionTimeInDays property controls the recovery window after deletion.
Configure a CA for short-lived certificates
Applications that rotate certificates frequently can use short-lived certificate mode, which allows certificates with validity up to seven days.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.acmpca.CertificateAuthority("example", {
usageMode: "SHORT_LIVED_CERTIFICATE",
certificateAuthorityConfiguration: {
keyAlgorithm: "RSA_4096",
signingAlgorithm: "SHA512WITHRSA",
subject: {
commonName: "example.com",
},
},
});
import pulumi
import pulumi_aws as aws
example = aws.acmpca.CertificateAuthority("example",
usage_mode="SHORT_LIVED_CERTIFICATE",
certificate_authority_configuration={
"key_algorithm": "RSA_4096",
"signing_algorithm": "SHA512WITHRSA",
"subject": {
"common_name": "example.com",
},
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/acmpca"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := acmpca.NewCertificateAuthority(ctx, "example", &acmpca.CertificateAuthorityArgs{
UsageMode: pulumi.String("SHORT_LIVED_CERTIFICATE"),
CertificateAuthorityConfiguration: &acmpca.CertificateAuthorityCertificateAuthorityConfigurationArgs{
KeyAlgorithm: pulumi.String("RSA_4096"),
SigningAlgorithm: pulumi.String("SHA512WITHRSA"),
Subject: &acmpca.CertificateAuthorityCertificateAuthorityConfigurationSubjectArgs{
CommonName: pulumi.String("example.com"),
},
},
})
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.Acmpca.CertificateAuthority("example", new()
{
UsageMode = "SHORT_LIVED_CERTIFICATE",
CertificateAuthorityConfiguration = new Aws.Acmpca.Inputs.CertificateAuthorityCertificateAuthorityConfigurationArgs
{
KeyAlgorithm = "RSA_4096",
SigningAlgorithm = "SHA512WITHRSA",
Subject = new Aws.Acmpca.Inputs.CertificateAuthorityCertificateAuthorityConfigurationSubjectArgs
{
CommonName = "example.com",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.acmpca.CertificateAuthority;
import com.pulumi.aws.acmpca.CertificateAuthorityArgs;
import com.pulumi.aws.acmpca.inputs.CertificateAuthorityCertificateAuthorityConfigurationArgs;
import com.pulumi.aws.acmpca.inputs.CertificateAuthorityCertificateAuthorityConfigurationSubjectArgs;
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 CertificateAuthority("example", CertificateAuthorityArgs.builder()
.usageMode("SHORT_LIVED_CERTIFICATE")
.certificateAuthorityConfiguration(CertificateAuthorityCertificateAuthorityConfigurationArgs.builder()
.keyAlgorithm("RSA_4096")
.signingAlgorithm("SHA512WITHRSA")
.subject(CertificateAuthorityCertificateAuthorityConfigurationSubjectArgs.builder()
.commonName("example.com")
.build())
.build())
.build());
}
}
resources:
example:
type: aws:acmpca:CertificateAuthority
properties:
usageMode: SHORT_LIVED_CERTIFICATE
certificateAuthorityConfiguration:
keyAlgorithm: RSA_4096
signingAlgorithm: SHA512WITHRSA
subject:
commonName: example.com
The usageMode property set to SHORT_LIVED_CERTIFICATE optimizes the CA for certificates that expire within seven days. This mode optionally omits revocation checking since certificates expire quickly, reducing operational overhead.
Publish certificate revocation lists to S3
General-purpose CAs typically publish Certificate Revocation Lists so clients can verify whether certificates have been revoked.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.s3.Bucket("example", {
bucket: "example",
forceDestroy: true,
});
const acmpcaBucketAccess = aws.iam.getPolicyDocumentOutput({
statements: [{
actions: [
"s3:GetBucketAcl",
"s3:GetBucketLocation",
"s3:PutObject",
"s3:PutObjectAcl",
],
resources: [
example.arn,
pulumi.interpolate`${example.arn}/*`,
],
principals: [{
identifiers: ["acm-pca.amazonaws.com"],
type: "Service",
}],
}],
});
const exampleBucketPolicy = new aws.s3.BucketPolicy("example", {
bucket: example.id,
policy: acmpcaBucketAccess.apply(acmpcaBucketAccess => acmpcaBucketAccess.json),
});
const exampleCertificateAuthority = new aws.acmpca.CertificateAuthority("example", {
certificateAuthorityConfiguration: {
keyAlgorithm: "RSA_4096",
signingAlgorithm: "SHA512WITHRSA",
subject: {
commonName: "example.com",
},
},
revocationConfiguration: {
crlConfiguration: {
customCname: "crl.example.com",
enabled: true,
expirationInDays: 7,
s3BucketName: example.id,
s3ObjectAcl: "BUCKET_OWNER_FULL_CONTROL",
},
},
}, {
dependsOn: [exampleBucketPolicy],
});
import pulumi
import pulumi_aws as aws
example = aws.s3.Bucket("example",
bucket="example",
force_destroy=True)
acmpca_bucket_access = aws.iam.get_policy_document_output(statements=[{
"actions": [
"s3:GetBucketAcl",
"s3:GetBucketLocation",
"s3:PutObject",
"s3:PutObjectAcl",
],
"resources": [
example.arn,
example.arn.apply(lambda arn: f"{arn}/*"),
],
"principals": [{
"identifiers": ["acm-pca.amazonaws.com"],
"type": "Service",
}],
}])
example_bucket_policy = aws.s3.BucketPolicy("example",
bucket=example.id,
policy=acmpca_bucket_access.json)
example_certificate_authority = aws.acmpca.CertificateAuthority("example",
certificate_authority_configuration={
"key_algorithm": "RSA_4096",
"signing_algorithm": "SHA512WITHRSA",
"subject": {
"common_name": "example.com",
},
},
revocation_configuration={
"crl_configuration": {
"custom_cname": "crl.example.com",
"enabled": True,
"expiration_in_days": 7,
"s3_bucket_name": example.id,
"s3_object_acl": "BUCKET_OWNER_FULL_CONTROL",
},
},
opts = pulumi.ResourceOptions(depends_on=[example_bucket_policy]))
package main
import (
"fmt"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/acmpca"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/iam"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/s3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
example, err := s3.NewBucket(ctx, "example", &s3.BucketArgs{
Bucket: pulumi.String("example"),
ForceDestroy: pulumi.Bool(true),
})
if err != nil {
return err
}
acmpcaBucketAccess := iam.GetPolicyDocumentOutput(ctx, iam.GetPolicyDocumentOutputArgs{
Statements: iam.GetPolicyDocumentStatementArray{
&iam.GetPolicyDocumentStatementArgs{
Actions: pulumi.StringArray{
pulumi.String("s3:GetBucketAcl"),
pulumi.String("s3:GetBucketLocation"),
pulumi.String("s3:PutObject"),
pulumi.String("s3:PutObjectAcl"),
},
Resources: pulumi.StringArray{
example.Arn,
example.Arn.ApplyT(func(arn string) (string, error) {
return fmt.Sprintf("%v/*", arn), nil
}).(pulumi.StringOutput),
},
Principals: iam.GetPolicyDocumentStatementPrincipalArray{
&iam.GetPolicyDocumentStatementPrincipalArgs{
Identifiers: pulumi.StringArray{
pulumi.String("acm-pca.amazonaws.com"),
},
Type: pulumi.String("Service"),
},
},
},
},
}, nil)
exampleBucketPolicy, err := s3.NewBucketPolicy(ctx, "example", &s3.BucketPolicyArgs{
Bucket: example.ID(),
Policy: pulumi.String(acmpcaBucketAccess.ApplyT(func(acmpcaBucketAccess iam.GetPolicyDocumentResult) (*string, error) {
return &acmpcaBucketAccess.Json, nil
}).(pulumi.StringPtrOutput)),
})
if err != nil {
return err
}
_, err = acmpca.NewCertificateAuthority(ctx, "example", &acmpca.CertificateAuthorityArgs{
CertificateAuthorityConfiguration: &acmpca.CertificateAuthorityCertificateAuthorityConfigurationArgs{
KeyAlgorithm: pulumi.String("RSA_4096"),
SigningAlgorithm: pulumi.String("SHA512WITHRSA"),
Subject: &acmpca.CertificateAuthorityCertificateAuthorityConfigurationSubjectArgs{
CommonName: pulumi.String("example.com"),
},
},
RevocationConfiguration: &acmpca.CertificateAuthorityRevocationConfigurationArgs{
CrlConfiguration: &acmpca.CertificateAuthorityRevocationConfigurationCrlConfigurationArgs{
CustomCname: pulumi.String("crl.example.com"),
Enabled: pulumi.Bool(true),
ExpirationInDays: pulumi.Int(7),
S3BucketName: example.ID(),
S3ObjectAcl: pulumi.String("BUCKET_OWNER_FULL_CONTROL"),
},
},
}, pulumi.DependsOn([]pulumi.Resource{
exampleBucketPolicy,
}))
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.S3.Bucket("example", new()
{
BucketName = "example",
ForceDestroy = true,
});
var acmpcaBucketAccess = Aws.Iam.GetPolicyDocument.Invoke(new()
{
Statements = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementInputArgs
{
Actions = new[]
{
"s3:GetBucketAcl",
"s3:GetBucketLocation",
"s3:PutObject",
"s3:PutObjectAcl",
},
Resources = new[]
{
example.Arn,
$"{example.Arn}/*",
},
Principals = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementPrincipalInputArgs
{
Identifiers = new[]
{
"acm-pca.amazonaws.com",
},
Type = "Service",
},
},
},
},
});
var exampleBucketPolicy = new Aws.S3.BucketPolicy("example", new()
{
Bucket = example.Id,
Policy = acmpcaBucketAccess.Apply(getPolicyDocumentResult => getPolicyDocumentResult.Json),
});
var exampleCertificateAuthority = new Aws.Acmpca.CertificateAuthority("example", new()
{
CertificateAuthorityConfiguration = new Aws.Acmpca.Inputs.CertificateAuthorityCertificateAuthorityConfigurationArgs
{
KeyAlgorithm = "RSA_4096",
SigningAlgorithm = "SHA512WITHRSA",
Subject = new Aws.Acmpca.Inputs.CertificateAuthorityCertificateAuthorityConfigurationSubjectArgs
{
CommonName = "example.com",
},
},
RevocationConfiguration = new Aws.Acmpca.Inputs.CertificateAuthorityRevocationConfigurationArgs
{
CrlConfiguration = new Aws.Acmpca.Inputs.CertificateAuthorityRevocationConfigurationCrlConfigurationArgs
{
CustomCname = "crl.example.com",
Enabled = true,
ExpirationInDays = 7,
S3BucketName = example.Id,
S3ObjectAcl = "BUCKET_OWNER_FULL_CONTROL",
},
},
}, new CustomResourceOptions
{
DependsOn =
{
exampleBucketPolicy,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.s3.Bucket;
import com.pulumi.aws.s3.BucketArgs;
import com.pulumi.aws.iam.IamFunctions;
import com.pulumi.aws.iam.inputs.GetPolicyDocumentArgs;
import com.pulumi.aws.s3.BucketPolicy;
import com.pulumi.aws.s3.BucketPolicyArgs;
import com.pulumi.aws.acmpca.CertificateAuthority;
import com.pulumi.aws.acmpca.CertificateAuthorityArgs;
import com.pulumi.aws.acmpca.inputs.CertificateAuthorityCertificateAuthorityConfigurationArgs;
import com.pulumi.aws.acmpca.inputs.CertificateAuthorityCertificateAuthorityConfigurationSubjectArgs;
import com.pulumi.aws.acmpca.inputs.CertificateAuthorityRevocationConfigurationArgs;
import com.pulumi.aws.acmpca.inputs.CertificateAuthorityRevocationConfigurationCrlConfigurationArgs;
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 example = new Bucket("example", BucketArgs.builder()
.bucket("example")
.forceDestroy(true)
.build());
final var acmpcaBucketAccess = IamFunctions.getPolicyDocument(GetPolicyDocumentArgs.builder()
.statements(GetPolicyDocumentStatementArgs.builder()
.actions(
"s3:GetBucketAcl",
"s3:GetBucketLocation",
"s3:PutObject",
"s3:PutObjectAcl")
.resources(
example.arn(),
example.arn().applyValue(_arn -> String.format("%s/*", _arn)))
.principals(GetPolicyDocumentStatementPrincipalArgs.builder()
.identifiers("acm-pca.amazonaws.com")
.type("Service")
.build())
.build())
.build());
var exampleBucketPolicy = new BucketPolicy("exampleBucketPolicy", BucketPolicyArgs.builder()
.bucket(example.id())
.policy(acmpcaBucketAccess.applyValue(_acmpcaBucketAccess -> _acmpcaBucketAccess.json()))
.build());
var exampleCertificateAuthority = new CertificateAuthority("exampleCertificateAuthority", CertificateAuthorityArgs.builder()
.certificateAuthorityConfiguration(CertificateAuthorityCertificateAuthorityConfigurationArgs.builder()
.keyAlgorithm("RSA_4096")
.signingAlgorithm("SHA512WITHRSA")
.subject(CertificateAuthorityCertificateAuthorityConfigurationSubjectArgs.builder()
.commonName("example.com")
.build())
.build())
.revocationConfiguration(CertificateAuthorityRevocationConfigurationArgs.builder()
.crlConfiguration(CertificateAuthorityRevocationConfigurationCrlConfigurationArgs.builder()
.customCname("crl.example.com")
.enabled(true)
.expirationInDays(7)
.s3BucketName(example.id())
.s3ObjectAcl("BUCKET_OWNER_FULL_CONTROL")
.build())
.build())
.build(), CustomResourceOptions.builder()
.dependsOn(exampleBucketPolicy)
.build());
}
}
resources:
example:
type: aws:s3:Bucket
properties:
bucket: example
forceDestroy: true
exampleBucketPolicy:
type: aws:s3:BucketPolicy
name: example
properties:
bucket: ${example.id}
policy: ${acmpcaBucketAccess.json}
exampleCertificateAuthority:
type: aws:acmpca:CertificateAuthority
name: example
properties:
certificateAuthorityConfiguration:
keyAlgorithm: RSA_4096
signingAlgorithm: SHA512WITHRSA
subject:
commonName: example.com
revocationConfiguration:
crlConfiguration:
customCname: crl.example.com
enabled: true
expirationInDays: 7
s3BucketName: ${example.id}
s3ObjectAcl: BUCKET_OWNER_FULL_CONTROL
options:
dependsOn:
- ${exampleBucketPolicy}
variables:
acmpcaBucketAccess:
fn::invoke:
function: aws:iam:getPolicyDocument
arguments:
statements:
- actions:
- s3:GetBucketAcl
- s3:GetBucketLocation
- s3:PutObject
- s3:PutObjectAcl
resources:
- ${example.arn}
- ${example.arn}/*
principals:
- identifiers:
- acm-pca.amazonaws.com
type: Service
The revocationConfiguration enables CRL distribution. ACM PCA writes CRLs to your S3 bucket at the interval specified by expirationInDays. The bucket policy grants the acm-pca.amazonaws.com service permission to write objects. The customCname property allows you to serve CRLs from a custom domain, though you must configure the DNS CNAME record separately.
Beyond these examples
These snippets focus on specific CA-level features: subordinate CA creation and configuration, short-lived certificate mode, and CRL distribution via S3. They’re intentionally minimal rather than full PKI deployments.
The examples may reference pre-existing infrastructure such as root CAs for signing subordinate CA certificates, and S3 buckets with appropriate service permissions. They focus on configuring the CA rather than provisioning the complete certificate hierarchy.
To keep things focused, common CA patterns are omitted, including:
- Root CA creation (type: ROOT)
- CA certificate installation (CertificateAuthorityCertificate resource)
- OCSP responder configuration
- Key storage security standards (keyStorageSecurityStandard)
These omissions are intentional: the goal is to illustrate how each CA feature is wired, not provide drop-in PKI modules. See the Certificate Authority resource reference for all available configuration options.
Let's create AWS Certificate Manager Private Certificate Authorities
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
CA Setup & Activation
PENDING_CERTIFICATE status and cannot issue certificates until you sign the Certificate Signing Request (CSR). The CSR is available in the certificateSigningRequest output attribute.certificateSigningRequest attribute and import it using the aws.acmpca.CertificateAuthorityCertificate resource. This completes the CA setup and moves it to ACTIVE status.enabled to false if the CA is in an ACTIVE state. Attempting to disable a CA in any other state will fail.Usage Modes & Certificate Types
GENERAL_PURPOSE (default) issues standard certificates that typically require revocation mechanisms. SHORT_LIVED_CERTIFICATE issues certificates with maximum seven-day validity that may optionally omit revocation since they expire quickly.ROOT CAs are self-signed and sit at the top of the certificate chain. SUBORDINATE CAs (default) are signed by another CA and are used for issuing end-entity certificates. This property is immutable after creation.usageMode set to SHORT_LIVED_CERTIFICATE are limited to a maximum validity of seven days.Certificate Revocation
revocationConfiguration with crlConfiguration settings including s3BucketName, enabled: true, and expirationInDays. You can optionally specify a customCname for the CRL distribution point.s3:GetBucketAcl, s3:GetBucketLocation, s3:PutObject, and s3:PutObjectAcl actions for the principal acm-pca.amazonaws.com. Apply this policy before creating the CA with CRL enabled.Configuration & Limits
permanentDeletionTimeInDays. The default is 30 days.FIPS_140_2_LEVEL_3_OR_HIGHER (default) and FIPS_140_2_LEVEL_2_OR_HIGHER. This setting is immutable after creation, and regional support varies.keyStorageSecurityStandard (the FIPS compliance level) and type (ROOT or SUBORDINATE). Choose these carefully during initial creation.