From 519eb3a3bbdb3587a1e0a9c2c98cbb5c0750faec Mon Sep 17 00:00:00 2001 From: Simon Gardling Date: Mon, 30 Mar 2026 19:34:56 -0400 Subject: [PATCH] fix: re-encrypt age secrets with SSH pubkey recipient (-R not -r) X25519 stanzas from ssh-to-age are incompatible with raw SSH identity. Use age -R with SSH public key directly to produce ssh-ed25519 stanzas. Updated AGENTS.md to document the correct process and warn against ssh-to-age. --- AGENTS.md | 6 +++++- secrets/ci-deploy-key.age | Bin 633 -> 645 bytes secrets/coturn-auth-secret.age | Bin 286 -> 298 bytes secrets/git-crypt-key-dotfiles.age | Bin 370 -> 382 bytes secrets/gitea-runner-token.age | Bin 269 -> 281 bytes secrets/matrix-reg-token.age | Bin 286 -> 298 bytes secrets/murmur-password-env.age | Bin 255 -> 267 bytes 7 files changed, 5 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index e109cf4..356feab 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -99,7 +99,11 @@ Each service file in `services/` follows this structure: - **git-crypt**: `secrets/` directory and `usb-secrets/usb-secrets-key*` are encrypted (see `.gitattributes`) - **agenix**: secrets declared in `modules/age-secrets.nix`, decrypted at runtime to `/run/agenix/` - **Identity**: USB drive at `/mnt/usb-secrets/usb-secrets-key` -- **Encrypting new secrets**: The agenix encryption key is in `usb-secrets/usb-secrets-key` (SSH private key, git-crypt encrypted). To create a new secret: derive the age public key with `ssh-keygen -y -f usb-secrets/usb-secrets-key | ssh-to-age`, then encrypt with `age -r -o secrets/.age`. +- **Encrypting new secrets**: The agenix identity is an SSH private key at `usb-secrets/usb-secrets-key` (git-crypt encrypted). To encrypt a new secret, use the SSH public key directly with `age -R`: + ```bash + age -R <(ssh-keygen -y -f usb-secrets/usb-secrets-key) -o secrets/.age /path/to/plaintext + ``` +- **DO NOT use `ssh-to-age`**. Using `ssh-to-age` to derive a native age public key and then encrypting with `age -r age1...` produces `X25519` recipient stanzas. The SSH private key identity on the server can only decrypt `ssh-ed25519` stanzas. This mismatch causes `age: error: no identity matched any of the recipients` at deploy time. Always use `age -R` with the SSH public key directly. - Never read or commit plaintext secrets. Never log secret values. ### Important Patterns diff --git a/secrets/ci-deploy-key.age b/secrets/ci-deploy-key.age index da1e327136fcefdef7b976b52a5a8676802beb72..5c52818c617b7e9d4db8ea218df564fab4531ed9 100644 GIT binary patch literal 645 zcmZQ@_Y83kiVO&0SoD@xlIixJB(WBTN%!x*U!QL`yY*cE^<8;w$GEiSd%yal)+M|4 zfc}cz%?}Kb#jy$}~Jz?V2MW4T&xa*Ow&0w!nQ!!J1ZQmt} z*8KawJg3H4l&$bKe!RfyXZNSTHjC28;a9`Aj& z`Pn1aws+5%CjT{mqHOZ=;#turytUeq)ieKYobf?l+Osi~f=`;#`eC3 z=LLJGFa#|~>HPj|zj9joJXfWJ_*a}I?E;#Y*r$ZtQIlTVqd2!9Qe3vaQ~1B%leDN` zrCuMxxmx%()ozwP#JK70OcC$P8uE!Mo!%|#p~5xsyN-X3xGQpiGkRXq1)C20!DIbII4gEc-M$R<1)=lsRrif2GgNtQ+cn3oB|Tg=!XUXi{IR{eso8UwG@{GdGyj zROi%r8Q68rnYlsxbl0N0X@8sNo_!c!u=j`NdHn1}l|B2NC!9I)<8%k&3V!0HbR(>rQ@7?<8#&QOzhvsC-CKM(XT;un9k-#{){jN^?7v34 z?Vrx_OqrxJ(Rh|mpSqmTH2#H5DJKqG3Y`|I{Xt7_#>IHm`-1gB)^%b(vahdjel=4# zYxaKm!#AXFn-xbbs$cv}h4IvdS%!uzg6=m9zfRp;{U?8eSY_GOBKtz?LnfR@&%c>j z^+tQ&x@*?L4+Tp3G8UGfz1@~SH9;@l`+i%=C!TAIS1ftLJblsKcdxyF=1h6%#pwIV zYSy-C9N(I!JZcT$eUbU^k>Hi3CQ~y*CoS16?6voeiT>4Jcc(C=tzcZ0?V2hgbM*T< zhX?=bte;8O<-Ya5@pp>ftujUxc;0LSfbr%r6mG;UTD zyQaNev)Va-N7dHMjn!#6s(13r|A21sSJUclroVf~D!(N+_fsn04W1<{D&L58 z&P!4HzV1U<`uz)=n%a)_9%^FxQl>aPs80UP0t=m`-#P#0c9n7@yX6T@&8PqXJ}x_c diff --git a/secrets/coturn-auth-secret.age b/secrets/coturn-auth-secret.age index d70dd043f1b21fae969159e7c60a47b7318b0147..6c2046b4730b78423a74f873385378b8eb62468e 100644 GIT binary patch literal 298 zcmZQ@_Y83kiVO&0SWx|3TK>9wOV|BRr~NkrLaP%$}W&JK(0K{Xg63#N6N? LSvAL&?QQ@7(z>7@ literal 286 zcmZQ@_Y83kiVO&0xI5oQ>6z@D`1@>GiFcX!ZydSasrTyW@(w9P4xV32Sk5O`Fa&-N&Ptzb|54@3jR|4%m0528Wt=C+<{*&PxO)~xM$f6ePw|KvA;dB-#i`&+bsB@T^1+bAM|}Cq zBR{>lXsG)CW^2EK!ZwZ$I|e;xy_1t~SbvfF^`qM5mz+W370)J*8nbZc{F;3%c8*(e vXIaXpU#j8xeem>whqsHCT}jPe%-#5z>EH>e8Rb&zJ#u0iqoRKEo!SckVpEI2 diff --git a/secrets/git-crypt-key-dotfiles.age b/secrets/git-crypt-key-dotfiles.age index 1483fad1f44e3c4a6a9569f6c3bb2e17868b22e4..2547cfef9cc9272125eaf30aec31cc91d087e8b5 100644 GIT binary patch literal 382 zcmZQ@_Y83kiVO&0$jy7;bwawToG~x%+zRcKj!(DVXRp8h@`$X^73JNRzI1CGY!z+1 z%CSVAUraK5{qfMS$ha@;UQ90wfykgIbyl4g}WTKN%QhwPfY21V5aJqF>}*;jZI<~v+}j#cR#3o z`}fr`)2sZcaTCIQ56&%#`)$opRq?`>B64 z_|}}>AGyT~Z7#V*TuRySzJFT!lH&O_EYtVtyg#@2n_Q9h(zA+1%psj3rLUG3pO_FD zbz`|iu&Go<)O_v`^Y}|M=Nwn!2s|FD>K-Xsv&ZOo@d>l<4T`t6rJ2dE;nmLk@58QG zw{BfRd(f`q9xaMmJ3TU^DnCkcfAbWM74HAwE3$udG&G6vb6ISOTMNyWZ&m2-uW%=zIhY?@>sPx literal 370 zcmZQ@_Y83kiVO&0_}Y^$$@pN;+nhxrw{jm|n33LaY(t{Bw~vp}w;5}uvV7%G{Dy6+{kyqL|h-}K`Xzl(b(9JiRiAdk_`5{LRYi6mNnhG3Rw_LNeseIR-&pzqAQGJ`P z-F~-Wu5J3g>DE-!%7fEXKfctN)9QS6zxM6`+oDNkA8x$gZSpqoS%16ZyN7(+;~ps5 g@-$?5if*`kQ6lQLQ-O~6R*x!g*Gge+)?<6J0q%#mtN;K2 diff --git a/secrets/gitea-runner-token.age b/secrets/gitea-runner-token.age index 8f687a8a5cdb7bf7a6195fc6dea78a2f21ef4e13..3c9d38e7dfcf8e5b1dcb04b3317009232c069219 100644 GIT binary patch literal 281 zcmZQ@_Y83kiVO&0Sn~L=Q=W;bpY@W^K!elUwB^kDJ~5`&8!87VeOk5SVD^niaScCM zpWSXdTWV+}w9fkDY~OYI-!d((H8Z|yiQylQ@)@tjRxpLd+DZ1a+ToMPJ@{b;A| z{%R)M5^{ZzX1-mx#6FZb$i@Jxul^5ECYQ?IvPI)6v> z*;MbnQ3r(TGC24AH(EWr*g?ETD=l3|eQKVR#W&ZJiLY~ZFWvV;{v+d2eSw>Y9XT!) zH#;m0Em#)&RqSc;r{g!KY!H+c3XGSE-;lGoU1UmUu;HqsJD)4A`(5F>r)$m9ocX1D qg3MkB9@RT(8}eTJelyqNV$c74B2p%wKb>TF@5pv%)g7zPXKVo10E;C6 literal 269 zcmZQ@_Y83kiVO&02+h=rK6P#0)2^`HAJ6AS&e+uz6=byOUhneV<=#Gvo~Hk6W6{4P zar}v^dEuKS*HpdMEjH7VG1>F|;F*;FUMGUC*py9eD=A%hAc|XU)pVxo2JSXfPk+xa zJ@w_ag6_fdeh$aC*z~5Jbj*HUasElp(ImsOHTCmuzk0mgB|YikOWW)@2dAYm8E;$s zzklJDH&aelC&@mQH;_wylDjee;5p8eUG3ff6B}8Zl<&zF9=fsni24_%-4Dx_RqvMy z7r5Lh#-e?BnY5wdtDST5xKqQ~XIb>mK3~e*cG*E;mVDKmjAhF|3go?z+pG8~@}9W0 f^(47amG4@c{=V?Pyza!@ZOZ3%@OHglvUmaj)L@9! diff --git a/secrets/matrix-reg-token.age b/secrets/matrix-reg-token.age index e5a73988daae62b7a2bd5084d60fc6cdf5270f5a..e2e74054faceb1fb33af1d2abfcea53d10e4cec4 100644 GIT binary patch literal 298 zcmZQ@_Y83kiVO&0xM#1;yrr(>+T*fxeMyI=UpefHI1Sx8m}3`z(1|RYl(0|S>*dCj zf3_2(`T3`-?&p5d(`FJhWpm7k01ENw%|dr*$%<4hA;W6 zK69|_VA9}v&%ZPM`>)d%rN5?Bq|{!2mdO@YAwN0e+{*Qg)BRfK@EI&xZ@$mB($i$F zLC9>0{5{qkeCODAP5F91i8DY)ar>=#HSd34nJjieKlVR^^0ke++x;%wmFf5{b9UyY z1jBQwjsab#XP$K3yL-*-3C=7+@-Y`1JJ$9b6BU+ldY9_JuxDAJqpIU?m#~x8Hcg+i It~y)-0Mt#1@&Et; literal 286 zcmZQ@_Y83kiVO&0U@FKK*HmKKwCUX6>dfg&*?OjPdAiP!J(l?EoL%CBy^k5T2mIGO z5qaZY?8ElQA??eX@6EY=WAE<^$9nVM)wxw%J%8-Rk$LYAH)7SK*Z?fBRPyJG}N8{qd6Z`ay zTUCl@PCaXN`o%^0$BUbjFV~!RsSRO1@kDLM{Jl$#+`4muZ-aPQ`pKSSRyBvFuJf49 xT`BNNKU{l4cCy#0slK)x%X?3A*y&j%P;8W>@ZvwUFV=LQzvqR-W%3G>GZetO?aNp;F?sPi|(G4Y>sSZ5HWo*5S zWK}vsL;tI+H06-sT)1jW{G9L`i}aG6CU=N*Z2#zZZ0VgvlQ!u`2&gak`n=w2hT{<( zd2a!ITi^AyXALLqE%UjW^(*!8y_(5EW$O)g1@GuHvL$mge+x8K

Yw##I(zD*U3;DH$L^$H6vbJlc)XVNjP~ZG Z*A7eadE2>2`IpKZepcu3D>BNy4FHg)b%g)` literal 255 zcmZQ@_Y83kiVO&0Fi-Evj#iw0zS;cz`}KM6l$T}cmgmS;yGh1)*H+X%>{j_MfQ`XQeKmQWcYt@IPa`sqEY&YZs03h)GtCSq@$@^={{@ z7BmOgnBNx)KfNSlbNM$mJzM6Fg3_LKavQc6R)bhb^rP005IxaU=i$