From 6b81ecd961951ffbf85be74627fcda896cc5a8e8 Mon Sep 17 00:00:00 2001 From: oddlama Date: Wed, 21 Jun 2023 01:36:44 +0200 Subject: [PATCH] feat: prepare sentinel for webapp oauth2 authentication --- README.md | 51 ++++++++------- flake.lock | 42 ++++++------ hosts/common/core/system.nix | 19 ++++++ hosts/sentinel/caddy.nix | 60 ++++++++++++++++-- hosts/sentinel/default.nix | 5 ++ hosts/sentinel/secrets/caddy-env.age | Bin 0 -> 495 bytes .../promtail-loki-basic-auth-password.age | 11 ++++ hosts/ward/microvms/loki/default.nix | 25 ++------ .../loki/secrets/loki-basic-auth-hashes.age | Bin 1049 -> 1169 bytes 9 files changed, 145 insertions(+), 68 deletions(-) create mode 100644 hosts/sentinel/secrets/caddy-env.age create mode 100644 hosts/sentinel/secrets/promtail-loki-basic-auth-password.age diff --git a/README.md b/README.md index 202b5b7..8c4c119 100644 --- a/README.md +++ b/README.md @@ -136,32 +136,39 @@ openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \ ```bash # Recover admin account (server must not be running) -> systemctl stop kanidm -> kanidmd recover-account -c server.toml admin -AhNeQgKkwwEHZ85dxj1GPjx58vWsBU8QsvKSyYwUL7bz57bp -> systemctl start kanidm +systemctl stop kanidm +kanidmd recover-account -c server.toml admin +> AhNeQgKkwwEHZ85dxj1GPjx58vWsBU8QsvKSyYwUL7bz57bp +systemctl start kanidm # Login with recovered root account -> kanidm login --name admin +kanidm login --name admin # Generate new credentials for idm_admin account -> kanidm service-account credential generate -D admin idm_admin -Yk0W24SQGzkLp97DNxxExCcryDLvA7Q2dR0A7ZuaVQevLR6B +kanidm service-account credential generate -D admin idm_admin +> Yk0W24SQGzkLp97DNxxExCcryDLvA7Q2dR0A7ZuaVQevLR6B # Generate new oauth2 app for grafana -> kanidm group create grafana-access -> kanidm group create grafana-server-admins -> kanidm group create grafana-admins -> kanidm group create grafana-editors -> kanidm system oauth2 create grafana "Grafana" https://grafana.${personalDomain} -> kanidm system oauth2 update-scope-map grafana grafana-access openid profile email -> kanidm system oauth2 update-sup-scope-map grafana grafana-server-admins server_admin -> kanidm system oauth2 update-sup-scope-map grafana grafana-admins admin -> kanidm system oauth2 update-sup-scope-map grafana grafana-editors editor -> kanidm system oauth2 show-basic-secret grafana +kanidm group create grafana-access +kanidm group create grafana-server-admins +kanidm group create grafana-admins +kanidm group create grafana-editors +kanidm system oauth2 create grafana "Grafana" https://grafana.${personalDomain} +kanidm system oauth2 update-scope-map grafana grafana-access openid profile email +kanidm system oauth2 update-sup-scope-map grafana grafana-server-admins server_admin +kanidm system oauth2 update-sup-scope-map grafana grafana-admins admin +kanidm system oauth2 update-sup-scope-map grafana grafana-editors editor +kanidm system oauth2 show-basic-secret grafana +# Generate new oauth2 app for proxied webapps +kanidm group create web-sentinel-access +kanidm group create web-sentinel-adguardhome-access +kanidm system oauth2 create web-sentinel "Web services" https://sentinel.${personalDomain} +kanidm system oauth2 update-scope-map web-sentinel web-sentinel-access openid profile email +kanidm system oauth2 update-sup-scope-map web-sentinel web-sentinel-adguardhome-access access_adguardhome +kanidm system oauth2 show-basic-secret web-sentinel # Add new user -> kanidm login --name idm_admin -> kanidm person create myuser "My User" -> kanidm person update myuser --legalname "Full Name" --mail "myuser@example.com" -> kanidm group add_members grafana-access myuser -> kanidm group add_members grafana-server-admins myuser +kanidm login --name idm_admin +kanidm person create myuser "My User" +kanidm person update myuser --legalname "Full Name" --mail "myuser@example.com" +kanidm group add-members grafana-access myuser +kanidm group add-members grafana-server-admins myuser ``` diff --git a/flake.lock b/flake.lock index 449ba50..5fc6d92 100644 --- a/flake.lock +++ b/flake.lock @@ -31,11 +31,11 @@ ] }, "locked": { - "lastModified": 1687090623, - "narHash": "sha256-LdlH20WGKY1ebO3YJ85gPgmMPlGJUP4JUdqM+k5MsZw=", + "lastModified": 1687304097, + "narHash": "sha256-VId0oZxpYm4HSHwbsuGKI84zFkL6Gp4wuoJbbl52oZg=", "owner": "oddlama", "repo": "agenix-rekey", - "rev": "317558abbec903324e6d38393e2e84b42c25f479", + "rev": "b1811920562ba287b680f35644ce3ed78d029cdf", "type": "github" }, "original": { @@ -119,11 +119,11 @@ ] }, "locked": { - "lastModified": 1687028856, - "narHash": "sha256-vKV3I31tmXwaWHiUOgfDVd27cEHqaPBr1lt9+NKdIp8=", + "lastModified": 1687134796, + "narHash": "sha256-gjBAkEtNPMQzqK4IHjTQBUv3VhggszOHLJbhXZy0OVQ=", "owner": "nix-community", "repo": "disko", - "rev": "64c9c78c15fd4c899d857bf09dba88bda771b43a", + "rev": "4823509bb3b014dc85abefc13efcfa076d36338a", "type": "github" }, "original": { @@ -169,11 +169,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1685518550, - "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", + "lastModified": 1687171271, + "narHash": "sha256-BJlq+ozK2B1sJDQXS3tzJM5a+oVZmi1q0FlBK/Xqv7M=", "owner": "numtide", "repo": "flake-utils", - "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", + "rev": "abfb11bd1aec8ced1c9bb9adfe68018230f4fb3c", "type": "github" }, "original": { @@ -210,11 +210,11 @@ ] }, "locked": { - "lastModified": 1687081547, - "narHash": "sha256-/JV70TxhvP2r4xYtTlbQ2rrRDcj7MqHnF13r5ZE0oFc=", + "lastModified": 1687301540, + "narHash": "sha256-vFbCrE9WlOSVpyAT5VNR3bqMB7W7sDzMNDcO6JqtmBw=", "owner": "nix-community", "repo": "home-manager", - "rev": "28c823032cabfaa340a09e1d84cf45d11375c644", + "rev": "9a76fb9a852fdf9edd3b0aabc119efa1d618f969", "type": "github" }, "original": { @@ -275,11 +275,11 @@ }, "nixlib": { "locked": { - "lastModified": 1685840432, - "narHash": "sha256-VJIbiKsY7Xy4E4WcgwUt/UiwYDmN5BAk8tngAjcWsqY=", + "lastModified": 1687049841, + "narHash": "sha256-FBNZQfWtA7bb/rwk92mfiWc85x4hXta2OAouDqO5W8w=", "owner": "nix-community", "repo": "nixpkgs.lib", - "rev": "961e99baaaa57f5f7042fe7ce089a88786c839f4", + "rev": "908af6d1fa3643c5818ea45aa92b21d6385fbbe5", "type": "github" }, "original": { @@ -296,11 +296,11 @@ ] }, "locked": { - "lastModified": 1686924781, - "narHash": "sha256-6r3Hm2Fxf4F7LIWRYKU9bsS/xJwlG6L2+/I/pdffvOs=", + "lastModified": 1687183443, + "narHash": "sha256-foX4pkph2AwUdJL3JURa7IHog+YRIheZ54vwHwxqwhU=", "owner": "nix-community", "repo": "nixos-generators", - "rev": "a54683aa7eff00ee5b33dec225525d0eb6ab02de", + "rev": "09140f23f5ffce828db4ef040070bdd9595b1f3a", "type": "github" }, "original": { @@ -388,11 +388,11 @@ "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1686668298, - "narHash": "sha256-AADh9NqHh6X2LOem4BvI7oCkMm+JPCSCE7iIw5nn0VA=", + "lastModified": 1687251716, + "narHash": "sha256-+sFS41thsB5U+lY/dBYPSmU4AJ7nz/VdM1WD35fXVeM=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "5b6b54d3f722aa95cbf4ddbe35390a0af8c0015a", + "rev": "7807e1851d95828ed98491930d2d9e7ddbe65da4", "type": "github" }, "original": { diff --git a/hosts/common/core/system.nix b/hosts/common/core/system.nix index 5fcd5a2..dfc4d8e 100644 --- a/hosts/common/core/system.nix +++ b/hosts/common/core/system.nix @@ -362,6 +362,25 @@ lib.mkIf (pubkeyPath != null && lib.pathExists pubkeyPath) pubkeyPath; }; + age.generators.basic-auth.script = { + pkgs, + lib, + decrypt, + deps, + ... + }: + lib.flip lib.concatMapStrings deps ({ + name, + host, + file, + }: '' + echo " -> Aggregating "${lib.escapeShellArg host}":"${lib.escapeShellArg name}"" >&2 + echo -n ${lib.escapeShellArg host}"+"${lib.escapeShellArg name}" " + ${decrypt} ${lib.escapeShellArg file} \ + | ${pkgs.caddy}/bin/caddy hash-password --algorithm bcrypt \ + || die "Failure while aggregating caddy basic auth hashes" + ''); + boot = { initrd.systemd = { enable = true; diff --git a/hosts/sentinel/caddy.nix b/hosts/sentinel/caddy.nix index 6988959..b6fba7e 100644 --- a/hosts/sentinel/caddy.nix +++ b/hosts/sentinel/caddy.nix @@ -1,14 +1,19 @@ { config, - lib, - nodes, - nodeName, pkgs, ... }: { users.groups.acme.members = ["caddy"]; - services.caddy = { + age.secrets.caddy-env = { + rekeyFile = ./secrets/caddy-env.age; + mode = "440"; + group = "caddy"; + }; + + services.caddy = let + proxyAuthDomain = "sentinel.${config.repo.secrets.local.personalDomain}"; + in { enable = true; package = pkgs.caddy.withPackages { plugins = [ @@ -19,5 +24,52 @@ ]; vendorHash = "sha256-RqSXQihtY5+ACaMo7bLdhu1A+qcraexb1W/Ia+aUF1k"; }; + + virtualHosts.${proxyAuthDomain} = { + useACMEHost = config.lib.extra.matchingWildcardCert proxyAuthDomain; + extraConfig = '' + import common + authenticate with myportal + ''; + }; + + globalConfig = '' + order authenticate before respond + order authorize before basicauth + + security { + oauth identity provider kanidm { + realm kanidm + driver generic + client_id web-sentinel + client_secret {env.KANIDM_CLIENT_SECRET} + scopes openid email profile + base_auth_url https://${config.proxiedDomains.kanidm}/ui/oauth2 + metadata_url https://${config.proxiedDomains.kanidm}/oauth2/openid/sentinel/.well-known/openid-configuration + } + + authentication portal myportal { + enable identity provider kanidm + cookie domain ${config.repo.secrets.local.personalDomain} + ui { + links { + "My Identity" "/whoami" icon "las la-user" + } + } + + transform user { + match realm kanidm + action add role authp/user + } + + #transform user { + # match realm kanidm + # match scope read:access_aguardhome + # action add role authp/admin + #} + } + ''; }; + + systemd.services.caddy.serviceConfig.environmentFile = config.age.secrets.caddy-env.path; } diff --git a/hosts/sentinel/default.nix b/hosts/sentinel/default.nix index ca21c68..776caba 100644 --- a/hosts/sentinel/default.nix +++ b/hosts/sentinel/default.nix @@ -16,4 +16,9 @@ ./acme.nix ./caddy.nix ]; + + extra.promtail = { + enable = true; + proxy = "sentinel"; + }; } diff --git a/hosts/sentinel/secrets/caddy-env.age b/hosts/sentinel/secrets/caddy-env.age new file mode 100644 index 0000000000000000000000000000000000000000..e778980d3279b496a6801fe57d31fc64cab8eeb5 GIT binary patch literal 495 zcmWm8JB!l*003ZJj=Q+J2ntz_1A8$^o1}?DA!%&-OfN}mlB#H$rfJ@3UQHu7-R9tM z%YixzA}5HTAPC|l=pYJ;;>{v@;3z)u?iYNYW*U&;>(MeytiV4PL?)b}08|5&GLEAZ zIBnQ+F-W^`)KpNqf%mvN-q5YKlkz4``-EUPG%2tbFEnVt8jGzFNk|=qr5SXHBnB&M zQV&kWMNUg?RbVUDG{hNMMUI5f%Al}}6JS1<3{n8;64#GWnMvIeSKmrvYa#ea#qLm* zo*)&HC!sTGthNOlQR{$+P@K%&z%#Vx zxK%doh?pn)aiYp2Y`z3sr|x0xR!hqyUh4}wZ02J^7y=Lkfs*gVa-Iveo<{I;E6nGj zPE`%cZSx$Hll<6eGJI>&T2>rj=i2=PY=eHc+r6{@arJVaJh@#(wtwwiy%nrHy#4C= zq;%>uCx3mi{`UL7^EZp(mDNAbzHQvQ{_+y^{?X^XnezBWcje8Q6N|q;zU2EmpEd`_ YYroIl{jhe-n5?~??LKgS-r%492Q$X6*8l(j literal 0 HcmV?d00001 diff --git a/hosts/sentinel/secrets/promtail-loki-basic-auth-password.age b/hosts/sentinel/secrets/promtail-loki-basic-auth-password.age new file mode 100644 index 0000000..0699c11 --- /dev/null +++ b/hosts/sentinel/secrets/promtail-loki-basic-auth-password.age @@ -0,0 +1,11 @@ +age-encryption.org/v1 +-> X25519 5yDq2pctzyK8uUxKxekOz9tHbmUq4JKCzEbBCYQ79w0 +lFsTmuUufwYoZ1fAbs7BCmaU3h6Mck8w98TmUdahWP8 +-> piv-p256 xqSe8Q Aul+3eIiUD0DWAiRPR7Ms4l9ohF+62P98EYqngOFOwU9 +TdW4WUaIeT7rC9eeGjEM1jPEp/LE1q2V3/fQFLyjbtk +-> yYnni-grease 2a +SV/4RAhtPi8LsDwcXpwT8AZQCwwJ1tu0R3aN8r7J5cs2RCNGKvNYhU3WRZ6XUi84 +S1SGmd886W3twPhMYSjm9j8IqqJ5iaWq0IXPpxLZIpv1viS4jDoLgMcKxFbKI97z +5OCc +--- 30SxKU9DX+vU3e/fd4upxOLcv4DSujy06P+Ja2yHPjM +?Gu>ir7yۦm`"AM7^ M*O%BRQ“^Hx_;edW3q0\4: \ No newline at end of file diff --git a/hosts/ward/microvms/loki/default.nix b/hosts/ward/microvms/loki/default.nix index 21931dd..38ddbb6 100644 --- a/hosts/ward/microvms/loki/default.nix +++ b/hosts/ward/microvms/loki/default.nix @@ -26,27 +26,9 @@ in { age.secrets.loki-basic-auth-hashes = { rekeyFile = ./secrets/loki-basic-auth-hashes.age; - generator = { - # Dependencies are added by the nodes that define passwords (using distributed-config). - script = { - pkgs, - lib, - decrypt, - deps, - ... - }: - lib.flip lib.concatMapStrings deps ({ - name, - host, - file, - }: '' - echo " -> Aggregating "${lib.escapeShellArg host}":"${lib.escapeShellArg name}"" >&2 - echo -n ${lib.escapeShellArg host}"+"${lib.escapeShellArg name}" " - ${decrypt} ${lib.escapeShellArg file} \ - | ${pkgs.caddy}/bin/caddy hash-password --algorithm bcrypt \ - || die "Failure while aggregating caddy basic auth hashes" - ''); - }; + # Copy only the script so the dependencies can be added by the nodes + # that define passwords (using distributed-config). + generator.script = config.age.generators.basic-auth.script; mode = "440"; group = "caddy"; }; @@ -55,6 +37,7 @@ in { useACMEHost = sentinelCfg.lib.extra.matchingWildcardCert lokiDomain; extraConfig = '' import common + skip_log basicauth { import ${sentinelCfg.age.secrets.loki-basic-auth-hashes.path} } diff --git a/hosts/ward/microvms/loki/secrets/loki-basic-auth-hashes.age b/hosts/ward/microvms/loki/secrets/loki-basic-auth-hashes.age index 122be11c716efbd4902d6ff853ff6f14365fa643..738a26e150df4d4ee60a65d355235d5abe5a0d87 100644 GIT binary patch delta 1152 zcmV-`1b_RP2$2bpAb)aUcw=p5Ra9a_QEx#oY;9I#RckMJbVPMRa8^-iF*8{!XD~%V zb5>|pcM54~O;$BQGEg#FWNSe;X-qb1PI5zHa#>7lFjzxwa5!>NV^T&pYDic@a|$g! zAaH4REpRe5HXwL$Q)M_&AVDu|bZ=H9MmJY9bZ==xdM{L3 zQdMM9L^5baYIF*BLrZs4Z(~7lb2LS4NmfxQCdfIRBl8vWlLE(GfYZ2QEzNgR#Qb(S64|| zOi4B}VM$R?L4P(vMNvd%OKxpuD^+Y|Pc%(Z!=|aR!>)I zWKTmxYFA4&cM2^nEg)KESV?bsZZTp)Mo3UAYf?FOc}QAELv&3zPcK?pcSu)8D^5Xn zNN+D;V+wk6DAdiFB*0n6Z&x6sNQSYP9Bvcht9_|Yqf{Df z{oNx=4Aot^p^+r}4%wrSnvtkC~Q9uQasjVn)q}!(H z;zWsB97j8@JhEbMw=h1CL(EN)-p1)PAVQmqS$~Z{h)cXtvYBiA7$M(VYltye`;RiI zUb}+7GA!wC99UX4>&9J-??wm{eNKdaaxx0KZ}~OmWQ|##(zU>2Jhi7#+~4;Ja_S^1 z2=n*Z5k&J4dl(CiC^eOxvpjZ{irx}}%`A6CSTv^QMgq{)15Oj!dNNz@*i!}qIrPDf z{eQkQ*;aiF$;;xdrAWx(ReX=ZazhF#_Ke_ONy&v+Jkn8p_)WlN=Tcpe_AL*C5f>`X>tC-DI9g1O6{+b!;CkBm^&Q?bFz^Z z@EUVzZEvJm$fE2NR9+h~#!|vyA&mN~P>C%Arrkahd1tkjW9Yc`rt`X8t3ug>|9NH% zdfLNo7Uq6V8$C2!Ux(iI4tCf`f04a+larwC2WgT6qb5mVG9!3zjEAfHJd4~TOsUqXJi%~C1VD(k>Dk7KJYXZ-IOC<(CGW{ZZ1`JS8=q4(=pz6m9Mrsa Sl04#2ua4+S6|Tpmct74$ZTL+9 delta 1032 zcmV+j1o!)q37H6xAb&+pT32^@G;&FKN!mtIaEnkVPY|FRSGRW zAaH4REpRe5HXwL$Q)M_&AVG3aYb$VBOEx)fNl;5RWl3#rQ-3jNPFiL{Y-2e@N>^tz zGe>H2QFB*NPc;fTT5(cxc}-C>WJGpRGjA|APB%eWcxF&ZWO`?DH*$7#GFN0ZQ!!~W zH**RtJ|HwqFGXBqQE)A1a%Ew2WgsvuUV1A=Rv=JWNi;uDLm*^g3P){IYgsrqaWha( zR5o!?O-y2FaesJZVsC9%I7V(^IWTE=byZAvIc9icSw}Q8M0#;iV{=MIYG+|;ZbDHq zO$se7Eg)HSYI#{`N=|rpY-3keHcV4DFLYQ#OGrafbwyEeacOWbIAKmnK~yy>YYN{t zx6b7q3*H-e{Sq7Y8pjdPm18jVj9AJhn{`Lj`$C`F{C_j4)+cs~!4k!kI*WF4X^O-e zD4z_%<<|ASFMKYHuhqMgBD|dYvav9Nwv7twCuhr^GU3_^#;8>&L(nx)n&XmAOzugo7E`Ls!Jsr0sSO5jD*_I?9_S^&Rw$Hm|YueCTs4yR%{9M*hy~08}jxtxGL|*TYvds4P;G5!o4xSKdA-#5S@7r*85?& zDCD^jGZ+$$jqXL0t|U>{ed@y%GW^R-(q5ygm)Yg}^o{JWQ{_bk!I8{mB$(ke({7ET zW+MAQd~=qS+#aJ-rafRRnS-PSObnyvgT|^sJMVwRMEE(fOx@B4_u{ILc#p@hf4Td{ zr+=_}jpqePP3tV*Fe#MJCRAI1gJq@C;Q8 z_>@vAvPQ2x^K*j*lrqu#cO*Sb2G!Ff3(;!IdoU@KND%_Tz_RigKQ@3(4(dY`k1cCxOzZ zZeZz63jk)dVBEVm<&9O{l&Gk zAoKqA*~uOAn!#=%hJ60V#_sC@k}edgz|P$kaPGd^PFF3q)A3yL13Xh#)6C@Dy8$}5 C#oTrP