AWS Cert Manager integration with Prometheus with Domain Name
Tags: aws, monitoring, prometheus, sre
Published: 2024-06-18 20:29:34

**Problem**
When using CloudWatch metrics for ACM (AWS Certificate Manager), there is a limitation in that only the ARN (Amazon Resource Name) of ACM certificates is displayed. This makes it difficult to easily identify which domain is expiring, as ARNs are not human-friendly and are hard to interpret at a glance. Instead, having the domain name displayed would be more user-friendly and would make it easier to manage and monitor certificate expirations.

**Solution**
One effective solution to this problem is to integrate Prometheus for monitoring ACM certificates. Prometheus allows for more customizable and readable metrics. Here is how you can set up Prometheus to monitor ACM certificates by domain name:

Install Prometheus: First, install Prometheus on your monitoring server or use a managed service like Amazon Managed Service for Prometheus.
Set Up Exporter: Use a custom exporter or an existing one that can fetch ACM certificates details, including domain names. The exporter will query AWS ACM and transform the ARN-based metrics into domain-based metrics.
Prerequisites
Before we dive into the integration process, ensure you have the following:

An AWS account with access to AWS Certificate Manager.
A running Prometheus instance.
Basic understanding of AWS IAM roles and permissions.
Step 1: Setting Up AWS IAM Permissions
To allow Prometheus to access ACM, you’ll need to set up appropriate IAM permissions.

Create an IAM Policy:
Navigate to the IAM console in AWS.

Click on “Policies” and then “Create policy”.

Add the following JSON to allow read-only access to ACM:

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "acm:ListCertificates",
        "acm:DescribeCertificate"
      ],
      "Resource": "*"
    }
  ]
}
```
2. Create an IAM Role:

Go to the IAM console and click on “Roles” > “Create role”.

Select the “EC2” service, assuming Prometheus is running on an EC2 instance. Attach the policy you created in the previous step and assign role to an instance running Prometheus.

Step 2: Create a python script to fetch ACM details from AWS.

```
import boto3
import http.server
import socketserver
import json
import time
import logging

PORT = 9102

# Set up logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

class ACMExporter(http.server.SimpleHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/metrics':
            self.send_response(200)
            self.send_header('Content-type', 'text/plain')
            self.end_headers()
            try:
                metrics = self.generate_metrics()
                self.wfile.write(metrics.encode())
            except Exception as e:
                logging.error(f"Error generating metrics: {e}")
                self.send_response(500)
                self.end_headers()
        else:
            self.send_response(404)
            self.end_headers()

    def generate_metrics(self):
        acm_client = boto3.client('acm', region_name='us-west-1')  # Change the region if necessary
        try:
            response = acm_client.list_certificates()
        except Exception as e:
            logging.error(f"Error listing certificates: {e}")
            raise

        certificates = response.get('CertificateSummaryList', [])

        metrics = []
        for cert in certificates:
            try:
                expiration_time = int(cert['NotAfter'].timestamp())
                cert_arn = cert['CertificateArn']
                domain_name = self.get_certificate_domain(acm_client, cert_arn)
                metrics.append(f'acm_cert_expiration_timestamp{{domain_name="{domain_name}"}} {expiration_time}')
            except Exception as e:
                logging.error(f"Error processing certificate {cert['CertificateArn']}: {e}")

        return '\n'.join(metrics)

    def get_certificate_domain(self, acm_client, certificate_arn):
        try:
            response = acm_client.describe_certificate(CertificateArn=certificate_arn)
            certificate_detail = response['Certificate']
            domain_name = certificate_detail['DomainName']
            return domain_name
        except Exception as e:
            logging.error(f"Error describing certificate {certificate_arn}: {e}")
            raise

def run(server_class=socketserver.TCPServer, handler_class=ACMExporter):
    server_address = ('', PORT)
    httpd = server_class(server_address, handler_class)
    logging.info(f'Starting ACM exporter on port {PORT}...')
    httpd.serve_forever()

if __name__ == "__main__":
    run()
```
Now, run the script using nohupcommand. Before running command install all the required libraries using pip3 .

`nohup python3 cert-manager-metric.py &`

Once above script is running using PORT: 9102 . Use curl command to check if this script is getting metric or not.

`curl http://localhost:9102`

Step 3: Configure Prometheus to read metrics
Edit the Prometheus configuration file and following lines to 

```
scrape_configs

  - job_name: 'acm-exporter'
    static_configs:
      - targets: ['localhost:9102']
```
Once you are done with above configuration, restart Prometheus service

`systemctl restart prometheus
`
And you are done. Now go to the Prometheus and check the metrics.