Skip to content

OCI runtime wrapper to modify container configs before creation

License

Notifications You must be signed in to change notification settings

picoCTF/oci-interceptor

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OCI Interceptor

An OCI runtime wrapper that modifies containers' runtime configuration according to specified rules before forwarding the container to a real runtime for creation.

This can be used to enforce certain policies on created containers, or to work around limitations in higher-level container management tools such as Docker.

Installation

Download the latest release, extract the tarball, and copy the binary to an appropriate location:

$ tar xzf oci-interceptor_x86_64-unknown-linux-gnu.tar.gz
$ cp oci-interceptor /usr/local/bin

Alternatively, build and install from source:

$ cargo install --locked --path .

Currently, prebuilt binaries are only available for x86 Linux (glibc-based). Other platforms must installed from source.

Usage

All oci-interceptor flags are prefixed with --oi in order to avoid conflicts with the underlying OCI runtime.

Usage: oci-interceptor [OPTIONS] [runtime-options]...

Arguments:
  [runtime-options]...  All additional options will be forwarded to the OCI runtime.

Options:
      --oi-runtime-path <runtime-path>
          Path to OCI runtime. [default: runc]
      --oi-readonly-networking-mounts
          Mount networking files as readonly
      --oi-write-debug-output
          Write debug output
      --oi-debug-output-dir <debug-output-dir>
          Debug output location [default: /var/log/oci-interceptor]
      --oi-env <NAME=VALUE>
          Set an environment variable if not already present in config
      --oi-env-force <NAME=VALUE>
          Override an environment variable, regardless of any original value
      --oi-version
          Print version
      --oi-help
          Print help

With Docker

The Docker daemon configuration must be modified to add this runtime. If you want it to be invoked every time a container is created, you should also make it the default runtime (instead of runc).

If you are not using an alternative OCI runtime such as crun or youki, you can omit the --oi-runtime-path option, as it defaults to runc, the default runtime bundled with Docker.

Example /etc/docker/daemon.json contents

{
    "default-runtime": "oci-interceptor",
    "runtimes": {
        "oci-interceptor": {
            "path": "/usr/local/bin/oci-interceptor",
            "runtimeArgs": [
                "--oi-readonly-networking-mounts"
            ]
        }
    }
}

The Docker daemon must be restarted (systemctl restart docker.service) in order to apply changes to this configuration file.

Note that if you set oci-interceptor as the default runtime, you can still bypass it for a specific container by specifying docker run --runtime=runc.

While it is not possible to override runtimeArgs with a docker run option, you could specify multiple interceptor "runtimes" (with different flags) and switch between them using docker run --runtime=<name>.

Supported Customizations

Read-only networking mounts

Works around the fact that Docker mounts the following files as read/write by default:

  • /etc/hosts
  • /etc/hostname
  • /etc/resolv.conf

When XFS project quotas are used to restrict a container's writable layer size, these files provide an escape hatch for malicious users to fill the host storage volume.

This can usually only be circumvented by manually creating read-only bind mounts over these paths (in which case Docker can no longer manage the container's DNS configuration) or by making the entire rootfs read-only (which severely constrains the workloads possible inside the container).

To avoid this issue, specify the --oi-readonly-networking-mounts flag. This modifies these mounts to be read-only, preventing writes from inside the container.

Related issues

Overriding environment variables

Allows specifying default environment variable values for containers without using docker run --env or --env-file.

Use --oi-env <NAME=VALUE> to set a default for an environment variable. This will not take precedence over a value explicitly specified via docker run --env or --env-file.

Alternatively, use --oi-env-force <NAME=VALUE> to force an certain value even when otherwise specified via docker run --env or --env-file.

Related issues

Debug output

Specify the --oi-write-debug-output flag to write original, parsed, and modified container configs to the directory specified as --oi-debug-output-dir (default /var/log/oci-interceptor).

The resulting files will be named:

  • <container_hostname>_original.json (the original config)
  • <container_hostname>_parsed.json (the parsed config)
  • <container_hostname>_modified.json (the modified config, only written if modification occurred)

Additionally, forwarded calls to the underlying OCI runtime will be appended to the file runtime_calls.log within the debug output directory.