Skip to content

Kubernetes Connector

The Kubernetes connector adds pod-level attribution to your egress data. Without it, traffic from an EKS cluster is attributed to the node (EC2 instance) that sent it; with it, each flow is attributed to the individual pod and workload.

The sensor is a small in-cluster Deployment that watches pod metadata and registers pod IP ↔ workload mappings with Outbound. It does not touch your traffic — forwarding still happens through the Outbound gateway in your VPC.

  • An EKS cluster with an OIDC provider (for IRSA).
  • The AWS connector already set up, so the /cloudphilos/outbound/api-key secret exists in your account.
  • Helm 3.

By default the AWS VPC CNI source-NATs pod traffic to the node’s IP, which makes pods indistinguishable from their node. Enable external SNAT so pod IPs are preserved on their way to the Outbound gateway (which performs the NAT instead):

Terminal window
kubectl set env daemonset -n kube-system aws-node AWS_VPC_K8S_CNI_EXTERNALSNAT=true

Or, if you manage the VPC CNI as an EKS addon:

{
"env": {
"AWS_VPC_K8S_CNI_EXTERNALSNAT": "true"
}
}

The sensor needs exactly one AWS permission:

PermissionResource scopeWhy we need it
secretsmanager:GetSecretValue/cloudphilos/outbound/api-key*Fetch the API key used to authenticate registrations to Outbound’s ingest endpoint.

Inside the cluster, the sensor only reads pod metadata (names, labels, IPs) to build the pod ↔ workload mapping. It never modifies cluster resources; the exact RBAC rules ship with the Helm chart.

Terraform:

data "aws_iam_policy_document" "outbound_sensor_assume" {
statement {
actions = ["sts:AssumeRoleWithWebIdentity"]
principals {
type = "Federated"
identifiers = [var.eks_oidc_provider_arn]
}
condition {
test = "StringEquals"
variable = "${var.eks_oidc_provider}:sub"
values = ["system:serviceaccount:outbound-system:outbound-k8s-sensor"]
}
condition {
test = "StringEquals"
variable = "${var.eks_oidc_provider}:aud"
values = ["sts.amazonaws.com"]
}
}
}
resource "aws_iam_role" "outbound_sensor" {
name = "cloudphilos-outbound-k8s-sensor-role"
assume_role_policy = data.aws_iam_policy_document.outbound_sensor_assume.json
}
resource "aws_iam_role_policy" "outbound_sensor" {
name = "cloudphilos-outbound-k8s-sensor-policy"
role = aws_iam_role.outbound_sensor.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = "secretsmanager:GetSecretValue"
Resource = "arn:aws:secretsmanager:${var.region}:${var.account_id}:secret:/cloudphilos/outbound/api-key*"
}]
})
}

The in-app wizard (Integrations → Add integration → Kubernetes) generates the same role as a CloudFormation snippet if you prefer.

Terminal window
helm repo add cloudphilos https://charts.outbound.net
helm repo update
helm install outbound-k8s-sensor cloudphilos/outbound-k8s-sensor \
--namespace outbound-system \
--create-namespace \
--set env.tenantId=<your-tenant-id> \
--set env.awsRegion=<region> \
--set env.apiKeySecretName=/cloudphilos/outbound/api-key \
--set serviceAccount.roleArn=arn:aws:iam::<account-id>:role/cloudphilos-outbound-k8s-sensor-role

The chart deploys a single-replica Deployment with minimal footprint (requests: 10m CPU / 64Mi memory) under the outbound-k8s-sensor service account.

Terminal window
kubectl get pods -n outbound-system
kubectl logs -n outbound-system deploy/outbound-k8s-sensor

Within a few minutes, egress from cluster workloads should appear in the dashboard attributed to pods and workloads rather than nodes.

Terminal window
helm uninstall outbound-k8s-sensor -n outbound-system

Egress attribution falls back to node level; traffic itself is unaffected. If you also disable AWS_VPC_K8S_CNI_EXTERNALSNAT, do so only if the node-SNAT path is what you want going forward.