# NixOS와 비밀값

> Clean Markdown view of GeekNews topic #29328. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=29328](https://news.hada.io/topic?id=29328)
- GeekNews Markdown: [https://news.hada.io/topic/29328.md](https://news.hada.io/topic/29328.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2026-05-10T02:02:22+09:00
- Updated: 2026-05-10T02:02:22+09:00
- Original source: [isabelroses.com](https://isabelroses.com/blog/nixos-and-secrets/)
- Points: 1
- Comments: 1

## Topic Body

- NixOS에서 비밀값을 Nix 설정, 비공개 Git 저장소, `git-crypt`에 평문으로 두면 **Nix store**가 누구나 읽을 수 있어 머신 접근자가 비밀값을 읽을 수 있음
- **sops-nix**는 `.sops.yaml` 규칙과 `sops` 편집 흐름으로 비밀값 파일을 암호화하고, 활성화 시 호스트 SSH 키로 복호화해 `/run/secrets/&lt;name&gt;`의 **tmpfs**에 평문을 둠
- **agenix**는 `secrets.nix`에서 비밀값별 수신자 공개키를 지정하고 `.age` 파일을 `/run/agenix/&lt;name&gt;`의 **tmpfs**에 복호화하며, 새 호스트나 키 교체 때 재키잉이 필요함
- 파일시스템에 비밀값을 직접 두는 방식은 단일 서버나 노트북에는 가능하지만, `builtins.readFile "/var/lib/myservice/token"`처럼 평가 시점에 읽으면 값이 **Nix store**에 들어가므로 피해야 함
- 처음 시작하고 독립적인 토큰 몇 개라면 **agenix**가 절차가 적고, 메일 서버처럼 관련 비밀값이 많은 호스트라면 여러 값을 한 파일에 묶는 **sops-nix**가 더 잘 맞음

---

### NixOS에서 비밀값을 다룰 때의 기본 위험
- NixOS에서 비밀값 관리는 `sops-nix`, `agenix`/`ragenix`, 파일시스템 활용, 비공개 Git 저장소, `git-crypt`, Nix 설정에 직접 작성하는 방식으로 나뉨
- 비공개 Git 저장소, `git-crypt`, Nix 설정 직접 작성 방식은 머신을 공유하거나 설정을 공개할 계획이 있으면 쓰면 안 됨
  - **Nix store**는 누구나 읽을 수 있어, 머신 접근 권한이 있는 사람이 비밀값을 읽을 수 있음
  - 이 위험은 [CVE-2026-31431(copyfail)](https://copy.fail/)와 [CVE-2026-43284 및 CVE-2026-43500(dirtyfrag)](https://github.com/V4bel/dirtyfrag) 같은 취약점이 있는 시점에 특히 중요함
- 공개된 설정에서 비밀값이 최소 두 번 유출된 적이 있으며, 예시는 [1](https://github.com/isabelroses/dotfiles/blob/f84c2265720107530d9d9c85e61aed47bc2f839c/hosts/hydra/settings.nix#L63), [2](https://github.com/isabelroses/dotfiles/blob/796597ead9c7ea70413faae1a695cb9fb43c9536/env.nix)에 남아 있음

### sops-nix
- [sops-nix](https://github.com/Mic92/sops-nix)는 처음 접할 때 설정이 어렵게 느껴질 수 있지만, 문서가 크게 개선됐고 `sops`가 SSH 키로 비밀값 암복호화를 기본 지원하게 된 점이 큰 개선임
- 다만 `sops-nix`는 이 SSH 키 지원에서 아직 뒤처져 있으며 [sops-nix#779](https://github.com/Mic92/sops-nix/pull/779), [sops-nix#922](https://github.com/Mic92/sops-nix/pull/922)에서 관련 작업이 진행 중
- 사용 흐름은 `.sops.yaml`에 암복호화 규칙을 만들고, `sops` 명령으로 비밀값 파일을 편집하는 방식
  - 예시는 `secrets/*.yaml` 경로에 대해 `age` 수신자로 SSH 공개키를 지정하는 형태
  - `sops secrets/shush.yaml`을 실행하면 선택한 편집기가 열리고, `hello: sops` 같은 YAML 값을 작성할 수 있음
  - 편집기를 종료하면 값은 `ENC[AES256_GCM,...]` 형태로 암호화되고, 같은 명령으로 다시 편집 가능함
- NixOS 설정에서는 `sops-nix` 모듈이 대부분의 작업을 처리함
  - `defaultSopsFile = ./secrets/shush.yaml;`로 기본 비밀값 파일을 지정함
  - `age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];`로 호스트 SSH 키를 지정함
  - `secrets."hello"`에 `owner`, `group`, `mode`를 지정해 파일 권한을 설정함
- 활성화 시점에 `sops-nix`가 호스트의 SSH 키로 파일을 복호화하고 평문을 `/run/secrets/&lt;name&gt;`에 둠
  - 이 경로는 **tmpfs**이므로 비밀값이 디스크에 닿지 않음
  - 값을 필요로 하는 서비스는 해당 경로를 읽으면 됨
- **템플릿** 기능은 공유 설정이나 다른 사용자가 참조하는 설정에서 유용함
  - 서비스 설정 파일이 평문과 일부 비밀값을 함께 요구할 때 전체 파일을 암호화하지 않아도 됨
  - 예를 들어 `SMTP_USER=isabel`은 평문으로 두고, `SMTP_PASSWORD=${config.sops.placeholder."mailserver/smtp_password"}`처럼 비밀값 자리표시자를 넣을 수 있음

### agenix
- [agenix](https://github.com/ryantm/agenix)는 `sops-nix`와 달리 `secrets.nix`에서 비밀값과 접근 가능한 키를 설정하므로 Nix에 더 가까운 사용감을 줌
- `secrets.nix`에는 사용자와 호스트의 SSH 공개키를 바인딩하고, 각 `.age` 파일에 어떤 공개키들이 접근 가능한지 지정함
  - 예를 들어 `"secret1.age".publicKeys = [ isabel host1 ];`, `"secret2.age".publicKeys = [ isabel host2 ];`처럼 비밀값마다 수신자 목록을 다르게 둘 수 있음
- 비밀값 파일은 `agenix` CLI로 만들어야 함
  - `agenix -e secret1.age` 명령으로 `secret1.age`를 생성하거나 나중에 다시 편집할 수 있음
- 호스트 설정에 연결하는 방식은 `sops-nix`와 비슷하지만, 각 비밀값이 별도 파일이므로 표면적이 더 작음
  - `age.secrets.secret1.file = ./secrets/secret1.age;`로 파일을 지정함
  - `owner`, `group`, `mode`로 소유자와 권한을 지정함
- 부팅 시 호스트의 SSH 키로 각 `.age` 파일을 복호화해 `/run/agenix/&lt;name&gt;`에 둠
  - 이 경로도 **tmpfs** 위에 있음
- 가장 자주 걸리는 부분은 **재키잉(rekeying)** 임
  - 새 호스트를 추가하거나 키를 교체하면, `secrets.nix`에서 `publicKeys` 목록이 바뀐 모든 비밀값을 다시 암호화해야 함
  - `agenix --rekey`가 이를 처리하지만, 기존 암호문을 읽기 위해 현재 수신자 중 하나의 개인키가 필요함
  - 실제로는 새로 올리려는 호스트가 아니라 가장 신뢰하는 머신에서 재키잉이 이뤄짐

### 파일시스템만 사용하는 방식
- 파일시스템에 비밀값을 직접 두는 방식은 설정이 더 이상 머신을 완전히 설명하지 못한다는 비용이 있음
- 재설치 시 모든 파일을 올바른 위치와 소유권으로 다시 넣어야 함
  - 새벽 2시에 서버를 복구하는 상황처럼 복구 작업에서는 큰 재앙이 될 수 있음
- 피해야 할 패턴은 `builtins.readFile "/var/lib/myservice/token"` 같은 형태
  - 이 방식은 평가 시점에 파일을 읽고 내용을 **Nix store**에 포함함
  - Nix store는 누구나 읽을 수 있으므로, 처음 경고한 실패 방식과 정확히 같아짐
- 대신 서비스에는 값 자체가 아니라 경로를 넘겨야 함
  - 예로 [services.*.environmentFiles](https://search.nixos.org/options?channel=unstable&query=services.*.environmentFiles) 같은 옵션을 사용할 수 있음
- 단일 서버나 노트북에서는 괜찮을 수 있지만, 플릿이거나 설정만으로 처음부터 재구축하고 싶은 환경이라면 `sops-nix`나 `agenix`가 더 적합함
- 머신마다 진짜 저장소에 넣으면 안 되는 값이 한두 개 있을 때는 괜찮지만, 나중에 다시 넣어야 할 책임이 미래의 자신에게 생김

### sops-nix와 agenix 비교
- `sops-nix`를 선택하는 주요 이유는 가능한 많은 데이터를 하나의 파일에 묶을 수 있다는 점
  - 메일 서버처럼 관련 비밀값이 많은 경우, `agenix`처럼 5개 안팎의 파일로 나누지 않고 한 파일에 더 많은 비밀값을 둘 수 있음
  - 강력한 도구로 계속 쓰기에 적합하며, 메일 서버처럼 비밀값이 매우 많은 호스트에서 먼저 선택할 만함
- `agenix`는 **단순성**에서 강점이 있음
  - 배워야 할 YAML 스키마가 없음
  - 동기화해야 할 `.sops.yaml`이 없음
  - `secrets.nix`가 그냥 Nix이므로 호스트와 사용자에 쓰던 `let ... in` 바인딩을 키에도 그대로 쓸 수 있음
  - 사고 모델은 “비밀값 하나, 파일 하나, 수신자 목록 하나”이며 접근 제어 방식과 잘 맞음
  - 움직이는 부품이 가장 적은 편이면서도 호스트별 키 접근 제어를 제공하므로 NixOS 머신의 비밀값 관리를 처음 묻는 사람에게 추천하기 좋은 선택지임
- 두 도구 모두 문제를 해결하며, 현재 차이는 대부분 **사용성**에 가까움
  - 처음 시작하고 여러 서비스가 관련 비밀값 묶음을 요구한다면 `sops-nix`가 더 잘 확장됨
  - 처음 시작하고 대부분 독립적인 토큰 몇 개만 있다면 `agenix`가 더 적은 절차로 목적지에 도달함
  - 첫 비밀값 도구를 고른다면 `agenix`로 흐름에 익숙해지고, “비밀값 하나당 파일 하나” 방식의 불편함을 실제로 느낄 때 `sops-nix`로 넘어가는 편이 좋음
- 양자 내성 관련 내용은 정정됨
  - `age`와 `sops`는 양자 내성 보안 암호화 키를 지원함
  - [age#578](https://github.com/FiloSottile/age/issues/578)이 닫히고 [v1.3.0](https://github.com/FiloSottile/age/releases/tag/v1.3.0)이 릴리스됨
  - `age` 키를 만들 때 `-pq`를 포함하면 되며, 예시는 `age-keygen -pq -o key.txt`임

## Comments



### Comment 57125

- Author: neo
- Created: 2026-05-10T02:02:23+09:00
- Points: 1

###### [Lobste.rs 의견들](https://lobste.rs/s/w2nz01/nixos_secrets) 
- sops-nix와 agenix가 복호화된 비밀값을 디스크에 저장하지 않는다는 설명은 봤지만, 실제로 어떤 이점이 있는지 궁금함  
  암호화된 비밀값과 그 키가 둘 다 디스크에 있는 것 아닌가? 아니면 둘 중 하나가 **TPM** 같은 곳에 저장되는 건가?  
  Nix를 막 쓰기 시작했고, 작은 셀프호스팅 배포에서는 단순해서 `scp`로 파일시스템에 넣는 방식을 쓰고 있음  
  조금 찾아보니 SSH 개인키를 TPM으로 보호할 수 있는 듯하고, VM에서도 가능한지 궁금했는데 **vTPM** 지원이 있을 수 있다니 스스로 답을 찾은 셈임
  - 내 서버에서는 sops-nix를 쓰는데, 내 **위협 모델**에는 충분하고 잘 동작한다고 봄. 이제 SSH 개인키를 TPM에 저장하는 방식이 궁금해짐  
    서버 쪽에는 NixOps 접근도 있음. Colmena가 하는 방식을 보면 됨: https://colmena.cli.rs/0.4/features/keys.html  
    핵심은 비밀값을 가진 신뢰된 머신이 원격 서버로 밀어 넣는 구조임. 지금 `scp`로 하는 것과 비슷하지만, 그 과정을 더 Nix답게 구동함
  - 좋아하는 표현을 꺼낼 때가 됐네. “상황에 따라 다름!” 여기서 비밀값 관리는 두 문제를 동시에 다룸: 디스크 위의 비밀 파일을 보호하는 것, 그리고 시스템을 빌드하는 데 쓰는 설정 안의 비밀값을 보호하는 것. 결국 그 값들은 **어딘가에는 있어야** 하기 때문임  
    최근 며칠 밤을 들여 내 시스템 flake에 agenix 계열을 다시 세팅했기 때문에, agenix에 대해서만 말할 수 있음. 관심 있는 사람에게는 [agenix-rekey](https://github.com/oddlama/agenix-rekey#agerekeymasteridentities)를 골랐는데, 비밀값이 들어간 `.yml` 파일을 둘 필요가 없고 이미 해둔 것처럼 비밀값을 전부 Nix 안에서 설정할 수 있기 때문임  
    암호화된 비밀값은 Nix store에 있고, Nix store의 다른 것들처럼 전역 읽기 가능함. 그 비밀값을 푸는 SSH 개인키는 보통 실제 SSH 서버의 개인키이고, 선택적으로 [그렇지 않게](https://github.com/oddlama/agenix-rekey#agerekeyhostpubkey) 할 수도 있음. 비밀값은 활성화 시점, 대략 부팅 시점에 복호화되어 `/run/agenix/&lt;user&gt;`에 놓임  
    [secrix](https://github.com/platonic-systems/secrix)라는 도구는 더 나아가 비밀값을 systemd 서비스에 묶고, 그 서비스를 비밀값이 필요한 서비스에 다시 묶음. 그래서 해당 서비스가 실행 중일 때만 비밀값이 복호화됨. 다만 실제로는 NixOS 사용자가 서비스를 자주 켰다 끄는 일이 드물어서 대부분 계속 실행 중이라는 뜻이 되기 쉽다. 사용자 생성 같은 시스템 활성화용 비밀값에는 맞을 수 있음  
    agenix-rekey는 재키잉을 덜 귀찮게 만들고, `secrets.nix` 대신 flake 출력으로 대체해 줌. 키의 한쪽 절반으로 **YubiKey 분할 ID**를 쓴다. 재키잉은 그 키와 다른 절반으로 인증해서 비밀값을 복호화한 뒤, 서버의 SSH 공개키로 다시 키를 거는 과정임. 공개키는 시스템 설치 시점에 생성되며, 나는 [nixos-anywhere](https://github.com/nix-community/nixos-anywhere/blob/main/docs/quickstart.md)에 `--copy-host-keys`를 써서 설치 클로저에서 생성된 키를 가져옴. 암호화된 비밀값은 저장소 안에 두지만, 신뢰된 빌더만 접근 가능한 별도 서브모듈에 둠  
    참고로 [vTPM](https://trustedcomputinggroup.org/about/what-is-a-virtual-trusted-platform-module-vtpm/)은 대개 하드웨어 기반이 아니고, 많은 제공자는 TPM을 제공하더라도 대부분 TPM v2가 아니라 TPM v1.2만 제공함. 내 제공자인 BinaryLane도 그렇다. 보안 계층이 하나 더 생기는 건 맞지만, 실제 TPM 같은 마법의 **HSM**은 아니며 제공자나 호스트 노드 침해로부터 보호해 주지는 못함. 실제 HSM 기반 vTPM을 허용하려면 제공자 입장에서는 비용이 매우 클 것 같고, AWS는 AWS 가격으로 제공하는 듯함
  - 나는 `agenix` + `agenix-rekey` + `age-plugin-1p`를 씀  
    마스터 키는 **1Password** 안에 있어서, 노트북 디스크에 어떤 자격 증명도 두지 않고도 어느 서버의 비밀번호든 편집, 조회, 재키잉할 수 있음  
    실행 중 키 접근이 필요한 서버에는 접근권을 줄 수 있음. agenix-rekey에 해당 서버가 어떤 키를 볼 수 있는지 알려주고 `agenix rekey`를 실행하면, 그 서버가 복호화할 수 있는 암호화된 키 버전이 Nix store에 기록됨. 해당 서버의 SSH 개인키는 그 서버에만 있고 절대 밖으로 나가지 않음. agenix-rekey는 재키잉에 공개키만 필요함  
    따라서 비밀값이 털리는 경우는 내 1Password 계정이 해킹되거나, 그 비밀값을 쓰는 서버가 해킹되는 경우임
  - Agenix에서는 기본적으로 암호화된 비밀값을 `/etc/ssh/ssh_host_ed25519_key`로 복호화한 뒤, `/run/agenix.d`에 마운트된 **ramfs**에 넣음  
    그래서 맞음. 암호화된 내용, 암호화 키, 복호화된 내용이 모두 파일시스템에서 접근 가능함
  - 이렇게 하면 전체 **NixOS 설정**을 공개로 공유할 수도 있음. 그렇게 하는 사람은 많지 않지만, Nix의 약속 중 절반은 다른 사람도 내 시스템 문제를 같이 디버깅할 수 있다는 데 있다고 느낌
- agenix와 agenix-rekey를 써보려고 생각만 하고 있었음. 많은 사람이 말하는 고통 지점을 꽤 줄여줄 것 같은데 아직 해보진 못함  
  https://github.com/oddlama/agenix-rekey
- agenix로 자격 증명을 관리하다가 그냥 파일시스템에 두는 방식으로 옮겼음. 더 단순하고, 재설치도 내게는 드문 일이기 때문임  
  게다가 오래 유지되는 자격 증명도 점점 줄고 있음. **장기 자격 증명 복사**에서 벗어나 하드웨어 기반 자격 증명으로 가고 있고, 그것을 직접 쓰거나 짧게 유지되는 자격 증명으로 교환하는 방향으로 옮겨가는 중임
