Reference
Data and access
What the Napwake operator and its doorman read, write and send, for a security review. The chart's RBAC matches it.
- Never reads
- Your Secrets. The doorman reads one of its own
- Deletes only
- Its own ManagedWorkloads, EndpointSlices and forwarder Deployments
- Leaves the cluster
- Nothing, unless configured to
- Telemetry
- None
What it reads
Section titled “What it reads”| Resource | Why | How |
|---|---|---|
| Deployments, StatefulSets | Replicas, pod template, labels and annotations of the workloads it manages | Watched |
| Pods | Its running pods’ requests. CPU activity is judged against the app containers’, and all containers’, sidecars included, price it. Which pod sent a request that woke a workload. Requests of every pod bound to a node, to measure each node pool’s spare capacity, which saved is worked out from. With doorman.negForwarder.enabled, forwarder pods’ addresses and readiness |
Watched, caching only bound, unfinished pods, and only their name, node, phase and requests. The rest is read from the API server. App containers’ requests at most every 5 minutes. Not watched with watchNamespaces |
| Pods, by the doorman | The pod each endpoint of a woken workload names, to check the address is that pod’s | Addresses kept 30 seconds |
Pod metrics (metrics.k8s.io) |
CPU use, the activity clock’s main signal | When needed, not cached |
| Services | Which to route a paused workload’s requests through, and which workload an address in an environment names | Watched |
| Ingresses | Class and backend Services, to find those a GKE Ingress puts behind container-native load balancing, which can’t be routed to the doorman | Watched |
| EndpointSlices | Its own, routing paused workloads to the doorman, and the doorman Service’s, to find the doorman’s pods | Watched |
| EndpointSlices, by the doorman | All in the watched namespaces, to find a woken workload’s Ready pods | Watched |
| ConfigMaps | Those a managed workload takes environment variables from, to learn its dependencies. kube-system/cluster-autoscaler-status, whose existence shows Cluster Autoscaler runs |
One by one with get, not cached, never listed or written. Only the metadata of cluster-autoscaler-status, every 10 minutes |
| PersistentVolumeClaims | Size, to price the storage a paused workload keeps | Watched |
| HorizontalPodAutoscalers, KEDA ScaledObjects | What scales a workload, and its range | Watched |
| Namespaces | Labels, for opt-in, settings and protection | Watched |
| Nodes | Labels (instance type, region, spot, node pool), to price workloads and group them into pools. Allocatable CPU and memory, schedulable and Ready, to measure each pool’s spare capacity | Watched, keeping only those fields and dropping image lists and the rest. Metadata listed every 10 minutes, to tell which node autoscaler runs |
Karpenter NodePools (karpenter.sh/v1) |
Names and spec.disruption, to report which node autoscaler runs |
Listed every 10 minutes, not cached. Nothing without Karpenter installed |
Deployments in kube-system |
Names, to find a Cluster Autoscaler that hasn’t written its status ConfigMap | Metadata listed every 10 minutes, only while that ConfigMap is missing |
| ManagedWorkloads | Its own configuration | Watched |
Its wake key Secret, <fullname>-doorman-wake-key, by the doorman |
The key it signs the asleep page’s Wake it button with, shared by its replicas | Read by name every minute, from the API server, not cached. Written once, to fill it when it’s empty |
| Any other Secret | Never, of any kind, anywhere. An address set in a Secret is learned only from the request it’s used for |
What it writes
Section titled “What it writes”| Resource | What |
|---|---|
| Deployments, StatefulSets | Replicas, through the scale subresource. While paused, the napwake.dev/paused-from annotation, a copy of what the pause changed, removed on hand-back. No other field, and never a delete |
Its own Deployments, with doorman.negForwarder.enabled |
A forwarder, napwake-forwarder-<workload>, in the namespace of each paused workload whose Service is behind GKE container-native load balancing. Owned by its ManagedWorkload, deleted a minute after the workload wakes |
| KEDA ScaledObjects | autoscaling.keda.sh/paused-replicas, while their workload is paused or resuming, then its old value, or none |
| EndpointSlices | Its own, routing a paused workload’s Services to the doorman, deleted when it wakes |
| ManagedWorkloads | Status, with each workload’s forecast state. The ones it creates for labelled workloads. The napwake.dev/cleanup finalizer, so deleting one restores its workload first, removed once it has. napwake.dev/operator, its namespace. napwake.dev/last-activity on a dependency it wakes |
| ManagedWorkloads, by the doorman | napwake.dev/last-request and napwake.dev/last-request-from (the caller’s IP address), on one a request wakes. napwake.dev/turned-away, a count of the requests it turned away from one that asks, with nothing of the requests themselves |
| Its wake key Secret, by the doorman | A random key, when it’s empty. Nothing else |
| Events | On ManagedWorkloads and workloads, saying what it did and why |
| Leases | Leader election, in its own namespace |
| Anything else | Never. No other resource or workload field. It deletes only its own ManagedWorkloads, EndpointSlices and forwarder Deployments |
What it sends
Section titled “What it sends”| To | What |
|---|---|
| The Kubernetes API server | Everything above, always |
Prometheus, at prometheus.url |
Only if set. The activity queries workloads configure. Once for each new ManagedWorkload, a range query for up to four weeks of its own containers’ CPU (container_cpu_usage_seconds_total), an hour a point, to start its forecast from, narrowed by prometheus.selector if set |
| The woken pod, from the doorman | The requests it held. Their contents are never stored or logged |
| The doorman, from a forwarder | Connections, passed on, never stored or logged. A forwarder reads nothing from the API server |
| Anywhere else | Nothing. No telemetry, usage reporting or update checks |
What the Helm chart grants a release named napwake. Resource names start with the release’s full name. Rules marked namespaced go in ClusterRoles, or with watchNamespaces, only in a Role in each watched namespace.
Operator
Section titled “Operator”ServiceAccount napwake, with ClusterRole and ClusterRoleBinding napwake-manager.
| API group | Resources | Verbs | Scope |
|---|---|---|---|
"" |
namespaces, nodes |
get, list, watch |
always cluster-wide |
karpenter.sh |
nodepools |
list |
always cluster-wide |
"" |
configmaps |
get |
namespaced |
"" |
events |
create, patch |
namespaced |
events.k8s.io |
events |
create, patch |
namespaced |
"" |
services |
get, list, watch |
namespaced |
networking.k8s.io |
ingresses |
get, list, watch |
namespaced |
"" |
pods |
get, list, watch |
namespaced |
"" |
persistentvolumeclaims |
get, list, watch |
namespaced |
discovery.k8s.io |
endpointslices |
get, list, watch, create, update, patch, delete |
namespaced |
apps |
deployments, statefulsets |
get, list, watch, patch |
namespaced |
apps |
deployments/scale, statefulsets/scale |
get, update |
namespaced |
autoscaling |
horizontalpodautoscalers |
get, list, watch |
namespaced |
keda.sh |
scaledobjects |
get, list, watch, patch |
namespaced |
napwake.dev |
managedworkloads |
get, list, watch, create, update, patch, delete |
namespaced |
napwake.dev |
managedworkloads/status |
get, update, patch |
namespaced |
napwake.dev |
managedworkloads/finalizers |
update |
namespaced |
metrics.k8s.io |
pods |
get, list |
namespaced |
| Role | With | Grants |
|---|---|---|
Role napwake-doorman-endpoints, in the release namespace |
watchNamespaces and the doorman enabled |
get, list and watch on endpointslices there, to find the doorman’s pods |
Role napwake-leader-election, in the release namespace |
Leader election | coordination.k8s.io leases (get, create, update) and "" events (create, patch) |
ClusterRole and ClusterRoleBinding napwake-forwarder, or a Role and RoleBinding of that name in each watched namespace |
doorman.negForwarder.enabled |
apps deployments (create, delete), for the forwarders. A forwarder runs as its namespace’s default ServiceAccount, without its token or any access to the API server |
Doorman
Section titled “Doorman”ServiceAccount napwake-doorman, with ClusterRole and ClusterRoleBinding napwake-doorman, or a Role in each watched namespace.
| API group | Resources | Verbs |
|---|---|---|
napwake.dev |
managedworkloads |
get, list, watch, patch |
discovery.k8s.io |
endpointslices |
get, list, watch |
"" |
pods |
get |
"", events.k8s.io |
events |
create, patch |
And a Role and RoleBinding napwake-doorman-wake-key in the release namespace, for its wake key, the one Secret it may read.
| API group | Resources | Resource names | Verbs |
|---|---|---|---|
"" |
secrets |
napwake-doorman-wake-key |
get, update |
Guards, people, admission and metrics
Section titled “Guards, people, admission and metrics”| For | Granted | With | Grants |
|---|---|---|---|
| Guards | ServiceAccount, ClusterRole and ClusterRoleBinding napwake-uninstall-guard, and the same named napwake-upgrade-guard |
guard.uninstall, and with watchNamespaces, guard.upgrade (the defaults) |
list on napwake.dev managedworkloads, cluster-wide even with watchNamespaces. Helm hooks, like their Jobs, existing only while helm uninstall runs its pre-delete hook, or helm upgrade or helm rollback its pre-upgrade or pre-rollback hook. Those refuse to leave ManagedWorkloads without an operator |
| People | ClusterRoles napwake-view and napwake-edit |
Nothing to Napwake itself. Aggregated into the built-in roles, so view, edit and admin gain get, list and watch on napwake.dev managedworkloads, and get on their status. edit and admin also gain create, update, patch and delete |
|
| Admission | ValidatingAdmissionPolicy and binding napwake-doorman, cluster-scoped |
doorman.admissionPolicy.enabled (the default) |
Refuses any change the doorman’s ServiceAccount makes to a ManagedWorkload, except to its napwake.dev/last-request, last-request-from and turned-away annotations |
| Admission | ValidatingAdmissionPolicy and binding napwake-request-stamps, cluster-scoped |
doorman.admissionPolicy.enabled |
Refuses anyone else setting those two annotations. Limited to watchNamespaces if set |
| Metrics | ClusterRoleBindings napwake-auth-delegator and napwake-doorman-auth-delegator, to the built-in system:auth-delegator ClusterRole |
metrics.enabled and metrics.secure (the defaults) |
Lets the operator and the doorman check the tokens of whoever scrapes them |
| Metrics | ClusterRole napwake-metrics-reader, and a ClusterRoleBinding of that name |
metrics.enabled and metrics.secure |
get on the /metrics URL, bound to metrics.readerSubjects |
The plugin
Section titled “The plugin”kubectl napwake uses your own kubeconfig and permissions. It reads the same kinds of resources and their events, and changes only these.
| Command | Changes |
|---|---|
wake |
napwake.dev/wake-requested on a ManagedWorkload, with napwake.dev/active-until for --for |
pause |
napwake.dev/pause-requested on a ManagedWorkload, with napwake.dev/pause-overrides-forecast to pause one the forecast expects demand for. With --clear-hold, it removes its napwake.dev/active-until |
enable |
napwake.dev/dry-run, on a workload or its namespace, or spec.dryRun on a ManagedWorkload you wrote |
scan, status --html |
Nothing in the cluster. The report or page goes only to your machine, in a file only you can read. scan reads Prometheus through the API server’s service proxy, or at --prometheus-url |
For a workload Argo CD applies, scan, status, pause and enable read Argo CD’s Applications and its argocd-cm ConfigMap, to tell whether it leaves the replicas to Napwake.