AWS ACM Certificates Not Valid
More Info:
Ensure that all the requests made during SSL/TLS certificate issue or renewal process are validated. These requests are managed within your account by the Amazon Certificate Manager (ACM), an AWS service that lets you provision, deploy and maintain SSL/TLS certificates for use with other AWS resources such as ELB load balancers, CloudFront distributions or APIs via Amazon API Gateway.
Risk Level
Medium
Address
Security
Compliance Standards
PCIDSS, NIST
Remediation
How to ensure that API gateway ACM certificates are valid.
Using AWS Console
- Verify the certificate status in ACM:
- Go to the AWS Management Console and navigate to the ACM service.
- Select the region where your API Gateway ACM certificates are provisioned.
- Check the list of certificates and verify the status of each certificate.
- The valid certificates should have a status of "Issued."
- Check the expiration date:
- Review the expiration date of each certificate. (In the Cloudanix Console, navigate to "Misconfig" page and look for Affected Assets for "AWS ACM Certificates Not Valid" Policy.)
- Ensure that the certificates are not expired or nearing their expiration date.
- Renew or replace any certificates that are close to expiration.
- Monitor certificate health:
- Enable automatic renewal and monitoring for ACM certificates.
- ACM provides automated monitoring and renewal of certificates, helping to ensure their ongoing validity.
- Configure notifications or alarms to alert you if any issues arise with the certificates.
- Set up certificate expiration reminders:
- Establish a process or reminder system to proactively track the expiration dates of ACM certificates.
- This can help you stay ahead of certificate renewals and prevent any disruptions due to expired certificates.
- Implement certificate rotation practices:
- Consider implementing a regular certificate rotation schedule to maintain up-to-date and valid certificates.
- Rotate certificates periodically, even if they haven't reached their expiration date, to enhance security and stay current with best practices.
- Monitor API Gateway integration and deployment:
- Regularly review and monitor the integration between API Gateway and ACM certificates.
- Ensure that API Gateway is using the correct and valid ACM certificates for your APIs.
- Verify that the certificate bindings are correctly configured for each API and stage.
Triage and Remediation
- Remediation
Remediation
Using Console
Below are the console steps to fix invalid ACM certificates for an AWS API Gateway custom domain.
1. Identify why the certificate is “not valid”
- Open AWS Certificate Manager (ACM) in the same region as your API Gateway custom domain:
- For Edge-Optimized custom domains → ACM must be in us-east-1.
- For Regional custom domains → ACM must be in the same region as the API.
- In ACM, find the certificate used by your API Gateway custom domain.
- Check the Status and Not after (Expiration):
Pending validation→ DNS/Email validation incomplete.ExpiredorIn use but not valid→ needs replacement/renewal.Domain name mismatch(e.g., you useapi.example.combut cert is forexample.com) → need a new certificate with the correct SAN.
2. Request or renew a valid certificate in ACM
A. Request a new certificate (recommended if expired or mismatched)
- In ACM (correct region) click Request a certificate.
- Choose Request a public certificate → Next.
- Under Fully qualified domain name, enter:
- Exact domain used by API Gateway custom domain (e.g.,
api.example.com).
- Exact domain used by API Gateway custom domain (e.g.,
- Choose DNS validation (preferred) → Request.
Complete DNS validation
- After request creation, open the certificate, go to the Domains section.
- For each domain name listed, note the required CNAME record.
- Go to Route 53 → Hosted zones → select your domain’s hosted zone.
- Click Create record:
- Type:
CNAME - Name & Value: exactly as shown in ACM.
- Save record.
- Type:
- Wait until ACM certificate status becomes Issued.
B. Fix a pending-validation certificate (if one already exists)
- Open the existing certificate in ACM.
- Under Domains, verify DNS CNAMEs exist in Route 53 exactly as shown.
- If missing or incorrect:
- Edit/create the correct CNAME records in Route 53.
- Wait until status becomes Issued.
3. Attach the valid certificate to your API Gateway custom domain
- Open API Gateway console.
- In the left pane, choose Custom domain names.
- Click your custom domain (e.g.,
api.example.com).
If using API Gateway REST APIs
- Click Edit.
- Under ACM certificate, click the dropdown and select the new/valid Issued certificate.
- Save changes.
If using API Gateway HTTP APIs
- Select the custom domain → Edit.
- Under Custom domain configuration, choose the new ACM certificate.
- Save changes.
4. Ensure API mappings are still correct
- On the same custom domain page, check API mappings:
- API, Stage, and Path (if any) are correctly set.
- If needed, edit or re-add API mappings.
5. Confirm DNS points to the API Gateway domain
- On the custom domain detail page in API Gateway, note the Target domain name (e.g.,
d-xxxxxx.execute-api.us-east-1.amazonaws.com). - Go to Route 53 → Hosted zones → your domain.
- Ensure your custom domain (
api.example.com) has:- Type:
A - Routing policy: Alias to API Gateway (recommended)
- Alias target: the Target domain name from API Gateway.
- Type:
- Save (or correct) the record.
6. Test
- Wait a few minutes for DNS and certificate changes to propagate.
- Browse to
https://api.example.com. - Check:
- Browser shows a valid HTTPS connection.
- Certificate common name/SAN matches your domain.
- No TLS/SSL warnings.
If you share your current API Gateway custom domain type (Regional vs Edge) and current ACM cert status, I can tailor the exact steps to that configuration.
Using CLI
Below is a concise, CLI‑only workflow to fix “ACM certificate not valid” for an API Gateway custom domain.
Assumptions:
- You already have an API Gateway custom domain or plan to create one.
- You want to use AWS CLI only.
- Replace all UPPER_CASE placeholders with your values.
1. Identify why the ACM certificate is “not valid”
First, find the certificate you’re using (or plan to use) for the custom domain.
aws acm list-certificates --region us-east-1 # for edge-optimized APIs
# or
aws acm list-certificates --region YOUR_API_REGION # for regional APIs
Grab the CertificateArn you care about, then:
aws acm describe-certificate \
--region YOUR_CERT_REGION \
--certificate-arn YOUR_CERTIFICATE_ARN
Check:
Statusmust beISSUED(notPENDING_VALIDATION/EXPIRED/REVOKED).InUseByshould list your API Gateway domain (optional, after attachment).DomainName/SubjectAlternativeNamesmust include the exact custom domain (e.g.,api.example.com).
If these are wrong, continue with the appropriate path below.
2. (If needed) Request a new valid ACM certificate
2.1 Request the cert from ACM
For an edge‑optimized custom domain (CloudFront-backed):
- Region must be
us-east-1.
aws acm request-certificate \
--region us-east-1 \
--domain-name api.example.com \
--validation-method DNS \
--subject-alternative-names api2.example.com
For a regional custom domain:
- Use the same region as the API (e.g.,
us-west-2).
aws acm request-certificate \
--region YOUR_API_REGION \
--domain-name api.example.com \
--validation-method DNS
The output will contain a new CertificateArn.
2.2 Complete DNS validation
Get the validation CNAME records:
aws acm describe-certificate \
--region YOUR_CERT_REGION \
--certificate-arn NEW_CERTIFICATE_ARN \
--query "Certificate.DomainValidationOptions" \
--output json
For each DomainName, create the CNAME in your DNS provider exactly as shown:
ResourceRecord.Name-> CNAME nameResourceRecord.Value-> CNAME value
If DNS is in Route 53, you can create it via CLI (example):
aws route53 change-resource-record-sets \
--hosted-zone-id YOUR_HOSTED_ZONE_ID \
--change-batch '{
"Changes": [{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "NAME_FROM_ResourceRecord.Name",
"Type": "CNAME",
"TTL": 300,
"ResourceRecords": [{
"Value": "VALUE_FROM_ResourceRecord.Value"
}]
}
}]
}'
Wait until the certificate is ISSUED:
aws acm wait certificate-validated \
--region YOUR_CERT_REGION \
--certificate-arn NEW_CERTIFICATE_ARN
3. Attach the valid certificate to the API Gateway custom domain
3.1 Determine if your API domain is edge‑optimized or regional
Describe the domain:
aws apigateway get-domain-name \
--domain-name api.example.com
Look for:
regionalDomainName→ regional.distributionDomainName→ edge‑optimized.
Or for API Gateway v2 (HTTP/WebSocket APIs):
aws apigatewayv2 get-domain-name \
--domain-name api.example.com
Look for DomainNameConfigurations[].EndpointType (REGIONAL or EDGE).
3.2 For REST APIs (apigateway, v1)
Edge‑optimized custom domain
- Cert must be in
us-east-1. - Use
--certificate-arn.
Create the domain (if not existing):
aws apigateway create-domain-name \
--domain-name api.example.com \
--certificate-arn NEW_CERTIFICATE_ARN
Or update the existing domain to use the new cert:
aws apigateway update-domain-name \
--domain-name api.example.com \
--patch-operations op=replace,path=/certificateArn,value=NEW_CERTIFICATE_ARN
Regional custom domain
- Cert must be in the API region.
- Use
--regional-certificate-arn.
Create:
aws apigateway create-domain-name \
--region YOUR_API_REGION \
--domain-name api.example.com \
--regional-certificate-arn NEW_CERTIFICATE_ARN \
--endpoint-configuration types=REGIONAL
Or update:
aws apigateway update-domain-name \
--region YOUR_API_REGION \
--domain-name api.example.com \
--patch-operations op=replace,path=/regionalCertificateArn,value=NEW_CERTIFICATE_ARN
3.3 For HTTP / WebSocket APIs (apigatewayv2)
apigatewayv2 always uses regional endpoints.
Create new:
aws apigatewayv2 create-domain-name \
--domain-name api.example.com \
--domain-name-configurations "EndpointType=REGIONAL,CertificateArn=NEW_CERTIFICATE_ARN"
Or update existing:
aws apigatewayv2 update-domain-name \
--domain-name api.example.com \
--domain-name-configurations "EndpointType=REGIONAL,CertificateArn=NEW_CERTIFICATE_ARN"
4. Ensure base path mapping is still correct
For REST APIs:
aws apigateway get-base-path-mappings \
--domain-name api.example.com
If missing, create mapping:
aws apigateway create-base-path-mapping \
--domain-name api.example.com \
--rest-api-id YOUR_REST_API_ID \
--stage YOUR_STAGE_NAME \
--base-path '' # empty means root
For HTTP/WebSocket (v2):
aws apigatewayv2 create-api-mapping \
--domain-name api.example.com \
--api-id YOUR_API_ID \
--stage YOUR_STAGE_NAME \
--api-mapping-key '' # root path
5. Update DNS to point to the API Gateway domain
Get the target domain:
- For REST edge‑optimized:
distributionDomainName(CloudFront). - For REST regional / v2:
regionalDomainNameorDomainNameConfigurations[].ApiGatewayDomainName.
Example:
aws apigateway get-domain-name \
--domain-name api.example.com \
--query "{regional:regionalDomainName,edge:distributionDomainName}"
Then, in Route 53 (example):
aws route53 change-resource-record-sets \
--hosted-zone-id YOUR_HOSTED_ZONE_ID \
--change-batch '{
"Changes": [{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "api.example.com",
"Type": "CNAME",
"TTL": 300,
"ResourceRecords": [{
"Value": "TARGET_FROM_APIGW"
}]
}
}]
}'
6. Re-validate certificate status and connectivity
Confirm ACM status:
aws acm describe-certificate \
--region YOUR_CERT_REGION \
--certificate-arn NEW_CERTIFICATE_ARN \
--query "Certificate.{Status:Status,InUseBy:InUseBy}"
Then test:
curl -v https://api.example.com/
If the certificate is:
ISSUED,- In correct region for the endpoint type,
- Contains the exact domain name,
- Attached to the API Gateway custom domain,
- And DNS points to API Gateway,
the “AWS ACM Certificates Not Valid” issue for API Gateway will be remediated.
Using Python
Here’s how to fix invalid ACM certificates for an API Gateway custom domain using Python (boto3). This assumes the issue is something like: expired cert, not validated, wrong region, or not matching the domain.
1. Understand the key constraints
For API Gateway custom domains:
- Edge-optimized custom domain
- ACM certificate must be in
us-east-1.
- ACM certificate must be in
- Regional custom domain
- ACM certificate must be in the same region as the API Gateway endpoint.
- Certificate must:
- Be ISSUED (not PENDING_VALIDATION, EXPIRED, etc.).
- Have a domain name or SAN that matches your custom domain (e.g.,
api.example.com).
2. Install and configure boto3
pip install boto3
Configure credentials:
aws configure
3. Request / find a valid ACM certificate (Python)
3.1. Request a new certificate (if you don’t have a valid one)
Example for api.example.com with DNS validation:
import boto3
region = "us-east-1" # for edge-optimized; use your API region for regional domains
acm = boto3.client("acm", region_name=region)
response = acm.request_certificate(
DomainName="api.example.com",
ValidationMethod="DNS",
SubjectAlternativeNames=["api.example.com"],
Options={
"CertificateTransparencyLoggingPreference": "ENABLED"
}
)
certificate_arn = response["CertificateArn"]
print("Requested cert:", certificate_arn)
3.2. Create DNS validation records (Route 53 example)
import time
acm = boto3.client("acm", region_name=region)
route53 = boto3.client("route53")
def get_validation_records(cert_arn):
details = acm.describe_certificate(CertificateArn=cert_arn)
options = details["Certificate"]["DomainValidationOptions"]
records = []
for opt in options:
rec = opt["ResourceRecord"]
records.append(rec)
return records
def create_route53_records(hosted_zone_id, records):
changes = []
for rec in records:
changes.append({
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": rec["Name"],
"Type": rec["Type"],
"TTL": 300,
"ResourceRecords": [{"Value": rec["Value"]}],
},
})
route53.change_resource_record_sets(
HostedZoneId=hosted_zone_id,
ChangeBatch={"Changes": changes},
)
certificate_arn = certificate_arn # from above
hosted_zone_id = "Z123EXAMPLE" # your Route 53 hosted zone ID
records = get_validation_records(certificate_arn)
create_route53_records(hosted_zone_id, records)
print("DNS validation records created. Wait for validation...")
# Optional: poll until ISSUED
while True:
cert = acm.describe_certificate(CertificateArn=certificate_arn)["Certificate"]
status = cert["Status"]
print("Status:", status)
if status == "ISSUED":
break
elif status in ("FAILED", "REVOKED", "EXPIRED"):
raise RuntimeError(f"Certificate status = {status}")
time.sleep(30)
print("Certificate issued:", certificate_arn)
If DNS is managed outside Route 53, create equivalent CNAMEs manually using the values from ResourceRecord.
If you already have a valid cert, skip to step 4 and just set certificate_arn to that ARN.
4. Update the API Gateway custom domain to use the valid cert
4.1. For REST API custom domain (API Gateway v1)
import boto3
apigw_region = "us-east-1" # for edge-optimized; or your regional endpoint region
apigw = boto3.client("apigateway", region_name=apigw_region)
domain_name = "api.example.com" # custom domain
certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/..." # valid ISSUED cert
# If the custom domain exists, update it; otherwise, create it.
def ensure_custom_domain(domain_name, certificate_arn, endpoint_type="EDGE"):
try:
existing = apigw.get_domain_name(domainName=domain_name)
print("Custom domain exists, updating certificate...")
apigw.update_domain_name(
domainName=domain_name,
patchOperations=[
{
"op": "replace",
"path": "/certificateArn",
"value": certificate_arn,
}
],
)
except apigw.exceptions.NotFoundException:
print("Custom domain does not exist, creating...")
apigw.create_domain_name(
domainName=domain_name,
certificateArn=certificate_arn,
endpointConfiguration={"types": [endpoint_type]},
securityPolicy="TLS_1_2",
)
ensure_custom_domain(domain_name, certificate_arn, endpoint_type="EDGE")
print("Custom domain using updated certificate.")
For regional custom domain, use endpoint_type="REGIONAL" and ensure both API Gateway and ACM cert are in that region.
If you already have base path mappings, they’re preserved by update_domain_name. If not, you may need:
apigw.create_base_path_mapping(
domainName=domain_name,
basePath="(none)", # or "v1", etc.
restApiId="your-rest-api-id",
stage="prod",
)
4.2. For HTTP/REST APIs (API Gateway v2)
import boto3
apigwv2_region = "us-east-1" # must match your API region or edge requirement
apigwv2 = boto3.client("apigatewayv2", region_name=apigwv2_region)
domain_name = "api.example.com"
certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/..."
# Create or update custom domain
def ensure_v2_custom_domain(domain_name, certificate_arn):
domains = apigwv2.get_domain_names()["Items"]
existing = next((d for d in domains if d["DomainName"] == domain_name), None)
if existing:
print("Updating API Gateway v2 domain configuration...")
apigwv2.update_domain_name(
DomainName=domain_name,
DomainNameConfigurations=[
{
"CertificateArn": certificate_arn,
"EndpointType": existing["DomainNameConfigurations"][0]["EndpointType"],
"SecurityPolicy": "TLS_1_2",
}
],
)
else:
print("Creating API Gateway v2 custom domain...")
apigwv2.create_domain_name(
DomainName=domain_name,
DomainNameConfigurations=[
{
"CertificateArn": certificate_arn,
"EndpointType": "REGIONAL", # v2 only supports REGIONAL
"SecurityPolicy": "TLS_1_2",
}
],
)
ensure_v2_custom_domain(domain_name, certificate_arn)
print("API Gateway v2 custom domain configured with valid certificate.")
Then make or confirm ApiMapping:
apigwv2.create_api_mapping(
DomainName=domain_name,
ApiId="your-http-or-websocket-api-id",
Stage="prod",
ApiMappingKey="", # or "v1" for /v1 path
)
5. Update DNS to point the custom domain to API Gateway
After the custom domain is configured to use the new certificate, make sure DNS is correct.
For REST API / EDGE:
CNAMEto the CloudFront distribution name returned byget_domain_nameorget_domain_name(v2) response (distributionDomainNameorDomainNameConfigurations[0]['ApiGatewayDomainName']).
Example (Route 53):
import boto3
route53 = boto3.client("route53")
apigw = boto3.client("apigateway", region_name=apigw_region)
domain_name = "api.example.com"
hosted_zone_id = "Z123EXAMPLE"
domain = apigw.get_domain_name(domainName=domain_name)
target = domain["distributionDomainName"] # or 'regionalDomainName' for REGIONAL
route53.change_resource_record_sets(
HostedZoneId=hosted_zone_id,
ChangeBatch={
"Changes": [
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": domain_name,
"Type": "CNAME",
"TTL": 300,
"ResourceRecords": [{"Value": target}],
}
}
]
},
)
For API Gateway v2 / regional endpoints, use the ApiGatewayDomainName / RegionalDomainName in DomainNameConfigurations.
6. Common failure reasons checklist
- ACM cert not ISSUED → ensure DNS validation is correct and wait.
- ACM cert in wrong region:
- Edge-optimized REST: certificate must be in
us-east-1. - Regional REST or v2: cert region must match API region.
- Edge-optimized REST: certificate must be in
- Custom domain doesn’t match cert’s CN/SAN → recreate cert for correct domain.
- DNS still pointing to old endpoint → update CNAME/alias.
If you tell me:
- region,
- API type (REST v1, HTTP API, WebSocket),
- and the current ACM cert status / ARN,
I can give you a minimal, ready-to-run Python script tailored to your case.
Using Terraform
# Request a new ACM certificate for the API Gateway custom domain
resource "aws_acm_certificate" "api_gateway_cert" {
domain_name = "API_CUSTOM_DOMAIN_NAME" # e.g. api.example.com
validation_method = "DNS"
subject_alternative_names = ["OPTIONAL_ADDITIONAL_DOMAIN_1", "OPTIONAL_ADDITIONAL_DOMAIN_2"] # or []
tags = {
Name = "API Gateway certificate for API_CUSTOM_DOMAIN_NAME"
}
}
# Create DNS validation record in Route53
resource "aws_route53_record" "api_gateway_cert_validation" {
zone_id = "ROUTE53_HOSTED_ZONE_ID" # Hosted zone for example.com
name = aws_acm_certificate.api_gateway_cert.domain_validation_options[0].resource_record_name
type = aws_acm_certificate.api_gateway_cert.domain_validation_options[0].resource_record_type
records = [aws_acm_certificate.api_gateway_cert.domain_validation_options[0].resource_record_value]
ttl = 300
}
# Validate the ACM certificate
resource "aws_acm_certificate_validation" "api_gateway_cert_validation" {
certificate_arn = aws_acm_certificate.api_gateway_cert.arn
validation_record_fqdns = [aws_route53_record.api_gateway_cert_validation.fqdn]
}
# Attach the valid ACM certificate to an API Gateway v2 custom domain
resource "aws_apigatewayv2_domain_name" "api_custom_domain" {
domain_name = aws_acm_certificate.api_gateway_cert.domain_name
domain_name_configuration {
certificate_arn = aws_acm_certificate_validation.api_gateway_cert_validation.certificate_arn
endpoint_type = "REGIONAL" # or "EDGE" for edge-optimized (cert must be in us-east-1)
security_policy = "TLS_1_2"
}
}
Substitute:
API_CUSTOM_DOMAIN_NAMEwith your API Gateway custom domain (e.g.api.example.com).OPTIONAL_ADDITIONAL_DOMAIN_*with any SANs you need, or remove the line if none.ROUTE53_HOSTED_ZONE_IDwith the Route53 hosted zone ID for the parent domain.
This change does not force replacement of the API Gateway domain name resource; Terraform will update it in place to use the new, validated ACM certificate. After applying, terraform plan should show creation of aws_acm_certificate, aws_route53_record, aws_acm_certificate_validation, and an in-place update to aws_apigatewayv2_domain_name.api_custom_domain changing certificate_arn to the new valid certificate.