docker compose 실행시 sops에 등록된 age의 secret, public를 환경 변수로 주입하여 실행합니다.
실행 주체에 따라 아래와 같은 ENV 네이밍으로 넘겨주면 됩니다.

mise
secret: MISE_SOPS_AGE_KEY
public: MISE_SOPS_AGE_RECIPIENTS

sops
secret: SOPS_AGE_KEY
public: SOPS_AGE_RECIPIENTS


dockerfile

# ci/dockerfile
FROM alpine:3.22 AS base
 
WORKDIR /with-enc-env
 
ENV MISE_DATA_DIR="/mise" \
	MISE_CONFIG_DIR="/mise" \
	MISE_CACHE_DIR="/mise/cache" \
	MISE_INSTALL_PATH="/usr/local/bin/mise" \
	PATH="/mise/shims:$PATH" \
	MISE_OVERRIDE_CONFIG_FILENAMES="mise.ci.toml"
 
 
RUN apk add --no-cache ca-certificates curl openssh-client \
	&& rm -rf /var/cache/apk/* \
	&& curl -fsSL https://mise.run | sh
 
RUN ln -s /run/secrets/s1 ./s1.enc.yaml || true
RUN ln -s /run/secrets/s2 ./s2.enc.yaml || true
 
COPY mise.ci.toml .
 
RUN mise install
RUN mise trust
 
CMD ["sh", "-c", "mise run my-task"]

docker compose

secrets 파일은 이미지에 남지 않도록 시크릿으로 전달합니다.

# ci/docker-compose.yml
name: with-enc-env
services:
	with-env:
		build:
			context: .
			dockerfile: dockerfile
 
		secrets:
			- source: s1
				target: /run/secrets/s1
			- source: s2
				target: /run/secrets/s2
		
		environment:
			MISE_SOPS_AGE_KEY: ${MISE_SOPS_AGE_KEY?required}
			MISE_SOPS_AGE_RECIPIENTS: "ci-age-public-key"
 
secrets:
	s1:
		file: ./s1.enc.yaml
	s2:
		file: ./s2.enc.yaml

만약 해당 secrets에 대한 권한이 현재 로컬 컴퓨터에도 있다면 다음과 같이 로컬에서도 실행할 수 있습니다.

#!/usr/bin/env bash
set -euxo pipefail
 
# age는 현재 로컬 컴퓨터의 권한으로 실행함
MISE_SOPS_AGE_RECIPIENTS="age1amv4lddeydj9jzz7shynunmrnzt8e4mt4y25uuq2qemjtjvc5uwsnkzntc" \
MISE_SOPS_AGE_KEY=$(grep '^AGE-SECRET-KEY-' "$SOPS_AGE_KEY_FILE") \
docker compose run --build --rm with-enc-env

mise.ci.toml

mise의 태스크로 실행시 env에 있는 암호화된 시크릿이 주입되어 있는 격리된 환경에서 실행됩니다.
저는 mise의 sops 환경변수만 있어도 sops를 단독으로도 실행시킬 수 있도록 sops의 환경변수도 설정을 해주었습니다.

# ci/mise.ci.toml
[tools.sops]
version = "3.11.0"
 
 
[tools.age]
version = "1.2.1"
 
[tools.my-task]
run = '''
	echo "$MY_SECRET_1"
	echo "$MY_SECRET_2"
'''
 
[env]
SOPS_AGE_KEY = { value = "{{env.MISE_SOPS_AGE_KEY}}", redact = true, read_only = true }  
SOPS_AGE_RECIPIENTS = { value = "{{env.MISE_SOPS_AGE_RECIPIENTS}}", redact = true, read_only = true }
_.file = [
	{ path = "./s1.enc.yaml", redact = true, read_only = true },
	{ path = "./s2.enc.yaml", redact = true, read_only = true }
]
 

github ci

먼저 age secrets, public key 추가가 필요합니다.
저는 github CICD_SOPS 환경에 미리 아래처럼 추가했어요.

secret: SOPS_AGE_SECRET
public: SOPS_AGE_PUBLIC

# .github/workflows/ci.yml
 
name: Read secret test
 
on:
	push:
		branches:
			- main
		
		paths:
			- 'ci/*.enc.yaml'
			- '.github/workflows/ci.yml'
			- 'ci/dockerfile'
			- 'ci/docker-compose.yml'
 
  
jobs:
	run: test-run
		runs-on: ubuntu-latest
		environment: CICD_SOPS
		steps:
			- uses: actions/checkout@v5
			- name: Set up Docker Buildx
				uses: docker/setup-buildx-action@v3
			
			- name: Build Docker Image with Cache
				uses: docker/build-push-action@v6
					with:
						context: ci
						file: ci/dockerfile
						load: true 
						tags: with-enc-env:latest 
						cache-from: type=gha
						cache-to: type=gha,mode=max
			
			- name: Run VPS Sync
				env:
					MISE_SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_SECRET }}
					MISE_SOPS_AGE_RECIPIENTS: ${{ vars.SOPS_AGE_PUBLIC }}
				run: |
					cd ci
					docker compose run --rm with-enc-env

더 읽어볼 것

draft - 3. nix flake와 sops-nix를 통한 선언적 시스템 비밀 관리