> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Apigateway acm certificate valid remediation

### Triage and Remediation

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Using Console" defaultOpen="true">
        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”

        1. 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.
        2. In ACM, find the certificate used by your API Gateway custom domain.
        3. Check the **Status** and **Not after (Expiration)**:
           * `Pending validation` → DNS/Email validation incomplete.
           * `Expired` or `In use but not valid` → needs replacement/renewal.
           * `Domain name mismatch` (e.g., you use `api.example.com` but cert is for `example.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)

        1. In **ACM** (correct region) click **Request a certificate**.
        2. Choose **Request a public certificate** → **Next**.
        3. Under **Fully qualified domain name**, enter:
           * Exact domain used by API Gateway custom domain (e.g., `api.example.com`).
        4. Choose **DNS validation** (preferred) → **Request**.

        #### Complete DNS validation

        5. After request creation, open the certificate, go to the **Domains** section.
        6. For each domain name listed, note the required **CNAME** record.
        7. Go to **Route 53** → **Hosted zones** → select your domain’s hosted zone.
        8. Click **Create record**:
           * Type: `CNAME`
           * Name & Value: exactly as shown in ACM.
           * Save record.
        9. Wait until ACM certificate status becomes **Issued**.

        ***

        ### B. Fix a pending-validation certificate (if one already exists)

        1. Open the existing certificate in **ACM**.
        2. Under **Domains**, verify DNS CNAMEs exist in Route 53 exactly as shown.
        3. If missing or incorrect:
           * Edit/create the correct CNAME records in Route 53.
        4. Wait until status becomes **Issued**.

        ***

        ## 3. Attach the valid certificate to your API Gateway custom domain

        1. Open **API Gateway** console.
        2. In the left pane, choose **Custom domain names**.
        3. Click your custom domain (e.g., `api.example.com`).

        ### If using API Gateway REST APIs

        4. Click **Edit**.
        5. Under **ACM certificate**, click the dropdown and select the new/valid **Issued** certificate.
        6. Save changes.

        ### If using API Gateway HTTP APIs

        4. Select the custom domain → **Edit**.
        5. Under **Custom domain configuration**, choose the new **ACM certificate**.
        6. Save changes.

        ***

        ## 4. Ensure API mappings are still correct

        1. On the same custom domain page, check **API mappings**:
           * API, **Stage**, and **Path** (if any) are correctly set.
        2. If needed, edit or re-add API mappings.

        ***

        ## 5. Confirm DNS points to the API Gateway domain

        1. 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`).
        2. Go to **Route 53** → **Hosted zones** → your domain.
        3. 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.
        4. Save (or correct) the record.

        ***

        ## 6. Test

        1. Wait a few minutes for DNS and certificate changes to propagate.
        2. Browse to `https://api.example.com`.
        3. 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.
      </Accordion>

      <Accordion title="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.

        ```bash theme={null}
        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:

        ```bash theme={null}
        aws acm describe-certificate \
          --region YOUR_CERT_REGION \
          --certificate-arn YOUR_CERTIFICATE_ARN
        ```

        Check:

        * `Status` must be `ISSUED` (not `PENDING_VALIDATION` / `EXPIRED` / `REVOKED`).
        * `InUseBy` should list your API Gateway domain (optional, after attachment).
        * `DomainName` / `SubjectAlternativeNames` must 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`**.

        ```bash theme={null}
        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`).

        ```bash theme={null}
        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:

        ```bash theme={null}
        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 name
        * `ResourceRecord.Value` -> CNAME value

        If DNS is in Route 53, you can create it via CLI (example):

        ```bash theme={null}
        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`:

        ```bash theme={null}
        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:

        ```bash theme={null}
        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):

        ```bash theme={null}
        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):

        ```bash theme={null}
        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:

        ```bash theme={null}
        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:

        ```bash theme={null}
        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:

        ```bash theme={null}
        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:

        ```bash theme={null}
        aws apigatewayv2 create-domain-name \
          --domain-name api.example.com \
          --domain-name-configurations "EndpointType=REGIONAL,CertificateArn=NEW_CERTIFICATE_ARN"
        ```

        Or update existing:

        ```bash theme={null}
        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:

        ```bash theme={null}
        aws apigateway get-base-path-mappings \
          --domain-name api.example.com
        ```

        If missing, create mapping:

        ```bash theme={null}
        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):

        ```bash theme={null}
        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: `regionalDomainName` or `DomainNameConfigurations[].ApiGatewayDomainName`.

        Example:

        ```bash theme={null}
        aws apigateway get-domain-name \
          --domain-name api.example.com \
          --query "{regional:regionalDomainName,edge:distributionDomainName}"
        ```

        Then, in Route 53 (example):

        ```bash theme={null}
        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:

        ```bash theme={null}
        aws acm describe-certificate \
          --region YOUR_CERT_REGION \
          --certificate-arn NEW_CERTIFICATE_ARN \
          --query "Certificate.{Status:Status,InUseBy:InUseBy}"
        ```

        Then test:

        ```bash theme={null}
        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.
      </Accordion>

      <Accordion title="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`**.
        * **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

        ```bash theme={null}
        pip install boto3
        ```

        Configure credentials:

        ```bash theme={null}
        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:

        ```python theme={null}
        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)

        ```python theme={null}
        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)

        ```python theme={null}
        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:

        ```python theme={null}
        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)**

        ```python theme={null}
        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`:

        ```python theme={null}
        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**:

        * `CNAME` to the CloudFront distribution name returned by `get_domain_name` or `get_domain_name` (v2) response (`distributionDomainName` or `DomainNameConfigurations[0]['ApiGatewayDomainName']`).

        Example (Route 53):

        ```python theme={null}
        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

        1. ACM cert **not ISSUED** → ensure DNS validation is correct and wait.
        2. 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.
        3. Custom domain doesn’t match cert’s **CN/SAN** → recreate cert for correct domain.
        4. 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.
      </Accordion>

      <Accordion title="Using Terraform">
        ```hcl theme={null}
        # 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_NAME` with 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_ID` with 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.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
