Skip to content

47-Day Certificates Are Coming. Are You Ready?

Act Now →

Automate Microsoft CA Certificates in AWS ACM with the CertSecure Terraform Provider

Automate Microsoft CA Certificates in AWS ACM with Terraform

Introduction

AWS Certificate Manager (ACM) renews the certificates it issues, but it does not renew a certificate you imported. If your organization’s private trust is anchored in Microsoft Certificate Authority (Microsoft CA, also known as Active Directory Certificate Services or AD CS), every certificate you bring into ACM arrives with an expiry date that someone has to track, renew, and reimport by hand, usually under time pressure. 

Encryption Consulting has released the CertSecure Terraform provider. It lets platform teams request, renew, and revoke Microsoft CA certificates through CertSecure Manager in the same terraform apply that builds their infrastructure, while CertSecure keeps enforcing the templates, permissions, and approval workflows your PKI team already defined. 

This blog walks through that workflow for ACM from start to finish: the design behind the provider, a complete Terraform script, and what happens at first issuance, at renewal, at key rotation, and at teardown. It closes with the other use cases the same provider handles beyond ACM. 

The Problem With Imported Certificates in ACM 

ACM offers managed renewal only for certificates it issues itself. For imported certificates, AWS states plainly that you are responsible for monitoring the expiration date and renewing before it passes (AWS documentation). The renewal path is to obtain a new certificate from your issuer and reimport it into the same ACM certificate, which keeps its Amazon Resource Name (ARN) so load balancers, API gateways, and CloudFront distributions keep working. 

Enterprises that already run Microsoft CA usually face two unattractive options. They can stand up AWS Private CA as a second private hierarchy, with its own policies, its own inventory, and its own recurring cost. Or they can keep Microsoft CA and handle ACM by hand: a ticket to the PKI team, a certificate exported and imported, and a calendar reminder for next year. The first option splits governance across two PKIs. The second does not survive scale, or a missed reminder. 

Certificate lifetimes are also getting shorter. Under CA/Browser Forum Ballot SC-081, the maximum validity of publicly trusted TLS certificates dropped to 200 days on March 15, 2026, and falls to 100 days on March 15, 2027 and 47 days on March 15, 2029 (see our guide to 47-day certificate validity). Those rules govern public certificates, not certificates from your private Microsoft CA, but they are resetting expectations everywhere. Many security teams are shortening internal lifetimes as well, and manual renewal does not keep up with either.

How the CertSecure Terraform Provider Works 

The provider follows a composition design: three providers each do one job, and you connect them with ordinary Terraform references. 

  • Key and CSR: the HashiCorp tls provider (tls_private_key and tls_cert_request) creates the private key and the certificate signing request (CSR) inside Terraform. 
  • Issuance: certsecure_certificate sends the CSR to CertSecure Manager, which passes it to Microsoft CA through its connector under the template you name, and returns the certificate and its issuing chain. 
  • Delivery: the AWS provider’s aws_acm_certificate imports the certificate into ACM, exactly as it would any imported certificate. 

The request path is Terraform → CertSecure provider → CertSecure API → CertSecure connector → Microsoft CA. Two properties follow from this design. First, the private key never leaves your side: CertSecure only ever receives the CSR, and the provider never generates or stores a key. Second, the CertSecure provider contains no cloud SDKs and holds no cloud credentials. AWS credentials stay with the AWS provider, and CertSecure credentials stay with the CertSecure provider. 

Governance stays where your PKI team already manages it. The provider authenticates with an API token created in CertSecure, read from the CERTSECURE_URL and CERTSECURE_TOKEN environment variables, and the token’s role determines which CAs and templates a pipeline may use. Every certificate Terraform requests lands in the CertSecure inventory with its owner, tags, and notes, so expiry alerts, reporting, and audit work the same way as for certificates requested any other way. 

The Workflow, Step by Step 

The Terraform configuration 

The script below is a complete configuration. It creates a key and CSR, requests a certificate from Microsoft CA through CertSecure, imports it into ACM, and attaches it to an existing load balancer listener. The load balancer is only an example: an API Gateway custom domain (regional_certificate_arn) or a CloudFront distribution (acm_certificate_arn) references the ACM certificate by its ARN in the same way, so the rest of the workflow is unchanged. Replace the CA name, template, and domain with your own; the certsecure_templates data source lists the template names your token can use.

terraform { 

  required_providers { 

    certsecure = { 

      source  = "encryption-consulting-llc/certsecure" 

      version = "~> 0.3" 

    } 

    tls = { 

      source = "hashicorp/tls" 

    } 

    aws = { 

      source  = "hashicorp/aws" 

      version = "~> 6.0" 

    } 

  } 

} 

 

# Credentials come from the environment: 

#   CertSecure: CERTSECURE_URL and CERTSECURE_TOKEN 

#   AWS:        your usual AWS profile or role 

provider "certsecure" {} 

 

provider "aws" { 

  region = "us-east-1" 

} 

 

variable "common_name" { 

  default = "app.example.com" 

} 

 

# Existing HTTPS listener of your load balancer. 

variable "listener_arn" { 

  type = string 

} 

 

# Bump this number to rotate the private key. 

variable "key_version" { 

  default = 1 

} 

 

# 1. Key and CSR, created by Terraform. CertSecure never sees the key. 

resource "terraform_data" "key_version" { 

  input = var.key_version 

} 

 

resource "tls_private_key" "app" { 

  algorithm = "RSA" 

  rsa_bits  = 2048 

 

  lifecycle { 

    replace_triggered_by = [terraform_data.key_version] 

  } 

} 

 

resource "tls_cert_request" "app" { 

  private_key_pem = tls_private_key.app.private_key_pem 

 

  subject { 

    common_name  = var.common_name 

    organization = "Example Corp" 

  } 

  dns_names = [var.common_name] 

} 

 

# 2. Certificate from Microsoft CA, issued through CertSecure. 

resource "certsecure_certificate" "app" { 

  csr_pem             = tls_cert_request.app.cert_request_pem 

  ca_name             = "Issuing-CA-01" 

  template            = "WebServer" 

  owner_email         = "[email protected]" 

  tags                = ["terraform", "aws-acm"] 

  notes               = "Imported into AWS ACM by Terraform" 

  early_renewal_hours = 720 # renew 30 days before expiry 

 

  # Revoke the certificate in CertSecure on destroy or replacement. 

  revoke_on_destroy = true 

 

  timeouts { 

    create = "5m" 

    update = "5m" 

    delete = "5m" 

  } 

 

  # Issue the replacement before the old certificate is revoked. 

  lifecycle { 

    create_before_destroy = true 

  } 

} 

 

# 3. Delivery to ACM with the standard AWS provider. 

resource "aws_acm_certificate" "app" { 

  private_key       = tls_private_key.app.private_key_pem 

  certificate_body  = certsecure_certificate.app.certificate_pem 

  certificate_chain = certsecure_certificate.app.chain_pem 

 

  tags = { 

    Name   = var.common_name 

    issuer = "microsoft-ca-via-certsecure" 

  } 

} 

 

# 4. Serve it from an existing load balancer listener (or any service that uses the ACM ARN). 

resource "aws_lb_listener_certificate" "app" { 

  listener_arn    = var.listener_arn 

  certificate_arn = aws_acm_certificate.app.arn 

} 

 

output "acm_certificate_arn" { 

  value = aws_acm_certificate.app.arn 

} 

 

output "enrollment_id" { 

  value = certsecure_certificate.app.enrollment_id 

} 

 

output "not_after" { 

  value = certsecure_certificate.app.not_after 

}

A few arguments carry most of the lifecycle behavior: 

  • ca_name and template select the issuing CA and the Microsoft CA template (the template name, such as WebServer, not its display name). 
  • early_renewal_hours renews the certificate in place when it expires within that many hours. 
  • revoke_on_destroy revokes the certificate in CertSecure when Terraform destroys or replaces it. Combined with create_before_destroy, a replacement certificate reaches ACM before the old one is revoked. 
  • key_version is a simple pattern for key rotation: changing it replaces tls_private_key, which produces a new CSR. 

Running the lifecycle then takes four commands:

export CERTSECURE_URL="https://certsecure.example.com" 

export CERTSECURE_TOKEN="" 

 

terraform init 

terraform apply                      # issue and import 

terraform apply                      # scheduled run: renews inside the window 

terraform apply -var key_version=2   # rotate the private key 

terraform destroy                    # remove from ACM, then revoke 

Step 1: First apply issues and imports the certificate

terraform apply generates the key and CSR, submits the CSR to CertSecure, and waits for Microsoft CA to issue the certificate. The provider stores the CertSecure enrollment ID and task ID in Terraform state as soon as they are known, downloads the certificate and chain, and hands both to aws_acm_certificate. The output shows the ACM ARN and the CertSecure enrollment ID, so the same certificate can be found in ACM and in the CertSecure inventory. A second terraform apply reports no changes.

Step 2: Renewal before expiry, with the same ARN

When a run lands inside the early_renewal_hours window, the plan shows an in-place update, not a replacement. The provider renews through CertSecure with the existing CSR, and the AWS provider reimports the new certificate into the existing ACM certificate. The ARN does not change, so the load balancer listener and anything else that references it are untouched. CertSecure records the new certificate as a renewal of the old one and stops expiry alerts for the old one. The previous certificate is not revoked, because a destination may still be serving it until the reimport completes. 

Step 3: Key rotation without touching the load balancer

Changing key_version replaces the private key and therefore the CSR. The CertSecure provider treats a changed CSR as a renewal with a new key, again in place, and ACM receives the new key and certificate as a reimport into the same ARN. Rotating keys becomes a one-line change that goes through code review like any other change. 

Step 4: Teardown revokes the certificate 

terraform destroy removes the certificate from the services that use it, here the load balancer, and from ACM first, then revokes it in CertSecure and waits until CertSecure reports it as revoked. Ephemeral environments no longer leave valid certificates behind. Without revoke_on_destroy, destroy only removes the certificate from Terraform state and warns that it is still valid. 

What about approvals? 

If a template requires approval, CertSecure enforces it and the provider never approves its own requests. A renewal that waits for approval fails the apply with the task ID while the current certificate stays in place, and the next apply after approval resumes the same request instead of submitting a duplicate. A brand new certificate that waits for approval is saved in state, and terraform untaint followed by terraform apply resumes it; without the untaint, Terraform would submit a second request. The provider’s documentation covers both cases. 

Practical Recommendations 

Here is what we recommend to teams putting this into production. 

  • Run Terraform on a schedule. Renewal happens only when Terraform runs. Run a nightly plan and apply from your pipeline, and choose an early_renewal_hours window, such as 720 hours (30 days), that comfortably covers missed or failed runs. 
  • Protect your state. A key created with tls_private_key is stored in Terraform state in plain text. Keep state in an encrypted, access-controlled remote backend, and treat read access to it like access to the key. 
  • Scope API tokens. Give each pipeline its own CertSecure API token, with a role limited to the CAs and templates it needs. Tokens are created and rotated in CertSecure, never by Terraform. 
  • Keep the key type and template stable. ACM reimports cannot change the key type or size, or remove existing Key Usage and Extended Key Usage values (AWS knowledge center). Rotate keys as often as you like, but keep the algorithm, size, and template the same. 
  • Leave time for CloudFront. AWS notes that CloudFront can take up to 24 hours to pick up a reimported certificate, which is one more reason to renew weeks before expiry, not days.
  • Revoke what you destroy. Turn on revoke_on_destroy with create_before_destroy for environments that come and go, so a destroyed environment never leaves a valid certificate behind. 

Beyond ACM: Other Use Cases 

ACM is one destination. Because delivery is left to destination providers, the same certsecure_certificate resource works wherever Terraform can deliver a PEM certificate: 

  • Azure Key Vault: combine the certificate and key into the PEM bundle that azurerm_key_vault_certificate imports, for Azure Application Gateway, App Service, and other services that read from Key Vault. 
  • Kubernetes: write the certificate, chain, and key into a kubernetes_secret of type kubernetes.io/tls for ingress controllers and service meshes. 
  • Service identity and mTLS: request DNS, IP, email, or URI subject alternative names, such as spiffe:// URIs, for service-to-service authentication, where the template and CA policy allow them. 
  • Ephemeral and preview environments: issue certificates per environment and revoke them automatically at teardown. 
  • Certificates requested outside Terraform: the certsecure_certificate data source reads an existing certificate by its enrollment ID, for example one requested in the CertSecure portal or by another team, so Terraform can deliver it without issuing a new one. It returns the certificate and chain only; a destination that needs the private key, such as ACM, still takes it from where the CSR was created. 
  • Consolidating private PKI: teams moving off a second private CA can swap the issuing resource for certsecure_certificate and keep their delivery resources unchanged, so Microsoft CA becomes the single source of trust. 
  • Servers, appliances, and load balancers: any Terraform provider that accepts a PEM certificate and key can deliver one issued through CertSecure. 

How Encryption Consulting Can help? 

Encryption Consulting’s CertSecure Manager is a vendor-neutral certificate lifecycle management solution that centralizes discovery, automation, enrollment, policy enforcement, and integrations across your environment. It prevents outages through automated renewals, strengthens compliance, and unifies the management of public and private Certificate Authorities, including Microsoft CA, through a single, automated, and scalable platform. 

The CertSecure Terraform provider extends that platform into infrastructure as code. Beyond the platform, our PKI services help organizations design Microsoft CA hierarchies, certificate templates, and issuance policies that are ready for automated, short-lived certificates. 

Certificate Management

Prevent certificate outages, streamline IT operations, and achieve agility with our certificate management solution.

For more information related to our products and services please visit 

Conclusion 

Imported certificates are the one part of ACM that AWS leaves to you, and for organizations whose trust is anchored in Microsoft CA, that has meant manual renewals or a second private PKI. The CertSecure Terraform provider removes that trade-off. Terraform requests the certificate, CertSecure applies your policy and Microsoft CA issues it, and the AWS provider delivers it to ACM, with renewal and key rotation keeping the same ARN and teardown ending in revocation. 

The result is a certificate lifecycle that lives in code review instead of in calendar reminders. As certificate lifetimes keep shrinking, that is the difference between a renewal nobody notices and an outage everybody does.