me like nix
1{ inputs, ... }:
2
3let
4 sshAuthorizedKeys = [
5 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDCIqgZ7kedxo+mOW7YG73Vp3zel3h180y3GKvHtRsXfGlpIIvRDy7pgCBQ4AGXYD4y78URQmFohYSAPqCPOPaWcU2un3XG9KvCzEsHmsbskPonitUmCiKvrKkb6oW4jCBtd7AEtBn+AiajAQFtPZ7NN2Df3AmTypvR6Irg7R+nxnfc9NTIHmGvxSDyWcbb4pguL20sctUSqGL6xGh8q/bqhdOThSimM+z9bEUNxK/5rPhwkNniMrp4pJcUrUiAh5/4DiRFG6KT+oeg+/myoz/Z1sPvAs7u/8JDQI4RshRD8Hu0oTkRBN6Hxj478q2SXbeBUZlD6IdjP3RhGpmSecoDdtWqKbpuV3eVRtQtba3KL86GBeV/bugaOdJ1Aud+1SOFJreAAuvxzMMKT+cdQZk6oOPP148DA/No+mDm/2S43lcdCXh79wA6YRAmKQ8jmZxTCtPutrvuZK1rguvvUlEoG/vhdNHh7eDa4Td07V6bjCRPUl8qk/e4M0E3pwsTlZc="
6 "no-touch-required sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAILdilHXHdAP/V8Zq28EzHKtLAMMaFPu4+1det2N50QfhAAAABHNzaDo= sean@framework16"
7 ];
8in
9{
10 flake.modules.nixos.sean =
11 { pkgs, ... }:
12 {
13 users.groups.storage = { };
14 users.groups.plugdev = { };
15 users.users.sean = {
16 isNormalUser = true;
17 description = "Sean Aye";
18 extraGroups = [
19 "docker"
20 "networkmanager"
21 "wheel"
22 "video"
23 "disk"
24 "storage"
25 "input"
26 "plugdev"
27 "dialout"
28 ];
29 shell = pkgs.fish;
30 linger = true;
31 openssh.authorizedKeys.keys = sshAuthorizedKeys;
32 };
33
34 programs.fish.enable = true;
35 programs._1password.enable = true;
36 programs._1password-gui = {
37 enable = true;
38 polkitPolicyOwners = [ "sean" ];
39 };
40 };
41
42 flake.modules.homeManager.sean =
43 {
44 pkgs,
45 config,
46 lib,
47 ...
48 }:
49 {
50 home.username = "sean";
51 home.homeDirectory = "/home/sean";
52 home.stateVersion = "25.05";
53
54 nixpkgs.config.allowUnfree = true;
55 nixpkgs.config.permittedInsecurePackages = [
56 "libsoup-2.74.3"
57 ];
58
59 home.packages = with pkgs; [
60 inputs.agenix.packages.${pkgs.stdenv.hostPlatform.system}.default
61 age-plugin-yubikey
62 lxqt.lxqt-policykit
63 ];
64
65 programs.ssh = {
66 enable = true;
67 enableDefaultConfig = false;
68 matchBlocks = {
69 # For git/jj over SSH, try the local YubiKey-backed security key
70 # first. For Codeberg, restrict agent identities so 1Password is
71 # only used as a fallback after the YubiKey identity.
72 "codeberg.org" = lib.hm.dag.entryBefore [ "git-forges" ] {
73 identityFile = [
74 "${config.home.homeDirectory}/.ssh/id_ed25519_sk_rk"
75 "${config.home.homeDirectory}/.ssh/1password-codeberg.pub"
76 ];
77 identityAgent = [
78 "${config.home.homeDirectory}/.1password/agent.sock"
79 ];
80 identitiesOnly = true;
81 };
82 "git-forges" = {
83 host = "github.com gist.github.com gitlab.com";
84 identityFile = [
85 "${config.home.homeDirectory}/.ssh/id_ed25519_sk_rk"
86 ];
87 };
88 "*" = {
89 identityFile = [
90 "${config.home.homeDirectory}/.ssh/id_ed25519_sk_rk"
91 ];
92 };
93 };
94 };
95
96 age.secrets.aws-credentials.file = ../secrets/aws.age;
97
98 programs.awscli = {
99 enable = true;
100 settings = {
101 "default" = {
102 region = "us-east-1";
103 };
104 };
105 };
106
107 home.sessionVariables = {
108 EDITOR = "hx";
109 VISUAL = "hx";
110 SUDO_EDITOR = "hx";
111 SSH_ASKPASS = "${pkgs.openssh-askpass}/libexec/gtk-ssh-askpass";
112 SSH_ASKPASS_REQUIRE = "prefer";
113 AWS_SHARED_CREDENTIALS_FILE = config.age.secrets.aws-credentials.path;
114 };
115
116 # Prefer forwarded agents inside SSH sessions. Some login shells source
117 # hm-session-vars after sshd has set SSH_AUTH_SOCK, so recover sshd's
118 # original value from the parent process before falling back to the local
119 # 1Password GUI agent on graphical/local sessions.
120 home.sessionVariablesExtra = ''
121 if [ -n "$SSH_CONNECTION" ] || [ -n "$SSH_CLIENT" ]; then
122 forwarded_sock=$(tr '\0' '\n' < "/proc/$PPID/environ" 2>/dev/null | sed -n 's/^SSH_AUTH_SOCK=//p' | head -n1)
123 if [ -n "$forwarded_sock" ] && [ -S "$forwarded_sock" ]; then
124 export SSH_AUTH_SOCK="$forwarded_sock"
125 fi
126 elif [ -S "${config.home.homeDirectory}/.1password/agent.sock" ]; then
127 export SSH_AUTH_SOCK="${config.home.homeDirectory}/.1password/agent.sock"
128 fi
129 '';
130
131 # SSH allowed signers for commit signature verification
132 home.file.".ssh/allowed_signers".text = ''
133 hello@seanaye.ca ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDCIqgZ7kedxo+mOW7YG73Vp3zel3h180y3GKvHtRsXfGlpIIvRDy7pgCBQ4AGXYD4y78URQmFohYSAPqCPOPaWcU2un3XG9KvCzEsHmsbskPonitUmCiKvrKkb6oW4jCBtd7AEtBn+AiajAQFtPZ7NN2Df3AmTypvR6Irg7R+nxnfc9NTIHmGvxSDyWcbb4pguL20sctUSqGL6xGh8q/bqhdOThSimM+z9bEUNxK/5rPhwkNniMrp4pJcUrUiAh5/4DiRFG6KT+oeg+/myoz/Z1sPvAs7u/8JDQI4RshRD8Hu0oTkRBN6Hxj478q2SXbeBUZlD6IdjP3RhGpmSecoDdtWqKbpuV3eVRtQtba3KL86GBeV/bugaOdJ1Aud+1SOFJreAAuvxzMMKT+cdQZk6oOPP148DA/No+mDm/2S43lcdCXh79wA6YRAmKQ8jmZxTCtPutrvuZK1rguvvUlEoG/vhdNHh7eDa4Td07V6bjCRPUl8qk/e4M0E3pwsTlZc=
134 hello@seanaye.ca sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAILdilHXHdAP/V8Zq28EzHKtLAMMaFPu4+1det2N50QfhAAAABHNzaDo= sean@framework16
135 '';
136
137 # Public half of the 1Password Codeberg key, used to make OpenSSH try
138 # this agent identity only after the YubiKey security key.
139 home.file.".ssh/1password-codeberg.pub".text = ''
140 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHfOR2xQ1b+oZytOmbNvThIRym0R1zKtCd0dbwjPcxd1 SSH Key Codeberg
141 '';
142
143 # Yubikey identity for agenix
144 home.file.".config/agenix/yubikey-identity.txt".text = ''
145 # Serial: 26930059, Slot: 1
146 # Name: agenix
147 # Recipient: age1yubikey1qw64ag5lzvn9ekrflu5ruj4a6ucycscl6ctk39fjzf76jptsay39z442pxv
148 AGE-PLUGIN-YUBIKEY-1304E5QVZZD74FKSP8FMCT
149 '';
150
151 # Same identity for sops
152 home.file.".config/sops/age/keys.txt".text = ''
153 # Serial: 26930059, Slot: 1
154 # Name: agenix
155 # Recipient: age1yubikey1qw64ag5lzvn9ekrflu5ruj4a6ucycscl6ctk39fjzf76jptsay39z442pxv
156 AGE-PLUGIN-YUBIKEY-1304E5QVZZD74FKSP8FMCT
157 '';
158
159 # Yubikey sudo access
160 home.file.".config/Yubico/u2f_keys".text = ''
161 sean:2HY//CedY0ZSrKf57lT7abxG8+8bkPyxCfp/0HMlk/il/5W8pn4R5xLiZDcJtvL85U24h9IEIxa4CS22mpaDSA==,gcD/dpLdwvUFcGGPHS4qNsarH4lOEy1AJAT7zoC6BPlFRUYEa8DpVVKFTcvT6PotjnSHSrWWGb/f3U2k2jIOIw==,es256,+presence
162 '';
163
164 programs.home-manager.enable = true;
165 };
166}