Back to blog
AWSBest PracticesCloud SecurityMonitoring & LoggingReliability

ACM Certificate Expired: Detect, Fix, and Prevent TLS Outages

An expired AWS ACM certificate breaks TLS and takes down your endpoints. Learn how to detect, fix, and prevent expired certificates with CLI, Terraform, and alarms.

TL;DR

This check flags AWS Certificate Manager certificates that have passed their expiry date and are no longer valid. An expired cert breaks TLS, causing browser warnings, failed API calls, and outages. Reissue the certificate and rebind it to your load balancer, CloudFront distribution, or API Gateway, then enable auto-renewal where possible.

A TLS certificate that expires in production is one of those failures that always seems to happen at the worst possible time. The certificate was fine for months, nobody was watching it, and then one morning customers start seeing browser security warnings and your health checks go red. The ACM Certificate Expired check exists to catch this before your users do.

AWS Certificate Manager (ACM) handles a lot of the renewal work for you, but it does not cover every case. Certificates that are imported from outside AWS, or that ACM cannot validate automatically, will quietly run down to their expiry date and stop working. This check looks for any ACM certificate whose validity period has already passed.


What this check detects

The acm_expired check inspects every certificate in AWS Certificate Manager across your account and regions, and flags any whose NotAfter date is in the past. A certificate in this state has a status of EXPIRED and can no longer be used to terminate TLS connections.

ACM certificates fall into two broad groups, and the distinction matters a lot for why one might expire:

  • Amazon-issued certificates requested through ACM. These are eligible for managed renewal, where ACM tries to reissue them automatically before they expire.
  • Imported certificates that you uploaded from an external CA. ACM never renews these. You are fully responsible for replacing them before they expire.

Note: Managed renewal is not guaranteed. ACM can only auto-renew an Amazon-issued certificate if it can still validate domain ownership. For DNS-validated certs, the validation CNAME record must still exist in your hosted zone. For email-validated certs, someone has to click an approval link, which is why email validation is a common cause of unexpected expiry.


Why it matters

An expired certificate does not degrade gracefully. The moment it passes its expiry, every client that performs proper certificate validation will reject the connection. The impact depends on where the certificate was in use:

  • Public-facing web apps. Browsers show a full-page NET::ERR_CERT_DATE_INVALID warning. Most users will not click through it, so this is effectively a total outage for that endpoint.
  • APIs and service-to-service calls. HTTP clients with TLS verification enabled throw connection errors. This can cascade through a microservice architecture and take down functionality that has nothing to do with the certificate itself.
  • Mobile apps. Many mobile clients pin or strictly validate certificates and offer no override. An expired cert can break your app for every user at once.
  • Webhooks and integrations. Third-party services calling your endpoints will stop delivering events, and you may lose data that is never retried.

There is a reputational and compliance angle too. A browser warning that says your site is not secure erodes user trust quickly. For regulated workloads, an expired certificate can count as a control failure during an audit.

The cost of an expired certificate is almost never the certificate itself. It is the lost revenue during the outage, the on-call engineer pulled out of bed, and the support tickets the next morning.


How to fix it

The remediation depends on how the certificate was created. Start by identifying the expired certificate and where it is attached.

1. Find the expired certificate

aws acm list-certificates \
  --certificate-statuses EXPIRED \
  --region us-east-1 \
  --query 'CertificateSummaryList[].{Domain:DomainName,Arn:CertificateArn}' \
  --output table

Then describe it to see the validation method, the type, and what is currently using it:

aws acm describe-certificate \
  --certificate-arn arn:aws:acm:us-east-1:111122223333:certificate/abcd1234-... \
  --region us-east-1 \
  --query 'Certificate.{Type:Type,Status:Status,NotAfter:NotAfter,InUseBy:InUseBy,ValidationMethod:DomainValidationOptions[0].ValidationMethod}'

The InUseBy field lists the ARNs of every resource consuming the certificate, such as load balancers, CloudFront distributions, or API Gateway endpoints. You will need to rebind each of these to the new certificate.

2a. Fix an Amazon-issued certificate

You cannot un-expire a certificate. Request a fresh one for the same domains, preferably using DNS validation so renewals work automatically going forward:

aws acm request-certificate \
  --domain-name example.com \
  --subject-alternative-names "*.example.com" \
  --validation-method DNS \
  --region us-east-1

Get the DNS validation record and add it to your hosted zone:

aws acm describe-certificate \
  --certificate-arn arn:aws:acm:us-east-1:111122223333:certificate/NEW-ARN... \
  --region us-east-1 \
  --query 'Certificate.DomainValidationOptions[].ResourceRecord'

If your DNS is in Route 53, add the CNAME and ACM will validate and issue within a few minutes. Once the status is ISSUED, rebind your resources to the new ARN.

Tip: Leave the DNS validation CNAME record in place permanently. As long as that record exists, ACM can auto-renew the certificate indefinitely without any manual steps. Deleting the validation record after issuance is the single most common reason managed renewal silently fails.

2b. Fix an imported certificate

Obtain a new certificate, private key, and chain from your external CA, then re-import. You can re-import into the same ARN to avoid having to rebind every resource:

aws acm import-certificate \
  --certificate-arn arn:aws:acm:us-east-1:111122223333:certificate/EXISTING-ARN... \
  --certificate fileb://certificate.pem \
  --private-key fileb://private_key.pem \
  --certificate-chain fileb://certificate_chain.pem \
  --region us-east-1

Note: Reusing the same ARN on re-import means resources already pointing at that ARN pick up the new certificate without changes. If you create a brand new certificate instead, you must update every resource in the InUseBy list.

3. Rebind the certificate to your resources

For an Application Load Balancer HTTPS listener:

aws elbv2 modify-listener \
  --listener-arn arn:aws:elasticloadbalancing:us-east-1:111122223333:listener/app/my-alb/... \
  --certificates CertificateArn=arn:aws:acm:us-east-1:111122223333:certificate/NEW-ARN...

For a CloudFront distribution, update the ViewerCertificate in the distribution config:

Warning: CloudFront certificates must live in the us-east-1 region regardless of where the rest of your infrastructure runs. If you request a replacement in another region, CloudFront will not let you attach it. Always provision CloudFront certs in us-east-1.

# Get the current config and ETag
aws cloudfront get-distribution-config --id E1234567890ABC > dist.json

# Edit dist.json: set ViewerCertificate.ACMCertificateArn to the new ARN,
# then apply it using the ETag returned above
aws cloudfront update-distribution \
  --id E1234567890ABC \
  --distribution-config file://dist-config-only.json \
  --if-match ETAG_VALUE

4. Verify the fix

echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null \
  | openssl x509 -noout -dates

Confirm that notAfter now shows a future date and that your endpoint serves the new certificate without warnings.


How to prevent it from happening again

Expired certificates are almost always a monitoring and process failure rather than a technical one. A few layers of defense will keep them from recurring.

Prefer DNS validation over email validation

DNS-validated, Amazon-issued certificates renew themselves as long as the validation record stays in place. Email validation requires a human to act before each renewal, which does not scale and breaks the moment the recipient leaves or the inbox is ignored.

Alert on approaching expiry

ACM emits a DaysToExpiry metric to CloudWatch. Set an alarm well before the deadline so you have time to act:

aws cloudwatch put-metric-alarm \
  --alarm-name acm-cert-expiry-example-com \
  --namespace AWS/CertificateManager \
  --metric-name DaysToExpiry \
  --dimensions Name=CertificateArn,Value=arn:aws:acm:us-east-1:111122223333:certificate/ARN... \
  --statistic Minimum \
  --period 86400 \
  --evaluation-periods 1 \
  --threshold 30 \
  --comparison-operator LessThanThreshold \
  --alarm-actions arn:aws:sns:us-east-1:111122223333:cert-alerts

AWS Config also ships a managed rule, acm-certificate-expiration-check, that flags certificates within a configurable number of days of expiry across the account.

Manage certificates as code

Declaring certificates in Terraform makes renewal repeatable and reviewable. For DNS-validated certs in Route 53, the validation and binding happen automatically on apply:

resource "aws_acm_certificate" "main" {
  domain_name               = "example.com"
  subject_alternative_names = ["*.example.com"]
  validation_method         = "DNS"

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_route53_record" "validation" {
  for_each = {
    for dvo in aws_acm_certificate.main.domain_validation_options :
    dvo.domain_name => {
      name   = dvo.resource_record_name
      type   = dvo.resource_record_type
      record = dvo.resource_record_value
    }
  }

  zone_id = aws_route53_zone.main.zone_id
  name    = each.value.name
  type    = each.value.type
  records = [each.value.record]
  ttl     = 60
}

resource "aws_acm_certificate_validation" "main" {
  certificate_arn         = aws_acm_certificate.main.arn
  validation_record_fqdns = [for r in aws_route53_record.validation : r.fqdn]
}

Tip: The create_before_destroy lifecycle block matters here. It provisions the replacement certificate before tearing down the old one, so you avoid a window where no valid certificate exists during a Terraform apply.

Run continuous checks

A scheduled scan that catches both expired and soon-to-expire certificates across every region and account is the safety net for everything above. Lensix runs the acm_expired check on every scan so a missed renewal surfaces immediately instead of during an incident.


Best practices

  • Inventory all certificates. Track imported certs especially carefully, since ACM will never renew them for you. Maintain an owner and renewal date for each.
  • Standardize on short-lived, auto-renewing certs. Amazon-issued, DNS-validated certificates are the lowest-maintenance option. Use them wherever your architecture allows.
  • Alert at multiple thresholds. A single alert at 30 days is easy to miss. Layer alerts at 45, 30, and 7 days so the message escalates as the deadline approaches.
  • Test renewals before they are urgent. Run a renewal in a staging environment so the process is documented and the team has done it before real pressure hits.
  • Watch the us-east-1 requirement for CloudFront. Provision CloudFront certificates only in us-east-1 to avoid binding failures.
  • Avoid wildcard sprawl. A single wildcard certificate used everywhere becomes a single point of failure. Balance convenience against blast radius.

Certificate expiry is entirely preventable. With DNS validation, expiry alarms, and a regular check that scans your whole estate, the ACM Certificate Expired finding should be something you read about rather than something you live through.

ACM Certificate Expired: How to Fix and Prevent It | Lensix