diff --git a/cli/Dockerfile b/cli/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..4add00a0e518396ca1d7cc6f65be0b644e3854e1
--- /dev/null
+++ b/cli/Dockerfile
@@ -0,0 +1,102 @@
+FROM docker.io/hashicorp/terraform:1.0.0 AS terraform
+FROM docker.io/hashicorp/packer:1.7.3 AS packer
+
+
+# kubectl CLI cache
+FROM docker.io/library/fedora:34 as kubectl
+
+ARG KUBECTL_RELEASE=v1.22.0
+ENV KUBECTL_RELEASE=${KUBECTL_RELEASE}
+
+RUN curl -LO "https://dl.k8s.io/release/${KUBECTL_RELEASE}/bin/linux/amd64/kubectl" \
+    && curl -LO "https://dl.k8s.io/release/${KUBECTL_RELEASE}/bin/linux/amd64/kubectl-convert" \
+    && curl -LO "https://dl.k8s.io/${KUBECTL_RELEASE}/bin/linux/amd64/kubectl.sha256" \
+    && curl -LO "https://dl.k8s.io/${KUBECTL_RELEASE}/bin/linux/amd64/kubectl-convert.sha256" \
+    && echo "$(<kubectl.sha256) kubectl" | sha256sum --check \
+    && echo "$(<kubectl-convert.sha256) kubectl-convert" | sha256sum --check \
+    && install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl \
+    && install -o root -g root -m 0755 kubectl-convert /usr/local/bin/kubectl-convert
+
+# hcloud CLI cache
+FROM docker.io/library/fedora:34 as hcloud
+
+ARG HCLOUD_RELEASE=v1.26.1
+ENV HCLOUD_RELEASE=${HCLOUD_RELEASE}
+
+RUN curl -L "https://github.com/hetznercloud/cli/releases/download/${HCLOUD_RELEASE}/hcloud-linux-amd64.tar.gz" | tar xvzf - hcloud \
+    && install -o root -g root -m 0755 hcloud /usr/local/bin/hcloud
+
+# Helm CLI cache
+FROM docker.io/library/fedora:34 as helm
+
+ARG HELM_RELEASE=v3.6.3
+ENV HELM_RELEASE=${HELM_RELEASE}
+
+RUN curl -L "https://get.helm.sh/helm-${HELM_RELEASE}-linux-amd64.tar.gz" | tar xvzf - linux-amd64/helm --strip-components=1 \
+    && install -o root -g root -m 0755 helm /usr/local/bin/helm
+
+# Flux CLI cache
+FROM docker.io/library/fedora:34 as flux
+
+ARG FLUX_RELEASE=0.16.2
+ENV FLUX_RELEASE=${FLUX_RELEASE}
+
+RUN curl -L https://github.com/fluxcd/flux2/releases/download/v${FLUX_RELEASE}/flux_${FLUX_RELEASE}_linux_amd64.tar.gz | tar xvzf - flux \
+    && install -o root -g root -m 0755 flux /usr/local/bin/flux
+
+# SOPS CLI cache
+FROM docker.io/library/fedora:34 as sops
+
+ARG SOPS_RELEASE=v3.7.1
+ENV SOPS_RELEASE=${SOPS_RELEASE}
+
+RUN curl -L https://github.com/mozilla/sops/releases/download/${SOPS_RELEASE}/sops-${SOPS_RELEASE}.linux > ./sops \
+    && install -o root -g root -m 0755 sops /usr/local/bin/sops
+
+# Actual start of container build
+FROM docker.io/library/fedora:34
+
+ARG MAINTAINER="unmaintained"
+LABEL maintainer=$MAINTAINER
+
+RUN dnf upgrade -y
+
+RUN dnf install -y \
+      bash \
+      ca-certificates \
+      openssh-clients \
+      openssl \
+      ansible \
+      make \
+      rsync \
+      curl \
+      git \
+      jq \
+      httpd-tools \
+      python3 \
+      libvirt-client \
+      vim \
+      bash-completion \
+      butane \
+    && dnf clean all
+
+# External tools
+COPY --from=terraform /bin/terraform /usr/local/bin/terraform
+COPY --from=packer /bin/packer /usr/local/bin/packer
+COPY --from=kubectl /usr/local/bin/kubectl /usr/local/bin/kubectl
+COPY --from=kubectl /usr/local/bin/kubectl-convert /usr/local/bin/kubectl-convert
+COPY --from=hcloud /usr/local/bin/hcloud /usr/local/bin/hcloud
+COPY --from=helm /usr/local/bin/helm /usr/local/bin/helm
+COPY --from=flux /usr/local/bin/flux /usr/local/bin/flux
+COPY --from=sops /usr/local/bin/sops /usr/local/bin/sops
+
+RUN true \
+    && echo "command -v flux >/dev/null && . <(flux completion bash)" >> /root/.bashrc \
+    && echo "command -v kubectl >/dev/null && . <(kubectl completion bash)" >> /root/.bashrc \
+    && echo "command -v helm >/dev/null && . <(helm completion bash)" >> /root/.bashrc \
+    && echo "command -v hcloud >/dev/null && . <(hcloud completion bash)" >> /root/.bashrc \
+    && true
+
+# Create workspace
+RUN mkdir /workspace
+WORKDIR /workspace
diff --git a/cli/Makefile b/cli/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..cb48dfa89f2f4e490723c016831c39767501753c
--- /dev/null
+++ b/cli/Makefile
@@ -0,0 +1,10 @@
+.DEFAULT_GOAL := help
+
+include ../utils/help.mk
+
+.PHONY: install
+install: ## Install koolbox, the Kubernetes Toolbox for SI-Infrastructure
+	install -m 755 ./koolbox ~/bin/koolbox
+
+build: ## Build container locally instead of using one from upstream
+	podman build -t quay.io/sheogorath/koolbox:latest .
diff --git a/cli/koolbox b/cli/koolbox
new file mode 100755
index 0000000000000000000000000000000000000000..30996e6710d78e8cb79b9eff32c02c5017da3d02
--- /dev/null
+++ b/cli/koolbox
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+PROGRAM_NAME=koolbox
+CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/$PROGRAM_NAME"
+CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/$PROGRAM_NAME"
+DATA_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/$PROGRAM_NAME"
+
+# Warm up all directories and files mounted to the container
+mkdir -p "$CONFIG_DIR/"{kube,helm,ssh} "$CACHE_DIR/"helm "$DATA_DIR/"helm
+touch "$CONFIG_DIR/env"
+
+# Make sure this script never runs in home, since it would ruin all SELinux labels
+if [ "$(pwd)" = "$HOME" ]; then
+  echo "Can not run in home directory, would break SELinux labels." >&2
+  exit 1
+fi
+
+# Using systemd-resolved when available
+PODMAN_NETWORK_SETTINGS=""
+if systemctl is-active systemd-resolved.service > /dev/null 2>&1; then
+  PODMAN_NETWORK_SETTINGS="--network host --dns 127.0.0.53"
+fi
+
+podman run --rm -it \
+    $PODMAN_NETWORK_SETTINGS \
+    --env-file="$CONFIG_DIR/env" \
+    --hostname koolbox \
+    -v "$CONFIG_DIR/kube:/root/.kube:z" \
+    -v "$CONFIG_DIR/ssh:/root/.ssh:z" \
+    -v "$CONFIG_DIR/helm:/root/.config/helm:z" \
+    -v "$CONFIG_DIR/helm:/root/.cache/helm:z" \
+    -v "$DATA_DIR/helm:/root/.local/share/helm:z" \
+    -v "$(pwd):/workspace:z" -w /workspace \
+    quay.io/sheogorath/koolbox:latest /bin/bash $@