fixuid

repository·master·Indexed 19 days ago

https://github.com/boxboat/fixuid

A Go-based utility for development Docker containers that synchronizes internal user/group IDs and file permissions with the host user's UID/GID at runtime. It prevents permission issues with host-mounted volumes by remapping the container's internal user/group and updating the $HOME environment variable. Designed exclusively for development environments; not for use in production.

Tokens
2K
Snippets
8
Records
11
Agent score
69%

What's inside fixuid

  1. What is fixuid and when to use it

    master

    fixuid is a Go binary designed to solve UID/GID mismatch issues in development Docker containers. When you mount host volumes into a container, the files created by build tools (like yarn or gradle) often have ownership that doesn't match your host user, preventing your host IDE or tools from modifying them.

    How it works:

    1. You build a container with a specific user/group (e.g., docker:docker with UID/GID 1000:1000).
    2. You run the container with the host's actual UID/GID (e.g., docker run -u 1001:1002 ...).
    3. fixuid runs at startup, remapping the container's internal user/group to match the runtime UID/GID, updating file permissions, and updating the $HOME environment variable.

    CRITICAL: fixuid should ONLY be used in development Docker containers. DO NOT INCLUDE it in production container images.

  2. Install fixuid in a Dockerfile

    master

    To use fixuid, follow these four steps in your Dockerfile:

    1. Create a non-root user and group

    Create a user/group with a fixed UID/GID (1000:1000 is recommended). Use the command appropriate for your base image:

    Alpine:

    RUN addgroup -g 1000 docker && \
        adduser -u 1000 -G docker -h /home/docker -s /bin/sh -D docker

    Debian / Ubuntu:

    RUN addgroup --gid 1000 docker && \
        adduser --uid 1000 --ingroup docker --home /home/docker --shell /bin/sh --disabled-password --gecos "" docker

    Fedora:

    RUN groupadd -g 1000 docker && \
        useradd -u 1000 -g docker -d /home/docker -s /bin/sh docker

    2. Install the fixuid binary and configure it

    Download the binary, set the setuid bit (required), and create the configuration file at /etc/fixuid/config.yml. This step requires curl and must be run as root.

    RUN USER=docker && \
        GROUP=docker && \
        curl -SsL https://github.com/boxboat/fixuid/releases/download/v0.6.0/fixuid-0.6.0-linux-amd64.tar.gz | tar -C /usr/local/bin -xzf - && \
        chown root:root /usr/local/bin/fixuid && \
        chmod 4755 /usr/local/bin/fixuid && \
        mkdir -p /etc/fixuid && \
        printf "user: $USER\ngroup: $GROUP\n" > /etc/fixuid/config.yml

    3. Set the user and entrypoint

    Switch to the user created in step 1 and set fixuid as the entrypoint.

    USER docker:docker
    ENTRYPOINT ["fixuid"]

    4. Run the container with host UID/GID

    When running the container, pass your host's UID/GID using the -u flag.

    docker run --rm -it -u 1000:1000 <image name> sh
    # Example snippet for a Dockerfile
    RUN USER=docker && \
        GROUP=docker && \
        curl -SsL https://github.com/boxboat/fixuid/releases/download/v0.6.0/fixuid-0.6.0-linux-amd64.tar.gz | tar -C /usr/local/bin -xzf - && \
        chown root:root /usr/local/bin/fixuid && \
        chmod 4755 /usr/local/bin/fixuid && \
        mkdir -p /etc/fixuid && \
        printf "user: $USER\ngroup: $GROUP\n" > /etc/fixuid/config.yml
    
    USER docker:docker
    ENTRYPOINT ["fixuid"]
  3. Configure fixuid paths in config.yml

    master

    By default, fixuid scans the root path / and all files on the same device. It will not recurse into directories mounted on different devices (like Docker volumes).

    To ensure fixuid processes files within Docker volumes, you must explicitly list those paths in /etc/fixuid/config.yml under the paths key.

    Example configuration to include both the root filesystem and a specific cache directory on a volume:

    user: docker
    group: docker
    paths:
      - /
      - /home/docker/.cache
    user: docker
    group: docker
    paths:
      - /home/docker
      - /tmp
  4. How fixuid handles filesystem ownership

    master

    When needChown is triggered (because the runtime UID/GID does not match the configured container user/group), fixuid performs the following:

    1. It parses /proc/mounts to identify mount points.
    2. It recursively walks the paths specified in the paths configuration (defaulting to /).
    3. For every file encountered, it checks if the file is owned by the containerUID:containerGID defined in the config.
    4. If it matches, it performs an Lchown to the current runtime UID/GID.
    5. It avoids recursing into different mount points to prevent unintended side effects on mounted volumes.
  5. Run fixuid to update UID/GID and execute a command

    master

    fixuid can be used in two modes:

    1. Standalone Mode: If run without arguments, it performs the UID/GID updates, modifies /etc/passwd and /etc/group, performs recursive chown on configured paths, and then exits.
    2. Exec Mode: If arguments are provided, fixuid performs the updates and then uses syscall.Exec to replace itself with the specified command, running that command with the newly assigned UID/GID and supplementary groups.

    To ensure fixuid has the necessary permissions to modify system files and change ownership, the binary must meet these requirements:

    • Owned by root: chown root:root /path/to/fixuid
    • Setuid bit enabled: chmod u+s /path/to/fixuid
    • The container security profile must not have NoNewPrivileges enabled.
    • The volume containing the binary must not be mounted with the nosuid option.
    # Example: Using fixuid to run a shell as the updated user
    ./fixuid /bin/sh
    
    # Example: Using fixuid with quiet mode to suppress logs
    ./fixuid -q /bin/sh
  6. Set default UID/GID in Docker Compose

    master

    You can define default UID and GID values in your docker-compose.yml using environment variables. This allows developers to override the defaults in their local .env files to match their host environment.

    services:
      nginx:
        image: my-nginx
        user: ${FIXUID:-1000}:${FIXGID:-1000}
        volumes:
          - ./nginx:/etc/nginx
          - ./www:/var/www
    nginx:
      image: my-nginx
      user: ${FIXUID:-1000}:${FIXGID:-1000}
      volumes:
        - ./nginx:/etc/nginx
        - ./www:/var/www
  7. Use fixuid in a startup script instead of an entrypoint

    master

    If you prefer to run fixuid as part of a larger startup script rather than as the container's ENTRYPOINT, you must eval its output. This is necessary because fixuid exports the updated $HOME variable to the current shell session.

    Note: When running in a script, supplementary groups will not be set.

    #!/bin/sh
    
    # UID/GID map to unknown user/group, $HOME=/ (the default when no home directory is defined)
    eval $( fixuid )
    
    # UID/GID now match user/group, $HOME has been set to user's home directory
    #!/bin/sh
    
    eval $( fixuid )
  8. Docker Compose service definitions for fixuid images

    master

    The docker-compose.yml file defines three service configurations used to build and run fixuid on different base operating systems: alpine, fedora, and debian. Each service points to a specific build context within the ./docker/ directory and assigns a unique image name.

    version: "3.1"
    
    services:
      alpine:
        build: ./docker/alpine
        image: "fixuid-alpine"
    
      fedora:
        build: ./docker/fedora
        image: "fixuid-fedora"
    
      debian:
        build: ./docker/debian
        image: "fixuid-debian"
  9. Configure fixuid via configuration files

    master

    fixuid requires a configuration file to identify which user and group should be mapped to the current runtime UID/GID. It searches for a configuration file at /etc/fixuid/ using the following filenames in order:

    1. config.json
    2. config.toml
    3. config.yaml
    4. config.yml

    The configuration must contain the following keys:

    • user: The name of the container user to be updated.
    • group: The name of the container group to be updated.
    • paths (optional): An array of strings representing filesystem paths to recursively search and chown to the new UID/GID. If this key is missing or malformed, it defaults to searching /.

    Warning: fixuid is intended for development systems only. DO NOT USE IN PRODUCTION.