Skip to content
NewFinOps, Kubernetes and AI, on one platform
Book a demo

Trust center

Read-only by default, with write access you control

The KubeOn agent only reads. KubeOn changes a cluster only through pull requests or a separate controller you turn on, feature by feature, and you can pause it at any time.

Security at a glance

Read-only agent

get, list and watch only. No Secrets, no ConfigMaps. Write access is a separate, opt-in controller.

Outbound only

The hub never calls into your clusters. Agents push snapshots out over HTTPS.

Exports stay in your account

Billing exports are read in place through identities that cannot change them.

Encrypted and isolated

Encrypted at rest with UnitVane-managed keys and in transit with TLS 1.2 or later. Each organization's data is kept apart.

Least-privilege IAM

Billing roles read the export and write only query results. Agent roles can only add snapshots.

SSO and team scope

SAML 2.0 or OIDC sign-in, four roles, and team leads limited to their teams.

Audit log

Every mapping, policy, integration and proposal decision, with who and when.

Scanned supply chain

Images scanned on every build; high and critical findings block a release.

Published permissions

Agent and billing permissions, in the open

These are the exact rules the agent's ClusterRole and the AWS billing role contain. Azure and Google Cloud use the roles listed in the docs: Storage Blob Data Reader and Cost Management Reader on Azure, BigQuery Data Viewer and Job User on Google Cloud.

Agent ClusterRole
apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata:  name: kubeon-agent-readerrules:  - apiGroups: [""]    resources: [nodes, pods, namespaces, persistentvolumes,                persistentvolumeclaims, services]    verbs: [get, list, watch]  - apiGroups: [apps]    resources: [deployments, statefulsets, daemonsets, replicasets]    verbs: [get, list, watch]  - apiGroups: [batch]    resources: [jobs, cronjobs]    verbs: [get, list, watch]  - apiGroups: [storage.k8s.io]    resources: [storageclasses]    verbs: [get, list, watch]  - apiGroups: [metrics.k8s.io]    resources: [nodes, pods]    verbs: [get, list]  - apiGroups: [karpenter.sh]            # NodePools, on Karpenter clusters    resources: [nodepools, nodeclaims]    verbs: [get, list, watch]  - apiGroups: [autoscaling]    resources: [horizontalpodautoscalers]    verbs: [get, list, watch]  - apiGroups: [argoproj.io]             # where workloads are deployed from    resources: [applications, rollouts]    verbs: [get, list, watch]  - apiGroups: [kustomize.toolkit.fluxcd.io, helm.toolkit.fluxcd.io,                source.toolkit.fluxcd.io]    resources: [kustomizations, helmreleases, gitrepositories]    verbs: [get, list, watch]
AWS billing role policy
{  "Version": "2012-10-17",  "Statement": [    {      "Sid": "AthenaQuery",      "Effect": "Allow",      "Action": [        "athena:StartQueryExecution", "athena:GetQueryExecution",        "athena:GetQueryResults", "athena:StopQueryExecution", "athena:GetWorkGroup"      ],      "Resource": "arn:aws:athena:us-east-1:111122223333:workgroup/primary"    },    {      "Sid": "GlueCatalogRead",      "Effect": "Allow",      "Action": [        "glue:GetDatabase", "glue:GetDatabases", "glue:GetTable",        "glue:GetTables", "glue:GetPartition", "glue:GetPartitions"      ],      "Resource": [        "arn:aws:glue:us-east-1:111122223333:catalog",        "arn:aws:glue:us-east-1:111122223333:database/cur_database",        "arn:aws:glue:us-east-1:111122223333:table/cur_database/*"      ]    },    {      "Sid": "CurBucketRead",      "Effect": "Allow",      "Action": ["s3:GetObject", "s3:ListBucket", "s3:GetBucketLocation"],      "Resource": ["arn:aws:s3:::acme-cur-exports", "arn:aws:s3:::acme-cur-exports/*"]    },    {      "Sid": "AthenaResultsReadWrite",      "Effect": "Allow",      "Action": [        "s3:GetObject", "s3:PutObject", "s3:AbortMultipartUpload",        "s3:ListBucket", "s3:GetBucketLocation"      ],      "Resource": ["arn:aws:s3:::acme-athena-results", "arn:aws:s3:::acme-athena-results/*"]    },    {      "Sid": "STSAccess",      "Effect": "Allow",      "Action": "sts:GetCallerIdentity",      "Resource": "*"    }  ]}

KubeOn GPU optimizer

Components that can change a cluster, only where you install them

The GPU optimizer has its own Helm release, and the KubeOn controller for automated savings is off by default with one role per feature. Clusters with neither are never changed by KubeOn.

  • Installed only in clusters you choose, as its own Helm release, separate from the read-only agent
  • Acts only on the node pools and namespaces a policy names; everything else is out of reach
  • Hard limits per policy: minimum and maximum nodes, monthly cost, GPU-hour price
  • Disruptive steps such as drains and repartitions run only in the policy's change window
  • Evicts through the Eviction API, so PodDisruptionBudgets are always respected
  • No access to Secrets or ConfigMaps outside the GPU Operator config it manages
  • Pulls policies and approvals from the hub over HTTPS; the hub never connects into your cluster
  • Every action in the audit log with the policy that allowed it, and a one-click revert where the change can be undone
GPU optimizer ClusterRole
apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata:  name: kubeon-gpu-optimizerrules:  # Read what it optimizes  - apiGroups: [""]    resources: [nodes, pods, namespaces]    verbs: [get, list, watch]  - apiGroups: [apps]    resources: [deployments, statefulsets, replicasets]    verbs: [get, list, watch]  - apiGroups: [policy]    resources: [poddisruptionbudgets]    verbs: [get, list, watch]  # Label, taint and cordon GPU nodes; drain through the Eviction API  - apiGroups: [""]    resources: [nodes]    verbs: [patch]  - apiGroups: [""]    resources: [pods/eviction]    verbs: [create]  # Add and remove GPU capacity through Karpenter  - apiGroups: [karpenter.sh]    resources: [nodepools, nodeclaims]    verbs: [get, list, watch, create, patch, delete]  # Its own policies, synced from the hub, and their status  - apiGroups: [gpu.kubeon.io]    resources: [gpupolicies, gpupolicies/status]    verbs: [get, list, watch, create, update, patch, delete]---# Created only in namespaces named by a ScaleToZero policykind: Rolerules:  - apiGroups: [apps]    resources: [deployments/scale, statefulsets/scale]    verbs: [get, patch]---# In the gpu-operator namespace, for time-slicing onlykind: Rolerules:  - apiGroups: [""]    resources: [configmaps]    resourceNames: [time-slicing-config]    verbs: [get, patch]

Data

What the agent and hub read, and what they never touch

Collected

  • Node names, instance types, capacity, zones and provider IDs
  • Namespace, workload and pod names, labels and owner references
  • CPU and memory requests and measured usage per pod
  • PersistentVolume and PVC sizes, classes and status
  • Service types and load balancer hostnames
  • Billing line items from your export: cost, usage type, resource ID

Never collected

  • Secrets, ConfigMaps or environment variables
  • Container images, logs or application data
  • Request payloads or network packet contents from your clusters
  • Credentials of any kind from your clusters
  • Personal data about your customers, unless gateway prompts you choose to log contain it

UnitVane AI gateway

Model traffic, handled with care

The gateway sits in the path of your prompts, so it records as little as it can and keeps credentials out of your applications.

Metadata by default

Tokens, route, latency, cost and status are recorded. Bodies are logged only on routes with logging on; routes with the cache on keep responses until the cache TTL ends.

Email, phone and card masking

Email addresses, phone numbers and card numbers are masked before a request leaves the gateway. Names and other free text are not detected.

Credentials kept out of app code

Provider keys never sit in app code or gateway keys. UnitVane stores them encrypted and uses them only to call your provider.

Region pinning

Routes, fallback included, can be held to the providers and regions you choose.

Retention

How long data is kept

UnitVane keeps source data only as long as allocation and savings need it, and keeps the costs derived from it for the life of the workspace. These are the defaults.

On first connect, UnitVane reads 180 days of billing history and allocates it. The raw rows leave the hub after 90 days; the allocated costs stay for the life of the workspace. Whether evaluation data is deleted or kept when an evaluation ends is agreed before it starts.

Data retention defaults by kind of data
Source dataWhat the agent and your billing export deliver. UnitVane keeps it only as long as allocation and savings need it.
Cluster snapshotsOne compressed file per hourly agent run: nodes, pods, volumes and their usageKept: 14 daysDeleted by the snapshot bucket's lifecycle rule. Until then, a failed ingestion can be retried.
Pod usage samplesCPU and memory usage per pod from each agent runKept: 30 daysDeleted. Container rightsizing reads the last 7 days and node sizing the last 14.
Billing rowsLine items read from your billing exportKept: 90 daysDeleted from the hub. The costs allocated from them stay, and your export remains the record: a billing backfill re-reads up to 366 days of it.
Athena query results (AWS)Results of the billing queries UnitVane runsKept: 14 daysDeleted.
Derived dataThe cost information UnitVane computes from the source data.
Allocated costs and reportsCost per pod, namespace, team, label and day, with shared, idle and unallocated lines, and saved reportsKept: Life of the workspaceKept after the raw rows are gone. Late data is repaired automatically for the last 7 days. Admins and platform engineers can re-run allocation up to 92 days back from Data health; a day whose billing rows have left the hub (after 90 days by default) needs a billing backfill first.
Assistant usage ledgerEvery Ask KubeOn call: user, feature, model, tokens and estimated costKept: 365 daysDeleted.
UnitVane AI gatewayWhat the gateway keeps about the requests it routes. Bodies are not logged unless you turn logging on for a route, and routes with the cache on keep responses until the TTL ends.
Request metadataTokens, route, target, latency, status and cost of each requestKept: 90 days by defaultDeleted.
Prompt and response bodiesThe content of requests and responsesKept: Not logged by defaultWritten to the log only on routes where you turn logging on. Cached responses are covered in the next row.
Cached responsesResponses on routes with the cache onKept: Until the route's cache TTL endsExpire with the TTL.
At your model providerRequests sent to Azure OpenAI, Amazon Bedrock or Google Vertex AIKept: Set by your provider accountRequests go to your own provider account, so its data retention terms apply.

Controls

How the hub is hardened

Network

  • Internal load balancer by default, with an allow-list of private ranges
  • TLS 1.3 policy on the load balancer, HTTP redirected to HTTPS
  • Optional CloudFront with AWS WAF: IP allow-list, managed rules, rate limits

Application

  • The hub refuses to start without a signing secret, or without KMS outside development
  • Short-lived access tokens; lockout after 5 failed sign-ins for 15 minutes
  • Strict security headers on every response

Secrets

  • Secrets in your secrets manager, never in task definitions
  • Database password generated and rotated by the cloud provider
  • Integration credentials encrypted at rest

Build and release

  • Trivy image scans, gitleaks secret scanning, dependency audits
  • Checkov and tflint on every Terraform change
  • Non-root images, pinned chart versions

Compliance

Inside your compliance boundary

UnitVane runs every product for you and reads your billing exports in place, with read-only access you can review. We provide the architecture, data flow, permission lists and answers to your security questionnaire during evaluation. For data residency in the EU, see data sovereignty.

Responsible disclosure

Report a vulnerability

Email security@unitvane.com with the details. We acknowledge reports within two business days and keep you updated until the issue is fixed.

Bring your security team to the demo.

We walk through the agent's permissions, the data flow and the hub's controls on your architecture.