Installing on Amazon Web Services (AWS)
OpenCost may be installed on Kubernetes clusters running on EC2 or on Elastic Kubernetes Service (EKS).
You will need to install Prometheus, create your OpenCost namespace, configure your cluster pricing and cloud costs, and then install OpenCost.
Install Prometheus
Prometheus is a prerequisite for OpenCost installation. OpenCost requires Prometheus for scraping metrics and data storage. For the installation of Prometheus please use the following command:
helm install prometheus --repo https://prometheus-community.github.io/helm-charts prometheus \
--namespace prometheus-system --create-namespace \
--set prometheus-pushgateway.enabled=false \
--set alertmanager.enabled=false \
-f https://raw.githubusercontent.com/opencost/opencost/develop/kubernetes/prometheus/extraScrapeConfigs.yaml
This will install Prometheus in the prometheus-system namespace with default settings for use with OpenCost.
If you wish to use a different Prometheus installation or work with another compatible technology, please refer to the Prometheus installation page.
Create the OpenCost Namespace
Create the opencost namespace for your installation:
kubectl create namespace opencost
Alternate namespaces may be used if necessary.
AWS Configuration
Cost Allocation
OpenCost will automatically read the node information node.spec.providerID to determine the cloud service provider (CSP) in use. If it detects the CSP is AWS, it will attempt to pull the AWS on-demand pricing from the configured public API URL with no further configuration required.
OpenCost will request pricing data from the us-east-1 region for your node_region using the template:
https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonEC2/current/${node_region}/index.json
The location should be automatically detected, but this URL can be overwritten using the environment variable AWS_PRICING_URL.
AWS Spot Instance Data Feed
AWS Spot Instance Data Feed from the configured S3 bucket
- Set up Spot Instance Data Feed.
- Create a role for OpenCost with access to the spot feed bucket. Attach the policy below to the role and replace CHANGE-ME with your spot bucket name.
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:ListAllMyBuckets",
"s3:ListBucket",
"s3:HeadBucket",
"s3:HeadObject",
"s3:List*",
"s3:Get*"
],
"Resource": [
"arn:aws:s3:::CHANGE-ME"
],
"Effect": "Allow",
"Sid": "SpotDataAccess"
}
]
}
Configuration
The data feed will provide specific pricing information about any Spot instances in your account on an hourly basis. After setting this up, the bucket information can be provided through options in the AWS provider configuration file.
awsSpotDataBucket- The name of the S3 bucket Spot Instance Data Feed is publishing to.awsSpotDataRegion- The region configured for Spot Instance Data FeedawsSpotDataPrefix- The prefix (if any) configured for Spot Instance Data FeedprojectID- The AWS Account ID
Example configuration:
{
"provider": "aws",
"description": "AWS Provider Configuration. Provides default values used if instance type or spot information is not found.",
"CPU": "0.031611",
"spotCPU": "0.006655",
"RAM": "0.004237",
"GPU": "0.95",
"spotRAM": "0.000892",
"storage": "0.000138888889",
"zoneNetworkEgress": "0.01",
"regionNetworkEgress": "0.01",
"internetNetworkEgress": "0.143",
"spotLabel": "kops.k8s.io/instancegroup",
"spotLabelValue": "spotinstance-nodes",
"awsSpotDataRegion":"us-east-2",
"awsSpotDataBucket": "my-spot-bucket",
"awsSpotDataPrefix": "spot_pricing_prefix",
"projectID": "012345678901"
}
Security for AWS integration
OpenCost uses the AWS SDK for Go to pull Spot data feed information. There are multiple supported ways to configure security.
The recommended setup is to leverage IAM roles for Service Accounts or EKS Pod Identities.
IAM Roles for Service Accounts
After creating the role and policy, attach the role as an annotation on the service account in your local OpenCost Helm values file:
serviceAccount:
create: true
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/S3Access
EKS Pod Identities
See AWS Documentation on EKS Pod Identities
To use EKS Pod Identities with OpenCost:
- Configure the EKS Pod Identities add on: https://docs.aws.amazon.com/eks/latest/userguide/pod-id-agent-setup.html
- Create the EKS Pod Identity association: https://docs.aws.amazon.com/eks/latest/userguide/pod-id-association.html
- Update your local OpenCost Helm values file with:
serviceAccount:
create: true
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/S3Access
name: name-of-service-account-from-step-2 # can be omitted if the name of the service account is exactly 'opencost'
AWS Cloud Costs
The Cloud Costs feature is included in the stable releases as of 1.108.0. Please ensure you have the latest release to access this new feature.
Cloud Costs reads your AWS Cost and Usage Report (CUR) through Amazon Athena. You need:
- A CUR delivered to S3, either:
- CUR 2.0 (recommended), from Billing and Cost Management > Data Exports, or
- CUR 1.0 (legacy), from Billing and Cost Management > Cost and Usage Reports.
- An Athena database and table over that bucket. Both export types can create these for you.
- An S3 bucket for Athena query results, named
aws-athena-query-results-*.
CUR 2.0
OpenCost detects the version automatically: a table with any of resource_tags, line_item_usage_account_name, or bill_payer_account_name is treated as CUR 2.0. For CUR 2.0, OpenCost reads tags from the resource_tags map (resource_tags['user_team']) instead of per-tag columns, and filters on the billing_period partition instead of year/month.
When defining a CUR 2.0 export, include resource_tags and resource IDs. Without resource_tags, OpenCost falls back to CUR 1.0 handling and attributes no spend to Kubernetes beyond AmazonEKS line items.
Configuration file
Cloud Costs are configured with a cloud-integration.json file containing one or more Athena integrations:
{
"aws": {
"athena": [
{
"bucket": "s3://aws-athena-query-results-my-cur",
"region": "us-east-1",
"database": "athenacurcfn_my_cur",
"table": "my_cur_2_0",
"workgroup": "primary",
"account": "123456789012",
"authorizer": {
"authorizerType": "AWSAccessKey",
"id": "AKIAIOSFODNN7EXAMPLE",
"secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
}
}
]
}
}
| Field | Required | Description |
|---|---|---|
bucket | Yes | s3:// URI of the Athena query results bucket. OpenCost reads and writes it. |
region | Yes | AWS region Athena runs in. |
database | Yes | Athena database. For a CloudFormation-created legacy CUR, the physical ID of AWSCURDatabase in the stack. |
table | Yes | Athena table. For a legacy CUR, usually the database name without the athenacurcfn_ prefix. |
account | Yes | AWS account ID that holds the CUR. |
authorizer | Yes | How OpenCost authenticates. See Authorization. |
workgroup | No | Athena workgroup. Defaults to primary. |
catalog | No | Athena data catalog. Defaults to AwsDataCatalog. |
resultReuseMaxAgeMinutes | No | Reuse Athena query results for this many minutes. Useful when many clusters run the same query. |
Authorization
The authorizer block accepts one of four authorizerType values. Whichever you choose, attach the Cloud Costs IAM policy to the resulting identity.
Access Key
AWSAccessKey uses a long-lived IAM user access key. In the IAM console, open Access Management > Users, select the OpenCost user, and choose Security Credentials > Create Access Key:
{
"authorizerType": "AWSAccessKey",
"id": "AKIAIOSFODNN7EXAMPLE",
"secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
}
IAM Roles for Service Accounts (recommended)
AWSServiceAccount uses the pod's ambient credentials — an IRSA role, EKS Pod Identity, or EC2 instance profile — so no secrets are stored in the file:
{
"authorizerType": "AWSServiceAccount"
}
To set up IRSA:
-
Register an IAM OIDC provider for the cluster, if you have not already:
eksctl utils associate-iam-oidc-provider --cluster my-cluster --approve -
Create an IAM role the OpenCost ServiceAccount can assume. The OIDC host is the cluster's OIDC issuer URL without
https://.Trust policy
{"Version": "2012-10-17","Statement": [{"Effect": "Allow","Principal": {"Federated": "arn:aws:iam::123456789012:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE"},"Action": "sts:AssumeRoleWithWebIdentity","Condition": {"StringEquals": {"oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:sub": "system:serviceaccount:opencost:opencost","oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:aud": "sts.amazonaws.com"}}}]} -
Annotate the OpenCost ServiceAccount in your Helm values:
serviceAccount:create: trueannotations:eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/OpenCostRole
Assume Role
AWSAssumeRole assumes roleARN using another authorizer — use it to read a CUR in a different AWS account. The wrapped identity needs sts:AssumeRole on roleARN:
{
"authorizerType": "AWSAssumeRole",
"roleARN": "arn:aws:iam::123456789012:role/OpenCostRole",
"authorizer": {
"authorizerType": "AWSServiceAccount"
}
}
Web Identity
AWSWebIdentity exchanges an OIDC token from outside AWS for AWS credentials — use it when OpenCost runs on another cloud:
{
"authorizerType": "AWSWebIdentity",
"roleARN": "arn:aws:iam::123456789012:role/OpenCostRole",
"identityProvider": "Google",
"tokenRetriever": {
"aud": "sts.amazonaws.com"
}
}
Cloud Costs IAM policy
The identity needs to run Athena queries, read Glue table metadata, read and write the query results bucket, and read the CUR bucket (my-cur-bucket below). The Glue statement is required: OpenCost queries information_schema.columns to detect the CUR version, and without it no Cloud Costs are returned.
IAM policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Athena",
"Effect": "Allow",
"Action": [
"athena:StartQueryExecution",
"athena:GetQueryExecution",
"athena:GetQueryResults",
"athena:StopQueryExecution",
"athena:GetWorkGroup"
],
"Resource": "arn:aws:athena:us-east-1:123456789012:workgroup/primary"
},
{
"Sid": "Glue",
"Effect": "Allow",
"Action": [
"glue:GetDatabase",
"glue:GetDatabases",
"glue:GetTable",
"glue:GetTables",
"glue:GetPartitions"
],
"Resource": [
"arn:aws:glue:us-east-1:123456789012:catalog",
"arn:aws:glue:us-east-1:123456789012:database/athenacurcfn_my_cur",
"arn:aws:glue:us-east-1:123456789012:table/athenacurcfn_my_cur/my_cur_2_0"
]
},
{
"Sid": "QueryResultsBucket",
"Effect": "Allow",
"Action": ["s3:GetBucketLocation", "s3:ListBucket"],
"Resource": "arn:aws:s3:::aws-athena-query-results-my-cur"
},
{
"Sid": "QueryResultsObjects",
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::aws-athena-query-results-my-cur/*"
},
{
"Sid": "CurBucket",
"Effect": "Allow",
"Action": ["s3:GetBucketLocation", "s3:ListBucket"],
"Resource": "arn:aws:s3:::my-cur-bucket"
},
{
"Sid": "CurObjects",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-cur-bucket/*"
}
]
}
Deploy the configuration
Load the cloud-integration.json into a Kubernetes secret in your opencost namespace.
kubectl create secret generic cloud-costs --from-file=./cloud-integration.json --namespace opencost
Update your local OpenCost Helm values file to match the name of the secret and enable Cloud Costs:
opencost:
cloudIntegrationSecret: cloud-costs
cloudCost:
enabled: true
You may refer to the Cloud Costs documentation for configuring Cloud Costs for multiple accounts and cloud service providers.
Verifying
Look for AthenaIntegration[...]: GetCloudCost: in the OpenCost logs, then check that /model/cloudCost returns data. If nothing is attributed to Kubernetes, confirm your CUR 2.0 export includes resource_tags.
Install OpenCost
Helm is the preferred installation method for OpenCost.
Using the OpenCost Helm Chart
You may check out the source for the OpenCost Helm Chart or you may install the Helm chart directly to your Kubernetes cluster. Review the values.yaml for the settings available for customization. With your custom settings in the Helm values file local.yaml, install OpenCost:
helm install opencost --repo https://opencost.github.io/opencost-helm-chart opencost \
--namespace opencost -f local.yaml
Updating OpenCost via Helm
Upgrading the Helm chart version or updating settings may be done with the following:
helm upgrade opencost --repo https://opencost.github.io/opencost-helm-chart opencost \
--namespace opencost -f local.yaml
Installing with the OpenCost Manifest
Installing from the OpenCost manifest is supported on AWS.
OpenCost standalone Kubernetes manifest installation is no longer supported. Use the OpenCost Helm chart for installation and upgrades:
helm repo add opencost https://opencost.github.io/opencost-helm-chart
helm repo update
helm install opencost opencost/opencost --namespace opencost --create-namespace

