Skip to content

feat: Add SOPS and Age support to Periphery - #1053

Open
Nikhil-Gohil wants to merge 3 commits into
moghtech:mainfrom
Nikhil-Gohil:feat/add-sops-age-support
Open

feat: Add SOPS and Age support to Periphery#1053
Nikhil-Gohil wants to merge 3 commits into
moghtech:mainfrom
Nikhil-Gohil:feat/add-sops-age-support

Conversation

@Nikhil-Gohil

Copy link
Copy Markdown

Adding sops and age binaries to the runtime dependencies. This allows users to decrypt secrets (e.g., .env files) directly within the container for GitOps workflows, removing the need for pre-decryption scripts on the host. Will make it much easier to use sops + age based secret handling in komodo.

Right now, we have to build docker images for core/periphery (tedious) or bind mount these binaries to the docker containers (could break).

I tested this workflow by creating a komodo periphery image and running a stack:
Repo with periphery + sops/age is here: Komodo Periphery Sops

Can use this as a pre deploy for stacks in komodo assuming secrets are stored as .env.enc in git:
sops --decrypt --input-type yaml --output-type dotenv .env.enc > .env

One issue I can think about is this creates a slight difference between komodo periphery as a docker container and the systemd agent since it will be expected that if installing as a systemd agent, sops and age needs to be manually installed.

@NiXTheDev

NiXTheDev commented Dec 20, 2025

Copy link
Copy Markdown

One issue I can think about is this creates a slight difference between komodo periphery as a docker container and the systemd agent since it will be expected that if installing as a systemd agent, sops and age needs to be manually installed.

That can be handled in the periphery install script, that also needs a disclaimer, and different distros support because apt, dnf, pacman and others I very likely missed have different ways to install packages

apt/dnf install -y <package> #Oh lol, same syntax
pacman -Sy <package>

Or alternatively it can still have the pre-decryption script as a fallback if sops and age aren't installed, and then be slowly phased out(?), emitting a warning to the log about the requirement at first

@Bhuemann

Bhuemann commented Mar 7, 2026

Copy link
Copy Markdown

I built docker images to include the SOPS + Age binaries, and found that pre-deployment hooks run after a check is performed ensuring all files exist. This means if you use alternative names for .env a dummy file must exist to pass the check before the SOPS command can run

@Nikhil-Gohil
Nikhil-Gohil force-pushed the feat/add-sops-age-support branch from fa55f16 to 9622b96 Compare August 16, 2026 21:14
@Nikhil-Gohil

Copy link
Copy Markdown
Author

Realized that sops and age are only needed on the Periphery agents. Updated the PR to remove them from the Core and bumped the Periphery SOPS version to latest.

@Nikhil-Gohil Nikhil-Gohil changed the title feat: Add SOPS and Age support to Core and Periphery feat: Add SOPS and Age support to Periphery - #1053 Aug 16, 2026
@Nikhil-Gohil Nikhil-Gohil changed the title feat: Add SOPS and Age support to Periphery - #1053 feat: Add SOPS and Age support to Periphery Aug 16, 2026
@flowcool

Copy link
Copy Markdown

+1 on native SOPS support in Periphery. Sharing our custom-image approach as another data point, complementary to @Nikhil-Gohil's fork.

Dockerfile (both parents pinned by digest so builds cannot drift silently):

FROM ghcr.io/getsops/sops:v3.13.3@sha256:857f5a151ac0b2bfc55c1e4e5581d66fb8e268e4d106b38e74191f3bac9d58ea AS sops

FROM ghcr.io/moghtech/komodo-periphery:2.2.0@sha256:7fb1a4807d125ce036a17d37c940b4001402afcaf342a2c720c98d096b1b54da

COPY --from=sops /usr/local/bin/sops /usr/local/bin/sops

# Fail the build rather than ship an image whose sops is broken or missing.
RUN sops --version --disable-version-check

A tiny GHA reads the upstream version from the Dockerfile and rebuilds on every Periphery bump.

Notable design choices:

  • No age binary. sops implements age natively as a library and reads the private key via SOPS_AGE_KEY_FILE. The age CLI is only needed to generate keys, which happens off-host. One less binary in the image, one less supply-chain item. Verified: decryption works with age absent.
  • Age key mounted read-only from the host into the Periphery container — it never enters Komodo Core and is never a Komodo variable. Keeps the trust boundary clean.
  • Decryption via compose_cmd_wrapper: sops exec-env <path> '[[COMPOSE_COMMAND]]'. Secrets are decrypted only at deploy time, into env vars scoped to the compose process — never materialized as a .env file on disk. This also sidesteps the pre-deploy file-check ordering issue tracked in [Bug] Pre-deployment commands run after checks ensuring all files exist #1234.

Running this on 4 hosts (~30 stacks, ~4 months) with zero regressions. Happy to answer if any of this is useful for shaping the native design.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants