diff --git a/app.py b/app.py index c0c08d5..c8ba557 100644 --- a/app.py +++ b/app.py @@ -20,17 +20,13 @@ IMAGES = { "docker_image": "micro-fedora43-dev:latest", "label": "Fedora 43 Dev Box (micro-fedora43-dev)" }, - "alpine": { - "docker_image": "micro-alpine-dev:latest", - "label": "Alpine Linux Dev Box (micro-alpine-dev)" - }, } DEFAULT_IMAGE_KEY = "debian" DATA_ROOT = "/srv/microcontainers" # per-tenant metadata + disk.img MOUNT_ROOT = "/mnt/microcontainers" # where disk.img files are mounted -HOSTNAME = "localhost" # or "mentalnet.xyz" if you prefer +HOSTNAME = "arthur.lan" # or "mentalnet.xyz" if you prefer PORT_RANGE_START = 20000 PORT_RANGE_END = 21000 @@ -53,33 +49,6 @@ def find_free_port(start=PORT_RANGE_START, end=PORT_RANGE_END): raise RuntimeError("No free ports available in range") -def setup_tenant_environment(home_mount: str): - """ - Create default .bashrc, fastfetch config, and other user environment files. - Runs AFTER the home mount is created. - """ - - bashrc = os.path.join(home_mount, ".bashrc") - config_dir = os.path.join(home_mount, ".config", "fastfetch") - os.makedirs(config_dir, exist_ok=True) - - # Copy fastfetch config - source_cfg = os.path.join(os.path.dirname(__file__), "fastfetch_config.jsonc") - dest_cfg = os.path.join(config_dir, "config.jsonc") - - if os.path.exists(source_cfg): - subprocess.run(["cp", source_cfg, dest_cfg], check=True) - - # Write a curated .bashrc - with open(bashrc, "a") as f: - f.write("\n# ----- MicroContainers defaults -----\n") - f.write("if command -v fastfetch >/dev/null 2>&1; then fastfetch; fi\n") - f.write('alias fastfetch="fastfetch --config $HOME/.config/fastfetch/config.jsonc"\n') - - # Give proper ownership - subprocess.run(["chown", "-R", "1000:1000", home_mount], check=True) - - def validate_ssh_key(key: str) -> bool: """Very basic SSH public key validation.""" key = key.strip() @@ -107,24 +76,46 @@ def is_mounted(mount_point: str) -> bool: return False -def ensure_tenant_home_dir(container_name: str, ssh_key: str) -> str: - home_dir = os.path.join(DATA_ROOT, container_name, "home") - ssh_dir = os.path.join(home_dir, ".ssh") +def ensure_tenant_disk(container_name: str, ssh_key: str, size_gb: int = 3) -> str: + """ + Ensure a per-tenant disk.img exists, is formatted, mounted, and has + .ssh/authorized_keys populated. + Returns the host mount point path, which will be bind-mounted to /home/micro. + """ + tenant_root = os.path.join(DATA_ROOT, container_name) + os.makedirs(tenant_root, exist_ok=True) + + disk_img = os.path.join(tenant_root, "disk.img") + mount_point = os.path.join(MOUNT_ROOT, container_name) + os.makedirs(mount_point, exist_ok=True) + + # 1) Create sparse disk.img if it doesn't exist + if not os.path.exists(disk_img): + subprocess.run(["fallocate", "-l", f"{size_gb}G", disk_img], check=True) + subprocess.run(["mkfs.ext4", "-F", disk_img], check=True) + + # 2) Mount it if not already mounted + if not is_mounted(mount_point): + subprocess.run(["mount", "-o", "loop", disk_img, mount_point], check=True) + + # 3) Prepare /home/micro layout inside the filesystem + # (we're mounting this whole thing as /home/micro in the container) + ssh_dir = os.path.join(mount_point, ".ssh") os.makedirs(ssh_dir, exist_ok=True) - # Write authorized_keys auth_keys_path = os.path.join(ssh_dir, "authorized_keys") with open(auth_keys_path, "w") as f: f.write(ssh_key.strip() + "\n") + # Proper perms for SSH os.chmod(ssh_dir, 0o700) os.chmod(auth_keys_path, 0o600) - # Make it owned by micro:micro (uid 1000) - subprocess.run(["chown", "-R", "1000:1000", home_dir], check=True) + # Make everything in /home/micro look like micro:micro (uid/gid 1000) + subprocess.run(["chown", "-R", "1000:1000", mount_point], check=True) - return home_dir + return mount_point def run_docker_container(container_name: str, host_port: int, docker_image: str, home_mount: str): @@ -313,12 +304,9 @@ def index(): base_name = f"mc-{image_key}-{safe_note}" container_name = f"{base_name}-{suffix}" - # Ensure per-tenant disk (1 GB ext4) and authorized_keys + # Ensure per-tenant disk (3 GB ext4) and authorized_keys try: - home_mount = ensure_tenant_home_dir(container_name, ssh_key) - setup_tenant_environment(home_mount) - - + home_mount = ensure_tenant_disk(container_name, ssh_key, size_gb=3) except subprocess.CalledProcessError as e: flash(f"Error preparing tenant disk: {e}") return render_template_string( diff --git a/fastfetch_config.jsonc b/fastfetch_config.jsonc deleted file mode 100644 index cd6abaa..0000000 --- a/fastfetch_config.jsonc +++ /dev/null @@ -1,15 +0,0 @@ -{ - "display": { - "separator": " == " - }, - "modules": [ - "title", - "os", - "kernel", - "cpu", - "memory", - "disk", - "shell" - ] -} - diff --git a/micro-alpine-dev/Dockerfile b/micro-alpine-dev/Dockerfile deleted file mode 100644 index 5a0493a..0000000 --- a/micro-alpine-dev/Dockerfile +++ /dev/null @@ -1,53 +0,0 @@ -FROM alpine:latest - -# Core packages (Alpine equivalents) -RUN apk update && apk add --no-cache \ - openssh \ - sudo \ - ca-certificates \ - git \ - curl wget \ - vim nano \ - htop \ - build-base \ - fastfetch - -# Create 'micro' user with UID 1000 and primary group 'micro' -RUN addgroup -g 1000 micro && \ - adduser -D -u 1000 -G micro -s /bin/sh micro && \ - echo "micro:ChangeMe123" | chpasswd - -# Create sudo group and add micro to it -RUN addgroup -S sudo && \ - adduser micro sudo && \ - # Enable sudo for %sudo group in /etc/sudoers - sed -i 's/# %sudo/%sudo/' /etc/sudoers - -# Prepare .ssh directory -RUN mkdir -p /home/micro/.ssh && \ - chown -R micro:micro /home/micro && \ - chmod 700 /home/micro/.ssh - -# SSH server config: key-only login, use ~/.ssh/authorized_keys -RUN sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config || true && \ - sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config || true && \ - sed -i 's/#KbdInteractiveAuthentication yes/KbdInteractiveAuthentication no/' /etc/ssh/sshd_config || true && \ - sed -i 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config || true && \ - sed -i 's|#AuthorizedKeysFile.*|AuthorizedKeysFile .ssh/authorized_keys|' /etc/ssh/sshd_config || true && \ - echo 'UsePAM no' >> /etc/ssh/sshd_config - -# sshd runtime dirs + host keys -RUN mkdir -p /var/run/sshd && \ - ssh-keygen -A - -# Fastfetch config for micro -RUN mkdir -p /home/micro/.config/fastfetch -COPY fastfetch_config.json /home/micro/.config/fastfetch/config.jsonc -RUN chown -R micro:micro /home/micro/.config && \ - echo 'if command -v fastfetch >/dev/null 2>&1; then fastfetch; fi' >> /home/micro/.profile && \ - chown micro:micro /home/micro/.profile - -EXPOSE 22 - -CMD ["/usr/sbin/sshd", "-D"] - diff --git a/micro-alpine-dev/build-dockerfile.sh b/micro-alpine-dev/build-dockerfile.sh deleted file mode 100755 index f3a702f..0000000 --- a/micro-alpine-dev/build-dockerfile.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -IMAGE_NAME="$(basename "$(pwd)")" - -echo "Building Docker image: ${IMAGE_NAME}:latest" -docker build -t "${IMAGE_NAME}:latest" . - diff --git a/micro-alpine-dev/fastfetch_config.json b/micro-alpine-dev/fastfetch_config.json deleted file mode 100644 index cd6abaa..0000000 --- a/micro-alpine-dev/fastfetch_config.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "display": { - "separator": " == " - }, - "modules": [ - "title", - "os", - "kernel", - "cpu", - "memory", - "disk", - "shell" - ] -} -