diff --git a/layouts/default.html b/layouts/default.html index 4e1159a..9713da1 100644 --- a/layouts/default.html +++ b/layouts/default.html @@ -79,6 +79,23 @@ tab-size: 2; } + .doll-quote { + margin: 1rem; + margin-left: 0; + padding-left: 1rem; + width: fit-content; + } + + .doll-quote blockquote { + color: var(--bright1); + background-color: var(--dark1); + margin: 0; + border-left: 2px solid var(--middle1); + border-bottom: 1px dashed var(--middle1); + padding: 0.5rem 1.15rem; + width: fit-content; + } + .mermaid { width: fit-content; color: var(--middle1); diff --git a/log/002-soppy-wet-nix.doll b/log/002-soppy-wet-nix.doll new file mode 100644 index 0000000..4d23035 --- /dev/null +++ b/log/002-soppy-wet-nix.doll @@ -0,0 +1,381 @@ +--- +title: soppy_wet_nix log[002] +description: how it stores secrets alongside its code +--- + +&soppy wet nix (16MAY2025) ^a + + what if you read [code:/secrets/dont_leak] but it said [codeblock:: + dont_leak: ENC[AES256_GCM,data:psyelHNBMy+xglw=,iv:UhxfqAqVbCgMRMqRMA1MmvgIO18zTrVtQdFywupZyYA=,tag:Legj+njC3z8jX16n1pZszg==,type:str] + ] + + that's cool but what? + + let's face it; sometimes stuff is best left to one's own eyes. like auth tokens, passwords, private keys... + + most of the time, handling these manually once somewhere, dropping it in a file somewhere on a + remote machine or UI and that's the end of it. + + but what if you're like. the type of lazy that doing a lot of work now means not doing the work a second time? + [em:that's like this doll.] + + lets talk about our bestie [em(b):[link(https://github.com/Mic92/sops-nix):sops-nix]] + + &but first, sops. + + sops-nix is based on [link(https://github.com/getsops/sops):sops], so unfortunately we need to start there. + + [em(b):sops] is a way to automate encryption and decryption of secret data you might want tightly coupled to a use case. + + irl, one might pair this to AWS KMS or another type of distributed keystore; and that's cool. but. this isn't irl. + this is a video game, dolly. + + instead we'll focus on sops's [link(https://github.com/FiloSottile/age):age] encryption method, which is based on ed25519 SSH keys you already use (right?) + + [quote:: + it can hear those thoughts, + + [em:> aki wtf, this is 3 whole things, this one is getting overwhelmed] + ] + + yeah real + + we're going to store all of our secrets in this sort of tree, + + [codeblock:: + project + ├── secrets + │ ├── global.yaml + │ ├── machine-1 + │ │ └── secrets.yaml + │ ├── machine-2 + │ │ └── secrets.yaml + └── .sops.yaml + ] + + each machine gets a folder under secrets, and there's a global one for every machine too. + + there's also a [code:.sops.yaml] file to mention, to support our needs, we'll do... + + [codeblock:: + creation_rules: + - path_regex: secrets/[^/]+\.(yaml|json|env|ini)$ + key_groups: + - age: ??? # for doll + - age: ??? # for machine-1 + - age: ??? # for machine-2 + - path_regex: secrets/machine-1/[^/]+\.(yaml|json|env|ini)$ + key_groups: + - age: ??? # for doll + - age: ??? # for machine-1 + - path_regex: secrets/machine-2/[^/]+\.(yaml|json|env|ini)$ + key_groups: + - age: ??? # for doll + - age: ??? # for machine-2 + ] + + [em:wait. age. that ag-] - shh. be Still. + + &hold on ,... + + dolly,,, listen. yaml is. [em(b):[em:v]e[em:r]y [em:f]u[em:n]]. and so lets make it fun. + + [codeblock:: + keys: &all + - &op_doll ??? + - &m_machine-1 ??? + - &m_machine-2 ??? + + creation_rules: + - path_regex: secrets/[^/]+\.(yaml|json|env|ini)$ + key_groups: + - age: *all + - path_regex: secrets/machine-1/[^/]+\.(yaml|json|env|ini)$ + key_groups: + - age: *op_doll + - age: *m_machine-1 + - path_regex: secrets/machine-2/[^/]+\.(yaml|json|env|ini)$ + key_groups: + - age: *op_doll + - age: *m_machine-2 + ] + + now this isn't a sops thing, this is a yaml thing. yaml has anchors...... + + sops doesn't know what that [code:keys] key is, it gracefully ignores stuff it doesn't care about, so we can exploit this!!! + + this solves three huge problems with sops + age + + - which key is machine [code:age1lq5q5g5qjsdcc3k] anyway? - we solve this by naming every key + - the "global" group should always be every key... so we have that too + - a secret third problem + + ok. back to whatever we had before + + &how old is one's encryption + + age answers that question by letting you use ed25519 keys to encrypt and decrypt your data. + + [quote:ed25519 would be a good name for a doll... ^n] + + since we're deploying to machines with presumably an SSH server running, and presumably + the doll also has an SSH client, all of these ends have SSH keys we can use + + &lets start with the doll end, + + [codeblock:: + $> ssh-to-age -i ~/.ssh/id_ed25519.pub + + #|> age13c5wv623jxjja5mjz7fajg9qqwvypzgsfqrs4tmk7rpgyzu7aufs4ul9f9 + ] + + wow that's a string! yay! + + we'll plop that in our keys section. + + [codeblock:: + keys: &all + - &op_doll age13c5wv623jxjja5mjz7fajg9qqwvypzgsfqrs4tmk7rpgyzu7aufs4ul9f9 + - &m_machine-1 ??? + - &m_machine-2 ??? + ] + + sops will automatically use the [code:~/.ssh/id_ed25519] file, we're good to go!!! + + &the machines,, + + so SSH servers also have host keys, so when sops is ran on a specific host, it + can also decrypt like the doll can. + + we'll fetch machine-1's ssh public keys and slap those in too. + + [codeblock:: + $> ssh-keyscan -qt ed25519 machine-1.local | ssh-to-age + + #=> machine-1 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOGae8gFqSsfezM/ul7LnCmv9GAk6AIah18+tc212LQW + #=> age1jc6ghxfgxe3gx53xa55azxan447cfxaqfqeh5y5yzqapj7mw7ajql8kv02 + ] + + and yeet into the keys block, and machine-2's too. + + [codeblock:: + keys: &all + - &op_doll age13c5wv623jxjja5mjz7fajg9qqwvypzgsfqrs4tmk7rpgyzu7aufs4ul9f9 + - &m_machine-1 age1jc6ghxfgxe3gx53xa55azxan447cfxaqfqeh5y5yzqapj7mw7ajql8kv02 + - &m_machine-2 age1438lvn7gh4he0rnj0xnvnx56l97mpz0vsv3wktj8utk65kqs8ycqftcxze + ] + + &so.. lets sops!!!!!!!!! + + we did all the hard parts. lets do the secret parts. + + [codeblock:: + $> sops secrets/global.yaml + + # secret, set EDITOR to something.. + # like `EDITOR="code -w"` will open a vscode tab.... (close tab to save) + ] + + this usually shows a nice default yaml file, yeet all that into the garbage. + + we wanna store something useful like... an authentication token to a certain doll's + multicelluar digital cortex. + + [codeblock:: + doll_token: awawawa + ] + + lets save that file, and go inspect it. + + [codeblock:: + doll_token: ENC[AES256_GCM,data:DryFfMa/dQ==,iv:IdqvGEKKTSOaATlqMqyHQ3PEAwC6mJqjHbO3KwfTlHc=,tag:5ByySoYZu6qZexHBmnQBKA==,type:str] + sops: + age: + - recipient: age13c5wv623jxjja5mjz7fajg9qqwvypzgsfqrs4tmk7rpgyzu7aufs4ul9f9 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvdTBVb0FvM2xocWFVclJt + L05aRmpKOHh6d3hXcE9Vem9SL1hrSjFMRng4CmNrTmROTFVMRlc4QjllWVo1S3lv + MXo5UVFuazVoeWQ5TEE1NXJIUzl0K1EKLS0tICtrSTdoWHIrSlJLRTUweWpoVWlY + ZTNXNUM1ZEpsQlMzRlNoZHpkU2lhVzAKpYJAfihRyG/ok0tgJg4FjnN8vj6Bz/+z + 0Y/P21JJp/SnXq4LjivBCT4XJ0s6XoffUEqw/uxLzsY1wwox003pOA== + -----END AGE ENCRYPTED FILE----- + - recipient: age1jc6ghxfgxe3gx53xa55azxan447cfxaqfqeh5y5yzqapj7mw7ajql8kv02 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGWVUrWmIvOXUzYmJyWm9G + dmhNQ0lUNFh5ZTdXMmMxNWJENXlMU1daN3lzCnh5cmQyMFlSWDBQV1VSOCtoTUcv + anpmWVFVUmpmZ2svUFpFMUI0YUlwclkKLS0tIFc5NDRQWTdseXdyUE5BbXUwSFk4 + VXptdjk3cHFEV0twaXhSYzY2R0JrUzQK5RNS2XdR1m7/SGfpNFh5Z9Q2YGsJT1Cw + iJyW+7EseiuWEkFa2JFul6nsP8W1TmDobk2VXiYpc/BTm78hBlUhyg== + -----END AGE ENCRYPTED FILE----- + - recipient: age1438lvn7gh4he0rnj0xnvnx56l97mpz0vsv3wktj8utk65kqs8ycqftcxze + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtOUtYUXhOTzJlS2lHUTFz + TGwyQ2Y2aEZWWnNmWjVqWWtXeHdmQlFPTFFzCnNSU2FDVFdsTC9hWWV4NEtNQ1FF + bDRvOXJiR3hRb1Ryc0VuTkExQkxoMHMKLS0tIE1ETGJZc04yOHJkaTkwaTlyZW1j + N1pacGpGZGtnNWdFSjZxbjVuVlRZVzAKjDaMO/oKlq4D1QHTlD9lBY+0w81/gybv + 2+BSo93LG+bN+cNI9jYc9FU+t4GdlyhEcKQ4MTczgZyMaMOYkhgKcg== + -----END AGE ENCRYPTED FILE----- + ] + + sops completely obfuscates this file. + + this is now safe to send into git. or even over the internet. + or even a website like this one. haha. + + really, it is. these are real keys, and good encryption, and hopefully only intended targets can decrypt them. + the reader can even send this doll encrypted messages with that op_doll age key, if one wanted. + + what's happening is each "recipient" is getting an individual copy of the file encrypted with + the recipient's public key. + + the only way to get the data back out is to have one of these machine's private keys. + + &further sopping + + we can do [code: sops secrets/machine-1/secrets.yaml] and set up machine-specific secrets too. + + those won't be able to be decrypted by machine-2, nor vice versa, due to how we + set up [code:.sops.yaml] earlier. + + also, if one happens to rotate SSH keys or. delete/remake a server or somethin', + we can ask sops to redo its work with + + [codeblock:: + $> sops updatekeys -y secrets/global.yaml + ] + + [quote(protip):: + put in a op_doll_2 as a new key in all the same spots, then run the command above + + finally, remove the old key, and run the above command again. + + get rotated ! + ] + + &nix sauce + + 260 or so lines in and we haven't even talked about nix yet. + + sops-nix lets us use sops. from nix. incredible. + + we use flakes, so we add [code:github:Mic92/sops-nix] as an input, and work it into our machines. + + [codeblock:: + { inputs, ... }: { + imports = [ + inputs.sops-nix.nixosModules.sops + ]; + + # lets us shorthand for global secrets + sops.defaultSopsFile = ../path/to/../secrets/global.yaml; + + # allows sops-nix to decrypt using machine keys + sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; + } + ] + + now say we wanna use that token... there's a few different ways. + + &reference as a file directly + + nix is. weird. strings aren't strings. strings are files. and files are strings. and files are files. and secrets are files... + + for example, if we want to set up an openvpn client, doll's provider would give an .ovpn file. toss that in sops as a + yaml value (or json or whatever it guess)!! make it sopping. instantly. + + our [code:secrets/machine-1/secrets.yaml]: + [codeblock:: + ovpn_file: | + client + dev tun + proto udp + remote 41.66.66.66 41666 + #... + ] + + our [code:modules/openvpn.nix]: + [codeblock:: + { config, ... }: { + # the "ovpn_file" here matches the YAML key above. + sops.secrets.ovpn_file = { + sopsFile = ../machine-1/secrets.yaml + }; + + services.openvpn.servers.doll = { + config = '' + config ${config.sops.secrets.ovpn_file.path} + ''; + } + } + ] + + &templates! + + but wait haha there's usually like a login username and password right? + + good catch, lets add those to our [code:secrets/machine-1/secrets.yaml]: + [codeblock:: + ovpn_username: doll + ovpn_password: witchesRme4n + ovpn_file: | + #... + ] + + and lets make a template! + [codeblock:: + { config, ... }: { + sops.secrets.ovpn_file = { + sopsFile = ../machine-1/secrets.yaml + }; + + # our two new friends + sops.secrets.ovpn_username = { + sopsFile = ../machine-1/secrets.yaml + }; + sops.secrets.ovpn_password = { + sopsFile = ../machine-1/secrets.yaml + }; + + # this is just how openvpn likes it. no typos. + sops.templates.ovpn_credentials = { + content = '' + ${config.sops.placeholder.ovpn_username} + ${config.sops.placeholder.ovpn_password} + ''; + }; + + services.openvpn.servers.doll = { + config = '' + config ${config.sops.secrets.ovpn_file.path} + + auth-user-pass ${config.sops.templates.ovpn_credentials.path} + ''; + } + } + ] + + wow. it can do everything. + + doll might notice the "consumer" side of sops-nix uses [code:config] a lot. yep. its a little self-referential. + + &secrets........ but what about automation + + that silly [code:.sops.yaml] thing huh, c: + + why did we tag the age keys with [code:op_] and [code:m_]? so we can find them. in a script. + + and then generate the yaml so when one adds a new machine its like one command. :> + + we did this with some simple JS script + [link(https://git.sapphic.engineer/noe/nixos/src/branch/main/tools/onboard-machine.js):doll could reference.] + (it runs via bun so no node_modules!!!) + + this allows us to run a little [code:onboard-machine.js 41.66.66.66 machine-1] and pull the right + key from a remote machine + + &is doll soppy yet + + sure hope so. \ No newline at end of file diff --git a/plugins/logroll.sh b/plugins/logroll.sh index eff63e2..e3d2c30 100755 --- a/plugins/logroll.sh +++ b/plugins/logroll.sh @@ -4,7 +4,8 @@ cd log echo "