Dennis-Mircea Ciupitu created FLINK-40414:
---------------------------------------------

             Summary: Autoscaler state ConfigMap is treated as trusted input
                 Key: FLINK-40414
                 URL: https://issues.apache.org/jira/browse/FLINK-40414
             Project: Flink
          Issue Type: Bug
          Components: Autoscaler, Kubernetes Operator
            Reporter: Dennis-Mircea Ciupitu


h1. Summary

The autoscaler persists its state in a per-resource ConfigMap 
({{autoscaler-<name>}}): scaling history, collected metrics, scaling tracking, 
delayed scale-down, parallelism overrides and config overrides. The operator 
reads that ConfigMap back on every cycle and acts on its contents, but treats 
it as trusted input. The ConfigMap is writable by any workload in the 
namespace, so a poisoned or corrupt entry can break a reconcile or influence a 
managed deployment.

h1. Trust boundary

The autoscaler state ConfigMap is created and owned by the operator, but the 
default Flink job Role grants the job service account 
{{create/update/patch/delete}} on {{configmaps}} in its namespace (required for 
Kubernetes HA). Tenant code running in a TaskManager or JobManager pod can 
therefore write any ConfigMap in the namespace, including the autoscaler state 
of another job.

Among the ConfigMaps the operator handles, only the autoscaler state ConfigMap 
has its content deserialized and acted upon. The generated cluster config and 
pod-template ConfigMaps are write-only from the operator, and the Kubernetes HA 
ConfigMaps are read only by name and key presence, never by value. The 
autoscaler state ConfigMap is the operator's untrusted-input surface.

h1. Problems

h2. Reads are not uniformly fail-closed

The six read paths handle a bad stored value inconsistently:

* {{getParallelismOverrides}} has no error handling. A malformed value throws 
out of the read and into the reconcile loop.
* {{getConfigChanges}} falls back to empty on a bad value but does not discard 
the poisoned entry, so it is re-read and re-parsed every cycle.
* The remaining four discard the bad entry and fall back to empty.

So the same class of input is variously ignored, re-read, or allowed to 
propagate an exception.

h2. Config overrides are applied to the deployment spec unfiltered

When memory tuning is enabled, the config overrides read from the ConfigMap are 
merged into {{spec.flinkConfiguration}} with no key filtering. A poisoned entry 
can therefore inject arbitrary Flink configuration, for example 
{{env.java.opts}} or a pod template, into a managed deployment. This is an 
escalation from "write one ConfigMap" to influencing how and what the managed 
cluster runs, potentially across jobs within a namespace.

h2. No value sanity

Values read from the ConfigMap, such as the per-vertex parallelism overrides, 
are applied without basic validity checks.

h1. Impact

* Integrity and availability: a crafted entry can break a reconcile through an 
unhandled exception, or feed the autoscaler bogus history and metrics that 
steer scaling for that job or a co-tenant.
* Config injection: with memory tuning enabled, arbitrary Flink configuration 
reaches the managed deployment spec.
* Current exposure is bounded by {{job.autoscaler.memory.tuning.enabled}} 
(default off) for the injection path, but the design flaw is independent of 
that flag.

This is not a deserialization remote-code-execution issue. The mapper uses no 
default typing and binds to concrete types, so malformed input fails to bind 
rather than instantiating arbitrary classes. The risk is integrity, 
availability and config injection.

h1. Scope

This completes the autoscaler-adjacent security review alongside FLINK-40400 
(artifact fetch SSRF) and FLINK-40401 (decompression bomb on the compressed 
state fields). Those two harden individual fields or paths as issues surfaced. 
This item addresses the general untrusted-read boundary of the state ConfigMap 
so the class of problem is closed rather than one instance.

h1. Proposed approach

At a high level:

* Treat every read from the autoscaler state ConfigMap as untrusted: 
deserialize uniformly and fail closed, discarding the offending entry and 
falling back to empty on any failure, plus light value sanity on the values 
that are applied.
* Filter config overrides on apply against the set of keys memory tuning is 
actually allowed to set, so that only memory-tuning keys can reach the 
deployment spec.

Out of scope: deeper hardening of scaling decisions against plausible but wrong 
metrics, and the decompression size bound owned by FLINK-40401.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to