Skip to main content
Network Cost Attribution for Kubernetes allocates network spend to the individual pods that drive it. When enabled, the Vantage Kubernetes agent attributes network costs down to the pod level, so they appear in Cost Reports alongside compute, memory, GPU, and storage costs. Each pod’s network cost is broken out by destination type, such as intra-zone, intra-region (cross-AZ), cross-region, and internet egress, so you can see not just how much a workload spent on the network, but what type of traffic drove the cost. You can then use Virtual Tags to roll these costs up to the teams, applications, or business units that generated them.

How It Works

When network cost collection is enabled, the Vantage Kubernetes agent Helm chart deploys a per-node network collector that runs as a DaemonSet. The collector reads Linux connection-tracking (conntrack) data on each node, attributes each pod’s traffic, and classifies the transmitted bytes into mutually exclusive billing buckets by destination. The agent pulls these per-pod summaries each report cycle and joins them with your provider’s data transfer rates to produce a per-pod network cost.
The collector does not retain full flow records; it summarizes traffic into cost buckets and reports running totals. There is no flow log storage or query infrastructure to operate, and enabling this feature does not require VPC Flow Logs.

Network Cost Attribution vs. Network Flow Reports

Network Cost Attribution is different from Network Flow Reports. Network Flow Reports use VPC Flow Log data to analyze source/destination flows and route classification at the cloud-provider level (answering “where is my traffic going?”). Kubernetes Network Cost Attribution allocates pod-level network cost using connection-tracking data observed inside the cluster (answering “which workload owns this network spend?”). It classifies traffic by destination type (intra-zone, intra-region, cross-region, internet, and more) rather than showing individual destination addresses. The two features are complementary: use Network Flow Reports when you need to investigate where specific traffic is going, and use Kubernetes Network Cost Attribution when you need to put a per-pod dollar amount on network spend and charge it back to a team.

Supported Providers

Network Cost Attribution supports the following providers at launch:
  • Amazon Elastic Kubernetes Service (EKS)
  • Azure Kubernetes Service (AKS)
  • Google Kubernetes Engine (GKE)
Collection works on any node where the collector can run within these providers, including IPv6 and dual-stack (IPv4/IPv6) clusters.
The collector reads traffic from Linux connection tracking (conntrack). On clusters where the CNI datapath bypasses kernel netfilter, for example, Cilium with kube-proxy replacement, conntrack sees little or no traffic, so network costs are not attributed. These configurations are not supported at launch.
Oracle Cloud (OKE) and on-premises clusters are not supported at launch. AWS network discovery and S3 path-aware pricing are available on EKS only; other supported providers use manual subnet configuration.

Prerequisites

Before you enable network cost collection, ensure you meet the following requirements:
  • A working Vantage Kubernetes agent integration.
  • Vantage Kubernetes agent version 1.3.3 or later, available as part of Helm chart version 1.9.5 or later. This version includes the network collector, AWS network discovery, and the collector metrics endpoint.
  • Connection-tracking byte accounting must be enabled on every node. Set the net.netfilter.nf_conntrack_acct=1 sysctl cluster-wide before traffic is generated. When this is off (the default on many node images), the kernel leaves conntrack byte counters at zero, so the collector cannot attribute traffic. Only connections opened after the sysctl is set receive counters.
    nf_conntrack_acct is a node-level kernel setting that Vantage and the Helm chart cannot enable for you. It’s applied through your node configuration, so it’s typically handled by whoever manages your cluster’s nodes. To check whether it is already on for a node (a value of 1 means it is):
    After it’s enabled, confirm it took effect with the vantage_collector_conntrack_acct_enabled metric (see Monitor the Collector); the collector also logs a warning at startup when byte accounting is disabled.
  • The collector runs as a DaemonSet with host network access and an elevated security context (the NET_ADMIN capability) so it can read conntrack for local pods. The Helm chart configures this for you (hostNetwork: true and capabilities.add: ["NET_ADMIN"]). Its ServiceAccount needs read-only (get/list/watch) access to pods, nodes, and ConfigMaps.
    The network collector is opt-in and can be disabled per cluster if your security policy does not permit a privileged, host-network DaemonSet. Nodes where the collector cannot run (for example, Fargate or hybrid nodes without conntrack access) will not report network costs.

Enable Network Cost Collection

Enable the collector and provide your subnet configuration through the Vantage Kubernetes agent Helm chart.
1
Enable net.netfilter.nf_conntrack_acct=1 on every node (see Prerequisites).
2
Set agent.networkCost.enabled=true and populate agent.networkCost.subnets with your cluster’s destination CIDRs. See Configure Subnets for how to inventory them. For example:
3
Upgrade the agent to apply the changes:
Allocated network costs begin appearing in your Kubernetes Cost Reports within one full collection cycle (approximately 24 hours).

Configure Subnets

The collector compares each flow’s remote IP with your subnet map to classify it as in_zone, in_region, or cross_region. Populate agent.networkCost.subnets with the private destination CIDRs your workloads can reach: cluster subnets, peered networks, private managed services, and overlay pod CIDRs where applicable. Keep the following guidelines in mind when defining your subnets:
  • A zone enables same-zone classification. When only a region is supplied, all same-region matches are reported as in_region. The region is derived from the zone when omitted (for example, us-east-1a resolves to us-east-1).
  • On a dual-stack cluster, add both IPv4 and IPv6 ranges. IP families are matched independently.
  • The collector does not assume that an unmatched private address is internet traffic. It reports the traffic as unknown until you add the CIDR or an override.
Use the tabs below to inventory the cluster network for your provider, then add the output to your Helm values.
AWS subnets are Availability Zone scoped. List every IPv4 subnet in a VPC in the same cidr/zone shape used by the Helm value:
Add the results to your Helm values:
For an EKS cluster that can grant the agent EC2 read permissions, prefer AWS network discovery. It discovers VPC subnets automatically and also enables S3 egress-path classification, so you don’t have to maintain the subnet list by hand.

Overlay Networks and Pod CIDRs

Overlay networking (for example, Calico, Cilium, kubenet, or GKE VPC-native networking) can allocate pod addresses outside the node’s primary VPC/VNet subnet. When a remote pod address does not match an entry in subnets, it is classified as unknown. Add the relevant pod CIDR with the cluster’s zone or region:

NAT, Peering, and Overrides

Use overrides to force a bucket for a destination CIDR. Overrides take precedence over subnet entries, and the most-specific CIDR wins. Use them when destination ownership or topology cannot be represented accurately by a zone/region map.
A managed NAT gateway normally source-NATs traffic on its way to a public destination; it is not the remote IP visible in the pod’s conntrack flow. Do not add its private address merely to classify ordinary internet egress. The public destination already falls into internet. Reserve NAT overrides for cases where a NAT or proxy appliance is itself the remote endpoint. For a same-region peered VPC, prefer a normal subnets entry with its actual region rather than a cross_region override.

Validate the Rendered Configuration

After you apply the Helm values, inspect the ConfigMap mounted by the network collector to confirm your configuration rendered correctly:
The rendered document should include both subnets: and overrides: (the latter may be an empty list).

Optional AWS Network Discovery (EKS)

On EKS, you can let the agent discover your network topology automatically instead of maintaining subnet lists by hand. Enable it with agent.networkCost.discovery.enabled=true. Discovery has two benefits:
  • Turnkey subnet inventory: Classification depends on knowing every subnet CIDR in the cluster’s VPC(s) and each subnet’s zone/region. Maintaining that list by hand is error-prone and drifts whenever someone adds a subnet, AZ, or VPC. Any missed subnet classifies traffic as unknown or internet instead of the correct bucket. Discovery enumerates all subnets in the tagged VPC(s) directly from the EC2 APIs, so the inventory stays complete and current. With discovery on, the manual subnet list can be as small as subnets: [] plus any human-only overrides.
  • Accurate S3 egress pricing: The S3 path-aware buckets exist because the cost of reaching S3 depends on how each source subnet egresses (a gateway VPC endpoint is free; a NAT gateway is not). Discovery resolves each subnet’s S3 egress path and fetches the regional S3 prefix lists automatically, so S3 traffic is priced correctly without hand-authored fields.
Discovery requires the following read-only EC2 permissions on the agent’s ServiceAccount (via IRSA or EKS Pod Identity):
  • ec2:DescribeSubnets
  • ec2:DescribeRouteTables
  • ec2:DescribeManagedPrefixLists
  • ec2:GetManagedPrefixListEntries
Discovery is fail-closed. If the region cannot be resolved, credentials are missing, or the permission probe fails, the agent logs a warning and leaves discovery off. It does not crash-loop, and classification continues on the manual subnet configuration.

Billing Buckets

Transmitted bytes are grouped into mutually exclusive buckets. Each bucket is priced by the destination and, for S3-bound traffic, by how the source subnet egresses. The label in the first column is what appears in Cost Reports. The configuration key is the value you use in a subnet override.
The S3 path-aware buckets require AWS network discovery. Without it, S3 traffic falls through to standard destination matching (often Internet Egress). Rates are blended per-GB rates derived from your provider’s actual data transfer charges over the month.

View Network Costs in Cost Reports

Pod-level network costs appear in Cost Reports under the Kubernetes provider, alongside compute, memory, GPU, and storage costs. To isolate network costs, filter the Kubernetes provider by Category and select network. The vntg:category tag also works and is the same pattern used for CPU, RAM, GPU, and storage (see Filter by CPU, RAM, Storage, and GPU).
Network costs are not part of Kubernetes Efficiency Reports. Efficiency Reports measure utilization of provisioned capacity, whereas network traffic is charged per byte and has no notion of idle reserved capacity. Network costs can still surface optimization opportunities, such as cross-AZ traffic, NAT gateway processing, internet egress, or inefficient S3 routing, through Cost Reports.
1
Create or open a Kubernetes Cost Report.
2
Add a filter: All costs from Kubernetes where Category is network. (Filtering by Tag vntg:category is network works too.)
3
Use the report’s Group By menu to break the network costs down. Group by Subcategory to see the destination breakdown (Intra-Zone Egress, Intra-Region Egress, Cross-Region Egress, Internet Egress, and the S3 paths), which shows how a workload’s traffic is classified. To roll network costs up to the owning team or application, group by Tag and choose the namespace tag, a workload label, or a Virtual Tag. On Kubernetes Cost Reports, namespace and labels are surfaced as tags.
Because network costs carry the same pod, namespace, label, and annotation tags as the pod’s compute costs, any Virtual Tag you already use for chargeback will allocate network costs alongside compute, memory, and GPU. For step-by-step chargeback setups—such as mapping costs to a team tag or allocating shared costs by usage—see Virtual Tagging Examples.
Kubernetes network costs are re-derived from your cloud provider’s data transfer charges (for AWS, the Data Transfer and NAT Gateway charges already in your Cost and Usage Report). As with compute, reporting on both your primary provider and Kubernetes in the same Cost Report double counts these charges. Removing the overlap is only approximate: data transfer and NAT gateway line items usually aren’t tagged with the cluster, so there is no clean way to exclude only the cluster’s share. Excluding all of a provider’s data transfer and NAT gateway charges also removes network spend from non-Kubernetes workloads, while excluding none leaves the double count in place. Choose whichever approximation better fits your reporting, and see Avoid Double Counting Costs in Cost Reports for the compute equivalent.

Example: Charge Network Costs Back to a Team

Suppose unallocated network spend currently lands on your platform team, and you want each application team to own its network costs alongside compute. If your workloads are labeled with a team identifier (for example, a team pod label or the app.kubernetes.io/part-of label), you can roll network costs up to that team.
1
Confirm the label is collected by the agent. Labels matching app.kubernetes.io/* are collected by default; to collect a custom label such as team, add it to the agent’s allowed labels. Collected labels appear as tags on Kubernetes cost rows, including network rows.
2
(Optional) If team names vary across clusters or providers, create a team Custom Value Virtual Tag that maps the underlying labels and namespaces to standardized team values.
3
Open a Kubernetes Cost Report and group by your team tag. To view only the network portion, add the filter where Category is network; to show each team’s full Kubernetes bill, leave the category filter off so network rolls up alongside compute, memory, GPU, and storage.
Each team’s row now includes the network costs their workloads drove, so the platform team no longer absorbs unallocated network spend.

Troubleshooting

If network reporting looks empty or incomplete, check the following in order. The agent and collector expose Prometheus metrics (see Monitor the Collector) that correspond to each check.
1

Collector coverage gaps

Confirm a collector is running on every node. A missing collector (from scheduling, a crash loop, or a taint without a matching toleration) means those nodes report no network costs. Add tolerations for any tainted nodes you want network costs from.
2

Connection-tracking accounting disabled

If net.netfilter.nf_conntrack_acct is not enabled, byte counters stay at zero and no traffic is attributed, even when the collector is healthy. Enable the sysctl cluster-wide, and remember that only connections opened afterward receive counters.
3

Agent cannot pull from a collector

If the agent cannot retrieve reports from a collector, or has not succeeded within your report interval, network data will be stale or missing for that node’s pods.
4

Traffic shown as Unclassified Egress

Costs appearing under Unclassified Egress (the unknown bucket) mean a private destination CIDR is missing from your configuration. Add the subnet (or an override), or enable AWS network discovery on EKS.
5

Short-lived pods

Very short-lived pods may not be captured if your collection interval is coarse. Tune the Kubernetes polling interval based on the shortest-lived workload you need to attribute.

Monitor the Collector

The agent exposes network metrics on its existing metrics endpoint (default port 9010), and the network collector exposes its own metrics endpoint (default port 8883). Point your Prometheus scrape configuration at both. The following series are the most useful for catching silent failures and undercounting in cases where pods look healthy but network data is missing, stale, or incomplete. The following Prometheus alert rules are useful starting points. Tune the stale-pull threshold to match your deployed report interval (the example assumes the default ~1 hour interval).