Kubernetes developers often use emptyDir when a pod needs temporary storage shared between containers. It is simple, fast, and useful for caching, temporary files, and intermediate data.

But emptyDir is still a filesystem, so Linux ownership and permissions matter.

If multiple containers share the same emptyDir, incorrect permissions can allow one container to modify files that another container expects to control. Running containers as root can make the situation worse.

This article explains how emptyDir permissions work and how to configure them safely.

What Is emptyDir?

An emptyDir volume is created when a pod is assigned to a node and exists for the lifetime of that pod.

volumes:
  - name: shared-data
    emptyDir: {}

A container can mount it with:

volumeMounts:
  - name: shared-data
    mountPath: /data

The basic lifecycle is:

Pod starts
   |
   v
emptyDir created
   |
   v
Containers use /data
   |
   v
Pod removed
   |
   v
emptyDir removed

The data should therefore be considered temporary.

Why Permissions Matter

Consider two containers sharing the same directory:

Pod
 |
 +-- Container A -> /data
 |
 +-- Container B -> /data

If both containers can write everything inside /data, Container B could potentially modify files created by Container A.

For applications with different trust levels, this may be undesirable.

The goal should be:

Container A
   |
   +-- Access only what it needs

Container B
   |
   +-- Access only what it needs

Run Containers as Non-Root

A good starting point is to run applications with a dedicated UID/GID.

apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 10001
    runAsGroup: 10001
    fsGroup: 10001

  containers:
    - name: app
      image: example/app:1.0
      volumeMounts:
        - name: data
          mountPath: /data

  volumes:
    - name: data
      emptyDir: {}

The important settings are:

  • runAsNonRoot: prevents the application from running as root.

  • runAsUser: specifies the process UID.

  • runAsGroup: specifies the process GID.

  • fsGroup: can provide group ownership for supported volumes.

Do not assume fsGroup behaves identically for every storage implementation. Test the actual workload.

Using fsGroup With emptyDir

For a shared temporary directory, fsGroup can simplify access.

securityContext:
  runAsUser: 10001
  runAsGroup: 10001
  fsGroup: 10001

The application can then create files using the configured identity.

You can verify the identity from inside the container:

id

And inspect the directory:

ls -ld /data

This is much better than solving permission problems by running the entire container as root.

Shared emptyDir Between Containers

A common pattern is a producer and consumer:

Container A
   |
   | writes
   v
/data
   ^
   | reads
   |
Container B

For example:

spec:
  securityContext:
    fsGroup: 10001

  containers:
    - name: producer
      image: example/producer:1.0
      volumeMounts:
        - name: shared
          mountPath: /data

    - name: consumer
      image: example/consumer:1.0
      volumeMounts:
        - name: shared
          mountPath: /data

  volumes:
    - name: shared
      emptyDir: {}

This works when both containers are designed to share the same access level.

If they should not have identical access, consider using separate volumes or a different application design.

Use Separate Volumes When Isolation Is Required

Instead of:

Container A
     |
     +----+
          |
        /data
          |
     +----+
     |
Container B

use:

Container A -> /data-a
Container B -> /data-b

Example:

volumes:
  - name: app-a-data
    emptyDir: {}

  - name: app-b-data
    emptyDir: {}

This creates a clearer security boundary.

emptyDir With Memory

Kubernetes also supports memory-backed emptyDir volumes:

volumes:
  - name: cache
    emptyDir:
      medium: Memory

This stores data in memory rather than ordinary node filesystem storage.

It can be useful for temporary sensitive data or high-speed temporary files, but memory-backed storage consumes the pod's available memory.

Set an appropriate size limit where needed:

volumes:
  - name: cache
    emptyDir:
      medium: Memory
      sizeLimit: 256Mi

Do not use memory-backed storage without considering memory pressure.

Common Permission Problems

Permission denied

Check the container identity:

id

Then:

ls -ld /data

Compare the UID/GID with the directory ownership.

One Container Cannot Read Another Container's Files

Check:

  • File ownership

  • Group ownership

  • File mode

  • fsGroup

  • Whether both containers actually need to share the directory

Do not automatically use:

chmod 777 /data

That solves the immediate symptom by removing meaningful access restrictions.

Why chmod 777 Is a Bad Fix

This is a common shortcut:

chmod -R 777 /data

It allows virtually any user with access to the directory to read, modify, and execute files according to the filesystem permissions.

A better approach is to use a specific UID/GID and appropriate permissions.

For example:

Owner: application user
Group: application group
Permissions: only what the workload requires

The principle is least privilege, not maximum accessibility.

Important emptyDir Characteristics

Characteristic

emptyDir

Created

When the pod is assigned to a node

Data lifetime

Pod lifetime

Persistent after pod deletion

No

Shared between containers

Yes

Suitable for temporary files

Yes

Suitable for permanent application data

No

Can use memory

Yes

Best Practices

  1. Run containers as non-root.

  2. Use explicit UID/GID settings where appropriate.

  3. Use fsGroup when shared volume access requires it.

  4. Do not use chmod 777 as a default solution.

  5. Use separate emptyDir volumes when containers need isolation.

  6. Use medium: Memory only when the memory impact is understood.

  7. Never treat emptyDir as permanent storage.

  8. Use Pod Security controls to prevent unnecessarily privileged workloads.

Summary

emptyDir is simple temporary storage, but its permissions should still be designed carefully.

For most workloads, running containers as non-root and using appropriate UID/GID settings provides a strong baseline. When multiple containers share an emptyDir, make sure they genuinely need the same level of access.

Avoid shortcuts such as chmod 777. If stronger isolation is required, use separate volumes rather than giving every container unrestricted access to the same directory.

The main rule is straightforward: temporary storage does not mean unrestricted storage. Treat emptyDir permissions with the same least-privilege mindset used for other application resources.