Update to use a base64 encoded key
This commit is contained in:
129
Dockerfile
129
Dockerfile
@@ -4,35 +4,47 @@
|
||||
# ────────────
|
||||
# This Dockerfile needs SSH access to git.kadil.dev during the
|
||||
# `npm install` step (the `goods-editor` dependency is a git+ssh:
|
||||
# URL). We pass an SSH private key in as a BuildKit secret named
|
||||
# `ssh_key`. The secret is mounted into the build for just that one
|
||||
# RUN step, used to authenticate the git fetch, then unmounted —
|
||||
# nothing about the key ends up in any image layer or in
|
||||
# `docker history`.
|
||||
# URL). We pass a base64-encoded SSH private key as a BuildKit
|
||||
# secret named `ssh_key`, then decode it inside the build.
|
||||
#
|
||||
# Get an SSH key with read access to the goods-editor-module repo
|
||||
# on Gitea registered first (the same key you use for git push works,
|
||||
# OR a dedicated deploy key with read-only access — recommended for
|
||||
# CI / servers). The public half goes in Gitea Settings → SSH Keys,
|
||||
# or as a deploy key on the repo itself.
|
||||
# Why base64-encoded rather than raw PEM
|
||||
# ───────────────────────────────────────
|
||||
# The primary deploy target is Dokploy, whose Build-time Secrets UI
|
||||
# is a dotenv-parsed textarea (one KEY=VALUE per line). PEM keys are
|
||||
# multi-line and break dotenv parsing. Base64 collapses the key to a
|
||||
# single line of safe ASCII that any dotenv parser accepts. We use
|
||||
# base64 everywhere (Dokploy and local builds) so the Dockerfile has
|
||||
# exactly one input format — no branching logic for raw vs encoded.
|
||||
#
|
||||
# Then build, picking whichever invocation matches where the key is:
|
||||
# Register a deploy key first
|
||||
# ─────────────────────────────
|
||||
# Generate a read-only deploy key dedicated to this build and add
|
||||
# its public half to Gitea (repo Settings → Deploy Keys):
|
||||
# ssh-keygen -t ed25519 -f ~/.ssh/goods-editor-deploy -N "" -C "deploy"
|
||||
# cat ~/.ssh/goods-editor-deploy.pub # → paste into Gitea
|
||||
#
|
||||
# 1. From a file on disk (typical local dev / deployment server):
|
||||
# docker build \
|
||||
# --secret id=ssh_key,src=$HOME/.ssh/id_ed25519 \
|
||||
# -t apparel-designer .
|
||||
# Then base64-encode the PRIVATE half for build-time use:
|
||||
# base64 < ~/.ssh/goods-editor-deploy | tr -d '\n' | pbcopy
|
||||
# The `tr -d '\n'` strips line wrapping so the output is a single
|
||||
# physical line, which the Dokploy textarea (and dotenv parsers in
|
||||
# general) require.
|
||||
#
|
||||
# 2. From an environment variable (typical CI — secret store
|
||||
# injects the key as an env var, no file ever touches disk):
|
||||
# docker build \
|
||||
# --secret id=ssh_key,env=SSH_PRIVATE_KEY \
|
||||
# -t apparel-designer .
|
||||
# (BuildKit 1.5+ supports the `env=` source.)
|
||||
# Dokploy
|
||||
# ───────
|
||||
# Paste into the application's Environment → Build-time Secrets
|
||||
# textarea as a single line:
|
||||
# ssh_key=<that base64 string>
|
||||
# Then redeploy.
|
||||
#
|
||||
# 3. Via docker-compose: see docker-compose.yml — the `secrets:`
|
||||
# block there wires the same secret. Then:
|
||||
# SSH_KEY_FILE=$HOME/.ssh/id_ed25519 docker compose build
|
||||
# Local build with the same approach
|
||||
# ───────────────────────────────────
|
||||
# base64 < ~/.ssh/goods-editor-deploy | tr -d '\n' > /tmp/key.b64
|
||||
# docker build --secret id=ssh_key,src=/tmp/key.b64 -t apparel-designer .
|
||||
# rm /tmp/key.b64
|
||||
#
|
||||
# Or via env var:
|
||||
# SSH_KEY_B64="$(base64 < ~/.ssh/goods-editor-deploy | tr -d '\n')" \
|
||||
# docker build --secret id=ssh_key,env=SSH_KEY_B64 -t apparel-designer .
|
||||
#
|
||||
# Requires Docker 23+ (BuildKit is the default; older Docker needs
|
||||
# `DOCKER_BUILDKIT=1` exported in the environment).
|
||||
@@ -97,42 +109,53 @@ COPY package*.json ./
|
||||
# a host-provided secret at /run/secrets/ssh_key inside this single
|
||||
# RUN step. The secret is NEVER copied into any image layer; once
|
||||
# the RUN command finishes, the mount disappears and nothing about
|
||||
# the key remains in the built image. `docker history` won't show
|
||||
# it either.
|
||||
# the key remains in the built image.
|
||||
#
|
||||
# Steps:
|
||||
# 1. Create ~/.ssh with 0700 perms (ssh refuses to use a config
|
||||
# directory that's world-readable).
|
||||
# 2. ssh-keyscan git.kadil.dev → ~/.ssh/known_hosts. Without this,
|
||||
# ssh would prompt "Are you sure you want to continue connecting?"
|
||||
# with no stdin to answer it, and the install would hang forever.
|
||||
# 3. Run npm install with GIT_SSH_COMMAND pointing at the mounted
|
||||
# secret. npm shells out to git for the git+ssh: dependency, git
|
||||
# respects GIT_SSH_COMMAND, ssh uses the key at /run/secrets/ssh_key.
|
||||
# `IdentitiesOnly=yes` prevents ssh from trying any other key
|
||||
# it might find (none in this container, but defensive).
|
||||
# Dokploy-specific note: Dokploy's Build-time Secrets UI is a single
|
||||
# textarea that gets parsed as dotenv (one KEY=VALUE per line),
|
||||
# which doesn't tolerate multi-line values. PEM-formatted SSH keys
|
||||
# ARE multi-line. The workaround is to base64-encode the key before
|
||||
# pasting into Dokploy and decode here at use-time. Base64 produces
|
||||
# a single line of ASCII with no characters that confuse dotenv
|
||||
# parsers.
|
||||
#
|
||||
# Why use GIT_SSH_COMMAND rather than copying the key to ~/.ssh/id_ed25519:
|
||||
# the secret mount is a clean way to use a file without it ever
|
||||
# touching the filesystem proper. If we copied, we'd have to be
|
||||
# careful to `rm` it in the same RUN step before layer commit; with
|
||||
# GIT_SSH_COMMAND, the file is only ever at /run/secrets/, which
|
||||
# BuildKit clears automatically.
|
||||
# Encode locally:
|
||||
# base64 < ~/.ssh/goods-editor-deploy | tr -d '\n' | pbcopy
|
||||
# Then paste in Dokploy as:
|
||||
# ssh_key=<that base64 string>
|
||||
#
|
||||
# Steps in this RUN:
|
||||
# 1. mkdir ~/.ssh with 0700 (ssh refuses world-readable config dirs)
|
||||
# 2. ssh-keyscan git.kadil.dev so we don't hang on the
|
||||
# "continue connecting?" prompt
|
||||
# 3. base64-decode /run/secrets/ssh_key into /tmp/ssh_key. The
|
||||
# decoded file holds the original PEM private key.
|
||||
# 4. chmod 0600 the decoded key so ssh accepts it.
|
||||
# 5. Run npm install with GIT_SSH_COMMAND pointing at the decoded
|
||||
# key. IdentitiesOnly=yes prevents ssh from trying any other
|
||||
# key it might find.
|
||||
# 6. rm the decoded key. Since we created it in the same RUN, it
|
||||
# never gets committed to a layer.
|
||||
#
|
||||
# If the build aborts here:
|
||||
# • "Permission denied (publickey)" → the secret was provided but
|
||||
# the key doesn't have access to the repo. Verify the public
|
||||
# half is registered in Gitea (account settings or deploy key).
|
||||
# • "required secret 'ssh_key' not provided" → forgot the `--secret`
|
||||
# flag on the build command (see docblock at top of file).
|
||||
# • Hangs at "Cloning into …" → ssh-keyscan didn't populate
|
||||
# known_hosts (network issue inside the build). Try again with
|
||||
# `--no-cache`.
|
||||
# • "Permission denied (publickey)" → the key in Dokploy doesn't
|
||||
# match the deploy key registered in Gitea. Re-base64-encode and
|
||||
# re-paste, OR re-check the Gitea deploy key.
|
||||
# • "Identity file /tmp/ssh_key not accessible: No such file or
|
||||
# directory" → the secret wasn't mounted. Verify the Dokploy
|
||||
# Build-time Secrets textarea contains exactly `ssh_key=...` as
|
||||
# a single line.
|
||||
# • "base64: invalid input" → the Dokploy textarea has trailing
|
||||
# whitespace, line breaks inside the base64, or extra content.
|
||||
# Re-paste from a fresh `base64 < key | tr -d '\n' | pbcopy`.
|
||||
RUN --mount=type=secret,id=ssh_key \
|
||||
mkdir -p -m 0700 ~/.ssh && \
|
||||
ssh-keyscan git.kadil.dev >> ~/.ssh/known_hosts 2>/dev/null && \
|
||||
GIT_SSH_COMMAND="ssh -i /run/secrets/ssh_key -o IdentitiesOnly=yes -o UserKnownHostsFile=/root/.ssh/known_hosts" \
|
||||
npm install
|
||||
base64 -d /run/secrets/ssh_key > /tmp/ssh_key && \
|
||||
chmod 0600 /tmp/ssh_key && \
|
||||
GIT_SSH_COMMAND="ssh -i /tmp/ssh_key -o IdentitiesOnly=yes -o UserKnownHostsFile=/root/.ssh/known_hosts" \
|
||||
npm install && \
|
||||
rm -f /tmp/ssh_key
|
||||
|
||||
COPY . .
|
||||
|
||||
|
||||
Reference in New Issue
Block a user