Mozilla sops (Secrets OPerationS) je kontejner a editor šifrovaných souborů, který podporuje formáty YAML, JSON, ENV, INI a BINARY a šifruje pomocí AWS KMS, GCP KMS, Azure Key Vault, PGP a nedávno popisovaného age.
Co se dozvíte v článku
Podobných nástrojů existuje více, sops se inspiroval nástrojem credstash
a passwordstore
. Samotný SOPS je napsaný v Go a je distribuován jako statická binárka, takže běží skoro všude. Zároveň umí pracovat se různými nástroji pro šifrování, takže je velmi vhodný pro slepování různých nástrojů, které se spoluprací původně nepočítaly.
Instalace probíhá pomocí stažení binárky a přidání do PATH
, případně pomocí binenv.
$ binenv install sops
Vytvoření šifrovaného kontejneru
Pro účely tohoto příkladu si vytvoříme soubor secrets.yaml
a do něho si vložime nějaké citlivé informace:
routerAccess: username: admin password: nbusr124
Před zašifrováním souboru je dobrý nápad ujasnit si, kdo ho bude moci rozšifrovat. V našem případě to budou dva vývojáři s GPG klíči a interní nástroj pro deployment, který používá nástroj age.
Použijeme parametr --encrypt
( -e
), a zadáme identity, které mohou zašifrovaný soubor rozšifrovat. Pro různé druhy identit (GPG, age, …) nabízí sops
různé přepínače.
$ sops --encrypt \ --age age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw \ --pgp 4DEDE685FFA0FC4976B3EF37F7E33058D6AB767D,CE8981E4BBCBB6EC0 --output secrets.enc.yaml \ secrets.yaml
Pak sops
uloží soubor s šifrovaným kontejnerem secrets.enc.yaml
.
Kromě GPG a age
je možné použít i další nástroje pro správu klíčů, nejčastěji používáme třeba AWS KMS, které umožňuje poměrně pěkně řídit přístup ke klíči pomocí rolí IAM. Stačí zadat --kms
a klíče ARN KMS.
Naopak, pokud nechceme zadávat parametry na příkazové řádce, můžeme použít proměnné prostředí – laskavého čtenáře zde odkážu na README. Proměnné prostředí s oblibou používáme například v CI/CD pipelinách.
$ export SOPS_AGE_RECIPIENTS=age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw $ export SOPS_PGP_FP=4DEDE685FFA0FC4976B3EF37F7E33058D6AB767D,CE8981E4BBCBB6EC08A2246BCBFB9F30F3F82399 $ sops --encrypt secrets.yaml > secrets.enc.yaml
Pokud rozebereme zašifrovaný soubor (kontejner) secrets.enc.yaml
, zjistíme, že obsahuje otevřené původní klíče YAML, a zašifrované jsou pouze jejich hodnoty.
Kromě toho si sops do souboru YAML přidá nový klíč sops:
, který obsahuje nový klíč AES (v dokumentaci nazývaný jako data encryption key), který je zašifrovaný pomocí veřejných klíčů, které jsme zadali při šifrování.
Výhodou je, že zašifrovaný kontejner dokážeme vložit do gitovského repozitáře. Pokud ho případný útočník získá bez přístupu ke klíčům, neměl by být schopen kontejner rozšifrovat.
routerAccess: username: ENC[AES256_GCM,data:VvjNI8A=,iv:PxSN8MDBPY ... password: ENC[AES256_GCM,data:cuGAxjkXGRY=,iv:VK+ZYre ... sops: age: - recipient: age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfa ... enc: | -----BEGIN AGE ENCRYPTED FILE----- YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaMXUrd0RCVU9sZDg0SXhH bUdoZUwzYkU3NUpDc28xQklFMHhNeUtCZzFZClEwaUxZYWJkRkcxZHd1aDU4UTdB ... pgp: - created_at: "2022-12-20T21:05:50Z" enc: | -----BEGIN PGP MESSAGE----- hQIMA/fjMFjWq3Z9AQ/+Nsz9DnIXnrFOF4yywthtd+OWPVmRa1NxR1B7+0MsO6TA xMF0U0/Kc9iNbwvNSh4zNpJ/XDrwzr1BVR+eKhIkJRdH3AZ8y3sjagYeB/Z8YNG9 ...
Je zřejmé, že předchozí příklad očekával, že v lokálním úložišti GPG máme dostupné veřejné klíče adresátů.
Editace souboru
Pokud budeme chtít obsah šifrovaného kontejneru zobrazit, můžeme použít:
$ sops secrets.enc.yaml
sops
zjistí, které soukromé klíče má k dispozici, vhodný klíč použije pro rozšifrování, otevře editor a v něm otevře dočasnou rozšifrovanou verzi souboru. Po zavření editoru se soubor zase zašifruje, uloží a dočasná kopie se zahodí.
Pro rozšifrování nám stačí použít sops
s přepínačem --decrypt
( -d
), při dešifrování se zahodí metadata uložená pod klíčem sops:
.
$ sops -d secrets.enc.yaml routerAccess: username: admin password: nbusr124
Další formáty
Kromě YAML umí sops
pracovat i se soubory ve formátu JSON, INI a dotenv, typ souboru se snaží rozpoznat podle přípony. Pokud neuhodne, můžeme mu napovědět přepínačem --input-type
( -i
) a --output-type
( -o
). Do obou typů souborů si sops
vkládá metadata potřebná pro dešifrování pod klíč sops
.
Elegantní použití sops
u a souborů ve formátu dotenv je pro správu proměnných prostředí. Pokud mám k dispozici například soubor s údaji pro AWS (config.ini
), mohu si ho zašifrovat.
# config.ini AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
API klíče zašifrujeme a dotenv si necháme uložit ve formátu JSON.
$ sops --encrypt \ --input-type dotenv --output-type json \ --output config.enc.json \ config.ini
Výsledkem bude opět validní JSON, do kterého si sops
přidal vlastní klíče s metadaty potřebnými pro dešifrování.
sops
potom umí rozšifrovat kontejner, uložit klíče ho do proměnných prostředí a spustit program, který proměnné prostředí použije.
$ sops exec-env config.enc.json 'aws sts get-caller-identity'
Pokud potřebujeme poslat obsah původního souboru do nějakého programu, můžeme použít volání sops exec-file
. sops
potom vytvoří pojmenovanou rouru (FIFO), do které na požádání pošle obsah souboru.
$ sops exec-file --no-fifo config.enc.json 'cat {}'
Výchozí nastavení klíčů
Pokud nechceme při vytváření šifrovaného kontejneru pokaždé zadávat klíče, můžeme si pravidla pro používání klíčů uložit do souboru ~/.sops.yaml
.
# use one age key and these PGP ones creation_rules: - path_regex: '(\.yml|\.yaml)$' age: age1yt3tfqlfrwdwx0z0ynwplcr6qxcxfaqycuprpmy89nr83ltx74tqdpszlw pgp: >- 4DEDE685FFA0FC4976B3EF37F7E33058D6AB767D, CE8981E4BBCBB6EC08A2246BCBFB9F30F3F82399
Při vytváření nového šifrovaného kontejneru zkusí sops
najít soubor .sops.yaml
v aktuálním adresáři a v případě úspěchu použije pravidla z něj. Pokud ho nenajde, zkusí se podívat do nadřízeného adresáře.
Doporučená praktika je tedy uložit .sops.yaml
s popisem pravidel do kořene gitovského adresáře s projektem.
Pokud potřebujeme upravit šifrovací klíče podle aktuálních pravidel, můžeme použít příkaz updatekeys
.
$ sops updatekeys secrets.enc.yaml
Nástroj sops
porovná původní a požadované klíče použité pro šifrování kontejneru, porovná je, zobrazí změny a zeptá se, jestli to myslíme upřímně. Po potvrzení se změny v klíčích aplikují do kontejneru.
Použití mimo CLI
Existuje Terraform provider pro SOPS, který umožňuje šifrovat a dešifrovat soubory přímo z Terraformu. Stačí mít k dispozici ty správné poloviny klíčů, které byly použity při šifrování.
Terraform provider sops přidává Terraform Data Source sops_file
a sops-external
, které umí otevřít kontejner SOPS.
data "sops_file" "production" { source_file = "secrets/production.yml" }
Výsledek Data Source pak můžeme použít ve zbytku modulu.
output "release_password" { value = data.sops_file.production.data["release_password"] }
Použití v Kubernetes
Pro Kubernetes existuje několik wrapperů okolo sops
, které umožňují používat sops
podle zvyklostí v Kubernetes.
Jeden z nich je sops operator – očekává v API serveru uložené objekty CRD typu SopsSecret
, které obsahují právě šifrovaný kontejner. Po zapnutí pak operátor na pozadí šifrované kontejnery otevře a uloží je do Kubernetes Secrets. Při změně SopsSecret
se automaticky aktualizují i relevantní Secrets.
Mějme CRD otevřený objekt v secrets-template.yml
, který necheme uložit do gitu.
apiVersion: isindir.github.com/v1alpha2 kind: SopsSecret metadata: name: wrapped-secrets spec: secretTemplates: - name: pull-secret type: kubernetes.io/dockerconfigjson data: .dockerconfigjson: | IF9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXwo8IE5hIHRvbXRvIG3DrXN0 xJsgbcWvxb5lIGLDvXQgVmHFoWUgcmVrbGFtYSEgPgogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tCiAgICAgICAgXCAgIF5fX14KICAgICAgICAgXCAgKG9vKVxfX19fX19f CiAgICAgICAgICAgIChfXylcICAgICAgIClcL1wKICAgICAgICAgICAgICAgIHx8LS0tLXcgfAog ICAgICAgICAgICAgICAgfHwgICAgIHx8Cg== - name: aws-access-tokens type: Opaque stringData: AWS_ACCESS_KEY_ID: AKIAIOSFODNN7EXAMPLE AWS_SECRET_ACCESS_KEY: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
YAML soubor s CRD objektem pak můžeme zašifrovat:
$ sops \ --encrypt \ --encrypted-regex '^(stringData|data)$' \ --output encrypted-secrets.yml \ secret-template.yml
Dostaneme opět zašifrovaný kontejner. Protože jsme použili při spuštění sops
parametr --encrypted-regex
, zašifroval se pouze obsah pod klíči stringData
a data
.
apiVersion: isindir.github.com/v1alpha2 kind: SopsSecret metadata: name: wrapped-secrets spec: secretTemplates: - name: pull-secret type: kubernetes.io/dockerconfigjson data: .dockerconfigjson: ENC[AES256_GCM,data:Ofp6i/8N0... - name: aws-access-tokens type: Opaque stringData: AWS_ACCESS_KEY_ID: ENC[AES256_GCM,data:4U7jdT0G8M... AWS_SECRET_ACCESS_KEY: ENC[AES256_GCM,data:5Ugz4H... sops: ...
Protože do Kubernetes vkládáme validní YAML manifest, API server ho akceptuje a zbytek souboru stále vypadá jako validní manifest Kubernetes v YAML a můžeme ho vložit do API serveru.
Je potom úkolem sops-operatoru, aby vytvořil Kubernetes secrets pull-secret
a aws-access-token
. Pokud se změní Kubernetes objekt SopsSecret se zašifrovaným kontejnerem, operátor se probudí a upraví závislé secrets.
Podobnou funkcionality v Kubernetes (bez sops
) samozřejmě nabízí mnoho dalších vlastností, např sealed-secrets nebo external-secrets. Výhodou použití SOPS je možnost implementace šifrování s použitím různých druhů klíčů.
Další možnosti
Zajímavou možností je i použití příkazu sops publish
, kdy sops
umí po změně šifrovaný kontejner odložit do nějakého externího úložiště, například S3, GCP bucketu či Hashicorp Vaultu. Z externího úložiště si pak kontejner může stáhnout nějaká další část CI pipeline.
Kromě použití jednoho klíče pro šifrování je možné v rámci jednoho kontejneru použít více klíčů. Používá se pro to nastavení key_groups
a v .sops.yaml
.
Vlastností, které sops umí je mnohem více, laskavého čtenáře odkážu do dokumentace – sops
umí využít Shamir thresholds, více klíčů v jednom souboru a mnoho dalších vlastností.
Využití
sops
používáme u zákazníků nejčastěji pro šifrování tajných informací v terraformových modulech v prostředí AWS. Při zašifrování hesel s využitím klíče z KMS dokážeme poměrně pěkně řídit přístup včetně základního auditování.
Zdá se, že SOPS se stává oblíbeným nástrojem pro ukládání zašifrovaných tajemství. Kromě zmiňovaného použití v Terraformu a Kubernetes jsem narazil na podporu v Terragruntu, Ansible, Fluxu a ve spoustě dalších nástrojů.
Velikou výhodou je, že se dá použít jak při nasazení v cloudech, tak i na vlastním hardware.