fix(security): constrain SOPS writes and custody argument handoff
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a1346b-72a4-7d40-b8bd-8b8ca346cfa2
This commit is contained in:
parent
b01a30bd49
commit
8f808577d6
8 changed files with 573 additions and 44 deletions
46
Makefile
46
Makefile
|
|
@ -53,39 +53,39 @@ hooks-test: ## Test that the pre-commit hook blocks plaintext secrets
|
|||
sops-setup: ## Validate the registered public age recipient; never install a private key
|
||||
@python3 sso-mfa/bootstrap/sops-private.py setup
|
||||
|
||||
sops-edit: ## Edit an encrypted file with SOPS: make sops-edit FILE=secrets/foo.yaml
|
||||
@[[ -n "$(FILE)" ]] || (echo "Usage: make sops-edit FILE=secrets/path/to/file.yaml"; exit 1)
|
||||
sops $(FILE)
|
||||
# Raw values prevent both Make-function evaluation and shell interpolation.
|
||||
unexport FILE INPUT OUTPUT COMMAND OPERATOR_AGE_PUBKEY
|
||||
sops-edit sops-encrypt sops-decrypt sops-rotate: export NK_SOPS_FILE := $(value FILE)
|
||||
sops-edit: export NK_SOPS_INPUT := $(value INPUT)
|
||||
sops-decrypt: export NK_SOPS_OUTPUT := $(value OUTPUT)
|
||||
|
||||
sops-encrypt: ## Encrypt a file in place: make sops-encrypt FILE=secrets/foo.yaml
|
||||
@[[ -n "$(FILE)" ]] || (echo "Usage: make sops-encrypt FILE=secrets/path/to/file.yaml"; exit 1)
|
||||
sops --encrypt --in-place $(FILE)
|
||||
@echo "✔ Encrypted $(FILE)"
|
||||
sops-edit: ## Replace encrypted content from private INPUT outside Git; explicit custody required
|
||||
@python3 sso-mfa/bootstrap/sops-write.py edit
|
||||
|
||||
sops-encrypt: ## Encrypt private, untracked FILE in place with the registered public recipient
|
||||
@python3 sso-mfa/bootstrap/sops-write.py encrypt
|
||||
|
||||
sops-decrypt: export NK_SOPS_FILE = $(FILE)
|
||||
sops-decrypt: export NK_SOPS_OUTPUT = $(OUTPUT)
|
||||
sops-decrypt: ## Decrypt age-only JSON/YAML to new private OUTPUT outside Git; explicit custody required
|
||||
@python3 sso-mfa/bootstrap/sops-private.py decrypt
|
||||
|
||||
sops-rotate: ## Rotate SOPS recipients after updating .sops.yaml: make sops-rotate FILE=secrets/foo.yaml
|
||||
@[[ -n "$(FILE)" ]] || (echo "Usage: make sops-rotate FILE=secrets/path/to/file.yaml"; exit 1)
|
||||
sops --rotate --in-place $(FILE)
|
||||
@echo "✔ Recipients rotated for $(FILE)"
|
||||
sops-rotate: ## Rotate the SOPS data key; recipient changes require a separate reviewed procedure
|
||||
@python3 sso-mfa/bootstrap/sops-write.py rotate
|
||||
|
||||
sops-custody-check: ## Validate a custody age key against keys/age.pub without keeping it on disk
|
||||
sops-custody-check sops-custody-shell sops-custody-run: export NK_CUSTODY_RECIPIENT := $(value OPERATOR_AGE_PUBKEY)
|
||||
sops-custody-run: export NK_CUSTODY_COMMAND := $(value COMMAND)
|
||||
|
||||
sops-custody-check: ## Validate a custody age key without keeping it on disk
|
||||
@bash sso-mfa/bootstrap/sops-custody-unlock.sh \
|
||||
--expected-recipient "$(OPERATOR_AGE_PUBKEY)" \
|
||||
--check-only
|
||||
--expected-recipient "$$NK_CUSTODY_RECIPIENT" --check-only
|
||||
|
||||
sops-custody-shell: ## Open a shell with a temporary SOPS_AGE_KEY_FILE from custody material
|
||||
@bash sso-mfa/bootstrap/sops-custody-unlock.sh \
|
||||
--expected-recipient "$(OPERATOR_AGE_PUBKEY)"
|
||||
--expected-recipient "$$NK_CUSTODY_RECIPIENT"
|
||||
|
||||
sops-custody-run: ## Run COMMAND with a temporary custody age key: make sops-custody-run COMMAND='make -C ../inter-hub recovery-drill'
|
||||
@[[ -n "$(COMMAND)" ]] || (echo "Usage: make sops-custody-run COMMAND='make -C ../inter-hub recovery-drill'"; exit 1)
|
||||
@COMMAND='$(COMMAND)' bash sso-mfa/bootstrap/sops-custody-unlock.sh \
|
||||
--expected-recipient "$(OPERATOR_AGE_PUBKEY)" \
|
||||
-- bash -lc "$$COMMAND"
|
||||
sops-custody-run: ## Run COMMAND inside the temporary custody handoff
|
||||
@[[ -n "$$NK_CUSTODY_COMMAND" ]] || (echo "Usage: make sops-custody-run COMMAND='<approved command>'"; exit 1)
|
||||
@bash sso-mfa/bootstrap/sops-custody-unlock.sh \
|
||||
--expected-recipient "$$NK_CUSTODY_RECIPIENT" -- bash -lc "$$NK_CUSTODY_COMMAND"
|
||||
|
||||
check-secrets: ## Fail if any file under secrets/ is not SOPS-encrypted
|
||||
@echo "Checking for unencrypted files under secrets/..."
|
||||
|
|
@ -100,7 +100,7 @@ check-secrets: ## Fail if any file under secrets/ is not SOPS-encrypted
|
|||
done < <(git ls-files --others --cached 'secrets' 2>/dev/null | grep -v '/$$'); \
|
||||
if [[ "$$bad" -ne 0 ]]; then \
|
||||
echo ""; \
|
||||
echo "ERROR: Unencrypted secret(s) detected. Encrypt with: sops --encrypt --in-place <file>"; \
|
||||
echo "ERROR: Unencrypted file detected. For private untracked input: make sops-encrypt FILE=<file>; tracked plaintext requires incident review."; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo "✔ All secrets/ files appear SOPS-encrypted"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue