commit f0f0229345a7760aa095a6491f95315a1dd1eb2d Author: Konarak Date: Sun Aug 17 20:37:46 2025 +0530 initial commit diff --git a/.sops.yaml b/.sops.yaml new file mode 100644 index 0000000..e69de29 diff --git a/config/configuration.nix b/config/configuration.nix new file mode 100644 index 0000000..2ef02af --- /dev/null +++ b/config/configuration.nix @@ -0,0 +1,45 @@ +{ config, lib, pkgs, ... }: + +{ + sops.defaultSopsFile = ../secrets/secrets.yaml; + + imports = [ + # Include the results of the hardware scan. + ./hardware-configuration.nix + + ../modules/sixnix + ]; + + # Use the GRUB 2 boot loader. + boot.loader.grub.enable = true; + + # Enable the Flakes feature and the accompanying new nix command-line tool + nix.settings.experimental-features = [ "nix-command" "flakes" ]; + + environment.systemPackages = with pkgs; [ git curl btop emacs-nox ]; + + # Copy the NixOS configuration file and link it from the resulting system + # (/run/current-system/configuration.nix). This is useful in case you + # accidentally delete configuration.nix. + # system.copySystemConfiguration = true; + + # This option defines the first version of NixOS you have installed on this particular machine, + # and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions. + # + # Most users should NEVER change this value after the initial install, for any reason, + # even if you've upgraded your system to a new NixOS release. + # + # This value does NOT affect the Nixpkgs version your packages and OS are pulled from, + # so changing it will NOT upgrade your system - see https://nixos.org/manual/nixos/stable/#sec-upgrading for how + # to actually do that. + # + # This value being lower than the current NixOS release does NOT mean your system is + # out of date, out of support, or vulnerable. + # + # Do NOT change this value unless you have manually inspected all the changes it would make to your configuration, + # and migrated your data accordingly. + # + # For more information, see `man configuration.nix` or https://nixos.org/manual/nixos/stable/options#opt-system.stateVersion . + system.stateVersion = "25.05"; # Did you read the comment? + +} diff --git a/config/hardware-configuration.nix b/config/hardware-configuration.nix new file mode 100644 index 0000000..a590721 --- /dev/null +++ b/config/hardware-configuration.nix @@ -0,0 +1,41 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + + boot.initrd.availableKernelModules = + [ "virtio_pci" "virtio_scsi" "ahci" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "wireguard" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = { + device = "/dev/sda"; + fsType = "ext4"; + }; + + swapDevices = [ ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + # networking.useDHCP = lib.mkDefault true; + # networking.interfaces.enp0s4.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + + boot.kernelParams = [ "console=ttyS0,19200n8" ]; + boot.loader.grub.extraConfig = '' + serial --speed=19200 --unit=0 --word=8 --parity=no --stop=1; + terminal_input serial; + terminal_output serial; + ''; + boot.loader.grub.forceInstall = true; + boot.loader.grub.device = "nodev"; + boot.loader.timeout = 10; + +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..39c4bb3 --- /dev/null +++ b/flake.nix @@ -0,0 +1,25 @@ +{ + description = "Server Configuration for WireGuard provider"; + + inputs = { + nixpkgs.url = "nixpkgs/nixos-25.05"; + nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable"; + + sops-nix.url = "github:Mic92/sops-nix"; + sops-nix.inputs.nixpkgs.follows = "nixpkgs"; + + }; + + outputs = { self, nixpkgs, nixpkgs-unstable, sops-nix, }@attrs: { + nixosConfigurations = { + "tunnels" = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + specialArgs = attrs; + modules = [ + (import ./config/maa1-ops/configuration.nix) + sops-nix.nixosModules.sops + ]; + }; + }; + }; +} diff --git a/modules/access.nix b/modules/access.nix new file mode 100644 index 0000000..00d9f1b --- /dev/null +++ b/modules/access.nix @@ -0,0 +1,44 @@ +{ config, pkgs, ... }: + +let + keys = [ + ]; + + root.password = config.sops.secrets.password-root.path; +in { + + sops.secrets = let def = { neededForUsers = true; }; + in { + "password-root" = def; + }; + + services.openssh = { + enable = true; + settings.PermitRootLogin = "no"; + }; + + # protect from ssh spammers + services.sshguard.enable = true; + + # disable kernel from logging REFUSED CONNECTIONS messages when we actually drop this traffic + networking.firewall.logRefusedConnections = false; + + # enable mosh and open firewall ports + programs.mosh.enable = true; + + security.sudo.wheelNeedsPassword = false; + + users.mutableUsers = false; + + users.users.root = { + hashedPasswordFile = root.password; + openssh.authorizedKeys.keys = keys; + }; + + # users.users. = { + # isNormalUser = true; + # extraGroups = [ "wheel" ]; + # hashedPasswordFile = ; + # openssh.authorizedKeys.keys = ; + # }; +} diff --git a/modules/default.nix b/modules/default.nix new file mode 100644 index 0000000..deb780f --- /dev/null +++ b/modules/default.nix @@ -0,0 +1 @@ +{ config, pkgs, ... }: { imports = [ ./access.nix ./network.nix ]; } diff --git a/modules/network.nix b/modules/network.nix new file mode 100644 index 0000000..1c44930 --- /dev/null +++ b/modules/network.nix @@ -0,0 +1,68 @@ +{ config, pkgs, ... }: +let + hostname = "tunnels"; + domain = "example.com"; + + resolvers = [ "9.9.9.9" "2620:fe::fe" ]; + + egress = { + interface = "eth0"; + + ipv4.gateway = "198.51.100.10"; + ipv4.address = "198.51.100.1/24"; + + ipv6.gateway = "fe80::1"; + ipv6.address = "2001:DB8:10:cafe:dcaf::3210/64"; + }; + + tunnels = [{ + interface = "wg0"; + serverPort = 51820; + serverAddress = "2001:db8:de:ff0::1/128"; + clientAddress = "2001:db8:de:ff0::2/128"; + clientSubnet = "2001:db8:de:f00::/60"; + serverPrivateKeyFile = "wg0-server-private"; + clientPublicKeyFile = "wg0-client-public"; + }]; +in { + + networking.hostName = hostname; + networking.domain = domain; + + # Enable systemd-networkd + systemd.network.enable = true; + networking.useNetworkd = true; + + # Tools for monitoring/key generation + environment.systemPackages = with pkgs; [ wireguard-tools tcpdump ]; + + # Configure Ethernet interface (eth0) + systemd.network.networks."10-egress" = { + matchConfig.Name = egress.interface; + networkConfig = { + DHCP = "no"; + IPv6AcceptRA = "no"; + IPv6PrivacyExtensions = "yes"; + IPv6Forwarding = "yes"; + }; + + address = [ egress.ipv4.address egress.ipv6.address ]; + gateway = [ egress.ipv4.gateway egress.ipv6.gateway ]; + + dns = resolvers; + }; + + imports = [ ./wireguard.nix ]; + + wireguard.interfaces = tunnels; + + networking.firewall = { allowedUDPPorts = map (x: x.serverPort) tunnels; }; + + networking.nat = { + enable = true; + externalInterface = egress.interface; + internalInterfaces = map (x: x.interface) tunnels; + enableIPv6 = true; + }; + +} diff --git a/modules/wireguard.nix b/modules/wireguard.nix new file mode 100644 index 0000000..a5881c4 --- /dev/null +++ b/modules/wireguard.nix @@ -0,0 +1,120 @@ +{ config, lib, pkgs, ... }: + +let + inherit (lib) mkOption types; + + wgConfigType = types.listOf (types.submodule { + options = { + interface = mkOption { + type = types.str; + description = "WireGuard interface name."; + }; + serverAddress = mkOption { + type = types.str; + description = + "IPv6 address with CIDR prefix to bind WireGuard (e.g., 2001:db8::1/64)."; + }; + serverPort = mkOption { + type = types.port; + description = "Port for WireGuard."; + }; + clientAddress = mkOption { + type = types.str; + description = "Peer IPv6 address with CIDR (e.g., 2001:db8::2/128)."; + }; + clientSubnet = mkOption { + type = types.str; + description = "Peer subnet IPv6 CIDR (e.g., 2001:db8::/64)."; + }; + serverPrivateKeyFile = mkOption { + type = types.str; + description = "Name of the sops secret containing server private key."; + }; + clientPublicKeyFile = mkOption { + type = types.str; + description = "Name of the sops secret containing client public key."; + }; + }; + }); + + interfaces = config.wireguard.interfaces; + + extract = attr: map (x: x.${attr}) interfaces; + + assertUnique = name: values: { + assertion = values == lib.unique values; + message = + "Duplicate values found for '${name}': ${builtins.toString values}"; + }; + + secretAssertions = lib.flatten (map (cfg: [ + { + assertion = builtins.hasAttr cfg.serverPrivateKeyFile config.sops.secrets; + message = "Missing sops secret: ${cfg.serverPrivateKeyFile}"; + } + { + assertion = builtins.hasAttr cfg.clientPublicKeyFile config.sops.secrets; + message = "Missing sops secret: ${cfg.clientPublicKeyFile}"; + } + ]) interfaces); + + uniquenessAssertions = [ + (assertUnique "interface" (extract "interface")) + (assertUnique "serverAddress" (extract "serverAddress")) + (assertUnique "serverPort" (extract "serverPort")) + (assertUnique "clientAddress" (extract "clientAddress")) + (assertUnique "clientSubnet" (extract "clientSubnet")) + ]; + +in { + options.wireguard.interfaces = mkOption { + type = wgConfigType; + description = "List of WireGuard interface configurations."; + }; + + config = { + sops.secrets = lib.mkMerge (map (cfg: { + "${cfg.serverPrivateKeyFile}" = { }; + "${cfg.clientPublicKeyFile}" = { }; + }) interfaces); + + assertions = lib.mkAfter (secretAssertions ++ uniquenessAssertions); + + systemd.network.enable = true; + + systemd.network.netdevs = lib.mkMerge (map (cfg: { + "${cfg.interface}" = { + netdevConfig = { + Kind = "wireguard"; + Name = cfg.interface; + }; + wireguardConfig = { + PrivateKeyFile = config.sops.secrets.${cfg.serverPrivateKeyFile}.path; + ListenPort = cfg.serverPort; + }; + wireguardPeers = [{ + PublicKeyFile = config.sops.secrets.${cfg.clientPublicKeyFile}.path; + AllowedIPs = [ cfg.clientAddress cfg.clientSubnet ]; + }]; + }; + }) interfaces); + + systemd.network.networks = lib.mkMerge (map (cfg: { + "${cfg.interface}" = { + matchConfig = { Name = cfg.interface; }; + address = [ cfg.serverAddress ]; + + routes = [ + { + Destination = cfg.clientAddress; + Scope = "link"; + } + { + Destination = cfg.clientSubnet; + Scope = "link"; + } + ]; + }; + }) interfaces); + }; +} diff --git a/secrets/secrets.yaml b/secrets/secrets.yaml new file mode 100644 index 0000000..e69de29