Skip to content

Java agent dir /instrumentations/java ships as 0644 (no exec bit) → non-root / cap-dropped workloads can't load javaagent.jar #5156

Description

@agarwalvivek29

Summary

The Java instrumentation directory /instrumentations/java in the odigos-agents image ships with mode 0644 (drw-r--r--) — no execute/search bit. Every other language directory in the same image is 0755 (drwxr-xr-x). With mountMethod: k8s-init-container, the injected init container does a plain cp -r /instrumentations/java /var/odigos/java, which preserves the broken mode into the shared emptyDir. As a result, any instrumented Java workload that does not run as root-with-full-capabilities cannot traverse the directory to open javaagent.jar, and the JVM aborts at agent load:

Error opening zip file or JAR manifest missing : /var/odigos/java/javaagent.jar
Error occurred during initialization of VM
agent library failed Agent_OnLoad: instrument
-> CrashLoopBackOff

This makes Java auto-instrumentation unusable for any workload that follows the Kubernetes Pod Security Standards "restricted" baseline (i.e. securityContext.capabilities.drop: ["ALL"]), which is extremely common.

Environment

  • Odigos v1.26.0 (community); also confirmed still present in latest v1.28.9
  • EKS (Auto Mode), instrumentor.mountMethod: k8s-init-container
  • Java workload (OpenJDK 21), distro: java-community

The directory mode in the image

$ ls -la /instrumentations/
drwxr-xr-x   ... dotnet
drw-r--r--   ... java        <-- 0644, the ONLY dir missing the execute/search bit
drwxr-xr-x   ... loader
drwxr-xr-x   ... nodejs-community
drwxr-xr-x   ... python
drwxr-xr-x   ... ruby

javaagent.jar itself is -rw-r--r-- (world-readable). Only the directory is missing the search bit, so the file is unreachable for any process lacking CAP_DAC_READ_SEARCH.

Root cause / proof

A 0644 directory is traversable by nobody under standard DAC — not even its root owner — without CAP_DAC_READ_SEARCH / CAP_DAC_OVERRIDE (capabilities(7)). Controlled in-cluster test: init container (root, full caps) stages the dir as-is (0644) and again with chmod -R a+rX (0755); two app containers read javaagent.jar from each:

staged dir mode app: runAsUser:0 + drop:[ALL] app: non-root + drop:[ALL]
0644 (as shipped) Permission denied Permission denied
0755 (a+rX) OK OK

Notes:

  • runAsUser: 0 alone does not help when capabilities.drop: ["ALL"] is set, because that strips CAP_DAC_READ_SEARCH.
  • Adding the capability back to a non-root container does not help either, because Kubernetes places securityContext.capabilities.add in the bounding/permitted sets but not the ambient set, so it is dropped when the process execs as a non-root UID.
  • The only ways to make it work today are (a) runAsUser: 0 and capabilities.add: ["DAC_READ_SEARCH"], or (b) patch the image — neither is reasonable to ask of every instrumented workload.

Recommended fix

Make /instrumentations/java world-traversable in the image build, matching every other language directory:

RUN chmod -R a+rX /instrumentations/java
# or ensure the dir is created 0755 in the first place

a+rX adds the search bit to directories only and leaves the already-0644 jar untouched. This keeps the existing cp -r semantics intact while letting fully non-root, capability-dropped workloads load the agent with no runAsUser:0 and no added capabilities.

(Alternatively, the instrumentor-injected init container could chmod -R a+rX the destination after copying, but fixing the image is simpler and also benefits the k8s-host-path / k8s-virtual-device paths.)

Current workaround

We override the agents image via odigos.images.agents with FROM odigos-agents:<tag> + RUN chmod -R a+rX /instrumentations/java, which fully resolves the crash and lets the workloads run instrumented without root or added capabilities.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions