OpenCost on AWS
Use this guide to deploy OpenCost components for Kubernetes Billing exports to Amazon S3.
Prerequisites
Before you begin, make sure you have:
- Infrastructure & permissions
- An Amazon EKS cluster
- Cluster administrator access
- Required tools
- AWS CLI (
aws) kubectl- Helm (v3.x or later)
- AWS CLI (
Set Up an S3 Bucket
Create an S3 bucket for OpenCost Parquet exports:
- In the AWS console, navigate to the S3 console.
- Click Create bucket.
- Set Bucket name, for example,
opencost-exports. The bucket name must be unique. - Leave the default settings as is and click Create bucket.
Additional requirements:
- Create the bucket in the same AWS Region as the EKS cluster.
- Update the Cloudaware billing policy in your AWS account to allow access to this bucket.
Use the bucket name consistently in the later steps.
Configure IAM Role for Service Account (IRSA)
Create an IAM role that the OpenCost pod will assume to write data to S3.
Retrieve Your Cluster’s OIDC Provider URL
- Navigate to the Amazon EKS console → Clusters and select your cluster.
- On the Overview tab under Details, find OpenID Connect provider URL and note the value.
Create the IAM Policy
This policy grants permission for OpenCost to write to your S3 bucket.
-
Open the IAM console. Go to Policies → Create policy.
-
Switch to the JSON tab and paste the following policy, replacing
{YOUR_OPENCOST_S3_BUCKET_NAME}with your S3 bucket name:{"Version": "2012-10-17","Statement": [{"Action": ["s3:PutObject", "s3:GetObject"],"Effect": "Allow","Resource": "arn:aws:s3:::{YOUR_OPENCOST_S3_BUCKET_NAME}/*"}]} -
Name the policy
opencost-s3-policy, then create it.
Create the IAM Role
- In the IAM console, go to Roles → Create role.
- For Trusted entity type, select Web identity.
- For Identity provider, choose the OIDC provider retrieved earlier (for example,
oidc.eks.us-east-1.amazonaws.com/id/YOUR_OIDC_ID). - For Audience, use
sts.amazonaws.com. - Add a condition so that only the OpenCost service account can assume this role:
- Key: your EKS OIDC provider.
- Condition:
StringEquals. - Value:
system:serviceaccount:opencost:opencost-aws.
- Attach the
opencost-s3-policypolicy created in the previous step. - Name the role
opencost-eks-role, then create it.
Deploy Prometheus
If you use an external Prometheus instance, skip this step and review the Configuration notes (1) for external Prometheus below.
-
Add the Prometheus Helm repository:
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts -
Create the Prometheus namespace:
kubectl create namespace prometheus-system -
Install Prometheus:
helm install prometheus prometheus-community/prometheus \--namespace prometheus-system \--set prometheus-pushgateway.enabled=false \--set alertmanager.enabled=false
Deploy OpenCost
-
Add the OpenCost Helm repository:
helm repo add opencost https://opencost.github.io/opencost-helm-chart -
Create the OpenCost namespace:
kubectl create namespace opencost -
Install OpenCost with an IRSA-enabled service account. Replace
{YOUR_IAM_ROLE_ARN}with the ARN of theopencost-eks-role(for example,arn:aws:iam::123456789012:role/opencost-eks-role):helm --namespace opencost install opencost opencost/opencost -f - <<EOFserviceAccount:create: truename: opencost-awsannotations:eks.amazonaws.com/role-arn: "{YOUR_IAM_ROLE_ARN}"opencost:prometheus:namespaceName: prometheus-systempodAnnotations:prometheus.io/path: /metricsprometheus.io/port: "9003"prometheus.io/scrape: "true"EOFtipThe
podAnnotationsensure that Prometheus scrapes metrics from the OpenCost pods, enabling label‑based metadata in reports.
Configuration Notes
-
If your cluster already has an external Prometheus, configure OpenCost to use the existing Prometheus instance by setting the following Helm values. Replace
{YOUR_PROMETHEUS_URL}with the correct endpoint:opencost:prometheus:external:enabled: trueurl: {YOUR_PROMETHEUS_URL} -
If your cluster uses
prometheus-operator, enableServiceMonitor; otherwise OpenCost metrics will not be scraped automatically:opencost:metrics:serviceMonitor:enabled: true
Deploy the Parquet Exporter
Install the component that exports OpenCost data to S3. The same service account (opencost-aws) is reused.
-
To store reports in subfolders or use a naming prefix, use the command below, replacing
{YOUR_CLUSTER_PREFIX},{YOUR_OPENCOST_S3_BUCKET_NAME}and{YOUR_CLUSTER_ARN}with the appropriate values:helm install parquet-exporter opencost/opencost-parquet-exporter \--namespace opencost \--set schedule="0 */12 * * *" \--set existingServiceAccount=opencost-aws \--values - <<EOFresources:limits:cpu: "1"memory: 1Girequests:cpu: 100mmemory: 100MisecurityContext: nullenv:- name: OPENCOST_PARQUET_SVC_HOSTNAMEvalue: "opencost.opencost.svc.cluster.local"- name: OPENCOST_PARQUET_STORAGE_BACKENDvalue: "aws"- name: OPENCOST_PARQUET_S3_BUCKETvalue: "{YOUR_OPENCOST_S3_BUCKET_NAME}"- name: OPENCOST_PARQUET_FILE_KEY_PREFIXvalue: "{YOUR_CLUSTER_PREFIX}/{YOUR_CLUSTER_ARN}"- name: OPENCOST_PARQUET_JSON_SEPARATORvalue: "_"EOF -
To store reports in the root folder, use this variant instead, replacing
{YOUR_OPENCOST_S3_BUCKET_NAME}and{YOUR_CLUSTER_ARN}with the appropriate values:helm install parquet-exporter opencost/opencost-parquet-exporter \--namespace opencost \--set schedule="0 */12 * * *" \--set existingServiceAccount=opencost-aws \--values - <<EOFresources:limits:cpu: "1"memory: 1Girequests:cpu: 100mmemory: 100MisecurityContext: nullenv:- name: OPENCOST_PARQUET_SVC_HOSTNAMEvalue: "opencost.opencost.svc.cluster.local"- name: OPENCOST_PARQUET_STORAGE_BACKENDvalue: "aws"- name: OPENCOST_PARQUET_S3_BUCKETvalue: "{YOUR_OPENCOST_S3_BUCKET_NAME}"- name: OPENCOST_PARQUET_FILE_KEY_PREFIXvalue: "{YOUR_CLUSTER_ARN}"- name: OPENCOST_PARQUET_JSON_SEPARATORvalue: "_"EOF
For multi‑cluster environments, deploy the Parquet exporter separately on each cluster.
Verify the Deployment
-
Verify that all pods are running:
kubectl get pods -n prometheus-systemkubectl get pods -n opencost -
Access the OpenCost UI using port‑forwarding:
kubectl port-forward -n opencost service/opencost 9090:9090
Then open http://localhost:9090 in your browser.
The first Parquet export may take up to 24 hours. To verify the export, check your S3 bucket for newly created Parquet files.
Next Steps
Return to the parent guide Kubernetes Billing (OpenCost) to proceed with the Kubernetes Billing setup in Cloudaware.