ClusterNap

Security overview

What ClusterNap can touch, and what it can't

Written for the security engineer reviewing us. Every permission the agent holds is on this page, with the reason it needs it.

How it works

One agent pod runs inside your cluster: every 5 minutes it reads each opted-in namespace's schedule and scales its Deployments and StatefulSets to zero or back, and every 15 seconds it checks for wake-up requests. A weekly report job sends the savings summary and, if you enable it, scans AWS for unused resources.

Both connect out to the ClusterNap API over HTTPS to send status and fetch wake-up requests. No inbound connection to your cluster or network is ever needed, and the agent keeps working if the API is unreachable.

Kubernetes permissions

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
rules:
  - apiGroups: [""]
    resources: [namespaces]
    verbs: [get, list, update]
  - apiGroups: [apps]
    resources: [deployments, statefulsets]
    verbs: [get, list, update]
  - apiGroups: [""]
    resources: [nodes]
    verbs: [list]
PermissionWhy
namespaces: get, listFind namespaces that carry a cost-optimizer.io/schedule annotation.
namespaces: updateRecord sleep state and wake-until time in cost-optimizer.io/* annotations.
deployments, statefulsets: get, listRead replica counts and the CPU/memory requests used to price savings.
deployments, statefulsets: updateChange spec.replicas, and store the original count in an annotation on the workload.
nodes: listRead-only. Tell whether freed capacity is removed (Karpenter, Cluster Autoscaler, EKS Auto Mode, Fargate) so savings are shown honestly.
ingresses: get, list, update (only with wake on visit)Point a sleeping namespace's Ingresses at the waking-up page and restore them exactly on wake.
services: get, create, delete (only with wake on visit)Create and remove one ExternalName Service, clusternap-waker, in each sleeping namespace.

Unless you turn on wake on visit, the agent cannot create or delete anything, cannot read Secrets, ConfigMaps or pod logs, and cannot exec into pods. It only acts on namespaces you annotate; a workload annotated cost-optimizer.io/exclude: "true" is never scaled.

AWS permissions (optional)

Only needed for the unused-resource scan. Grant it to the agent's service account with IAM Roles for Service Accounts (IRSA), so no long-lived keys exist:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": ["ec2:DescribeVolumes", "ec2:DescribeAddresses"],
    "Resource": "*"
  }]
}

Both actions are read-only. ClusterNap never deletes, detaches or modifies AWS resources; it lists them so you can decide.

Data that leaves your cluster

Sent to the APIExample
Namespace name, schedule, time zonefeature-checkout, sun-fri 20:00-08:00, Asia/Tbilisi
Sleep state and timestampsasleep since 2026-10-13 20:00 UTC
Savings per finished sleep12 hours, $4.31
Unused AWS resourcesvol-0a1b2c3d, 500 GiB gp2, $50/month

Never sent: pod specs, container images, environment variables, Secrets, ConfigMaps, logs or metrics. The Slack webhook URL stays in a Secret in your cluster; reports go straight from your cluster to Slack.

Credentials and storage

  • Each cluster gets its own API token. We store only its SHA-256 hash, so a database leak does not expose usable tokens. Deleting the cluster in the dashboard revokes the token immediately.
  • Dashboard passwords are hashed with bcrypt. Sessions use HttpOnly, SameSite cookies, stored hashed and expiring after 14 days.
  • Every dashboard query is scoped to your organization; tests check that one organization cannot read or change another's data.
  • Three wrong passwords for an account lock sign-in for that account from that address for 30 minutes; twenty from anywhere lock the account for 30 minutes. Unknown emails are treated the same, so sign-in does not reveal who has an account.

Agent hardening

  • Distroless, static image with no shell or package manager.
  • Runs as a non-root user with a read-only root filesystem, all Linux capabilities dropped and the RuntimeDefault seccomp profile.
  • Nothing listens on a port: the agent only makes outbound calls.
  • The agent sends its token only over HTTPS and refuses a plain-http API address, except on the local machine for testing.
  • Wake-up requests from the dashboard are honoured only for namespaces you annotated. Even a compromised ClusterNap API could not make the agent touch any other namespace.

Reporting a vulnerability

Email mikheiljibuti@yahoo.com. We reply within two business days and credit researchers who want to be credited.