Skip to main content

AWS CloudWatch Exporter Configuration

Caution

Cost notice for using CloudWatch Exporter

CloudWatch Exporter retrieves metrics via the AWS CloudWatch API, so AWS CloudWatch usage charges may apply depending on the number of metrics queried and the volume of API calls. Charges are based on usage of CloudWatch metrics, API requests, logs, dashboards, alarms, and more. Refer to the official AWS pricing page for details.

Prerequisites

AWS account requirements

  • AWS account and console access
  • Permission to create IAM policies and users
  • CloudWatch metric read permission

Create an IAM policy

Create a minimum-privilege policy that allows CloudWatch Exporter to call the AWS CloudWatch API.

  1. In the AWS Console, navigate to IAM → Policies → Create policy.

  2. Select the JSON tab and enter the following content.

    Note

    The policy below is an example. It is recommended to include only the permissions for the services you actually use.

    ServiceRequired permissionNotes
    EC2ec2:DescribeInstances
    EBSec2:DescribeVolumes
    ALB/NLB/CLBelasticloadbalancing:DescribeLoadBalancers
    ALB/NLB Target Groupelasticloadbalancing:DescribeTargetGroups, elasticloadbalancing:DescribeTargetHealthRequired for collecting target group health status
    Auto Scaling Groupautoscaling:DescribeAutoScalingGroups
    RDS / Aurorards:DescribeDBInstances
    ElastiCacheelasticache:DescribeCacheClusters, elasticache:DescribeReplicationGroups
    Elastic Beanstalkelasticbeanstalk:DescribeEnvironments, elasticbeanstalk:DescribeEnvironmentHealth
    Lambdalambda:ListFunctions
    ECSecs:ListClusters, ecs:DescribeClusters
    S3s3:ListAllMyBuckets
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Sid": "CloudWatchReadPolicy",
    "Effect": "Allow",
    "Action": [
    "cloudwatch:ListMetrics",
    "cloudwatch:GetMetricStatistics",
    "cloudwatch:GetMetricData"
    ],
    "Resource": "*"
    },
    {
    "Sid": "ResourceDiscoveryPolicy",
    "Effect": "Allow",
    "Action": [
    "tag:GetResources",
    "ec2:DescribeInstances",
    "ec2:DescribeVolumes",
    "elasticloadbalancing:DescribeLoadBalancers",
    "elasticloadbalancing:DescribeTargetGroups",
    "elasticloadbalancing:DescribeTargetHealth",
    "autoscaling:DescribeAutoScalingGroups",
    "rds:DescribeDBInstances",
    "elasticache:DescribeCacheClusters",
    "elasticache:DescribeReplicationGroups",
    "elasticbeanstalk:DescribeEnvironments",
    "elasticbeanstalk:DescribeEnvironmentHealth",
    "lambda:ListFunctions",
    "s3:ListAllMyBuckets",
    "ecs:ListClusters",
    "ecs:DescribeClusters"
    ],
    "Resource": "*"
    }
    ]
    }
    Tip
    • tag:GetResources is required when using the aws_tag_select feature. You can remove it if you do not use tag-based filtering.
    • Following the principle of least privilege, it is recommended to include only the permissions for the services you are actually monitoring.
  3. Enter a policy name (e.g., CloudWatchExporterReadOnlyPolicy) and create it.

Create an IAM user

  1. In the AWS Console, navigate to IAM → Users → Create user.

  2. Enter a username (e.g., cloudwatch-exporter).

  3. Under permission settings, choose Attach policies directly → select CloudWatchExporterReadOnlyPolicy.

  4. Complete the user creation.

  5. In the Security credentials tab, click Create access key.

  6. Select Application running outside AWS as the use case.

  7. Save the Access Key ID and Secret Access Key.

Caution

The Secret Access Key is only visible on this screen. Make sure to store it in a safe location.

Configure AWS Credentials

Configure the authentication information that allows CloudWatch Exporter to access the AWS API.

export AWS_ACCESS_KEY_ID="AKIAXXXXXXXXXXXXXXXX"
export AWS_SECRET_ACCESS_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

For persistent configuration, add to ~/.bashrc or ~/.bash_profile:

echo 'export AWS_ACCESS_KEY_ID="AKIAXXXXXXXXXXXXXXXX"' >> ~/.bashrc
echo 'export AWS_SECRET_ACCESS_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"' >> ~/.bashrc
source ~/.bashrc
Caution

Storing credentials in plain text in ~/.bashrc exposes them to any user with access to that file. For production environments, Method 2 (Credentials file) is recommended.

Method 2: AWS Credentials file

# Create directory
mkdir -p ~/.aws

# Create credentials file
cat <<EOF > ~/.aws/credentials
[default]
aws_access_key_id = AKIAXXXXXXXXXXXXXXXX
aws_secret_access_key = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
EOF

# Create config file
cat <<EOF > ~/.aws/config
[default]
output = json
EOF

# Set permissions
chmod 600 ~/.aws/credentials
chmod 600 ~/.aws/config

Install Java

CloudWatch Exporter requires Java 11 or later.

  • Amazon Linux 2 / CentOS / RHEL
# Install Amazon Corretto 11 (Amazon Linux 2)
sudo yum install -y java-11-amazon-corretto-headless

# Or install OpenJDK 11
sudo yum install -y java-11-openjdk-headless
  • Ubuntu / Debian
sudo apt update
sudo apt install -y openjdk-11-jre-headless

Install CloudWatch Exporter

Create working directory

sudo mkdir -p /opt/cloudwatch-exporter
sudo chown $USER:$USER /opt/cloudwatch-exporter
cd /opt/cloudwatch-exporter

Download JAR file

The latest version is available on GitHub Releases.

# Check the latest version on the GitHub Releases page below and set it in VERSION.
# https://github.com/prometheus/cloudwatch_exporter/releases
VERSION="0.16.0"

# Download JAR file
wget https://github.com/prometheus/cloudwatch_exporter/releases/download/v${VERSION}/cloudwatch_exporter-${VERSION}-jar-with-dependencies.jar

# Create a symbolic link to simplify the filename
ln -sf cloudwatch_exporter-${VERSION}-jar-with-dependencies.jar cloudwatch_exporter.jar

The final directory structure is as follows.

/opt/cloudwatch-exporter/
├── cloudwatch_exporter.jar # Symbolic link
├── cloudwatch_exporter-0.16.0-jar-with-dependencies.jar # Actual JAR file
└── config.yml # Configuration file (created in the next section)

Writing the configuration file (config.yml)

Traditional cloud monitoring enables collection via toggle buttons, but the OpenMetrics approach requires you to write a config.yml file directly to configure collection targets and metrics.

Metric documentation by major service

ServiceNamespaceMetric documentation
EC2AWS/EC2https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/viewing_metrics_with_cloudwatch.html
RDSAWS/RDShttps://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-metrics.html
AuroraAWS/RDShttps://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/Aurora.AuroraMonitoring.Metrics.html
ALBAWS/ApplicationELBhttps://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-cloudwatch-metrics.html
NLBAWS/NetworkELBhttps://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-cloudwatch-metrics.html
CLBAWS/ELBhttps://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-cloudwatch-metrics.html
LambdaAWS/Lambdahttps://docs.aws.amazon.com/lambda/latest/dg/monitoring-metrics.html
EBSAWS/EBShttps://docs.aws.amazon.com/ebs/latest/userguide/using_cloudwatch_ebs.html
S3AWS/S3https://docs.aws.amazon.com/AmazonS3/latest/userguide/cloudwatch-monitoring.html
ECSAWS/ECShttps://docs.aws.amazon.com/AmazonECS/latest/developerguide/cloudwatch-metrics.html
EKSAWS/EKShttps://docs.aws.amazon.com/eks/latest/userguide/cloudwatch.html
DynamoDBAWS/DynamoDBhttps://docs.aws.amazon.com/amazondynamodb/latest/developerguide/metrics-dimensions.html
ElastiCacheAWS/ElastiCachehttps://docs.aws.amazon.com/AmazonElastiCache/latest/dg/CacheMetrics.html
SQSAWS/SQShttps://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-available-cloudwatch-metrics.html
SNSAWS/SNShttps://docs.aws.amazon.com/sns/latest/dg/sns-monitoring-using-cloudwatch.html
API GatewayAWS/ApiGatewayhttps://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-metrics-and-dimensions.html
CloudFrontAWS/CloudFronthttps://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/monitoring-using-cloudwatch.html
NAT GatewayAWS/NATGatewayhttps://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway-cloudwatch.html
AutoScalingAWS/AutoScalinghttps://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-metrics.html
ElasticBeanstalkAWS/ElasticBeanstalkhttps://docs.aws.amazon.com/elasticbeanstalk/latest/dg/health-enhanced-cloudwatch.html
Note

S3 storage metrics are daily metrics, so period_seconds must be set to 86400 (1 day).

Basic structure of config.yml

Required parameter descriptions

ParameterDescriptionExample
regionAWS regionap-northeast-2
aws_namespaceAWS service namespaceAWS/EC2, AWS/RDS
aws_metric_nameName of the metric to collectCPUUtilization
aws_dimensionsMetric classification criteria[InstanceId]
aws_statisticsStatistics type[Average, Maximum, Sum]
period_secondsData point interval (seconds)300 (5 minutes)
range_secondsTime range to query (seconds)600 (10 minutes)
delay_secondsCloudWatch data delay compensation (seconds)600 (10 minutes)

Statistics types (aws_statistics)

StatisticDescriptionUsage example
AverageAverage valueCPU utilization, memory utilization
SumTotalNetwork traffic, request count
MaximumMaximum valuePeak CPU, maximum latency
MinimumMinimum valueMinimum free space
SampleCountNumber of samplesData point count
Serviceperiod_secondsrange_secondsdelay_seconds
EC2 (basic monitoring)300600600
EC2 (detailed monitoring)60300120
EBS Volume300600600
RDS60300120
Lambda60300120
ELB / ALB / NLB60300120
DynamoDB60300120
CloudFront60300120
ElastiCache60300120
S3 (request metrics)60300120
S3 (storage metrics)86400172800600
ECS60300120
ECS/ContainerInsights60300120
AutoScaling60300120
ElasticBeanstalk60300120

Formula for determining values

  • period_seconds = The publishing interval of the service
  • range_secondsperiod_seconds × 2 (safety margin, typically 2–5×)
  • delay_secondsperiod_seconds × 2
Note

Exceptions / Notes

  • EC2 basic monitoring: The default is 5-minute intervals. Reducing period_seconds to 60 will not produce more data — it still publishes once every 5 minutes and only generates empty data points.
  • EBS Volume: Same as EC2 — 5-minute intervals.
  • S3 storage metrics: Published once per day. Set period_seconds to 86400 (1 day) and make delay_seconds sufficiently large.
  • Custom metrics (high resolution): 1-second resolution is possible but incurs higher costs. 60 seconds is usually sufficient.

Why CloudWatch data refers to a past point in time

  1. Statistics are only calculated after the aggregation window ends — A 5-minute average cannot be computed until that full window has elapsed. Querying the 10:00–10:05 average at 10:03 returns no data because the window has not yet closed.
  2. Query delay to avoid ingestion lag (delay_seconds) — CloudWatch can take several minutes to reflect metrics in its API. To avoid fetching incomplete data, OpenAgent is configured to query only data older than a certain threshold. Based on current settings, data from EC2, ALB, and EBS is reliably available from approximately 10–15 minutes ago, and data from ElastiCache and ECS from approximately 1–2 minutes ago. (This varies by service depending on period_seconds and delay_seconds settings.)
  3. EC2 basic monitoring publishes on a 5-minute interval — This is the default AWS publishing frequency. Enabling detailed monitoring (paid) allows 1-minute collection.

config.yml configuration example

# config.yml example
region: ap-northeast-2 # AWS region
metrics: # List of metrics to collect
- aws_namespace: AWS/EC2 # AWS service namespace
aws_metric_name: CPUUtilization # Metric name
aws_dimensions: [InstanceId] # Dimension (classification criteria)
aws_tag_select: # Tag-based filtering and label addition
resource_type_selection: "ec2:instance" # Resource type
resource_id_dimension: InstanceId # Resource ID mapped to dimension
aws_statistics: [Average] # Statistics type
period_seconds: 300 # Data point interval
range_seconds: 600 # Query time range
delay_seconds: 600 # Data delay time

Openmetrics cloudwatch config.yml

Advanced parameters: Filtering

  • aws_dimension_select (collect specific resources only)
- aws_namespace: AWS/EC2
aws_metric_name: CPUUtilization
aws_dimensions: [InstanceId]
aws_dimension_select:
InstanceId:
- i-xxxxxxxxxxxxxxxx1
- i-xxxxxxxxxxxxxxxx2
aws_statistics: [Average]
period_seconds: 300
range_seconds: 600
delay_seconds: 600
  • aws_dimension_select_regex (regex-based filtering)
- aws_namespace: AWS/EC2
aws_metric_name: CPUUtilization
aws_dimensions: [InstanceId]
aws_dimension_select_regex:
InstanceId: "^i-0123.*"
aws_statistics: [Average]
period_seconds: 300
range_seconds: 600
delay_seconds: 600
  • aws_tag_select (tag-based filtering) - recommended
- aws_namespace: AWS/EC2
aws_metric_name: CPUUtilization
aws_dimensions: [InstanceId]
aws_tag_select:
tag_selections:
Environment: ["production", "staging"]
Team: ["devops"]
resource_type_selection: "ec2:instance"
resource_id_dimension: InstanceId
aws_statistics: [Average]
period_seconds: 300
range_seconds: 600
delay_seconds: 600
Caution

If a key is specified in tag_selections, resources that do not have that tag are excluded from metric collection. If metrics are missing, first verify that the target resources have the relevant tags configured.

Serviceresource_type_selectionresource_id_dimension
EC2ec2:instanceInstanceId
ALBelasticloadbalancing:loadbalancer/appLoadBalancer
NLBelasticloadbalancing:loadbalancer/netLoadBalancer
CLBelasticloadbalancing:loadbalancerLoadBalancerName
RDSrds:dbDBInstanceIdentifier
Aurorards:clusterDBClusterIdentifier
EBSec2:volumeVolumeId
ElastiCacheelasticache:clusterCacheClusterId

Run CloudWatch Exporter

Run with nohup (for quick testing)

cd /opt/cloudwatch-exporter

# Run in background
nohup java -jar cloudwatch_exporter.jar 9106 config.yml > cloudwatch_exporter.log 2>&1 &

# Check process
ps aux | grep cloudwatch_exporter

# Check logs
tail -100f cloudwatch_exporter.log

# Stop
pkill -f cloudwatch_exporter.jar

Method 1: Environment variable

sudo vi /etc/systemd/system/cloudwatch-exporter.service
[Unit]
Description=Prometheus CloudWatch Exporter
After=network-online.target

[Service]
Type=simple
WorkingDirectory=/opt/cloudwatch-exporter

# Set AWS Credentials directly as environment variables
Environment="AWS_ACCESS_KEY_ID=AKIAXXXXXXXXXXXXXXXX"
Environment="AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

ExecStart=/usr/bin/java -jar /opt/cloudwatch-exporter/cloudwatch_exporter.jar 9106 /opt/cloudwatch-exporter/config.yml
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Method 2: AWS Credentials file

sudo vi /etc/systemd/system/cloudwatch-exporter.service
[Unit]
Description=Prometheus CloudWatch Exporter
After=network-online.target

[Service]
Type=simple
WorkingDirectory=/opt/cloudwatch-exporter

# AWS SDK references the $HOME/.aws/credentials file
# ex: uses /root/.aws/credentials
Environment="HOME=/root"

ExecStart=/usr/bin/java -jar /opt/cloudwatch-exporter/cloudwatch_exporter.jar 9106 /opt/cloudwatch-exporter/config.yml
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Start the service

sudo systemctl daemon-reload
sudo systemctl start cloudwatch-exporter
sudo systemctl enable cloudwatch-exporter
sudo systemctl status cloudwatch-exporter

Download and configure OpenAgent

All files must be located in the same directory.

## Example
/opt/whatap/openagent/
├── openagent # Executable file
├── whatap.conf # Configuration file
└── scrape_config.yaml # Scraping configuration file
mkdir -p /opt/whatap/openagent
cd /opt/whatap/openagent

## AMD64 (Intel/AMD 64-bit processor)
wget https://repo.whatap.io/openagent/latest/amd/openagent

## ARM64 (ARM processor in Linux environment)
## CAUTION: macOS Apple Silicon not supported
wget https://repo.whatap.io/openagent/latest/arm/openagent

Set execute permission

chmod +x openagent

Create scrape_config.yaml

When the scrape_config.yaml file is modified, OpenAgent automatically detects the changes and reloads the configuration. No restart is required.

#scrape_config.yaml
features:
openAgent:
enabled: true
targets:
- targetName: cloudwatch-exporter
type: StaticEndpoints
# Target is enabled by default (enabled: true), this can be omitted
enabled: true
endpoints:
- address: "192.168.49.2:9106"
path: "/metrics"
scheme: "http"
interval: "300s"
metricRelabelConfigs:
- source_labels: [__name__]
regex: ".*"
action: keep

Run in foreground

./openagent standalone

Run in background

nohup ./openagent standalone > /dev/null 2>&1 &

Check logs

tail -f logs/whatap-boot-{yyyymmdd}.log

Process management

# Check process
ps aux | grep openagent

# Terminate process
pkill openagent

StaticEndpoints configuration elements

  • targetName: Name of the target (for identification)
  • type: Target type ("StaticEndpoints")
  • endpoints: Definition of endpoints to scrape
    • address: Target address to scrape (IP:PORT or HOSTNAME:PORT)
    • path: Metrics path (default: /metrics)
    • scheme: Scraping protocol (http or https, default: http)
    • interval: Scraping interval (default: 60s)
    • metricRelabelConfigs: Metric relabeling configuration applied after scraping

Metric relabeling configuration (metricRelabelConfigs)

OpenAgent supports metric relabeling functionality similar to Prometheus's metric_relabel_configs.

Relabeling configuration elements

  • source_labels: List of source labels (array)
  • separator: Separator used when concatenating source label values (default: ;)
  • target_label: Target label (label where the result is stored)
  • regex: Regular expression applied to source label values
  • replacement: Replacement value (can reference regex capture groups, e.g., ${1})
  • action: Action to perform (keep, drop, replace)

Supported actions

  • keep: Retain only metrics matching the regex
  • drop: Remove metrics matching the regex
  • replace: Replace the value of the target label with the replacement value

Examples

1. Collect all metrics

metricRelabelConfigs:
- source_labels: [__name__]
regex: ".*"
action: keep

2. Keep specific metrics only

metricRelabelConfigs:
- source_labels: [__name__]
regex: "aws_ec2_cpuutilization_average"
action: keep

3. Filter metrics using regex

metricRelabelConfigs:
- source_labels: [__name__]
regex: "aws_ec2_(cpu|network).*"
action: keep

4. Rename a label

metricRelabelConfigs:
- source_labels: [instance_id]
target_label: ec2_instance_id
replacement: "${1}"
action: replace

5. Add a static label

metricRelabelConfigs:
- target_label: metric_src
replacement: "whatap-open-agent"
action: replace