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.
Summary
The Java instrumentation directory
/instrumentations/javain theodigos-agentsimage ships with mode0644(drw-r--r--) — no execute/search bit. Every other language directory in the same image is0755(drwxr-xr-x). WithmountMethod: k8s-init-container, the injected init container does a plaincp -r /instrumentations/java /var/odigos/java, which preserves the broken mode into the sharedemptyDir. As a result, any instrumented Java workload that does not run as root-with-full-capabilities cannot traverse the directory to openjavaagent.jar, and the JVM aborts at agent load: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
instrumentor.mountMethod: k8s-init-containerdistro: java-communityThe directory mode in the image
javaagent.jaritself is-rw-r--r--(world-readable). Only the directory is missing the search bit, so the file is unreachable for any process lackingCAP_DAC_READ_SEARCH.Root cause / proof
A
0644directory is traversable by nobody under standard DAC — not even its root owner — withoutCAP_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 withchmod -R a+rX(0755); two app containers readjavaagent.jarfrom each:runAsUser:0+drop:[ALL]drop:[ALL]0644(as shipped)0755(a+rX)Notes:
runAsUser: 0alone does not help whencapabilities.drop: ["ALL"]is set, because that stripsCAP_DAC_READ_SEARCH.securityContext.capabilities.addin the bounding/permitted sets but not the ambient set, so it is dropped when the process execs as a non-root UID.runAsUser: 0andcapabilities.add: ["DAC_READ_SEARCH"], or (b) patch the image — neither is reasonable to ask of every instrumented workload.Recommended fix
Make
/instrumentations/javaworld-traversable in the image build, matching every other language directory:a+rXadds the search bit to directories only and leaves the already-0644jar untouched. This keeps the existingcp -rsemantics intact while letting fully non-root, capability-dropped workloads load the agent with norunAsUser:0and no added capabilities.(Alternatively, the instrumentor-injected init container could
chmod -R a+rXthe destination after copying, but fixing the image is simpler and also benefits thek8s-host-path/k8s-virtual-devicepaths.)Current workaround
We override the agents image via
odigos.images.agentswithFROM 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.