Initial commit

This commit is contained in:
Daniel Frank 2022-01-22 14:31:29 +01:00
commit f6b942023c
Signed by: tokudan
GPG key ID: 063CCCAD04182D32
10 changed files with 345 additions and 0 deletions

1
.envrc Normal file
View file

@ -0,0 +1 @@
export NIX_PATH=nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos:nixos-config=$(expand_path .)/configuration.nix:/nix/var/nix/profiles/per-user/root/channels

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
result
.*.swp

18
README.md Normal file
View file

@ -0,0 +1,18 @@
hamburg.freifunk.net Statistik
===============================
Initiales Setup
-----
1. System starten
2. Passwörter liegen nach dem Start des ersten Dienstes jeweils unter `/var/lib/*/*.pw`
3. Nginx konfigurieren um ACME zu benutzen
4. services.influxdb.extraConfig.http.auth-enabled auf true setzen
5. Config für Collector erstellen und hier ablegen: /var/lib/private/collector/ffhh.conf
6. Grafana konfigurieren
Development
-----
Starten des Systems:
QEMU_NET_OPTS="hostfwd=tcp:127.0.0.1:2222-:22,hostfwd=tcp:127.0.0.1:8080-:80" nixos-shell
Zugriff dann per SSH über 127.0.0.1:2222 und HTTP über 127.0.0.1:8080.

9
acme.nix Normal file
View file

@ -0,0 +1,9 @@
{ ... }:
{
security.acme.acceptTerms = true;
security.acme.email = "kontakt@hamburg.freifunk.net";
users.groups.certs = {
members = [ "nginx" ];
};
}

29
collector.nix Normal file
View file

@ -0,0 +1,29 @@
{ config, lib, pkgs, ... }:
let
collector = pkgs.fetchFromGitHub {
owner = "tokudan";
repo = "ffhh-stats";
rev = "76c61a0c0f7d276fd79026b551780e318901adf6";
sha256 = "0irnc8ffm413aq3sh64sd2457yp2ax4paaf0ss9r1pkbkb8q5dgx";
};
in
{
systemd.services.collector = {
wantedBy = [ "multi-user.target" ];
after = [ "network-online.target" ];
requires = [ "influxdb.service" ];
path = [ pkgs.wget ];
serviceConfig = {
Type = "simple";
Restart = "always";
RestartSec = 65;
DynamicUser = true;
PrivateTmp = true;
StateDirectory = "collector";
# The config file is actually in /var/lib/private/collector, systemd maps that path to /var/lib/collector
ExecStart = "${pkgs.ruby.withPackages (ps: with ps; [ json ])}/bin/ruby ${collector}/query-data.influx --config /var/lib/collector/ffhh.conf";
};
};
}

104
configuration.nix Normal file
View file

@ -0,0 +1,104 @@
# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running nixos-help).
{ config, pkgs, ... }:
{
imports =
[
./acme.nix
./sshusers.nix
./nginx.nix
./grafana.nix
./influxdb.nix
./collector.nix
];
# Use the GRUB 2 boot loader.
boot.loader.grub.enable = true;
boot.loader.grub.version = 2;
boot.loader.grub.device = "/dev/vda";
swapDevices = [{ device = "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi0-0-0-0-part2"; randomEncryption.enable = true; randomEncryption.source = "/dev/random"; }];
networking = {
hostName = "stats";
domain = "hamburg.freifunk.net";
hostId = "7d7135dd";
firewall.rejectPackets = true;
firewall.logRefusedConnections = false;
usePredictableInterfaceNames = false;
dhcpcd.enable = false;
nameservers = [ "213.133.99.99" "213.133.100.100" "213.133.98.98" ];
interfaces.eth0 = {
ipv4.addresses = [ { address = "142.132.181.225"; prefixLength = 32; } ];
ipv6.addresses = [ { address = "2a01:4f8:1c17:dbfb::1"; prefixLength = 64; } ];
};
defaultGateway = { address = "172.31.1.1"; interface = "eth0"; };
defaultGateway6 = { address = "fe80::1"; interface = "eth0"; };
};
# Automatic update each day
system.autoUpgrade.enable = true;
system.autoUpgrade.allowReboot = true;
nix = {
autoOptimiseStore = true;
gc.automatic = true;
gc.options = "--delete-older-than 14d";
};
# Select internationalisation properties.
i18n.defaultLocale = "de_DE.UTF-8";
# Set your time zone.
time.timeZone = "Europe/Berlin";
# List packages installed in system profile. To search, run:
# $ nix search wget
environment.systemPackages = with pkgs; [
git htop lsof mosh nano screen socat traceroute vim wget
];
# Some programs need SUID wrappers, can be configured further or are
# started in user sessions.
programs.mtr.enable = true;
programs.screen.screenrc = ''
hardstatus alwayslastline
hardstatus string '%{= kG}[ %{G}%H %{g}][%= %{= kw}%?%-Lw%?%{r}(%{W}%n*%f%t%?(%u)%?%{r})%{w}%?%+Lw%?%?%= %{g}][%{B} %m-%d %{W}%c:%s %{g}]'
defscrollback 1000
'';
# List services that you want to enable:
# Support mosh connections
programs.mosh.enable = true;
# Open ports in the firewall.
# networking.firewall.allowedTCPPorts = [ ... ];
# networking.firewall.allowedUDPPorts = [ ... ];
# User configuration for root.
# Other users are defined in sshusers.nix
users.extraUsers.root = {
hashedPassword = "!!";
};
users.motd = with config; ''
Welcome to ${networking.hostName}.${networking.domain}
- This server is NixOS
- All changes must be done through the git repository at
/etc/nixos or https://github.com/freifunkhamburg/stats-nixos-config/
- Other changes will be lost
OS: NixOS ${system.nixos.release} (${system.nixos.codeName})
Version: ${system.nixos.version}
Kernel: ${boot.kernelPackages.kernel.version}
'';
# This value determines the NixOS release with which your system is to be
# compatible, in order to avoid breaking some software such as database
# servers. You should change this only after NixOS release notes say you
# should.
system.stateVersion = "21.11"; # Did you read the comment?
}

53
grafana.nix Normal file
View file

@ -0,0 +1,53 @@
{ config, lib, pkgs, ... }:
{
services.grafana = {
enable = true;
analytics.reporting.enable = false;
protocol = "socket";
rootUrl = "https://stats.besaid.de/";
auth.anonymous.enable = false;
security = {
adminUser = "dfrank";
adminPasswordFile = "/var/lib/grafana/admin.pw";
secretKeyFile = "/var/lib/grafana/security.key";
};
};
systemd.services.grafana.serviceConfig = {
# upstream module already defines most hardening options
IPAddressDeny = "any";
IPAddressAllow = "localhost";
MemoryDenyWriteExecute = true;
PrivateUsers = true;
ExecStartPost = [
(pkgs.writeScript "grafana-socket-perms" ''
#!${pkgs.stdenv.shell}
until chmod -c 666 /run/grafana/grafana.sock ; do sleep 1; done
'')
];
};
systemd.services.grafana-init = {
description = "Grafana Service Daemon - initialize files";
wantedBy = [ "grafana.service" ];
before = [ "grafana.service" ];
serviceConfig.Type = "oneshot";
script = ''
#!${pkgs.stdenv.shell}
set -euo pipefail
# Make sure everything but the password ends up on stderr
exec 3>&1 >&2
mkdir -p /var/lib/grafana
if [ ! -s /var/lib/grafana/admin.pw ]; then
head -c 30 /dev/urandom | base64 > /var/lib/grafana/admin.pw
chmod 400 /var/lib/grafana/admin.pw
chown grafana:grafana /var/lib/grafana/admin.pw
fi
if [ ! -s /var/lib/grafana/security.key ]; then
head -c 30 /dev/urandom | base64 > /var/lib/grafana/security.key
chmod 400 /var/lib/grafana/security.key
chown grafana:grafana /var/lib/grafana/security.key
fi
'';
};
}

80
influxdb.nix Normal file
View file

@ -0,0 +1,80 @@
{ config, lib, pkgs, ... }:
{
environment.systemPackages = [ pkgs.influxdb ];
services.influxdb = {
enable = true;
dataDir = "/var/lib/influxdb";
extraConfig = {
meta.reporting-disabled = true;
data.query-log-enabled = false;
http.bind-address = "localhost:8086";
http.auth-enabled = false;
http.log-enabled = false;
};
};
systemd.services.influxdb = {
before = [ "grafana.service" ];
serviceConfig = {
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
LockPersonality = true;
PrivateDevices = true;
PrivateTmp = true;
PrivateUsers = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
ReadWritePaths = "/var/lib/influxdb";
RestrictAddressFamilies = [ "~AF_PACKET" "~AF_NETLINK" "~AF_UNIX" ];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
RemoveIPC = true;
SystemCallArchitectures = "native";
SystemCallFilter = [ "~@clock" "~@cpu-emulation" "~@debug" "~@module" "~@mount" "~@obsolete" "~@privileged" "~@raw-io" "~@reboot" "~@resources" "~@swap" ];
CapabilityBoundingSet = "";
IPAddressDeny = "any";
IPAddressAllow = "localhost";
UMask = "077";
RuntimeDirectory = "influxdb";
ExecStartPost = lib.mkForce [ (pkgs.writeShellScript "influxdb-first-run" ''
#!${pkgs.stdenv.shell}
set -euo pipefail
if [ ! -s /var/lib/influxdb/admin.pw ]; then
INIT=1
head -c 30 /dev/urandom | base64 > /var/lib/influxdb/admin.pw
chmod 400 /var/lib/influxdb/admin.pw
fi
if [ ! -s /var/lib/influxdb/knotendaten.pw ]; then
head -c 30 /dev/urandom | base64 > /var/lib/influxdb/knotendaten.pw
chmod 400 /var/lib/influxdb/knotendaten.pw
fi
if [ ! -s /var/lib/influxdb/grafana.pw ]; then
head -c 30 /dev/urandom | base64 > /var/lib/influxdb/grafana.pw
chmod 400 /var/lib/influxdb/grafana.pw
fi
until ${pkgs.curl}/bin/curl --connect-timeout 1 http://127.0.0.1:8086/ping; do
sleep 1
done
if [ -v INIT ]; then
read -r adminpw < /var/lib/influxdb/admin.pw
read -r knotendatenpw < /var/lib/influxdb/knotendaten.pw
read -r grafanapw < /var/lib/influxdb/grafana.pw
${config.services.influxdb.package}/bin/influx -execute 'create database freifunk'
${config.services.influxdb.package}/bin/influx -database freifunk -execute "create user admin with password '$adminpw'"
${config.services.influxdb.package}/bin/influx -database freifunk -execute "create user grafana with password '$grafanapw'"
${config.services.influxdb.package}/bin/influx -database freifunk -execute "create user knotendaten with password '$knotendatenpw'"
${config.services.influxdb.package}/bin/influx -database freifunk -execute "grant read on freifunk to grafana"
${config.services.influxdb.package}/bin/influx -database freifunk -execute "grant all on freifunk to admin"
fi
'') ];
};
};
}

17
nginx.nix Normal file
View file

@ -0,0 +1,17 @@
{ config, lib, pkgs, ... }:
{
networking.firewall.allowedTCPPorts = [ 80 ];
services.nginx = {
enable = true;
#logError = "/dev/null";
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
virtualHosts."stats" = {
default = true;
locations."/".proxyPass = "http://unix:${config.services.grafana.socket}:/";
};
};
}

32
sshusers.nix Normal file
View file

@ -0,0 +1,32 @@
{ lib, pkgs, ... }:
# Setup users. To add a new user:
# 1. Add the name of the user to the list in the second-to-last line
# 2. Make sure that the git repo contains the key as "$USER.pub"
# 3. Make sure that the commit ("rev") contains the latest commit hash. If it correct, jump to step 7.
# 4. If you changed the commit, manipulate the sha512 entry by changing the first character from 0 to 1 or 1 to 0.
# 5. Run "nixos-rebuild build"
# 6. Wait for a message about an invalid hash and replace the hash in this file with the new one.
# 7. Run "nixos-rebuild switch"
# 8. Let the user login and change their password
let
sshkeys = pkgs.fetchFromGitHub {
owner = "freifunkhamburg";
repo = "ssh-keys";
rev = "286c324f0c0c9ddfd37eee286d064b36dc5e4c2c";
sha512 = "034d5y75wr8vyz3r222hxar1wm0vmqryvgcji2lh1f8jxpgs3nchb0w2qv44msz085s9p4i92s96z9cb8zapmwj3anm0p8f156pf34c";
};
getpubkeys = user: builtins.readFile "${sshkeys}/${user}.pub";
mkuser = user: { name = user; isNormalUser = true; extraGroups = [ "wheel" ]; initialPassword = "test1234"; openssh.authorizedKeys.keys = [ (getpubkeys user) ]; };
in
{
services.openssh = {
enable = true;
# Only allow login through pubkey
passwordAuthentication = false;
challengeResponseAuthentication = false;
};
users.users = lib.genAttrs [ "tokudan" ] mkuser ;
}