Skip to main content

id-configurator

id-configurator is a CLI tool by InterDiode that configures a device (typically a Docker image) in an air-gapped environment: no network access is required or ever used.

It reads a single configuration (JSON or YAML), and applies it to a filesystem tree, writing only the files that need to change: root certificates, system package manager sources (APT, YUM/DNF, APK) and language-specific package manager settings (pip/uv/poetry, Maven/Gradle/Ivy/SBT/Leiningen, Composer, npm, cargo, Go modules, RubyGems, NuGet). The result can then be used to build a Docker image or otherwise deployed to the target device.

How it works

  • --dst points to the destination directory that receives every modified or created file. id-configurator never writes anywhere else.
  • --src (optional) points to an existing filesystem, used to detect the current configuration (existing APT sources, existing Java keystores, etc.) so it can be extended or disabled instead of blindly overwritten.
  • The configuration is loaded from a file (--config), from a base64-encoded string, typically an environment variable (--config-env / $ID_CONFIGURATOR_CONFIG), or downloaded over HTTP(S) from a URL (--config-url). --config-url-cacert-content optionally gives the PEM content of the CA certificate to trust for that one download, for an internal endpoint signed by a private CA the running system doesn't otherwise trust yet (e.g. before the certificates module has ever run) - it defaults to the system's own trust store otherwise. --config-url-insecure disables certificate (and hostname) verification entirely instead, overriding --config-url-cacert-content - insecure, only meant for a first bootstrap against a server whose certificate isn't trustable, or trusted, yet by any other means.
  • On apply, every module inspects the configuration and the source filesystem and decides for itself whether it has something to do; only relevant modules touch the destination directory. For example, the configured Alpine repositories are only written if --src can be identified as an Alpine filesystem (i.e. it has an /etc/apk directory); and a source cloning Debian's official repository is only configured if that official repository is actually present in the filesystem given via --src (via uri-to-replace, see "Replacing an existing repository" below).

Installation

As a CLI tool

# with pip
pip install id-configurator

# or with uv tool, in its own isolated environment
uv tool install id-configurator

Once installed this way, run it directly as id-configurator (rather than uv run id-configurator, which is only for the "from source" setup below).

As a Docker image

id-configurator is also published as interdiode/id-configurator on Docker Hub - handy since its output is typically meant to become another Docker image in the first place. One-off use:

docker run --rm -v "$(pwd)/config.yaml:/config.yaml:ro" -v "$(pwd)/output:/dst" -v "/:/src" \
  interdiode/id-configurator:latest \
  id-configurator apply --config /config.yaml --dst /dst --src /src

More typically, as a builder stage of the target image's own Dockerfile - <src> here is the target image itself, taken as of its target stage, before id-configurator's own changes are copied back on top of it:

FROM debian:trixie-slim AS target
FROM interdiode/id-configurator:latest AS configuration
COPY --from=target / /src/
COPY config.yaml /config.yaml
RUN id-configurator apply --config /config.yaml --src /src --dst /dst
FROM target
COPY --from=configuration /dst/ /

From source (development)

uv sync

Usage

# Apply a configuration file to a destination directory
id-configurator apply --config config.yaml --dst ./output

# Take an existing filesystem into account (e.g. to extend its APT sources)
id-configurator apply --config config.yaml --src /path/to/rootfs --dst ./output

# Use a base64-encoded configuration from the environment instead of a file
export ID_CONFIGURATOR_CONFIG=$(base64 -w0 config.yaml)
id-configurator apply --dst ./output

# Download the configuration from an internal HTTPS server instead of a local file
id-configurator apply \
  --config-url https://config.internal.example/device.yaml \
  --config-url-cacert-content "$(cat internal-ca.pem)" \
  --dst ./output

# Validate a configuration without applying it
id-configurator validate --config config.yaml

# List the available modules
id-configurator list-modules

# Same thing, via the Docker image instead of installing anything locally
docker run --rm \
  -v "$(pwd)/config.yaml:/config.yaml:ro" \
  -v "$(pwd)/input:/src" \
  -v "$(pwd)/output:/dst" \
  interdiode/id-configurator:latest \
  id-configurator apply --config /config.yaml --dst /dst --src /src

The tool can also be invoked as python -m id_configurator.

Configuration format

The simplest way to generate a new configuration is InterDiode itself, through its simple interface - it also handles duplicating application mirrors onto disconnected networks.

The configuration is a JSON or YAML object. uuid, organisation and description are all optional (identifying metadata only - nothing in the tool itself relies on any of them), as is every configurations.* block - a module that finds nothing to do for it simply does not run. version is the configuration format's own schema version (currently "1.0", and the default if omitted) - independent of the id-configurator package version - so a future, incompatible format change can be told apart from this one:

version: "1.0"
uuid: <UUID, optional>
organisation: <string, optional>
description: <string, optional>
configurations:
  certificates:
    - name: <string>
      content: <PEM>
  apt:
    sources:
      - name: <string>
        uris: [<string>]
        suites: [<string>]
        components: [<string>]
        signed-by: <ASCII-armored GPG public key>       # or signed-by-file: <path already on the target>
        uri-to-replace: <fnmatch pattern, optional>      # see "Replacing an existing repository" below
  apk:
    repositories:
      - name: <string>
        url: <string>
        key: <RSA public key, optional>
        url_to_replace: <fnmatch pattern, optional>
  yum:
    repositories:
      - name: <string>
        index-url: <string>
        gpg-url: <string, optional>
        index-url-to-replace: <fnmatch pattern, optional>
    keys:
      - name: <string>
        content: <GPG key>
  python:
    repositories:
      - name: <string>
        index-url: <string>
  java:
    repositories:
      - name: <string>
        url: <string>
  php:
    repositories:
      - name: <string>
        url: <string>
  npm:
    repositories:
      - name: <string>
        url: <string>
  rust:
    repositories:
      - name: <string>
        url: <string>
  go:
    repositories:
      - name: <string>
        url: <string>
  ruby:
    repositories:
      - name: <string>
        url: <string>
  nuget:
    repositories:
      - name: <string>
        url: <string>

Replacing an existing repository

apt.sources[].uri-to-replace, apk.repositories[].url_to_replace and yum.repositories[].index-url-to-replace are optional fnmatch patterns. When set, the configured repository is only written if the pattern matches at least one URI/URL already present in --src's existing configuration - and only the matching existing entries are disabled, the rest are left untouched. This lets a configuration safely target "whatever machine this is applied to": e.g. uri-to-replace: "http://deb.debian.org/*" replaces Debian's default mirror if (and only if) it's actually there, without disturbing any other source a given machine might already have. Leaving the field unset never disables anything - the configured repository is simply added alongside whatever is already present.

Modules

Module Applies to
certificates Installs root certificates into the system's CA store, rebuilding the trust bundle in pure Python (Debian/Ubuntu and RHEL/Fedora trust stores).
apt Adds the configured APT sources (DEB822 format); disables only the existing entries matching uri-to-replace.
apk Adds the configured Alpine /etc/apk/repositories entries and their keys; disables only the existing lines matching url_to_replace.
yum Adds the configured YUM/DNF .repo files and imports their GPG keys; disables only the existing sections matching index-url-to-replace. Covers DNF too - same config files.
python Points pip, uv, poetry and easy_install to the configured Python package indexes.
java Adds root certificates to every detected JKS/PKCS12 keystore, and configures Maven, Gradle, Ivy, SBT and Leiningen repositories.
php Registers the configured repositories with Composer; sets openssl.cafile whenever any certificate is configured, so PHP's own OpenSSL calls trust it too.
npm Points npm at the configured registries and its own cafile; sets NODE_EXTRA_CA_CERTS system-wide whenever any certificate is configured, since Node ignores the system CA store.
rust Points cargo at the configured registries, replacing crates.io.
go Points the Go toolchain at the configured module proxies (GOPROXY), replacing proxy.golang.org, and disables GOSUMDB.
ruby Points RubyGems at the configured sources, replacing rubygems.org.
nuget Points NuGet at the configured package sources, replacing nuget.org.

This tool's own modular structure is meant to be extended: see CLAUDE.md for the module interface and how to add one.

Development

uv sync                            # install dependencies
uv run pytest                      # run the test suite
uv run ruff check --fix .          # lint
uv run ruff format .               # format
uv run pre-commit run --all-files  # run all pre-commit hooks

License

CeCILL v2.1 (GPL-compatible free software license). See LICENSE. Copyright InterDiode SA.

Metadata

Release files for id-configurator 2026.10.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for id-configurator 2026.10.2
File Size Uploaded
id_configurator-2026.10.2.tar.gz 46.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for id-configurator 2026.10.2
File Interpreter ABI Platform
id_configurator-2026.10.2-py3-none-any.whl Python 3 none any Details

Total release size: 101.2 kB

Release files / id_configurator-2026.10.2.tar.gz

Download URL id_configurator-2026.10.2.tar.gz
Size 46.5 kB
Tags Source
SHA-256 checksum
How to use checksums
c3b0764e11bbf0870b6d24706929b2da3b4b09f299c7bf8d9805f18e98a3bcc2
BLAKE2b-256 checksum
How to use checksums
cad45dd8ac3f4eeaad15dde778fe905255e994bb82c0996737bb9b7788c3bfa8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.22 {"installer":{"name":"uv","version":"0.12.22","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / id_configurator-2026.10.2-py3-none-any.whl

Download URL id_configurator-2026.10.2-py3-none-any.whl
Size 54.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a898378bdaba085eb26c98a1c034dc02926bd18c0aefbeb327aaac9493db6064
BLAKE2b-256 checksum
How to use checksums
680a8e6008d9a065c4eafc3045ea0a1337f4ba2c209b80a65af0ecb0744afb46
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.22 {"installer":{"name":"uv","version":"0.12.22","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

2026.10.2 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page