forked from M-Labs/it-infra
import from nix-scripts
This commit is contained in:
commit
5a0afc48d4
|
@ -0,0 +1,54 @@
|
||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
makeBackup = pkgs.writeScript "make-backup" ''
|
||||||
|
#!${pkgs.bash}/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
umask 0077
|
||||||
|
|
||||||
|
DBDUMPDIR=`mktemp -d`
|
||||||
|
pushd $DBDUMPDIR
|
||||||
|
|
||||||
|
${config.services.mysql.package}/bin/mysqldump --single-transaction flarum > flarum.sql
|
||||||
|
${pkgs.sudo}/bin/sudo -u mattermost ${config.services.postgresql.package}/bin/pg_dump mattermost > mattermost.sql
|
||||||
|
|
||||||
|
${pkgs.gnutar}/bin/tar cf - --exclude "/var/lib/gitea/repositories/*/*.git/archives" /etc/nixos /var/lib/gitea flarum.sql mattermost.sql | \
|
||||||
|
${pkgs.bzip2}/bin/bzip2 | \
|
||||||
|
${pkgs.gnupg}/bin/gpg --symmetric --batch --passphrase-file /etc/nixos/secret/backup-passphrase | \
|
||||||
|
${pkgs.rclone}/bin/rclone rcat --config /etc/nixos/secret/rclone.conf dropbox:backup-`date +%F`.tar.bz2.gpg
|
||||||
|
|
||||||
|
popd
|
||||||
|
rm -rf $DBDUMPDIR
|
||||||
|
|
||||||
|
echo Backup done
|
||||||
|
'';
|
||||||
|
cfg = config.services.mlabs-backup;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.services.mlabs-backup = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "Enable backups";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
systemd.services.mlabs-backup = {
|
||||||
|
description = "M-Labs backup";
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
User = "root";
|
||||||
|
Group = "root";
|
||||||
|
ExecStart = "${makeBackup}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.timers.mlabs-backup = {
|
||||||
|
description = "M-Labs backup";
|
||||||
|
wantedBy = [ "timers.target" ];
|
||||||
|
timerConfig.OnCalendar = "weekly";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,667 @@
|
||||||
|
# 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, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
netifWan = "enp0s31f6";
|
||||||
|
netifLan = "enp3s0";
|
||||||
|
netifWifi = "wlp1s0";
|
||||||
|
netifSit = "henet0";
|
||||||
|
hydraWwwOutputs = "/var/www/hydra-outputs";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports =
|
||||||
|
[
|
||||||
|
./hardware-configuration.nix
|
||||||
|
./homu/nixos-module.nix
|
||||||
|
./backup-module.nix
|
||||||
|
(builtins.fetchTarball {
|
||||||
|
url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/v2.3.0/nixos-mailserver-v2.3.0.tar.gz";
|
||||||
|
sha256 = "0lpz08qviccvpfws2nm83n7m2r8add2wvfg9bljx9yxx8107r919";
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
# Use the systemd-boot EFI boot loader.
|
||||||
|
boot.loader.systemd-boot.enable = true;
|
||||||
|
boot.loader.efi.canTouchEfiVariables = true;
|
||||||
|
boot.blacklistedKernelModules = ["iwlwifi"];
|
||||||
|
|
||||||
|
security.apparmor.enable = true;
|
||||||
|
|
||||||
|
networking = {
|
||||||
|
hostName = "nixbld";
|
||||||
|
firewall = {
|
||||||
|
allowedTCPPorts = [ 80 443 ];
|
||||||
|
allowedUDPPorts = [ 53 67 ];
|
||||||
|
trustedInterfaces = [ netifLan ];
|
||||||
|
};
|
||||||
|
interfaces."${netifLan}" = {
|
||||||
|
ipv4.addresses = [{
|
||||||
|
address = "192.168.1.1";
|
||||||
|
prefixLength = 24;
|
||||||
|
}];
|
||||||
|
ipv6.addresses = [{
|
||||||
|
address = "2001:470:f821:1::";
|
||||||
|
prefixLength = 64;
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
interfaces."${netifWifi}" = {
|
||||||
|
ipv4.addresses = [{
|
||||||
|
address = "192.168.12.1";
|
||||||
|
prefixLength = 24;
|
||||||
|
}];
|
||||||
|
ipv6.addresses = [{
|
||||||
|
address = "2001:470:f821:2::";
|
||||||
|
prefixLength = 64;
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
nat = {
|
||||||
|
enable = true;
|
||||||
|
externalInterface = netifWan;
|
||||||
|
internalInterfaces = [ netifLan netifWifi ];
|
||||||
|
forwardPorts = [
|
||||||
|
{ sourcePort = 2201; destination = "192.168.1.201:22"; proto = "tcp"; }
|
||||||
|
{ sourcePort = 2202; destination = "192.168.1.202:22"; proto = "tcp"; }
|
||||||
|
{ sourcePort = 2203; destination = "192.168.1.203:22"; proto = "tcp"; }
|
||||||
|
{ sourcePort = 2204; destination = "192.168.1.204:22"; proto = "tcp"; }
|
||||||
|
{ sourcePort = 2205; destination = "192.168.1.205:22"; proto = "tcp"; }
|
||||||
|
];
|
||||||
|
extraCommands = ''
|
||||||
|
iptables -w -N block-lan-from-wifi
|
||||||
|
iptables -w -A block-lan-from-wifi -i ${netifLan} -o ${netifWifi} -j DROP
|
||||||
|
iptables -w -A block-lan-from-wifi -i ${netifWifi} -o ${netifLan} -j DROP
|
||||||
|
iptables -w -A FORWARD -j block-lan-from-wifi
|
||||||
|
'';
|
||||||
|
extraStopCommands = ''
|
||||||
|
iptables -w -D FORWARD -j block-lan-from-wifi 2>/dev/null|| true
|
||||||
|
iptables -w -F block-lan-from-wifi 2>/dev/null|| true
|
||||||
|
iptables -w -X block-lan-from-wifi 2>/dev/null|| true
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
sits."${netifSit}" = {
|
||||||
|
dev = netifWan;
|
||||||
|
remote = "216.218.221.6";
|
||||||
|
local = "42.200.147.171";
|
||||||
|
ttl = 255;
|
||||||
|
};
|
||||||
|
interfaces."${netifSit}".ipv6 = {
|
||||||
|
addresses = [{ address = "2001:470:18:629::2"; prefixLength = 64; }];
|
||||||
|
routes = [{ address = "::"; prefixLength = 0; }];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = "1";
|
||||||
|
boot.kernel.sysctl."net.ipv6.conf.default.forwarding" = "1";
|
||||||
|
|
||||||
|
services.unbound = {
|
||||||
|
enable = true;
|
||||||
|
extraConfig =
|
||||||
|
''
|
||||||
|
server:
|
||||||
|
port: 5353
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
services.hostapd = {
|
||||||
|
enable = true;
|
||||||
|
interface = netifWifi;
|
||||||
|
hwMode = "g";
|
||||||
|
ssid = "M-Labs";
|
||||||
|
wpaPassphrase = (import /etc/nixos/secret/wifi_password.nix);
|
||||||
|
extraConfig = ''
|
||||||
|
ieee80211d=1
|
||||||
|
country_code=HK
|
||||||
|
ieee80211n=1
|
||||||
|
wmm_enabled=1
|
||||||
|
auth_algs=1
|
||||||
|
wpa_key_mgmt=WPA-PSK
|
||||||
|
rsn_pairwise=CCMP
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
services.dnsmasq = {
|
||||||
|
enable = true;
|
||||||
|
servers = ["::1#5353"];
|
||||||
|
extraConfig = ''
|
||||||
|
interface=${netifLan}
|
||||||
|
interface=${netifWifi}
|
||||||
|
bind-interfaces
|
||||||
|
dhcp-range=interface:${netifLan},192.168.1.81,192.168.1.254,24h
|
||||||
|
dhcp-range=interface:${netifWifi},192.168.12.10,192.168.12.254,24h
|
||||||
|
enable-ra
|
||||||
|
dhcp-range=interface:${netifLan},::,constructor:${netifLan},ra-names
|
||||||
|
dhcp-range=interface:${netifWifi},::,constructor:${netifWifi},ra-only
|
||||||
|
|
||||||
|
no-resolv
|
||||||
|
|
||||||
|
# Static IPv4s to make Red Pitayas less annoying
|
||||||
|
dhcp-host=rp-f05cc9,192.168.1.190
|
||||||
|
dhcp-host=rp-f0612e,192.168.1.191
|
||||||
|
# Static IPv4s to make port redirections work
|
||||||
|
dhcp-host=rpi-1,192.168.1.201
|
||||||
|
dhcp-host=rpi-2,192.168.1.202
|
||||||
|
dhcp-host=rpi-3,192.168.1.203
|
||||||
|
dhcp-host=rpi-4,192.168.1.204
|
||||||
|
dhcp-host=rpi-5,192.168.1.205
|
||||||
|
|
||||||
|
# Default IP addresses for ARTIQ boards
|
||||||
|
address=/thermostat/192.168.1.26
|
||||||
|
address=/kc705/192.168.1.50
|
||||||
|
address=/zc706/192.168.1.51
|
||||||
|
address=/zc706-2/192.168.1.52
|
||||||
|
address=/sayma/192.168.1.60
|
||||||
|
address=/metlino/192.168.1.65
|
||||||
|
address=/kasli/192.168.1.70
|
||||||
|
address=/kasli-customer/192.168.1.75
|
||||||
|
address=/stabilizer-customer/192.168.1.76
|
||||||
|
# uTCA MCH from NAT
|
||||||
|
address=/tschernobyl/192.168.1.80
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# Select internationalisation properties.
|
||||||
|
i18n.defaultLocale = "en_US.UTF-8";
|
||||||
|
console = {
|
||||||
|
font = "Lat2-Terminus16";
|
||||||
|
keyMap = "de";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Set your time zone.
|
||||||
|
time.timeZone = "Asia/Hong_Kong";
|
||||||
|
|
||||||
|
# List packages installed in system profile. To search, run:
|
||||||
|
# $ nix search wget
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
wget vim git file lm_sensors acpi pciutils psmisc telnet nixops
|
||||||
|
irssi tmux usbutils imagemagick jq zip unzip
|
||||||
|
];
|
||||||
|
|
||||||
|
# Some programs need SUID wrappers, can be configured further or are
|
||||||
|
# started in user sessions.
|
||||||
|
# programs.mtr.enable = true;
|
||||||
|
# programs.gnupg.agent = { enable = true; enableSSHSupport = true; };
|
||||||
|
|
||||||
|
# List services that you want to enable:
|
||||||
|
|
||||||
|
services.apcupsd.enable = true;
|
||||||
|
services.apcupsd.configText = ''
|
||||||
|
UPSTYPE usb
|
||||||
|
NISIP 127.0.0.1
|
||||||
|
BATTERYLEVEL 10
|
||||||
|
MINUTES 5
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Enable the OpenSSH daemon.
|
||||||
|
services.openssh.enable = true;
|
||||||
|
services.openssh.forwardX11 = true;
|
||||||
|
services.openssh.passwordAuthentication = false;
|
||||||
|
programs.mosh.enable = true;
|
||||||
|
|
||||||
|
programs.fish.enable = true;
|
||||||
|
|
||||||
|
# Enable CUPS to print documents.
|
||||||
|
services.avahi.enable = true;
|
||||||
|
services.avahi.interfaces = [ netifLan ];
|
||||||
|
services.avahi.publish.enable = true;
|
||||||
|
services.avahi.publish.userServices = true;
|
||||||
|
nixpkgs.config.allowUnfree = true;
|
||||||
|
services.printing.enable = true;
|
||||||
|
services.printing.drivers = [ pkgs.hplipWithPlugin ];
|
||||||
|
services.printing.browsing = true;
|
||||||
|
services.printing.listenAddresses = [ "*:631" ];
|
||||||
|
services.printing.defaultShared = true;
|
||||||
|
hardware.sane.enable = true;
|
||||||
|
hardware.sane.extraBackends = [ pkgs.hplipWithPlugin ];
|
||||||
|
|
||||||
|
users.extraGroups.plugdev = { };
|
||||||
|
users.extraUsers.sb = {
|
||||||
|
isNormalUser = true;
|
||||||
|
extraGroups = ["wheel" "plugdev" "dialout" "lp" "scanner"];
|
||||||
|
shell = pkgs.fish;
|
||||||
|
openssh.authorizedKeys.keys = [
|
||||||
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCyPk5WyFoWSvF4ozehxcVBoZ+UHgrI7VW/OoQfFFwIQe0qvetUZBMZwR2FwkLPAMZV8zz1v4EfncudEkVghy4P+/YVLlDjqDq9zwZnh8Nd/ifu84wmcNWHT2UcqnhjniCdshL8a44memzABnxfLLv+sXhP2x32cJAamo5y6fukr2qLp2jbXzR+3sv3klE0ruUXis/BR1lLqNJEYP8jB6fLn2sLKinnZPfn6DwVOk10mGeQsdME/eGl3phpjhODH9JW5V2V5nJBbC0rBnq+78dyArKVqjPSmIcSy72DEIpTctnMEN1W34BGrnsDd5Xd/DKxKxHKTMCHtZRwLC2X0NWN"
|
||||||
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCMALVC8RDTHec+PC8y1s3tcpUAODgq6DEzQdHDf/cyvDMfmCaPiMxfIdmkns5lMa03hymIfSmLUF0jFFDc7biRp7uf9AAXNsrTmplHii0l0McuOOZGlSdZM4eL817P7UwJqFMxJyFXDjkubhQiX6kp25Kfuj/zLnupRCaiDvE7ho/xay6Jrv0XLz935TPDwkc7W1asLIvsZLheB+sRz9SMOb9gtrvk5WXZl5JTOFOLu+JaRwQLHL/xdcHJTOod7tqHYfpoC5JHrEwKzbhTOwxZBQBfTQjQktKENQtBxXHTe71rUEWfEZQGg60/BC4BrRmh4qJjlJu3v4VIhC7SSHn1"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
users.extraUsers.rj = {
|
||||||
|
isNormalUser = true;
|
||||||
|
extraGroups = ["wheel" "plugdev" "dialout"];
|
||||||
|
};
|
||||||
|
users.extraUsers.astro = {
|
||||||
|
isNormalUser = true;
|
||||||
|
extraGroups = ["plugdev" "dialout"];
|
||||||
|
shell = pkgs.bashInteractive;
|
||||||
|
};
|
||||||
|
users.extraUsers.nix = {
|
||||||
|
isNormalUser = true;
|
||||||
|
};
|
||||||
|
security.sudo.wheelNeedsPassword = false;
|
||||||
|
security.hideProcessInformation = true;
|
||||||
|
boot.kernel.sysctl."kernel.dmesg_restrict" = true;
|
||||||
|
services.udev.packages = [ pkgs.sane-backends ];
|
||||||
|
|
||||||
|
nix.distributedBuilds = true;
|
||||||
|
nix.buildMachines = [
|
||||||
|
{
|
||||||
|
hostName = "localhost";
|
||||||
|
maxJobs = 4;
|
||||||
|
system = "x86_64-linux";
|
||||||
|
supportedFeatures = ["big-parallel"];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
hostName = "rpi-3";
|
||||||
|
sshUser = "nix";
|
||||||
|
sshKey = "/etc/nixos/secret/nix_id_rsa";
|
||||||
|
maxJobs = 1;
|
||||||
|
system = "aarch64-linux";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
services.hydra = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.hydra-unstable;
|
||||||
|
useSubstitutes = true;
|
||||||
|
hydraURL = "https://nixbld.m-labs.hk";
|
||||||
|
notificationSender = "hydra@m-labs.hk";
|
||||||
|
minimumDiskFree = 15; # in GB
|
||||||
|
minimumDiskFreeEvaluator = 1;
|
||||||
|
extraConfig =
|
||||||
|
''
|
||||||
|
binary_cache_secret_key_file = /etc/nixos/secret/nixbld.m-labs.hk-1
|
||||||
|
max_output_size = 10000000000
|
||||||
|
|
||||||
|
<runcommand>
|
||||||
|
job = web:web:web
|
||||||
|
command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/web
|
||||||
|
</runcommand>
|
||||||
|
|
||||||
|
<runcommand>
|
||||||
|
job = artiq:full:sipyco-manual-html
|
||||||
|
command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/sipyco-manual-html
|
||||||
|
</runcommand>
|
||||||
|
<runcommand>
|
||||||
|
job = artiq:full:sipyco-manual-latexpdf
|
||||||
|
command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/sipyco-manual-latexpdf
|
||||||
|
</runcommand>
|
||||||
|
|
||||||
|
<runcommand>
|
||||||
|
job = artiq:full-beta:artiq-manual-html
|
||||||
|
command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/artiq-manual-html-beta
|
||||||
|
</runcommand>
|
||||||
|
<runcommand>
|
||||||
|
job = artiq:full-beta:artiq-manual-latexpdf
|
||||||
|
command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/artiq-manual-latexpdf-beta
|
||||||
|
</runcommand>
|
||||||
|
<runcommand>
|
||||||
|
job = artiq:full-beta:conda-channel
|
||||||
|
command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/artiq-conda-channel-beta
|
||||||
|
</runcommand>
|
||||||
|
|
||||||
|
<runcommand>
|
||||||
|
job = artiq:full:artiq-manual-html
|
||||||
|
command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/artiq-manual-html
|
||||||
|
</runcommand>
|
||||||
|
<runcommand>
|
||||||
|
job = artiq:full:artiq-manual-latexpdf
|
||||||
|
command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/artiq-manual-latexpdf
|
||||||
|
</runcommand>
|
||||||
|
<runcommand>
|
||||||
|
job = artiq:full:conda-channel
|
||||||
|
command = [ $(jq '.buildStatus' < $HYDRA_JSON) = 0 ] && ln -sfn $(jq -r '.outputs[0].path' < $HYDRA_JSON) ${hydraWwwOutputs}/artiq-conda-channel
|
||||||
|
</runcommand>
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
systemd.services.hydra-www-outputs-init = {
|
||||||
|
description = "Set up a hydra-owned directory for build outputs";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
requiredBy = [ "hydra-queue-runner.service" ];
|
||||||
|
before = [ "hydra-queue-runner.service" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = [ "${pkgs.coreutils}/bin/mkdir -p ${hydraWwwOutputs}" "${pkgs.coreutils}/bin/chown hydra-queue-runner:hydra ${hydraWwwOutputs}" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
nix.extraOptions = ''
|
||||||
|
secret-key-files = /etc/nixos/secret/nixbld.m-labs.hk-1
|
||||||
|
'';
|
||||||
|
nix.sandboxPaths = ["/opt"];
|
||||||
|
|
||||||
|
services.munin-node.enable = true;
|
||||||
|
services.munin-cron = {
|
||||||
|
enable = true;
|
||||||
|
hosts = ''
|
||||||
|
[${config.networking.hostName}]
|
||||||
|
address localhost
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
services.mlabs-backup.enable = true;
|
||||||
|
|
||||||
|
services.gitea = {
|
||||||
|
enable = true;
|
||||||
|
httpPort = 3001;
|
||||||
|
rootUrl = "https://git.m-labs.hk/";
|
||||||
|
appName = "M-Labs Git";
|
||||||
|
cookieSecure = true;
|
||||||
|
disableRegistration = true;
|
||||||
|
mailerPasswordFile = "/etc/nixos/secret/mailerpassword";
|
||||||
|
extraConfig =
|
||||||
|
''
|
||||||
|
[mailer]
|
||||||
|
ENABLED = true
|
||||||
|
HOST = ssl.serverraum.org:587
|
||||||
|
FROM = sysop@m-labs.hk
|
||||||
|
USER = sysop@m-labs.hk
|
||||||
|
|
||||||
|
[service]
|
||||||
|
ENABLE_NOTIFY_MAIL = true
|
||||||
|
|
||||||
|
[attachment]
|
||||||
|
ALLOWED_TYPES = */*
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"L+ '${config.services.gitea.stateDir}/custom/templates/home.tmpl' - - - - ${./gitea-home.tmpl}"
|
||||||
|
];
|
||||||
|
|
||||||
|
services.mattermost = {
|
||||||
|
enable = true;
|
||||||
|
siteUrl = "https://chat.m-labs.hk/";
|
||||||
|
mutableConfig = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.matterbridge = {
|
||||||
|
enable = true;
|
||||||
|
configPath = "/etc/nixos/secret/matterbridge.toml";
|
||||||
|
};
|
||||||
|
|
||||||
|
nixpkgs.config.packageOverrides = super: let self = super.pkgs; in {
|
||||||
|
hydra-unstable = super.hydra-unstable.overrideAttrs(oa: {
|
||||||
|
patches = oa.patches or [] ++ [ ./hydra-conda.patch ./hydra-retry.patch ./hydra-unbreak-sysbuild.patch ];
|
||||||
|
hydraPath = oa.hydraPath + ":" + super.lib.makeBinPath [ super.jq ];
|
||||||
|
});
|
||||||
|
matterbridge = super.matterbridge.overrideAttrs(oa: {
|
||||||
|
patches = oa.patches or [] ++ [ ./matterbridge-disable-github.patch ];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
security.acme.acceptTerms = true;
|
||||||
|
security.acme.email = "sb" + "@m-labs.hk";
|
||||||
|
security.acme.certs = {
|
||||||
|
"nixbld.m-labs.hk" = {
|
||||||
|
group = "nginx";
|
||||||
|
user = "nginx";
|
||||||
|
webroot = "/var/lib/acme/acme-challenge";
|
||||||
|
extraDomains = {
|
||||||
|
"m-labs.hk" = null;
|
||||||
|
"www.m-labs.hk" = null;
|
||||||
|
"conda.m-labs.hk" = null;
|
||||||
|
"lab.m-labs.hk" = null;
|
||||||
|
"git.m-labs.hk" = null;
|
||||||
|
"chat.m-labs.hk" = null;
|
||||||
|
"hooks.m-labs.hk" = null;
|
||||||
|
"forum.m-labs.hk" = null;
|
||||||
|
"perso.m-labs.hk" = null;
|
||||||
|
"nmigen.org" = null;
|
||||||
|
"www.nmigen.org" = null;
|
||||||
|
|
||||||
|
"openhardware.hk" = null;
|
||||||
|
"git.openhardware.hk" = null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
services.nginx = {
|
||||||
|
enable = true;
|
||||||
|
recommendedProxySettings = true;
|
||||||
|
recommendedGzipSettings = true;
|
||||||
|
virtualHosts = let
|
||||||
|
mainWebsite = {
|
||||||
|
addSSL = true;
|
||||||
|
useACMEHost = "nixbld.m-labs.hk";
|
||||||
|
root = "${hydraWwwOutputs}/web";
|
||||||
|
extraConfig = ''
|
||||||
|
error_page 404 /404.html;
|
||||||
|
'';
|
||||||
|
locations."^~ /fonts/".extraConfig = ''
|
||||||
|
expires 60d;
|
||||||
|
'';
|
||||||
|
locations."^~ /js/".extraConfig = ''
|
||||||
|
expires 60d;
|
||||||
|
'';
|
||||||
|
locations."/MathJax/" = {
|
||||||
|
alias = "/var/www/MathJax/";
|
||||||
|
extraConfig = ''
|
||||||
|
expires 60d;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# legacy URLs, redirect to avoid breaking people's bookmarks
|
||||||
|
locations."/gateware.html".extraConfig = ''
|
||||||
|
return 301 /gateware/migen/;
|
||||||
|
'';
|
||||||
|
locations."/migen".extraConfig = ''
|
||||||
|
return 301 /gateware/migen/;
|
||||||
|
'';
|
||||||
|
locations."/artiq".extraConfig = ''
|
||||||
|
return 301 /experiment-control/artiq/;
|
||||||
|
'';
|
||||||
|
locations."/artiq/resources.html".extraConfig = ''
|
||||||
|
return 301 /experiment-control/resources/;
|
||||||
|
'';
|
||||||
|
|
||||||
|
# autogenerated manuals
|
||||||
|
locations."/artiq/sipyco-manual/" = {
|
||||||
|
alias = "${hydraWwwOutputs}/sipyco-manual-html/share/doc/sipyco-manual/html/";
|
||||||
|
};
|
||||||
|
locations."=/artiq/sipyco-manual.pdf" = {
|
||||||
|
alias = "${hydraWwwOutputs}/sipyco-manual-latexpdf/share/doc/sipyco-manual/SiPyCo.pdf";
|
||||||
|
};
|
||||||
|
locations."/artiq/manual-beta/" = {
|
||||||
|
alias = "${hydraWwwOutputs}/artiq-manual-html-beta/share/doc/artiq-manual/html/";
|
||||||
|
};
|
||||||
|
locations."=/artiq/manual-beta.pdf" = {
|
||||||
|
alias = "${hydraWwwOutputs}/artiq-manual-latexpdf-beta/share/doc/artiq-manual/ARTIQ.pdf";
|
||||||
|
};
|
||||||
|
locations."/artiq/manual/" = {
|
||||||
|
alias = "${hydraWwwOutputs}/artiq-manual-html/share/doc/artiq-manual/html/";
|
||||||
|
};
|
||||||
|
locations."=/artiq/manual.pdf" = {
|
||||||
|
alias = "${hydraWwwOutputs}/artiq-manual-latexpdf/share/doc/artiq-manual/ARTIQ.pdf";
|
||||||
|
};
|
||||||
|
|
||||||
|
# legacy content
|
||||||
|
locations."/migen/manual/" = {
|
||||||
|
alias = "/var/www/m-labs.hk.old/migen/manual/";
|
||||||
|
};
|
||||||
|
locations."/artiq/manual-release-4/" = {
|
||||||
|
alias = "/var/www/m-labs.hk.old/artiq/manual-release-4/";
|
||||||
|
};
|
||||||
|
locations."/artiq/manual-release-3/" = {
|
||||||
|
alias = "/var/www/m-labs.hk.old/artiq/manual-release-3/";
|
||||||
|
};
|
||||||
|
locations."/artiq/manual-release-2/" = {
|
||||||
|
alias = "/var/www/m-labs.hk.old/artiq/manual-release-2/";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
"m-labs.hk" = mainWebsite;
|
||||||
|
"www.m-labs.hk" = mainWebsite;
|
||||||
|
"lab.m-labs.hk" = {
|
||||||
|
addSSL = true;
|
||||||
|
useACMEHost = "nixbld.m-labs.hk";
|
||||||
|
locations."/munin/".alias = "/var/www/munin/";
|
||||||
|
locations."/munin".extraConfig = ''
|
||||||
|
auth_basic "Munin";
|
||||||
|
auth_basic_user_file /etc/nixos/secret/muninpasswd;
|
||||||
|
'';
|
||||||
|
locations."/homu/".proxyPass = "http://127.0.0.1:54856/";
|
||||||
|
};
|
||||||
|
"nixbld.m-labs.hk" = {
|
||||||
|
forceSSL = true;
|
||||||
|
useACMEHost = "nixbld.m-labs.hk";
|
||||||
|
locations."/".proxyPass = "http://127.0.0.1:3000";
|
||||||
|
};
|
||||||
|
"conda.m-labs.hk" = {
|
||||||
|
forceSSL = true;
|
||||||
|
useACMEHost = "nixbld.m-labs.hk";
|
||||||
|
locations."/artiq-beta/" = {
|
||||||
|
alias = "${hydraWwwOutputs}/artiq-conda-channel-beta/";
|
||||||
|
extraConfig = ''
|
||||||
|
autoindex on;
|
||||||
|
index bogus_index_file;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
locations."/artiq/" = {
|
||||||
|
alias = "${hydraWwwOutputs}/artiq-conda-channel/";
|
||||||
|
extraConfig = ''
|
||||||
|
autoindex on;
|
||||||
|
index bogus_index_file;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"git.m-labs.hk" = {
|
||||||
|
forceSSL = true;
|
||||||
|
useACMEHost = "nixbld.m-labs.hk";
|
||||||
|
locations."/".proxyPass = "http://127.0.0.1:3001";
|
||||||
|
extraConfig = ''
|
||||||
|
client_max_body_size 300M;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
"chat.m-labs.hk" = {
|
||||||
|
forceSSL = true;
|
||||||
|
useACMEHost = "nixbld.m-labs.hk";
|
||||||
|
locations."/".proxyPass = "http://127.0.0.1:8065";
|
||||||
|
locations."~ /api/v[0-9]+/(users/)?websocket$".proxyPass = "http://127.0.0.1:8065";
|
||||||
|
locations."~ /api/v[0-9]+/(users/)?websocket$".proxyWebsockets = true;
|
||||||
|
};
|
||||||
|
"hooks.m-labs.hk" = {
|
||||||
|
forceSSL = true;
|
||||||
|
useACMEHost = "nixbld.m-labs.hk";
|
||||||
|
locations."/mattermost-github".extraConfig = ''
|
||||||
|
include ${pkgs.nginx}/conf/uwsgi_params;
|
||||||
|
uwsgi_pass unix:${config.services.uwsgi.runDir}/uwsgi-mgi.sock;
|
||||||
|
'';
|
||||||
|
locations."/rfq".extraConfig = ''
|
||||||
|
include ${pkgs.nginx}/conf/uwsgi_params;
|
||||||
|
uwsgi_pass unix:${config.services.uwsgi.runDir}/uwsgi-rfq.sock;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
"forum.m-labs.hk" = {
|
||||||
|
forceSSL = true;
|
||||||
|
useACMEHost = "nixbld.m-labs.hk";
|
||||||
|
root = "/var/www/flarum/public";
|
||||||
|
locations."~ \.php$".extraConfig = ''
|
||||||
|
fastcgi_pass unix:${config.services.phpfpm.pools.flarum.socket};
|
||||||
|
fastcgi_index index.php;
|
||||||
|
'';
|
||||||
|
extraConfig = ''
|
||||||
|
index index.php;
|
||||||
|
include /var/www/flarum/.nginx.conf;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
"perso.m-labs.hk" = {
|
||||||
|
addSSL = true;
|
||||||
|
useACMEHost = "nixbld.m-labs.hk";
|
||||||
|
root = "/var/www/perso";
|
||||||
|
};
|
||||||
|
"nmigen.org" = {
|
||||||
|
addSSL = true;
|
||||||
|
useACMEHost = "nixbld.m-labs.hk";
|
||||||
|
locations."/".extraConfig = ''
|
||||||
|
return 307 https://m-labs.hk/gateware/nmigen/;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
"www.nmigen.org" = {
|
||||||
|
addSSL = true;
|
||||||
|
useACMEHost = "nixbld.m-labs.hk";
|
||||||
|
locations."/".extraConfig = ''
|
||||||
|
return 307 https://m-labs.hk/gateware/nmigen/;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
"git.openhardware.hk" = {
|
||||||
|
forceSSL = true;
|
||||||
|
useACMEHost = "nixbld.m-labs.hk";
|
||||||
|
locations."/".proxyPass = "http://127.0.0.1:3002";
|
||||||
|
extraConfig = ''
|
||||||
|
client_max_body_size 300M;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
services.uwsgi = {
|
||||||
|
enable = true;
|
||||||
|
plugins = [ "python3" ];
|
||||||
|
instance = {
|
||||||
|
type = "emperor";
|
||||||
|
vassals = {
|
||||||
|
mattermostgithub = import ./mattermost-github-integration/uwsgi-config.nix { inherit config pkgs; };
|
||||||
|
rfq = import ./rfq/uwsgi-config.nix { inherit config pkgs; };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
services.mysql = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.mariadb;
|
||||||
|
};
|
||||||
|
services.phpfpm.pools.flarum = {
|
||||||
|
user = "nobody";
|
||||||
|
settings = {
|
||||||
|
"listen.owner" = "nginx";
|
||||||
|
"listen.group" = "nginx";
|
||||||
|
"listen.mode" = "0600";
|
||||||
|
"pm" = "dynamic";
|
||||||
|
"pm.max_children" = 5;
|
||||||
|
"pm.start_servers" = 2;
|
||||||
|
"pm.min_spare_servers" = 1;
|
||||||
|
"pm.max_spare_servers" = 3;
|
||||||
|
"pm.max_requests" = 500;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.homu = {
|
||||||
|
enable = true;
|
||||||
|
config = "/etc/nixos/secret/homu.toml";
|
||||||
|
};
|
||||||
|
|
||||||
|
mailserver = {
|
||||||
|
enable = true;
|
||||||
|
localDnsResolver = false; # conflicts with dnsmasq
|
||||||
|
# Some mail servers do reverse DNS lookups to filter spam.
|
||||||
|
# Getting a proper reverse DNS record from ISP is difficult, so use whatever already exists.
|
||||||
|
fqdn = "42-200-147-171.static.imsbiz.com";
|
||||||
|
domains = [ "nmigen.org" ];
|
||||||
|
loginAccounts = (import /etc/nixos/secret/email_accounts.nix);
|
||||||
|
certificateScheme = 3;
|
||||||
|
};
|
||||||
|
security.acme.certs."${config.mailserver.fqdn}".extraDomains = {
|
||||||
|
"mail.nmigen.org" = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
containers.openhardwarehk = {
|
||||||
|
autoStart = true;
|
||||||
|
config =
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
{
|
||||||
|
services.gitea = {
|
||||||
|
enable = true;
|
||||||
|
httpPort = 3002;
|
||||||
|
rootUrl = "https://git.openhardware.hk/";
|
||||||
|
appName = "Open Hardware HK";
|
||||||
|
cookieSecure = true;
|
||||||
|
disableRegistration = true;
|
||||||
|
extraConfig =
|
||||||
|
''
|
||||||
|
[attachment]
|
||||||
|
ALLOWED_TYPES = */*
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# 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 = "18.09"; # Did you read the comment?
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
{{template "base/head" .}}
|
||||||
|
<div class="home">
|
||||||
|
<div class="ui stackable middle very relaxed page grid">
|
||||||
|
<div class="sixteen wide center aligned centered column">
|
||||||
|
<div>
|
||||||
|
<img class="logo" src="{{AppSubUrl}}/img/gitea-lg.png" />
|
||||||
|
</div>
|
||||||
|
<div class="hero">
|
||||||
|
<h1 class="ui icon header title">
|
||||||
|
{{AppName}}
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ui stackable middle very relaxed page grid">
|
||||||
|
<div class="sixteen wide center column">
|
||||||
|
<p class="large">
|
||||||
|
Welcome! This Gitea instance is here to support projects related to <a href="https://m-labs.hk">M-Labs</a>. You may want to browse the <a href="https://git.m-labs.hk/M-Labs/">M-Labs organization</a> where many projects are located. If you would like an account (we give them to anyone who wants to contribute on projects related to Sinara, ARTIQ, nMigen, etc.), simply write a short email to sb@m-***.hk stating the username you would like to have.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{template "base/footer" .}}
|
|
@ -0,0 +1,13 @@
|
||||||
|
diff --git a/homu/git_helper.py b/homu/git_helper.py
|
||||||
|
index 0f70c69..f53fb57 100755
|
||||||
|
--- a/homu/git_helper.py
|
||||||
|
+++ b/homu/git_helper.py
|
||||||
|
@@ -7,7 +7,7 @@ SSH_KEY_FILE = os.path.join(os.path.dirname(__file__), '../cache/key')
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
- args = ['ssh', '-i', SSH_KEY_FILE, '-S', 'none'] + sys.argv[1:]
|
||||||
|
+ args = ['ssh', '-o', 'StrictHostKeyChecking=no', '-i', SSH_KEY_FILE, '-S', 'none'] + sys.argv[1:]
|
||||||
|
os.execvp('ssh', args)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
homu = pkgs.callPackage ./pkg.nix {};
|
||||||
|
cfg = config.services.homu;
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
options.services.homu = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "Enable the bot";
|
||||||
|
};
|
||||||
|
dbDir = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "/var/db/homu";
|
||||||
|
description = "Path to the database file (use the same path in config.toml)";
|
||||||
|
};
|
||||||
|
config = mkOption {
|
||||||
|
description = "Location of config.toml";
|
||||||
|
type = types.str;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
users.users.homu = {
|
||||||
|
group = "homu";
|
||||||
|
home = cfg.dbDir;
|
||||||
|
createHome = true;
|
||||||
|
};
|
||||||
|
users.groups.homu = {};
|
||||||
|
|
||||||
|
systemd.services.homu = {
|
||||||
|
description = "Homu bot";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
after = [ "network.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
ExecStart = "${homu}/bin/homu -c ${cfg.config}";
|
||||||
|
|
||||||
|
Restart = "always";
|
||||||
|
RestartSec = "5sec";
|
||||||
|
|
||||||
|
User = "homu";
|
||||||
|
Group = "homu";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
diff --git a/homu/git_helper.py b/homu/git_helper.py
|
||||||
|
index 0f70c69..732230c 100755
|
||||||
|
--- a/homu/git_helper.py
|
||||||
|
+++ b/homu/git_helper.py
|
||||||
|
@@ -3,7 +3,7 @@
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
-SSH_KEY_FILE = os.path.join(os.path.dirname(__file__), '../cache/key')
|
||||||
|
+SSH_KEY_FILE = os.path.expanduser("~/cache/key")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
diff --git a/homu/main.py b/homu/main.py
|
||||||
|
index 16b60a2..a2e109a 100644
|
||||||
|
--- a/homu/main.py
|
||||||
|
+++ b/homu/main.py
|
||||||
|
@@ -649,7 +649,7 @@ def git_push(git_cmd, branch, state):
|
||||||
|
|
||||||
|
|
||||||
|
def init_local_git_cmds(repo_cfg, git_cfg):
|
||||||
|
- fpath = 'cache/{}/{}'.format(repo_cfg['owner'], repo_cfg['name'])
|
||||||
|
+ fpath = '{}/cache/{}/{}'.format(os.path.expanduser("~"), repo_cfg['owner'], repo_cfg['name'])
|
||||||
|
url = 'git@github.com:{}/{}.git'.format(repo_cfg['owner'], repo_cfg['name']) # noqa
|
||||||
|
|
||||||
|
if not os.path.exists(SSH_KEY_FILE):
|
|
@ -0,0 +1,34 @@
|
||||||
|
{ python3Packages, python3, fetchFromGitHub, git, openssh }:
|
||||||
|
|
||||||
|
let
|
||||||
|
uritemplate_0_2_0 = python3Packages.github3_py.overrideAttrs(oa: rec {
|
||||||
|
version = "0.2.0";
|
||||||
|
src = python3Packages.fetchPypi {
|
||||||
|
pname = "uritemplate.py";
|
||||||
|
inherit version;
|
||||||
|
sha256 = "1pfk04pmnysz0383lwzgig8zqlwiv2n4pmq51f0mc60zz1jimq4g";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
github3_py_0_9_6 = python3Packages.github3_py.overrideAttrs(oa: rec {
|
||||||
|
version = "0.9.6";
|
||||||
|
src = python3Packages.fetchPypi {
|
||||||
|
pname = "github3.py";
|
||||||
|
inherit version;
|
||||||
|
sha256 = "1i8xnh586z4kka7pjl7cy08fmzjs14c8jdp8ykb9jjpzsy2xncdq";
|
||||||
|
};
|
||||||
|
propagatedBuildInputs = [ python3Packages.requests uritemplate_0_2_0 ];
|
||||||
|
});
|
||||||
|
in
|
||||||
|
python3Packages.buildPythonApplication {
|
||||||
|
name = "homu";
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "servo";
|
||||||
|
repo = "homu";
|
||||||
|
rev = "2ea53e76ebac3e5fa11bc39054b3cd4c42eff607";
|
||||||
|
sha256 = "1ih7s8zfbpq0qb9vqbxzr0r4s9ff52l4ipr916kwbck3ygliq3r9";
|
||||||
|
};
|
||||||
|
patches = [ ./patch-cache-directory.patch ./disable-ssh-host-keycheck.patch ];
|
||||||
|
postInstall = "chmod 755 $out/${python3.sitePackages}/homu/git_helper.py";
|
||||||
|
propagatedBuildInputs = [ github3_py_0_9_6 git openssh ] ++ (with python3Packages; [ toml jinja2 requests bottle waitress retrying ]);
|
||||||
|
checkPhase = "python -m unittest discover tests -v";
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
commit 5aa5f8d5742883d41d7278a2c8bc2c9a2ddfef45
|
||||||
|
Author: Sebastien Bourdeauducq <sb@m-labs.hk>
|
||||||
|
Date: Sun Apr 14 18:25:27 2019 +0800
|
||||||
|
|
||||||
|
add SVG icon for conda package
|
||||||
|
|
||||||
|
diff --git a/src/root/product-list.tt b/src/root/product-list.tt
|
||||||
|
index 298d0a66..85914bbd 100644
|
||||||
|
--- a/src/root/product-list.tt
|
||||||
|
+++ b/src/root/product-list.tt
|
||||||
|
@@ -157,6 +157,11 @@
|
||||||
|
<img src="[% c.uri_for("/static/images/debian.png") %]" alt="DEB" />
|
||||||
|
</td>
|
||||||
|
<td>Debian package</td>
|
||||||
|
+ [% CASE "conda" %]
|
||||||
|
+ <td>
|
||||||
|
+ <img src="[% c.uri_for("/static/images/conda.svg") %]" width="32" height="32" alt="Conda" />
|
||||||
|
+ </td>
|
||||||
|
+ <td>Conda package</td>
|
||||||
|
[% CASE "iso" %]
|
||||||
|
<td>
|
||||||
|
<img src="[% c.uri_for("/static/images/iso.png") %]" alt="ISO" />
|
||||||
|
diff --git a/src/root/static/images/conda.svg b/src/root/static/images/conda.svg
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..67859731
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/root/static/images/conda.svg
|
||||||
|
@@ -0,0 +1,18 @@
|
||||||
|
+<svg width="128" height="128" style="enable-background:new 0 0 128 128;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
+ <g id="g2">
|
||||||
|
+ <g>
|
||||||
|
+ <path d="M118.89,75.13c-1.31-2.72-3.46-5.53-6.97-7.33c-2.37-1.48-4.57-2.24-6.01-2.63 c1.53-5.6-0.64-10.06-3.69-13.39c-4.53-4.88-9.27-5.59-9.27-5.59l-0.01,0c1.56-3.03,2.15-6.54,1.36-9.99 c-1-4.26-3.29-6.94-6.31-8.73c-3.09-1.83-6.91-2.73-10.83-3.43c-1.88-0.34-9.81-1.45-13.1-6c-2.65-3.69-2.73-10.33-3.45-12.32 c-0.77-2.05-3.38-1.15-6.23,0.76c-3.33,2.22-10.23,9.35-12.89,16.49c-2.03,5.47-2.08,10.21-1.28,13.89 c-3.29,0.55-5.76,1.66-6.23,1.88c-0.16,0.05-0.32,0.1-0.49,0.17c-3.01,1.24-9.43,7.02-10.01,15.85c-0.2,3.14,0.21,6.31,1.2,9.26 c-3.94,1.1-6.22,2.54-6.26,2.57c-2,0.75-5.18,2.95-6.15,4.13c-1.97,2.38-3.34,5.21-4.15,8.18C6.35,85.36,7,92.71,10.14,98.67 c1.74,3.31,4.12,6.83,6.74,9.52c8.55,8.79,23.31,12.11,34.96,14.03c14.19,2.34,29.05,1.52,42.33-3.97 c19.92-8.22,25.22-21.44,26-25.17C121.92,84.77,119.8,77,118.89,75.13z" style="fill:#865D53;"/>
|
||||||
|
+ <g>
|
||||||
|
+ <g>
|
||||||
|
+ <ellipse cx="85.95" cy="66.39" rx="16.61" ry="15.5" style="fill:#FFFFFF;" transform="matrix(0.1106 -0.9939 0.9939 0.1106 10.453 144.4706)"/>
|
||||||
|
+ <path d="M92.63,66.36c-0.23,3.3-3.14,5.82-6.49,5.62c-3.36-0.19-5.9-3.04-5.67-6.34 c0.22-3.31,3.12-5.82,6.48-5.62C90.31,60.21,92.86,63.06,92.63,66.36" style="fill:#2F2F2F;"/>
|
||||||
|
+ </g>
|
||||||
|
+ <g>
|
||||||
|
+ <ellipse cx="42.46" cy="66.4" rx="15.5" ry="16.61" style="fill:#FFFFFF;" transform="matrix(0.9972 -0.0752 0.0752 0.9972 -4.8714 3.3796)"/>
|
||||||
|
+ <path d="M49.02,65.13c0.38,3.29-2.01,6.3-5.34,6.72c-3.34,0.43-6.36-1.9-6.74-5.18 c-0.4-3.29,1.99-6.3,5.33-6.73C45.6,59.52,48.63,61.85,49.02,65.13" style="fill:#2F2F2F;"/>
|
||||||
|
+ </g>
|
||||||
|
+ </g>
|
||||||
|
+ <path d="M87.35,89.46c-2.22-1.5-5.02-0.51-7.49,0c-6.9,1.42-12.95,1.48-15.86,1.48 c-2.91,0-8.96-0.06-15.86-1.48c-2.47-0.51-5.27-1.5-7.49,0c-2.82,1.9-0.74,8.74,3.7,13.36c2.68,2.79,9.07,8.21,19.66,8.21 c10.58,0,16.97-5.42,19.66-8.21C88.09,98.2,90.17,91.37,87.35,89.46z" style="fill:#ED6D31;"/>
|
||||||
|
+ </g>
|
||||||
|
+ </g>
|
||||||
|
+</svg>
|
||||||
|
\ No newline at end of file
|
|
@ -0,0 +1,19 @@
|
||||||
|
commit 86bf81c0b8a51bffa4b4b566e1caaac6f0e041d3
|
||||||
|
Author: Sebastien Bourdeauducq <sb@m-labs.hk>
|
||||||
|
Date: Thu Mar 14 17:45:32 2019 +0800
|
||||||
|
|
||||||
|
add option to disable retries on transient failures
|
||||||
|
|
||||||
|
diff --git a/src/hydra-queue-runner/build-remote.cc b/src/hydra-queue-runner/build-remote.cc
|
||||||
|
index 69c430eb..bdbc808d 100644
|
||||||
|
--- a/src/hydra-queue-runner/build-remote.cc
|
||||||
|
+++ b/src/hydra-queue-runner/build-remote.cc
|
||||||
|
@@ -344,7 +344,7 @@ void State::buildRemote(ref<Store> destStore,
|
||||||
|
break;
|
||||||
|
case BuildResult::TransientFailure:
|
||||||
|
result.stepStatus = bsFailed;
|
||||||
|
- result.canRetry = true;
|
||||||
|
+ result.canRetry = get(step->drv->env, "__hydraRetry").value_or("1") == "1";
|
||||||
|
result.errorMsg = "";
|
||||||
|
break;
|
||||||
|
case BuildResult::TimedOut:
|
|
@ -0,0 +1,25 @@
|
||||||
|
diff --git a/src/lib/Hydra/Schema/Builds.pm b/src/lib/Hydra/Schema/Builds.pm
|
||||||
|
index d4334300..014d07ce 100644
|
||||||
|
--- a/src/lib/Hydra/Schema/Builds.pm
|
||||||
|
+++ b/src/lib/Hydra/Schema/Builds.pm
|
||||||
|
@@ -608,6 +608,7 @@ makeQueries('', "");
|
||||||
|
makeQueries('ForProject', "and project = ?");
|
||||||
|
makeQueries('ForJobset', "and jobset_id = ?");
|
||||||
|
makeQueries('ForJob', "and jobset_id = ? and job = ?");
|
||||||
|
+makeQueries('ForJobName', "and jobset_id = (select id from jobsets j where j.name = ?) and job = ?");
|
||||||
|
|
||||||
|
|
||||||
|
my %hint = (
|
||||||
|
diff --git a/src/script/hydra-eval-jobset b/src/script/hydra-eval-jobset
|
||||||
|
index ea336bfc..2f208418 100755
|
||||||
|
--- a/src/script/hydra-eval-jobset
|
||||||
|
+++ b/src/script/hydra-eval-jobset
|
||||||
|
@@ -142,7 +142,7 @@ sub fetchInputSystemBuild {
|
||||||
|
$projectName ||= $project->name;
|
||||||
|
$jobsetName ||= $jobset->name;
|
||||||
|
|
||||||
|
- my @latestBuilds = $db->resultset('LatestSucceededForJob')
|
||||||
|
+ my @latestBuilds = $db->resultset('LatestSucceededForJobName')
|
||||||
|
->search({}, {bind => [$jobsetName, $jobName]});
|
||||||
|
|
||||||
|
my @validBuilds = ();
|
|
@ -0,0 +1,15 @@
|
||||||
|
diff --git a/bridge/mattermost/helpers.go b/bridge/mattermost/helpers.go
|
||||||
|
index 14b7469d..d9b77bdf 100644
|
||||||
|
--- a/bridge/mattermost/helpers.go
|
||||||
|
+++ b/bridge/mattermost/helpers.go
|
||||||
|
@@ -206,6 +206,10 @@ func (b *Bmattermost) skipMessage(message *matterclient.Message) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if message.Username == "github" {
|
||||||
|
+ return true
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
// if the message has reactions don't repost it (for now, until we can correlate reaction with message)
|
||||||
|
if message.Post.HasReactions {
|
||||||
|
return true
|
|
@ -0,0 +1,32 @@
|
||||||
|
{ fetchFromGitHub, python3Packages }:
|
||||||
|
with python3Packages;
|
||||||
|
|
||||||
|
buildPythonPackage rec {
|
||||||
|
pname = "mattermost-github-integration";
|
||||||
|
version = "0.0.0-unstable";
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "softdevteam";
|
||||||
|
repo = "mattermost-github-integration";
|
||||||
|
rev = "1124a0ff233b50ed6070cb84cfffd128ad219831";
|
||||||
|
sha256 = "1hfvjaxjhliy8sv9j3616fkdwd2jqhfsj9ai7ggx88zhxknrfx85";
|
||||||
|
};
|
||||||
|
propagatedBuildInputs = [
|
||||||
|
appdirs
|
||||||
|
click
|
||||||
|
flask
|
||||||
|
itsdangerous
|
||||||
|
jinja2
|
||||||
|
markupsafe
|
||||||
|
olefile
|
||||||
|
packaging
|
||||||
|
pillow
|
||||||
|
pyparsing
|
||||||
|
requests
|
||||||
|
six
|
||||||
|
werkzeug
|
||||||
|
];
|
||||||
|
checkInputs = [
|
||||||
|
pytest
|
||||||
|
];
|
||||||
|
doCheck = true;
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
{ config, pkgs }:
|
||||||
|
|
||||||
|
let
|
||||||
|
pkg = pkgs.callPackage ./pkg.nix {};
|
||||||
|
in {
|
||||||
|
type = "normal";
|
||||||
|
pythonPackages = self: [ pkg ];
|
||||||
|
module = "mattermostgithub:app";
|
||||||
|
env = [
|
||||||
|
"MGI_CONFIG_FILE=${./../secret/mattermost-github-integration.py}"
|
||||||
|
];
|
||||||
|
socket = "${config.services.uwsgi.runDir}/uwsgi-mgi.sock";
|
||||||
|
# allow access from nginx
|
||||||
|
chmod-socket = 666;
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
notifico = (pkgs.callPackage ./pkg.nix {})
|
||||||
|
.overrideAttrs (attrs: {
|
||||||
|
buildInputs = attrs.buildInputs ++ [ pkgs.makeWrapper ];
|
||||||
|
# Extend the module path so that local_config.py can be found
|
||||||
|
postInstall = ''
|
||||||
|
${attrs.postInstall}
|
||||||
|
|
||||||
|
wrapProgram $out/bin/notifico \
|
||||||
|
--set PYTHONPATH "$${PYTHONPATH}:${cfg.dbDir}"
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
cfg = config.services.notifico;
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
options.services.notifico = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "Enable the commit notification service";
|
||||||
|
};
|
||||||
|
enableLocalRedis = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Enable a local Redis server";
|
||||||
|
};
|
||||||
|
dbDir = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "/var/db/notifico";
|
||||||
|
description = "Home directory and location of the database file";
|
||||||
|
};
|
||||||
|
config = mkOption {
|
||||||
|
description = "Path to local_config.py, https://github.com/notifico/notifico/raw/master/notifico/config.py";
|
||||||
|
type = types.str;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
users.users.notifico = {
|
||||||
|
group = "notifico";
|
||||||
|
home = cfg.dbDir;
|
||||||
|
createHome = true;
|
||||||
|
};
|
||||||
|
users.groups.notifico = {};
|
||||||
|
|
||||||
|
services.redis = mkIf cfg.enableLocalRedis {
|
||||||
|
enable = true;
|
||||||
|
bind = "127.0.0.1";
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services =
|
||||||
|
let
|
||||||
|
User = "notifico";
|
||||||
|
Group = "notifico";
|
||||||
|
WorkingDirectory = "${cfg.dbDir}";
|
||||||
|
ExecStartPre = [
|
||||||
|
"${pkgs.coreutils}/bin/rm -f local_config.pyc"
|
||||||
|
"${pkgs.coreutils}/bin/ln -sf ${cfg.config} local_config.py"
|
||||||
|
];
|
||||||
|
|
||||||
|
notifico-init = {
|
||||||
|
description = "Notifico initialization";
|
||||||
|
serviceConfig = {
|
||||||
|
inherit User Group WorkingDirectory ExecStartPre;
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = "${notifico}/bin/notifico init";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
notificoService = component: {
|
||||||
|
description = "Notifico ${component}";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
after = [ "network.target" "notifico-init.service" ];
|
||||||
|
requires = [ "notifico-init.service" ];
|
||||||
|
serviceConfig = {
|
||||||
|
inherit User Group WorkingDirectory ExecStartPre;
|
||||||
|
Type = "simple";
|
||||||
|
ExecStart = "${notifico}/bin/notifico ${component}";
|
||||||
|
|
||||||
|
Restart = "always";
|
||||||
|
RestartSec = "5sec";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
inherit notifico-init;
|
||||||
|
notifico-www = notificoService "www";
|
||||||
|
notifico-worker = notificoService "worker";
|
||||||
|
notifico-bots = notificoService "bots";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
{ python2Packages, python2, fetchFromGitHub, fetchurl }:
|
||||||
|
|
||||||
|
let
|
||||||
|
Flask-Gravatar = python2Packages.buildPythonPackage {
|
||||||
|
name = "Flask-Gravatar";
|
||||||
|
src = python2Packages.fetchPypi {
|
||||||
|
pname = "Flask-Gravatar";
|
||||||
|
version = "0.5.0";
|
||||||
|
sha256 = "1qb2ylirjajdqsmldhwfdhf8i86k7vlh3y4gnqfqj4n6q8qmyrk0";
|
||||||
|
};
|
||||||
|
propagatedBuildInputs = with python2Packages; [
|
||||||
|
pytestrunner
|
||||||
|
flask
|
||||||
|
];
|
||||||
|
checkInputs = with python2Packages; [
|
||||||
|
check-manifest
|
||||||
|
coverage
|
||||||
|
isort
|
||||||
|
pydocstyle
|
||||||
|
pytestcache
|
||||||
|
pytestcov
|
||||||
|
pytestpep8
|
||||||
|
pytest
|
||||||
|
pygments
|
||||||
|
];
|
||||||
|
};
|
||||||
|
utopia = python2Packages.buildPythonPackage {
|
||||||
|
name = "utopia";
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "notifico";
|
||||||
|
repo = "utopia";
|
||||||
|
rev = "70293ed5e1ca55232e0fae71061e7e9b9b29be6f";
|
||||||
|
sha256 = "11cnh9l4d9jlhafnfis9si6kgk9zsdd5439qnhxh6dca3x4a986q";
|
||||||
|
};
|
||||||
|
propagatedBuildInputs = with python2Packages; [
|
||||||
|
gevent
|
||||||
|
blinker
|
||||||
|
];
|
||||||
|
doCheck = false;
|
||||||
|
};
|
||||||
|
Flask-WTF = python2Packages.flask_wtf.overrideAttrs(oa: rec {
|
||||||
|
version = "0.8.4";
|
||||||
|
src = python2Packages.fetchPypi {
|
||||||
|
pname = "Flask-WTF";
|
||||||
|
inherit version;
|
||||||
|
sha256 = "1khbwmlrcnk9f46f7kf531n06pkyfs6nc8fk273js9mj2igngg2y";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
Flask-XML-RPC = python2Packages.flask_wtf.overrideAttrs(oa: rec {
|
||||||
|
version = "0.1.2";
|
||||||
|
src = python2Packages.fetchPypi {
|
||||||
|
pname = "Flask-XML-RPC";
|
||||||
|
inherit version;
|
||||||
|
sha256 = "1dwalj7pc5iid9l1k50q5mllirnn9f5s7jq54a66x48a4j179p2a";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
in
|
||||||
|
python2Packages.buildPythonApplication {
|
||||||
|
name = "notifico";
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "notifico";
|
||||||
|
repo = "notifico";
|
||||||
|
rev = "6af849e4c75dff4d740051676f5a2093a44efcee";
|
||||||
|
sha256 = "18jifqdvjy4x5s1bh7vx501pin52g4n3hhw1z4m2c0h512z4spdr";
|
||||||
|
};
|
||||||
|
patches = [
|
||||||
|
(fetchurl {
|
||||||
|
url = https://github.com/whitequark/notifico/commit/22b582fad6cb97af6f7437e8462d720ddacc42ef.patch;
|
||||||
|
sha256 = "0w8i8hf1r8b0p1y1zn9vyvnyi20qp120aiyalqymhsxsh17mma52";
|
||||||
|
})
|
||||||
|
];
|
||||||
|
propagatedBuildInputs = with python2Packages; [
|
||||||
|
flask
|
||||||
|
Flask-WTF
|
||||||
|
Flask-Gravatar
|
||||||
|
flask_sqlalchemy
|
||||||
|
Flask-XML-RPC
|
||||||
|
flask_mail
|
||||||
|
flask-caching
|
||||||
|
Fabric
|
||||||
|
sqlalchemy
|
||||||
|
utopia
|
||||||
|
gevent
|
||||||
|
oauth2
|
||||||
|
redis
|
||||||
|
gunicorn
|
||||||
|
requests
|
||||||
|
PyGithub
|
||||||
|
xmltodict
|
||||||
|
unidecode
|
||||||
|
raven
|
||||||
|
blinker
|
||||||
|
docopt
|
||||||
|
celery
|
||||||
|
];
|
||||||
|
postInstall = ''
|
||||||
|
mkdir $out/bin
|
||||||
|
cat << EOF > $out/bin/notifico
|
||||||
|
#!${python2}/bin/python
|
||||||
|
import sys
|
||||||
|
from notifico.__main__ import main
|
||||||
|
|
||||||
|
sys.exit(main(sys.argv))
|
||||||
|
EOF
|
||||||
|
chmod +x $out/bin/notifico
|
||||||
|
'';
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
{ python3Packages, runCommand }:
|
||||||
|
|
||||||
|
# Note: we do not use fetchgit but a local copy instead to avoid
|
||||||
|
# chicken-and-egg problem if reinstalling nixbld.m-labs.hk from scratch.
|
||||||
|
with python3Packages; buildPythonPackage rec {
|
||||||
|
name = "rfq";
|
||||||
|
src = ./src;
|
||||||
|
propagatedBuildInputs = [ flask flask_mail python-dotenv ];
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
blinker
|
||||||
|
click
|
||||||
|
Flask
|
||||||
|
Flask-Mail
|
||||||
|
itsdangerous
|
||||||
|
Jinja2
|
||||||
|
MarkupSafe
|
||||||
|
python-dotenv
|
||||||
|
six
|
||||||
|
Werkzeug
|
|
@ -0,0 +1,75 @@
|
||||||
|
from os import getenv
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from flask import Flask
|
||||||
|
from flask import current_app
|
||||||
|
from flask import json
|
||||||
|
from flask import jsonify
|
||||||
|
from flask import make_response
|
||||||
|
from flask import request
|
||||||
|
from flask_mail import Mail
|
||||||
|
from flask_mail import Message
|
||||||
|
from werkzeug.middleware.proxy_fix import ProxyFix
|
||||||
|
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.config.update(
|
||||||
|
DEBUG=getenv("FLASK_DEBUG") == "True",
|
||||||
|
MAIL_SERVER=getenv("FLASK_MAIL_SERVER"),
|
||||||
|
MAIL_PORT=getenv("FLASK_MAIL_PORT"),
|
||||||
|
MAIL_USE_SSL=getenv("FLASK_MAIL_USE_SSL"),
|
||||||
|
MAIL_DEBUG=False,
|
||||||
|
MAIL_USERNAME=getenv("FLASK_MAIL_USERNAME"),
|
||||||
|
MAIL_PASSWORD=getenv("FLASK_MAIL_PASSWORD"),
|
||||||
|
MAIL_RECIPIENT=getenv("FLASK_MAIL_RECIPIENT"),
|
||||||
|
MAIL_SENDER=getenv("FLASK_MAIL_SENDER")
|
||||||
|
)
|
||||||
|
app.wsgi_app = ProxyFix(app.wsgi_app)
|
||||||
|
|
||||||
|
mail = Mail(app)
|
||||||
|
|
||||||
|
|
||||||
|
@app.after_request
|
||||||
|
def after(response):
|
||||||
|
response.headers["Access-Control-Allow-Origin"] = "*"
|
||||||
|
response.headers["Access-Control-Allow-Headers"] = "*"
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/rfq", methods=["POST"])
|
||||||
|
def send_rfq():
|
||||||
|
payload = request.json
|
||||||
|
payload = json.loads(json.htmlsafe_dumps(payload))
|
||||||
|
|
||||||
|
if payload is None:
|
||||||
|
resp = jsonify(error="invalid data")
|
||||||
|
return make_response(resp, 400)
|
||||||
|
|
||||||
|
if "email" not in payload:
|
||||||
|
resp = jsonify(error="missing email")
|
||||||
|
return make_response(resp, 400)
|
||||||
|
|
||||||
|
if "note" not in payload:
|
||||||
|
resp = jsonify(error="missing note")
|
||||||
|
return make_response(resp, 400)
|
||||||
|
|
||||||
|
if "configuration" not in payload:
|
||||||
|
resp = jsonify(error="missing configuration")
|
||||||
|
return make_response(resp, 400)
|
||||||
|
|
||||||
|
sender = current_app.config["MAIL_SENDER"]
|
||||||
|
recipient = current_app.config["MAIL_RECIPIENT"]
|
||||||
|
|
||||||
|
msg = Message(
|
||||||
|
"RFQ for Sinara hardware from {}".format(payload["email"]),
|
||||||
|
sender=sender,
|
||||||
|
recipients=[recipient, payload["email"]])
|
||||||
|
msg.body = ("From: {}\nConfiguration: {}\nNote: {}"
|
||||||
|
.format(payload["email"], payload["configuration"], payload["note"]))
|
||||||
|
|
||||||
|
with mail.connect() as conn:
|
||||||
|
conn.send(msg)
|
||||||
|
|
||||||
|
return jsonify("ok")
|
|
@ -0,0 +1,14 @@
|
||||||
|
from setuptools import setup
|
||||||
|
from setuptools import find_packages
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='rfq',
|
||||||
|
version='1.0.0',
|
||||||
|
packages=find_packages(),
|
||||||
|
zip_safe=False,
|
||||||
|
install_requires=[
|
||||||
|
'Flask',
|
||||||
|
'Flask-Mail',
|
||||||
|
'python-dotenv'
|
||||||
|
]
|
||||||
|
)
|
|
@ -0,0 +1,21 @@
|
||||||
|
{ config, pkgs }:
|
||||||
|
|
||||||
|
let
|
||||||
|
pkg = pkgs.callPackage ./pkg.nix {};
|
||||||
|
in {
|
||||||
|
type = "normal";
|
||||||
|
pythonPackages = self: [ pkg ];
|
||||||
|
module = "rfq:app";
|
||||||
|
env = [
|
||||||
|
"FLASK_MAIL_SERVER=ssl.serverraum.org"
|
||||||
|
"FLASK_MAIL_PORT=465"
|
||||||
|
"FLASK_MAIL_USE_SSL=True"
|
||||||
|
"FLASK_MAIL_USERNAME=sales@m-labs.hk"
|
||||||
|
"FLASK_MAIL_PASSWORD=${import /etc/nixos/secret/sales_password.nix}"
|
||||||
|
"FLASK_MAIL_RECIPIENT=sales@m-labs.hk"
|
||||||
|
"FLASK_MAIL_SENDER=sales@m-labs.hk"
|
||||||
|
];
|
||||||
|
socket = "${config.services.uwsgi.runDir}/uwsgi-rfq.sock";
|
||||||
|
# allow access from nginx
|
||||||
|
chmod-socket = 666;
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
-rw------- 1 root root backup-passphrase
|
||||||
|
-rw------- 1 root root email_accounts.nix
|
||||||
|
-rw------- 1 homu homu homu.toml
|
||||||
|
-rw-rw---- 1 gitea gitea mailerpassword
|
||||||
|
-rw------- 1 matterbridge matterbridge matterbridge.toml
|
||||||
|
-rw------- 1 uwsgi uwsgi mattermost-github-integration.py
|
||||||
|
-rw------- 1 nginx nginx muninpasswd
|
||||||
|
-rw-rw---- 1 hydra hydra nixbld.m-labs.hk-1
|
||||||
|
-rw-rw---- 1 hydra hydra nix_id_rsa
|
||||||
|
-rw------- 1 root root rclone.conf
|
||||||
|
-rw------- 1 root root wifi_password.nix
|
|
@ -0,0 +1,33 @@
|
||||||
|
# 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, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports =
|
||||||
|
[ <nixpkgs/nixos/modules/installer/scan/not-detected.nix>
|
||||||
|
];
|
||||||
|
|
||||||
|
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod" ];
|
||||||
|
boot.initrd.kernelModules = [ ];
|
||||||
|
boot.kernelModules = [ "kvm-intel" ];
|
||||||
|
boot.extraModulePackages = [ ];
|
||||||
|
|
||||||
|
fileSystems."/" =
|
||||||
|
{ device = "/dev/disk/by-uuid/89db7e45-7b7e-44ec-bebc-a02935cc5ba0";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/boot" =
|
||||||
|
{ device = "/dev/disk/by-uuid/060C-8772";
|
||||||
|
fsType = "vfat";
|
||||||
|
};
|
||||||
|
|
||||||
|
swapDevices = [ ];
|
||||||
|
|
||||||
|
nix.maxJobs = lib.mkDefault 16;
|
||||||
|
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
|
||||||
|
|
||||||
|
boot.loader.systemd-boot.enable = true;
|
||||||
|
boot.loader.efi.canTouchEfiVariables = true;
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports =
|
||||||
|
[ <nixpkgs/nixos/modules/installer/scan/not-detected.nix>
|
||||||
|
];
|
||||||
|
|
||||||
|
boot.initrd.availableKernelModules = [ "ata_generic" "uhci_hcd" "ehci_pci" "ahci" "usb_storage" "usbhid" "floppy" "sd_mod" "sr_mod" ];
|
||||||
|
boot.initrd.kernelModules = [ ];
|
||||||
|
boot.kernelModules = [ "kvm-intel" ];
|
||||||
|
boot.extraModulePackages = [ ];
|
||||||
|
|
||||||
|
fileSystems."/" =
|
||||||
|
{ device = "/dev/disk/by-uuid/35d9c50c-e479-43a9-8324-b8ded5b71844";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
|
||||||
|
swapDevices =
|
||||||
|
[ { device = "/dev/disk/by-uuid/d8480389-c558-4c46-a58f-00207315dbdd"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
nix.maxJobs = lib.mkDefault 2;
|
||||||
|
|
||||||
|
boot.loader.grub.enable = true;
|
||||||
|
boot.loader.grub.version = 2;
|
||||||
|
boot.loader.grub.device = "/dev/sda";
|
||||||
|
|
||||||
|
services.xserver.videoDrivers = ["intel"];
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
sb = {
|
||||||
|
isNormalUser = true;
|
||||||
|
extraGroups = ["wheel" "plugdev" "dialout"];
|
||||||
|
openssh.authorizedKeys.keys = [
|
||||||
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCyPk5WyFoWSvF4ozehxcVBoZ+UHgrI7VW/OoQfFFwIQe0qvetUZBMZwR2FwkLPAMZV8zz1v4EfncudEkVghy4P+/YVLlDjqDq9zwZnh8Nd/ifu84wmcNWHT2UcqnhjniCdshL8a44memzABnxfLLv+sXhP2x32cJAamo5y6fukr2qLp2jbXzR+3sv3klE0ruUXis/BR1lLqNJEYP8jB6fLn2sLKinnZPfn6DwVOk10mGeQsdME/eGl3phpjhODH9JW5V2V5nJBbC0rBnq+78dyArKVqjPSmIcSy72DEIpTctnMEN1W34BGrnsDd5Xd/DKxKxHKTMCHtZRwLC2X0NWN"
|
||||||
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCMALVC8RDTHec+PC8y1s3tcpUAODgq6DEzQdHDf/cyvDMfmCaPiMxfIdmkns5lMa03hymIfSmLUF0jFFDc7biRp7uf9AAXNsrTmplHii0l0McuOOZGlSdZM4eL817P7UwJqFMxJyFXDjkubhQiX6kp25Kfuj/zLnupRCaiDvE7ho/xay6Jrv0XLz935TPDwkc7W1asLIvsZLheB+sRz9SMOb9gtrvk5WXZl5JTOFOLu+JaRwQLHL/xdcHJTOod7tqHYfpoC5JHrEwKzbhTOwxZBQBfTQjQktKENQtBxXHTe71rUEWfEZQGg60/BC4BrRmh4qJjlJu3v4VIhC7SSHn1"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
rj = {
|
||||||
|
isNormalUser = true;
|
||||||
|
extraGroups = ["wheel" "plugdev" "dialout"];
|
||||||
|
openssh.authorizedKeys.keys = [
|
||||||
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDZOitjBp9uB+Hldt5M040Jq/3rVFBbw40Xemkau3BLvMn8TzkJs5NLrlNa4vcwFecA/nh7aPzdGHc1b/E2EYCfM29oo/oVBJsp/L66YUbnYrneFNVp8Ccw3tZPPAiADjLZWta0JQLVVY6Dqtt0SH/oU5jC1F1qCa+krWqkKAVE8rfxYVspBGagxlpZuE83UC0j2yXrbHq6ZrAW917wXUEpcIR+mKalDM2Aa1FAZZH9upty2yysyOHh6/ljurz6tMRqjzjdJtVJ2YXf4GZpIuYcxCU1kvLKPLN0MZA+aXtraCGmEdjdx38sfRqHBnffXhCkJIo+W4aw4Xae2xplmGeInWqnUwsWxuVJENdPfbBOBdMRuFemuPZdmBcohczDygOC3h+oljBvQF6Ffyvk38pVLbd91p1+qgvtW7OcXTUjm17K1Oa54RGUcm1W2w3yJKCc8RQZXlwVtneTX0VoK39LC1yWfyMBg8sWeT66oE+v2CCEzsB0A1xZx/dK0r5bdfv8uNAH5d8RGL++zNEVrsA4iZF6FEeXgaoje3tKMqKTgOx4EDh93ie2rv7oE8xrPL5g0vb8wBQ1Kf4rukd7FPVu+E4+W5oSnQ42BJ9Z4sFCLQ9Dnhbg4VvREzAe9rVzfAG368iCVKkFcSq+AaLquqrBpwLbz10V3GLDARlF2IZZGQ== rj@lab.m-labs.hk"
|
||||||
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC27krR8G8Pb59YuYm7+X2mmNnVdk/t9myYgO8LH0zfb2MeeXX5+90nW9kMjKflJss/oLl8dkD85jbJ0fRbRkfJd20pGCqCUuYAbYKkowigFVEkbrbWSLkmf+clRjzJOuBuUA0uq0XKS17uMC3qhu+dDdBOAIKb3L83NfVE8p8Pjb4BPktQrdxefM43/x4jTMuc7tgxVmTOEge3+rmVPK2GnLkUBgBn8b6S+9ElPd63HXI5J5f61v21l5N9V0mhTu1pv6PiDRdFIlFDK9dLVZcZ2qlzpKmCnFrOoreBEgre44SpfFe5/MMItxvWiVsj/rij/rHZZiol1k7JiQCnEHeCCbjjvcBBka5HxZgcb3vBZVceTOawrmjbdbA2dq35sUptz/bEgdZ1UVCmVpWsdROAlEDBmSSbcVwxzcvhoKnkpbuP4Q0V3tVKSLW053ADFNB4frtwY5nAZfsVErFLLphjwb8nlyJoDRNapQrn5syEiW0ligX2AAskZTYIl2A5AYyWPrmX6HJOPqZGatMU3qQiRMxs+hFqhyyCmBgl0kcsgW09MBKtJWk1Fbii98MHqgRUN9R7AUiYy5p78Pnv9DC8DT8Ubl9zoP0g5d40P9NGK2LAhMxLXvtckJ4ERqbSEcNZJw+q4jBrOHnMTz+NLdAUiEtru+6T2OdhaHv+eiNlFQ== robert-jordens-rsa4096"
|
||||||
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCUdbne3NtIG+iy/jer76/OY+IksuS3BDLSXPnWrGejWnig9h+L6sUV0lEVI6dqp+W/b8jWqPB8nh5S0NZsCd3Ta3Go82k/SPPkh9lB2PpfquhCjLnmC/RNc3TgC4FuiS+NZHqXaTggYHubNwEK+8gynMqkMQXjOGU02U0CtUfsYdAm75AW60DySZCRNwOcU0Ndpn1UCpha7fL1k179Dd/OtArkYsIL24ohlfxFeOB3jGYQK6ATmzbvCRjwIKXcyECuajWwfnDg9FtDWrqHNzu5dJlvmxoWm8zCDgMj53uiA7TjujQN81MYrIJNeEwSr5jXQMqzA3mzlk4k3Z0qs3TP robert-jordens-64FEFBAF-4D0749B2-rsa2048"
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMUaB2G1jexxfkdlly3fdWslH54/s/bOuvk9AxqpjtAY robert-jordens-ed25519"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
harry = {
|
||||||
|
isNormalUser = true;
|
||||||
|
extraGroups = ["plugdev" "dialout" "wireshark"];
|
||||||
|
openssh.authorizedKeys.keys = [
|
||||||
|
"ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBDcPNCgtdz8erFPRrAwCr4JrkeYXJUUvoRBgP0X2HlzJgDe1Inuo6sC6CGcO3IXbf4MwVA9XEp8BYPHARVeEHhufg/0wnIABLx2GcK99yxOLDUe4h/3YwtqvOcqHEsDx7w=="
|
||||||
|
];
|
||||||
|
};
|
||||||
|
astro = {
|
||||||
|
isNormalUser = true;
|
||||||
|
extraGroups = ["plugdev" "dialout"];
|
||||||
|
openssh.authorizedKeys.keys = [
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGJJTSJdpDh82486uPiMhhyhnci4tScp5uUe7156MBC8 a"
|
||||||
|
];
|
||||||
|
shell = pkgs.bashInteractive;
|
||||||
|
};
|
||||||
|
pca006132 = {
|
||||||
|
isNormalUser = true;
|
||||||
|
extraGroups = ["plugdev" "dialout"];
|
||||||
|
openssh.authorizedKeys.keys = [
|
||||||
|
"ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBE/sPOOiw3843+rrcYV2pOVkffNc1xsOgnuCUmy1Fa2VF8x9kqmgQv61sxsuKRkKKoinvqrASxLkWVd6nkiiDuEISibEXs8r1BwuT05cS7RkEhCakSMZ6y/iqOtjt2bx+A=="
|
||||||
|
];
|
||||||
|
};
|
||||||
|
occheung = {
|
||||||
|
isNormalUser = true;
|
||||||
|
extraGroups = ["plugdev" "dialout"];
|
||||||
|
openssh.authorizedKeys.keys = [
|
||||||
|
"ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBPEvmWmxpFpMgp5fpjKud8ev0cyf/+X5fEpQt/YD/+u4mbvZYPE300DLqQ0h/qjgvaGMz1ndf4idYnRdy+plJEC/+hmlRW5NlcpAr3S/LYAisacgKToFVl+MlBo+emS9Ig=="
|
||||||
|
];
|
||||||
|
};
|
||||||
|
dsleung = {
|
||||||
|
isNormalUser = true;
|
||||||
|
extraGroups = ["plugdev" "dialout"];
|
||||||
|
openssh.authorizedKeys.keys = [
|
||||||
|
"ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBDbE7HzZKSwGbgRnzwrzCzb3gZKLSritwnEpHS4sa9oXJ5oLFkuFZOpPYDeiMlbUJ9jCk5FRmkLYIkrbz06SUr7P/eUjxu79ENi3RhfVu+ZrrPvgkhKvM/CiXvw3xCOu0w=="
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,149 @@
|
||||||
|
{ host }:
|
||||||
|
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
let
|
||||||
|
m-labs = import (fetchTarball https://nixbld.m-labs.hk/channel/custom/artiq/full/artiq-full/nixexprs.tar.xz) { inherit pkgs; };
|
||||||
|
pkgs-unstable = import (fetchTarball https://github.com/NixOS/nixpkgs/archive/master.tar.gz) {};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
deployment.targetHost = host;
|
||||||
|
|
||||||
|
disabledModules = [ "security/pam.nix" ];
|
||||||
|
imports =
|
||||||
|
[
|
||||||
|
(./. + "/${host}-hardware-configuration.nix")
|
||||||
|
./pam_p11
|
||||||
|
];
|
||||||
|
|
||||||
|
networking.hostName = host;
|
||||||
|
|
||||||
|
time.timeZone = "Asia/Hong_Kong";
|
||||||
|
|
||||||
|
# List packages installed in system profile. To search, run:
|
||||||
|
# $ nix search wget
|
||||||
|
nixpkgs.config.allowUnfree = true;
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
opensc yubikey-manager yubikey-manager-qt
|
||||||
|
wget vim gitAndTools.gitFull firefox chromium thunderbird hexchat
|
||||||
|
usbutils pciutils file lm_sensors audacious acpi
|
||||||
|
gimp imagemagick
|
||||||
|
(python3.withPackages(ps: with ps; [ numpy scipy matplotlib qtconsole regex ]))
|
||||||
|
mosh psmisc libreoffice-fresh
|
||||||
|
gtkwave telnet unzip zip gnupg
|
||||||
|
gnome3.gnome-tweaks
|
||||||
|
jq sublime3 rink qemu_kvm
|
||||||
|
tmux xc3sprog m-labs.openocd screen gdb minicom picocom tigervnc
|
||||||
|
emacs bat ripgrep
|
||||||
|
pkgs-unstable.rust-analyzer
|
||||||
|
(pkgs-unstable.vscode-with-extensions.override {
|
||||||
|
vscodeExtensions = [
|
||||||
|
pkgs-unstable.vscode-extensions.matklad.rust-analyzer
|
||||||
|
];
|
||||||
|
})
|
||||||
|
(import ./fish-nix-shell)
|
||||||
|
];
|
||||||
|
programs.wireshark.enable = true;
|
||||||
|
|
||||||
|
services.openssh.enable = true;
|
||||||
|
services.openssh.forwardX11 = true;
|
||||||
|
services.openssh.passwordAuthentication = false;
|
||||||
|
hardware.u2f.enable = true;
|
||||||
|
services.pcscd.enable = true;
|
||||||
|
programs.ssh.extraConfig =
|
||||||
|
''
|
||||||
|
PKCS11Provider "${pkgs.opensc}/lib/opensc-pkcs11.so"
|
||||||
|
'';
|
||||||
|
programs.ssh.startAgent = true;
|
||||||
|
services.gnome3.gnome-keyring.enable = pkgs.lib.mkForce false;
|
||||||
|
programs.ssh.agentPKCS11Whitelist = "${pkgs.opensc}/lib/opensc-pkcs11.so";
|
||||||
|
security.pam.p11.enable = true;
|
||||||
|
|
||||||
|
# Enable CUPS to print documents.
|
||||||
|
services.printing = {
|
||||||
|
enable = true;
|
||||||
|
extraConf =
|
||||||
|
''
|
||||||
|
Browsing Off
|
||||||
|
BrowseLocalProtocols none
|
||||||
|
'';
|
||||||
|
browsedConf =
|
||||||
|
''
|
||||||
|
BrowseRemoteProtocols none
|
||||||
|
BrowseProtocols none
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
services.avahi = {
|
||||||
|
enable = true;
|
||||||
|
nssmdns = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Enable sound.
|
||||||
|
sound.enable = true;
|
||||||
|
hardware.pulseaudio = {
|
||||||
|
enable = true;
|
||||||
|
extraModules = [ pkgs.pulseaudio-modules-bt ];
|
||||||
|
package = pkgs.pulseaudioFull;
|
||||||
|
};
|
||||||
|
|
||||||
|
i18n.inputMethod = {
|
||||||
|
enabled = "fcitx";
|
||||||
|
fcitx.engines = with pkgs.fcitx-engines; [ table-extra m17n ];
|
||||||
|
};
|
||||||
|
fonts.fonts = [ pkgs.noto-fonts pkgs.noto-fonts-cjk pkgs.noto-fonts-emoji pkgs.noto-fonts-extra pkgs.emacs-all-the-icons-fonts ];
|
||||||
|
|
||||||
|
# Enable the X11 windowing system.
|
||||||
|
services.xserver.enable = true;
|
||||||
|
services.xserver.layout = "us";
|
||||||
|
services.xserver.xkbOptions = "eurosign:e";
|
||||||
|
|
||||||
|
# Enable touchpad support.
|
||||||
|
services.xserver.libinput.enable = true;
|
||||||
|
|
||||||
|
services.xserver.displayManager.gdm.enable = true;
|
||||||
|
services.xserver.displayManager.gdm.autoSuspend = false;
|
||||||
|
powerManagement.enable = false;
|
||||||
|
services.xserver.desktopManager.gnome3.enable = true;
|
||||||
|
environment.gnome3.excludePackages = [ pkgs.epiphany pkgs.gnome3.geary ];
|
||||||
|
|
||||||
|
hardware.bluetooth.enable = true;
|
||||||
|
|
||||||
|
programs.fish.enable = true;
|
||||||
|
programs.fish.promptInit = ''
|
||||||
|
fish-nix-shell --info-right | source
|
||||||
|
'';
|
||||||
|
users.mutableUsers = false;
|
||||||
|
users.defaultUserShell = pkgs.fish;
|
||||||
|
users.extraGroups.plugdev = { };
|
||||||
|
users.extraUsers = import ./common-users.nix { inherit pkgs; };
|
||||||
|
security.sudo.wheelNeedsPassword = false;
|
||||||
|
services.udev.packages = [ m-labs.openocd ];
|
||||||
|
services.udev.extraRules = ''
|
||||||
|
# leaf maple
|
||||||
|
SUBSYSTEM=="usb", ATTRS{idVendor}=="1eaf", ATTRS{idProduct}=="0003", MODE="0660", GROUP="plugdev"
|
||||||
|
SUBSYSTEM=="usb", ATTRS{idVendor}=="1eaf", ATTRS{idProduct}=="0004", MODE="0660", GROUP="plugdev"
|
||||||
|
# glasgow
|
||||||
|
SUBSYSTEM=="usb", ATTRS{idVendor}=="20b7", ATTRS{idProduct}=="9db1", MODE="0660", GROUP="plugdev"
|
||||||
|
# hackrf
|
||||||
|
SUBSYSTEM=="usb", ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="6089", MODE="0660", GROUP="plugdev"
|
||||||
|
# bladerf
|
||||||
|
SUBSYSTEM=="usb", ATTRS{idVendor}=="2cf0", ATTRS{idProduct}=="5250", MODE="0660", GROUP="plugdev"
|
||||||
|
# personal measurement device
|
||||||
|
SUBSYSTEM=="usb", ATTRS{idVendor}=="09db", ATTRS{idProduct}=="007a", MODE="0660", GROUP="plugdev"
|
||||||
|
# saleae
|
||||||
|
SUBSYSTEM=="usb", ATTRS{idVendor}=="0925", ATTRS{idProduct}=="3881", MODE="0660", GROUP="plugdev"
|
||||||
|
# ocean optics
|
||||||
|
SUBSYSTEM=="usb", ATTRS{idVendor}=="2457", ATTRS{idProduct}=="1002", MODE="0660", GROUP="plugdev"
|
||||||
|
# yubikey
|
||||||
|
SUBSYSTEM=="usb", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0116", MODE="0660", GROUP="plugdev"
|
||||||
|
'';
|
||||||
|
|
||||||
|
nix.binaryCachePublicKeys = ["nixbld.m-labs.hk-1:5aSRVA5b320xbNvu30tqxVPXpld73bhtOeH6uAjRyHc="];
|
||||||
|
nix.binaryCaches = ["https://nixbld.m-labs.hk" "https://cache.nixos.org"];
|
||||||
|
nix.sandboxPaths = ["/opt"];
|
||||||
|
|
||||||
|
# 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 = "19.03"; # Did you read the comment?
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018 haslersn
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,50 @@
|
||||||
|
# fish-nix-shell
|
||||||
|
fish support for the *nix-shell* environment of the Nix package manager.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Installation in the user environment
|
||||||
|
|
||||||
|
Execute
|
||||||
|
|
||||||
|
```
|
||||||
|
nix-env -if https://github.com/haslersn/fish-nix-shell/archive/master.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
and add the following to your *~/.config/fish/config.fish*. Create it if it doesn't exist.
|
||||||
|
|
||||||
|
```
|
||||||
|
fish-nix-shell --info-right | source
|
||||||
|
```
|
||||||
|
|
||||||
|
### System-wide installation
|
||||||
|
|
||||||
|
Add the package to your */etc/nixos/configuration.nix*:
|
||||||
|
|
||||||
|
```
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
#
|
||||||
|
# Other packages here ...
|
||||||
|
#
|
||||||
|
(import (fetchGit "https://github.com/haslersn/fish-nix-shell"))
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
and then execute: `sudo nixos-rebuild switch`
|
||||||
|
|
||||||
|
If you want to configure it system-wide, also add:
|
||||||
|
|
||||||
|
```
|
||||||
|
programs.fish.enable = true;
|
||||||
|
programs.fish.promptInit = ''
|
||||||
|
fish-nix-shell --info-right | source
|
||||||
|
'';
|
||||||
|
```
|
||||||
|
|
||||||
|
## Flags
|
||||||
|
|
||||||
|
The `fish-nix-shell` command **optionally** takes the following flags:
|
||||||
|
|
||||||
|
| Flag | Meaning |
|
||||||
|
| - | - |
|
||||||
|
| `--info-right` | While in a *fish-nix-shell*, display information about the loaded packages at the right.
|
|
@ -0,0 +1,34 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
function init_fish () {
|
||||||
|
cat <<EOF
|
||||||
|
|
||||||
|
# Overwrite the nix-shell command
|
||||||
|
function nix-shell
|
||||||
|
fish-nix-shell-wrapper \$argv
|
||||||
|
set -gx FISH_NIX_SHELL_EXIT_STATUS \$status
|
||||||
|
end
|
||||||
|
EOF
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
--info-right)
|
||||||
|
cat <<EOF
|
||||||
|
|
||||||
|
# Print additional information inside a nix-shell environment
|
||||||
|
function fish_right_prompt
|
||||||
|
nix-shell-info
|
||||||
|
set -e FISH_NIX_SHELL_EXIT_STATUS
|
||||||
|
end
|
||||||
|
EOF
|
||||||
|
;;
|
||||||
|
*) exit 1;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
cat <<EOF
|
||||||
|
# If you see this output, you probably forgot to pipe this output into 'source':
|
||||||
|
# fish-nix-shell $@ | source
|
||||||
|
EOF
|
||||||
|
|
||||||
|
init_fish "$@"
|
|
@ -0,0 +1,22 @@
|
||||||
|
#!/bin/sh
|
||||||
|
fns () {
|
||||||
|
pkgs=$FISH_NIX_SHELL_PKGS
|
||||||
|
for arg in "$@"; do
|
||||||
|
if [[ $arg == -* ]]; then
|
||||||
|
pkg=
|
||||||
|
if [[ $arg == --pure ]] || [[ $arg == --command ]] || [[ $arg == --run ]]; then
|
||||||
|
command nix-shell $@
|
||||||
|
return
|
||||||
|
elif [[ $arg == -p ]] || [[ $arg == --packages ]]; then
|
||||||
|
pkg=1
|
||||||
|
fi
|
||||||
|
elif [[ $pkg == 1 ]]; then
|
||||||
|
pkgs+=" "$arg
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ -n $name ]] && [[ $name != shell ]]; then
|
||||||
|
pkgs+=" "$name
|
||||||
|
fi
|
||||||
|
env FISH_NIX_SHELL_PKGS="$pkgs" nix-shell "$@" --command fish
|
||||||
|
}
|
||||||
|
fns "$@"
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/bin/sh
|
||||||
|
if [[ $IN_NIX_SHELL != "" ]]; then
|
||||||
|
printf "\033[1;32m"
|
||||||
|
output=$(echo $FISH_NIX_SHELL_PKGS | xargs)
|
||||||
|
if [[ -n $name ]] && [[ $name != shell ]]; then
|
||||||
|
output+=" "$name
|
||||||
|
fi
|
||||||
|
if [[ -n $output ]]; then
|
||||||
|
output=$(echo $output $additional_pkgs | tr ' ' '\n' | sort -u | tr '\n' ' ' | xargs)
|
||||||
|
printf "$output "
|
||||||
|
else
|
||||||
|
printf "[unknown nix-shell] "
|
||||||
|
fi
|
||||||
|
printf "\033[0m"
|
||||||
|
elif [[ $FISH_NIX_SHELL_EXIT_STATUS ]]; then
|
||||||
|
if [[ $FISH_NIX_SHELL_EXIT_STATUS == 0 ]]; then
|
||||||
|
printf "\033[1;36mexited nix-shell \033[0m"
|
||||||
|
else
|
||||||
|
printf "\033[1;31mERROR \033[0m"
|
||||||
|
fi
|
||||||
|
fi
|
|
@ -0,0 +1,16 @@
|
||||||
|
with import <nixpkgs> {}; stdenv.mkDerivation rec {
|
||||||
|
name = "fish-nix-shell";
|
||||||
|
src = fetchGit "https://github.com/haslersn/fish-nix-shell";
|
||||||
|
nativeBuildInputs = [ makeWrapper ];
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p $out
|
||||||
|
cp LICENSE $out
|
||||||
|
cp -r bin $out
|
||||||
|
wrapProgram $out/bin/fish-nix-shell
|
||||||
|
wrapProgram $out/bin/fish-nix-shell-wrapper --prefix PATH ":" ${fish}/bin
|
||||||
|
wrapProgram $out/bin/nix-shell-info
|
||||||
|
'';
|
||||||
|
meta.description = "fish support for the nix-shell environment of the Nix package manager.";
|
||||||
|
meta.license = "MIT";
|
||||||
|
meta.homepage = https://github.com/haslersn/fish-nix-shell;
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
# 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, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports =
|
||||||
|
[ <nixpkgs/nixos/modules/installer/scan/not-detected.nix>
|
||||||
|
];
|
||||||
|
|
||||||
|
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod" ];
|
||||||
|
boot.initrd.kernelModules = [ ];
|
||||||
|
boot.kernelModules = [ "kvm-intel" ];
|
||||||
|
boot.extraModulePackages = [ ];
|
||||||
|
|
||||||
|
fileSystems."/" =
|
||||||
|
{ device = "/dev/disk/by-uuid/a86f2eff-c873-4af1-bb80-a903383b9c8c";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/boot" =
|
||||||
|
{ device = "/dev/disk/by-uuid/8C30-F6DC";
|
||||||
|
fsType = "vfat";
|
||||||
|
};
|
||||||
|
|
||||||
|
swapDevices = [ ];
|
||||||
|
|
||||||
|
nix.maxJobs = lib.mkDefault 16;
|
||||||
|
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
|
||||||
|
|
||||||
|
boot.loader.systemd-boot.enable = true;
|
||||||
|
boot.loader.efi.canTouchEfiVariables = true;
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
# 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, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports =
|
||||||
|
[ <nixpkgs/nixos/modules/installer/scan/not-detected.nix>
|
||||||
|
];
|
||||||
|
|
||||||
|
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod" ];
|
||||||
|
boot.initrd.kernelModules = [ ];
|
||||||
|
boot.kernelModules = [ "kvm-intel" ];
|
||||||
|
boot.extraModulePackages = [ ];
|
||||||
|
|
||||||
|
fileSystems."/" =
|
||||||
|
{ device = "/dev/disk/by-uuid/2fe28058-4186-4e65-9d3d-f7ec5dffc171";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/boot" =
|
||||||
|
{ device = "/dev/disk/by-uuid/E085-5F21";
|
||||||
|
fsType = "vfat";
|
||||||
|
};
|
||||||
|
|
||||||
|
swapDevices = [ ];
|
||||||
|
|
||||||
|
nix.maxJobs = lib.mkDefault 16;
|
||||||
|
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
|
||||||
|
|
||||||
|
boot.loader.systemd-boot.enable = true;
|
||||||
|
boot.loader.efi.canTouchEfiVariables = true;
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports =
|
||||||
|
[ <nixpkgs/nixos/modules/installer/scan/not-detected.nix>
|
||||||
|
];
|
||||||
|
|
||||||
|
boot.initrd.availableKernelModules = [ "xhci_pci" "ehci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" "sr_mod" ];
|
||||||
|
boot.initrd.kernelModules = [ ];
|
||||||
|
boot.kernelModules = [ "kvm-intel" ];
|
||||||
|
boot.extraModulePackages = [ ];
|
||||||
|
|
||||||
|
fileSystems."/" =
|
||||||
|
{ device = "/dev/disk/by-uuid/62a38d9c-452c-4648-be12-6131e95b8276";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/boot" =
|
||||||
|
{ device = "/dev/disk/by-uuid/88F6-46F2";
|
||||||
|
fsType = "vfat";
|
||||||
|
};
|
||||||
|
|
||||||
|
swapDevices = [ ];
|
||||||
|
|
||||||
|
nix.maxJobs = lib.mkDefault 8;
|
||||||
|
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
|
||||||
|
|
||||||
|
boot.loader.systemd-boot.enable = true;
|
||||||
|
boot.loader.efi.canTouchEfiVariables = true;
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
{ host }:
|
||||||
|
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
{
|
||||||
|
deployment.targetHost = host;
|
||||||
|
|
||||||
|
disabledModules = [ "security/pam.nix" ];
|
||||||
|
imports =
|
||||||
|
[
|
||||||
|
(./. + "/${host}-hardware-configuration.nix")
|
||||||
|
./pam_p11
|
||||||
|
];
|
||||||
|
|
||||||
|
networking.hostName = host;
|
||||||
|
|
||||||
|
time.timeZone = "Asia/Hong_Kong";
|
||||||
|
|
||||||
|
# List packages installed in system profile. To search, run:
|
||||||
|
# $ nix search wget
|
||||||
|
documentation.enable = false;
|
||||||
|
nixpkgs.config.allowUnfree = true;
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
opensc
|
||||||
|
wget vim git firefox usbutils pciutils file lm_sensors acpi
|
||||||
|
gimp imagemagick
|
||||||
|
(python3.withPackages(ps: with ps; [ numpy scipy ]))
|
||||||
|
psmisc
|
||||||
|
telnet unzip zip gnupg
|
||||||
|
sublime3 rink
|
||||||
|
tmux screen tigervnc
|
||||||
|
(import ./fish-nix-shell)
|
||||||
|
];
|
||||||
|
programs.wireshark.enable = true;
|
||||||
|
|
||||||
|
services.openssh.enable = true;
|
||||||
|
services.openssh.forwardX11 = true;
|
||||||
|
services.openssh.passwordAuthentication = false;
|
||||||
|
hardware.u2f.enable = true;
|
||||||
|
services.pcscd.enable = true;
|
||||||
|
programs.ssh.extraConfig =
|
||||||
|
''
|
||||||
|
PKCS11Provider "${pkgs.opensc}/lib/opensc-pkcs11.so"
|
||||||
|
'';
|
||||||
|
programs.ssh.startAgent = true;
|
||||||
|
programs.ssh.agentPKCS11Whitelist = "${pkgs.opensc}/lib/opensc-pkcs11.so";
|
||||||
|
security.pam.p11.enable = true;
|
||||||
|
|
||||||
|
# Enable CUPS to print documents.
|
||||||
|
services.printing = {
|
||||||
|
enable = true;
|
||||||
|
extraConf =
|
||||||
|
''
|
||||||
|
Browsing Off
|
||||||
|
BrowseLocalProtocols none
|
||||||
|
'';
|
||||||
|
browsedConf =
|
||||||
|
''
|
||||||
|
BrowseRemoteProtocols none
|
||||||
|
BrowseProtocols none
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
services.avahi = {
|
||||||
|
enable = true;
|
||||||
|
nssmdns = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Enable sound.
|
||||||
|
sound.enable = true;
|
||||||
|
hardware.pulseaudio = {
|
||||||
|
enable = true;
|
||||||
|
extraModules = [ pkgs.pulseaudio-modules-bt ];
|
||||||
|
package = pkgs.pulseaudioFull;
|
||||||
|
};
|
||||||
|
|
||||||
|
i18n.inputMethod = {
|
||||||
|
enabled = "fcitx";
|
||||||
|
fcitx.engines = with pkgs.fcitx-engines; [ table-extra m17n ];
|
||||||
|
};
|
||||||
|
fonts.fonts = [ pkgs.noto-fonts pkgs.noto-fonts-cjk pkgs.noto-fonts-emoji pkgs.noto-fonts-extra ];
|
||||||
|
|
||||||
|
# Enable the X11 windowing system.
|
||||||
|
services.xserver.enable = true;
|
||||||
|
services.xserver.layout = "us";
|
||||||
|
services.xserver.xkbOptions = "eurosign:e";
|
||||||
|
|
||||||
|
# Enable touchpad support.
|
||||||
|
services.xserver.libinput.enable = true;
|
||||||
|
|
||||||
|
services.xserver.displayManager.lightdm.enable = true;
|
||||||
|
services.xserver.desktopManager.xfce.enable = true;
|
||||||
|
|
||||||
|
programs.fish.enable = true;
|
||||||
|
programs.fish.promptInit = ''
|
||||||
|
fish-nix-shell --info-right | source
|
||||||
|
'';
|
||||||
|
users.mutableUsers = false;
|
||||||
|
users.defaultUserShell = pkgs.fish;
|
||||||
|
users.extraGroups.plugdev = { };
|
||||||
|
users.extraUsers = import ./common-users.nix { inherit pkgs; };
|
||||||
|
|
||||||
|
security.sudo.wheelNeedsPassword = false;
|
||||||
|
|
||||||
|
nix.binaryCachePublicKeys = ["nixbld.m-labs.hk-1:5aSRVA5b320xbNvu30tqxVPXpld73bhtOeH6uAjRyHc="];
|
||||||
|
nix.binaryCaches = ["https://nixbld.m-labs.hk" "https://cache.nixos.org"];
|
||||||
|
nix.sandboxPaths = ["/opt"];
|
||||||
|
|
||||||
|
# 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 = "19.03"; # Did you read the comment?
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
rpi-1 = import ./rpi.nix { host = "rpi-1"; rpi4 = false; };
|
||||||
|
rpi-2 = import ./rpi.nix { host = "rpi-2"; rpi4 = false; };
|
||||||
|
rpi-3 = import ./rpi.nix { host = "rpi-3"; rpi4 = true; };
|
||||||
|
rpi-4 = import ./rpi.nix { host = "rpi-4"; rpi4 = true; };
|
||||||
|
rpi-5 = import ./rpi.nix { host = "rpi-5"; rpi4 = true; };
|
||||||
|
juno = import ./desktop.nix { host = "juno"; };
|
||||||
|
zeus = import ./desktop.nix { host = "zeus"; };
|
||||||
|
hera = import ./desktop.nix { host = "hera"; };
|
||||||
|
hestia = import ./desktop.nix { host = "hestia"; };
|
||||||
|
chiron = import ./desktop.nix { host = "chiron"; };
|
||||||
|
cnc = import ./light.nix { host = "cnc"; };
|
||||||
|
}
|
|
@ -0,0 +1,843 @@
|
||||||
|
# This module provides configuration for the PAM (Pluggable
|
||||||
|
# Authentication Modules) system.
|
||||||
|
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
pam_p11 = pkgs.callPackage ./pam_p11.nix {};
|
||||||
|
|
||||||
|
parentConfig = config;
|
||||||
|
|
||||||
|
pamOpts = { config, name, ... }: let cfg = config; in let config = parentConfig; in {
|
||||||
|
|
||||||
|
options = {
|
||||||
|
|
||||||
|
name = mkOption {
|
||||||
|
example = "sshd";
|
||||||
|
type = types.str;
|
||||||
|
description = "Name of the PAM service.";
|
||||||
|
};
|
||||||
|
|
||||||
|
unixAuth = mkOption {
|
||||||
|
default = true;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
Whether users can log in with passwords defined in
|
||||||
|
<filename>/etc/shadow</filename>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
rootOK = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
If set, root doesn't need to authenticate (e.g. for the
|
||||||
|
<command>useradd</command> service).
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
p11Auth = mkOption {
|
||||||
|
default = config.security.pam.p11.enable;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
If set, keys listed in
|
||||||
|
<filename>~/.ssh/authorized_keys</filename> and
|
||||||
|
<filename>~/.eid/authorized_certificates</filename>
|
||||||
|
can be used to log in with the associated PKCS#11 tokens.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
u2fAuth = mkOption {
|
||||||
|
default = config.security.pam.u2f.enable;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
If set, users listed in
|
||||||
|
<filename>$XDG_CONFIG_HOME/Yubico/u2f_keys</filename> (or
|
||||||
|
<filename>$HOME/.config/Yubico/u2f_keys</filename> if XDG variable is
|
||||||
|
not set) are able to log in with the associated U2F key. Path can be
|
||||||
|
changed using <option>security.pam.u2f.authFile</option> option.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
yubicoAuth = mkOption {
|
||||||
|
default = config.security.pam.yubico.enable;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
If set, users listed in
|
||||||
|
<filename>~/.yubico/authorized_yubikeys</filename>
|
||||||
|
are able to log in with the associated Yubikey tokens.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
googleAuthenticator = {
|
||||||
|
enable = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
If set, users with enabled Google Authenticator (created
|
||||||
|
<filename>~/.google_authenticator</filename>) will be required
|
||||||
|
to provide Google Authenticator token to log in.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
usbAuth = mkOption {
|
||||||
|
default = config.security.pam.usb.enable;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
If set, users listed in
|
||||||
|
<filename>/etc/pamusb.conf</filename> are able to log in
|
||||||
|
with the associated USB key.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
otpwAuth = mkOption {
|
||||||
|
default = config.security.pam.enableOTPW;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
If set, the OTPW system will be used (if
|
||||||
|
<filename>~/.otpw</filename> exists).
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
googleOsLoginAccountVerification = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
If set, will use the Google OS Login PAM modules
|
||||||
|
(<literal>pam_oslogin_login</literal>,
|
||||||
|
<literal>pam_oslogin_admin</literal>) to verify possible OS Login
|
||||||
|
users and set sudoers configuration accordingly.
|
||||||
|
This only makes sense to enable for the <literal>sshd</literal> PAM
|
||||||
|
service.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
googleOsLoginAuthentication = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
If set, will use the <literal>pam_oslogin_login</literal>'s user
|
||||||
|
authentication methods to authenticate users using 2FA.
|
||||||
|
This only makes sense to enable for the <literal>sshd</literal> PAM
|
||||||
|
service.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
fprintAuth = mkOption {
|
||||||
|
default = config.services.fprintd.enable;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
If set, fingerprint reader will be used (if exists and
|
||||||
|
your fingerprints are enrolled).
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
oathAuth = mkOption {
|
||||||
|
default = config.security.pam.oath.enable;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
If set, the OATH Toolkit will be used.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
sshAgentAuth = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
If set, the calling user's SSH agent is used to authenticate
|
||||||
|
against the keys in the calling user's
|
||||||
|
<filename>~/.ssh/authorized_keys</filename>. This is useful
|
||||||
|
for <command>sudo</command> on password-less remote systems.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
duoSecurity = {
|
||||||
|
enable = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
If set, use the Duo Security pam module
|
||||||
|
<literal>pam_duo</literal> for authentication. Requires
|
||||||
|
configuration of <option>security.duosec</option> options.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
startSession = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
If set, the service will register a new session with
|
||||||
|
systemd's login manager. For local sessions, this will give
|
||||||
|
the user access to audio devices, CD-ROM drives. In the
|
||||||
|
default PolicyKit configuration, it also allows the user to
|
||||||
|
reboot the system.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
setEnvironment = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = ''
|
||||||
|
Whether the service should set the environment variables
|
||||||
|
listed in <option>environment.sessionVariables</option>
|
||||||
|
using <literal>pam_env.so</literal>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
setLoginUid = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
Set the login uid of the process
|
||||||
|
(<filename>/proc/self/loginuid</filename>) for auditing
|
||||||
|
purposes. The login uid is only set by ‘entry points’ like
|
||||||
|
<command>login</command> and <command>sshd</command>, not by
|
||||||
|
commands like <command>sudo</command>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
forwardXAuth = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
Whether X authentication keys should be passed from the
|
||||||
|
calling user to the target user (e.g. for
|
||||||
|
<command>su</command>)
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
pamMount = mkOption {
|
||||||
|
default = config.security.pam.mount.enable;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
Enable PAM mount (pam_mount) system to mount fileystems on user login.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
allowNullPassword = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
Whether to allow logging into accounts that have no password
|
||||||
|
set (i.e., have an empty password field in
|
||||||
|
<filename>/etc/passwd</filename> or
|
||||||
|
<filename>/etc/group</filename>). This does not enable
|
||||||
|
logging into disabled accounts (i.e., that have the password
|
||||||
|
field set to <literal>!</literal>). Note that regardless of
|
||||||
|
what the pam_unix documentation says, accounts with hashed
|
||||||
|
empty passwords are always allowed to log in.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
nodelay = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
Wheather the delay after typing a wrong password should be disabled.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
requireWheel = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
Whether to permit root access only to members of group wheel.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
limits = mkOption {
|
||||||
|
description = ''
|
||||||
|
Attribute set describing resource limits. Defaults to the
|
||||||
|
value of <option>security.pam.loginLimits</option>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
showMotd = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = "Whether to show the message of the day.";
|
||||||
|
};
|
||||||
|
|
||||||
|
makeHomeDir = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
Whether to try to create home directories for users
|
||||||
|
with <literal>$HOME</literal>s pointing to nonexistent
|
||||||
|
locations on session login.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
updateWtmp = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = "Whether to update <filename>/var/log/wtmp</filename>.";
|
||||||
|
};
|
||||||
|
|
||||||
|
logFailures = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = "Whether to log authentication failures in <filename>/var/log/faillog</filename>.";
|
||||||
|
};
|
||||||
|
|
||||||
|
enableAppArmor = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
Enable support for attaching AppArmor profiles at the
|
||||||
|
user/group level, e.g., as part of a role based access
|
||||||
|
control scheme.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
enableKwallet = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
If enabled, pam_wallet will attempt to automatically unlock the
|
||||||
|
user's default KDE wallet upon login. If the user has no wallet named
|
||||||
|
"kdewallet", or the login password does not match their wallet
|
||||||
|
password, KDE will prompt separately after login.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
sssdStrictAccess = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = "enforce sssd access control";
|
||||||
|
};
|
||||||
|
|
||||||
|
enableGnomeKeyring = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
If enabled, pam_gnome_keyring will attempt to automatically unlock the
|
||||||
|
user's default Gnome keyring upon login. If the user login password does
|
||||||
|
not match their keyring password, Gnome Keyring will prompt separately
|
||||||
|
after login.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
text = mkOption {
|
||||||
|
type = types.nullOr types.lines;
|
||||||
|
description = "Contents of the PAM service file.";
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
name = mkDefault name;
|
||||||
|
setLoginUid = mkDefault cfg.startSession;
|
||||||
|
limits = mkDefault config.security.pam.loginLimits;
|
||||||
|
|
||||||
|
# !!! TODO: move the LDAP stuff to the LDAP module, and the
|
||||||
|
# Samba stuff to the Samba module. This requires that the PAM
|
||||||
|
# module provides the right hooks.
|
||||||
|
text = mkDefault
|
||||||
|
(''
|
||||||
|
# Account management.
|
||||||
|
account required pam_unix.so
|
||||||
|
${optionalString use_ldap
|
||||||
|
"account sufficient ${pam_ldap}/lib/security/pam_ldap.so"}
|
||||||
|
${optionalString (config.services.sssd.enable && cfg.sssdStrictAccess==false)
|
||||||
|
"account sufficient ${pkgs.sssd}/lib/security/pam_sss.so"}
|
||||||
|
${optionalString (config.services.sssd.enable && cfg.sssdStrictAccess)
|
||||||
|
"account [default=bad success=ok user_unknown=ignore] ${pkgs.sssd}/lib/security/pam_sss.so"}
|
||||||
|
${optionalString config.krb5.enable
|
||||||
|
"account sufficient ${pam_krb5}/lib/security/pam_krb5.so"}
|
||||||
|
${optionalString cfg.googleOsLoginAccountVerification ''
|
||||||
|
account [success=ok ignore=ignore default=die] ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so
|
||||||
|
account [success=ok default=ignore] ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_admin.so
|
||||||
|
''}
|
||||||
|
|
||||||
|
# Authentication management.
|
||||||
|
${optionalString cfg.googleOsLoginAuthentication
|
||||||
|
"auth [success=done perm_denied=bad default=ignore] ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so"}
|
||||||
|
${optionalString cfg.rootOK
|
||||||
|
"auth sufficient pam_rootok.so"}
|
||||||
|
${optionalString cfg.requireWheel
|
||||||
|
"auth required pam_wheel.so use_uid"}
|
||||||
|
${optionalString cfg.logFailures
|
||||||
|
"auth required pam_tally.so"}
|
||||||
|
${optionalString (config.security.pam.enableSSHAgentAuth && cfg.sshAgentAuth)
|
||||||
|
"auth sufficient ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so file=~/.ssh/authorized_keys:~/.ssh/authorized_keys2:/etc/ssh/authorized_keys.d/%u"}
|
||||||
|
${optionalString cfg.fprintAuth
|
||||||
|
"auth sufficient ${pkgs.fprintd}/lib/security/pam_fprintd.so"}
|
||||||
|
${let p11 = config.security.pam.p11; in optionalString cfg.p11Auth
|
||||||
|
"auth ${p11.control} ${pam_p11}/lib/security/pam_p11.so ${pkgs.opensc}/lib/opensc-pkcs11.so"}
|
||||||
|
${let u2f = config.security.pam.u2f; in optionalString cfg.u2fAuth
|
||||||
|
"auth ${u2f.control} ${pkgs.pam_u2f}/lib/security/pam_u2f.so ${optionalString u2f.debug "debug"} ${optionalString (u2f.authFile != null) "authfile=${u2f.authFile}"} ${optionalString u2f.interactive "interactive"} ${optionalString u2f.cue "cue"}"}
|
||||||
|
${optionalString cfg.usbAuth
|
||||||
|
"auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so"}
|
||||||
|
${let oath = config.security.pam.oath; in optionalString cfg.oathAuth
|
||||||
|
"auth requisite ${pkgs.oathToolkit}/lib/security/pam_oath.so window=${toString oath.window} usersfile=${toString oath.usersFile} digits=${toString oath.digits}"}
|
||||||
|
${let yubi = config.security.pam.yubico; in optionalString cfg.yubicoAuth
|
||||||
|
"auth ${yubi.control} ${pkgs.yubico-pam}/lib/security/pam_yubico.so mode=${toString yubi.mode} ${optionalString (yubi.mode == "client") "id=${toString yubi.id}"} ${optionalString yubi.debug "debug"}"}
|
||||||
|
'' +
|
||||||
|
# Modules in this block require having the password set in PAM_AUTHTOK.
|
||||||
|
# pam_unix is marked as 'sufficient' on NixOS which means nothing will run
|
||||||
|
# after it succeeds. Certain modules need to run after pam_unix
|
||||||
|
# prompts the user for password so we run it once with 'required' at an
|
||||||
|
# earlier point and it will run again with 'sufficient' further down.
|
||||||
|
# We use try_first_pass the second time to avoid prompting password twice
|
||||||
|
(optionalString (cfg.unixAuth &&
|
||||||
|
(config.security.pam.enableEcryptfs
|
||||||
|
|| cfg.pamMount
|
||||||
|
|| cfg.enableKwallet
|
||||||
|
|| cfg.enableGnomeKeyring
|
||||||
|
|| cfg.googleAuthenticator.enable
|
||||||
|
|| cfg.duoSecurity.enable)) ''
|
||||||
|
auth required pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} ${optionalString cfg.nodelay "nodelay"} likeauth
|
||||||
|
${optionalString config.security.pam.enableEcryptfs
|
||||||
|
"auth optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap"}
|
||||||
|
${optionalString cfg.pamMount
|
||||||
|
"auth optional ${pkgs.pam_mount}/lib/security/pam_mount.so"}
|
||||||
|
${optionalString cfg.enableKwallet
|
||||||
|
("auth optional ${pkgs.plasma5.kwallet-pam}/lib/security/pam_kwallet5.so" +
|
||||||
|
" kwalletd=${pkgs.libsForQt5.kwallet.bin}/bin/kwalletd5")}
|
||||||
|
${optionalString cfg.enableGnomeKeyring
|
||||||
|
"auth optional ${pkgs.gnome3.gnome-keyring}/lib/security/pam_gnome_keyring.so"}
|
||||||
|
${optionalString cfg.googleAuthenticator.enable
|
||||||
|
"auth required ${pkgs.googleAuthenticator}/lib/security/pam_google_authenticator.so no_increment_hotp"}
|
||||||
|
${optionalString cfg.duoSecurity.enable
|
||||||
|
"auth required ${pkgs.duo-unix}/lib/security/pam_duo.so"}
|
||||||
|
'') + ''
|
||||||
|
${optionalString cfg.unixAuth
|
||||||
|
"auth sufficient pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} ${optionalString cfg.nodelay "nodelay"} likeauth try_first_pass"}
|
||||||
|
${optionalString cfg.otpwAuth
|
||||||
|
"auth sufficient ${pkgs.otpw}/lib/security/pam_otpw.so"}
|
||||||
|
${optionalString use_ldap
|
||||||
|
"auth sufficient ${pam_ldap}/lib/security/pam_ldap.so use_first_pass"}
|
||||||
|
${optionalString config.services.sssd.enable
|
||||||
|
"auth sufficient ${pkgs.sssd}/lib/security/pam_sss.so use_first_pass"}
|
||||||
|
${optionalString config.krb5.enable ''
|
||||||
|
auth [default=ignore success=1 service_err=reset] ${pam_krb5}/lib/security/pam_krb5.so use_first_pass
|
||||||
|
auth [default=die success=done] ${pam_ccreds}/lib/security/pam_ccreds.so action=validate use_first_pass
|
||||||
|
auth sufficient ${pam_ccreds}/lib/security/pam_ccreds.so action=store use_first_pass
|
||||||
|
''}
|
||||||
|
auth required pam_deny.so
|
||||||
|
|
||||||
|
# Password management.
|
||||||
|
password sufficient pam_unix.so nullok sha512
|
||||||
|
${optionalString config.security.pam.enableEcryptfs
|
||||||
|
"password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"}
|
||||||
|
${optionalString cfg.pamMount
|
||||||
|
"password optional ${pkgs.pam_mount}/lib/security/pam_mount.so"}
|
||||||
|
${optionalString use_ldap
|
||||||
|
"password sufficient ${pam_ldap}/lib/security/pam_ldap.so"}
|
||||||
|
${optionalString config.services.sssd.enable
|
||||||
|
"password sufficient ${pkgs.sssd}/lib/security/pam_sss.so use_authtok"}
|
||||||
|
${optionalString config.krb5.enable
|
||||||
|
"password sufficient ${pam_krb5}/lib/security/pam_krb5.so use_first_pass"}
|
||||||
|
${optionalString config.services.samba.syncPasswordsByPam
|
||||||
|
"password optional ${pkgs.samba}/lib/security/pam_smbpass.so nullok use_authtok try_first_pass"}
|
||||||
|
${optionalString cfg.enableGnomeKeyring
|
||||||
|
"password optional ${pkgs.gnome3.gnome-keyring}/lib/security/pam_gnome_keyring.so use_authtok"}
|
||||||
|
|
||||||
|
# Session management.
|
||||||
|
${optionalString cfg.setEnvironment ''
|
||||||
|
session required pam_env.so conffile=${config.system.build.pamEnvironment} readenv=0
|
||||||
|
''}
|
||||||
|
session required pam_unix.so
|
||||||
|
${optionalString cfg.setLoginUid
|
||||||
|
"session ${
|
||||||
|
if config.boot.isContainer then "optional" else "required"
|
||||||
|
} pam_loginuid.so"}
|
||||||
|
${optionalString cfg.makeHomeDir
|
||||||
|
"session required ${pkgs.pam}/lib/security/pam_mkhomedir.so silent skel=${config.security.pam.makeHomeDir.skelDirectory} umask=0022"}
|
||||||
|
${optionalString cfg.updateWtmp
|
||||||
|
"session required ${pkgs.pam}/lib/security/pam_lastlog.so silent"}
|
||||||
|
${optionalString config.security.pam.enableEcryptfs
|
||||||
|
"session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"}
|
||||||
|
${optionalString use_ldap
|
||||||
|
"session optional ${pam_ldap}/lib/security/pam_ldap.so"}
|
||||||
|
${optionalString config.services.sssd.enable
|
||||||
|
"session optional ${pkgs.sssd}/lib/security/pam_sss.so"}
|
||||||
|
${optionalString config.krb5.enable
|
||||||
|
"session optional ${pam_krb5}/lib/security/pam_krb5.so"}
|
||||||
|
${optionalString cfg.otpwAuth
|
||||||
|
"session optional ${pkgs.otpw}/lib/security/pam_otpw.so"}
|
||||||
|
${optionalString cfg.startSession
|
||||||
|
"session optional ${pkgs.systemd}/lib/security/pam_systemd.so"}
|
||||||
|
${optionalString cfg.forwardXAuth
|
||||||
|
"session optional pam_xauth.so xauthpath=${pkgs.xorg.xauth}/bin/xauth systemuser=99"}
|
||||||
|
${optionalString (cfg.limits != [])
|
||||||
|
"session required ${pkgs.pam}/lib/security/pam_limits.so conf=${makeLimitsConf cfg.limits}"}
|
||||||
|
${optionalString (cfg.showMotd && config.users.motd != null)
|
||||||
|
"session optional ${pkgs.pam}/lib/security/pam_motd.so motd=${motd}"}
|
||||||
|
${optionalString cfg.pamMount
|
||||||
|
"session optional ${pkgs.pam_mount}/lib/security/pam_mount.so"}
|
||||||
|
${optionalString (cfg.enableAppArmor && config.security.apparmor.enable)
|
||||||
|
"session optional ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so order=user,group,default debug"}
|
||||||
|
${optionalString (cfg.enableKwallet)
|
||||||
|
("session optional ${pkgs.plasma5.kwallet-pam}/lib/security/pam_kwallet5.so" +
|
||||||
|
" kwalletd=${pkgs.libsForQt5.kwallet.bin}/bin/kwalletd5")}
|
||||||
|
${optionalString (cfg.enableGnomeKeyring)
|
||||||
|
"session optional ${pkgs.gnome3.gnome-keyring}/lib/security/pam_gnome_keyring.so auto_start"}
|
||||||
|
${optionalString (config.virtualisation.lxc.lxcfs.enable)
|
||||||
|
"session optional ${pkgs.lxc}/lib/security/pam_cgfs.so -c all"}
|
||||||
|
'');
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inherit (pkgs) pam_krb5 pam_ccreds;
|
||||||
|
|
||||||
|
use_ldap = (config.users.ldap.enable && config.users.ldap.loginPam);
|
||||||
|
pam_ldap = if config.users.ldap.daemon.enable then pkgs.nss_pam_ldapd else pkgs.pam_ldap;
|
||||||
|
|
||||||
|
# Create a limits.conf(5) file.
|
||||||
|
makeLimitsConf = limits:
|
||||||
|
pkgs.writeText "limits.conf"
|
||||||
|
(concatMapStrings ({ domain, type, item, value }:
|
||||||
|
"${domain} ${type} ${item} ${toString value}\n")
|
||||||
|
limits);
|
||||||
|
|
||||||
|
motd = pkgs.writeText "motd" config.users.motd;
|
||||||
|
|
||||||
|
makePAMService = name: service:
|
||||||
|
{ name = "pam.d/${name}";
|
||||||
|
value.source = pkgs.writeText "${name}.pam" service.text;
|
||||||
|
};
|
||||||
|
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
imports = [
|
||||||
|
(mkRenamedOptionModule [ "security" "pam" "enableU2F" ] [ "security" "pam" "u2f" "enable" ])
|
||||||
|
];
|
||||||
|
|
||||||
|
###### interface
|
||||||
|
|
||||||
|
options = {
|
||||||
|
|
||||||
|
security.pam.loginLimits = mkOption {
|
||||||
|
default = [];
|
||||||
|
example =
|
||||||
|
[ { domain = "ftp";
|
||||||
|
type = "hard";
|
||||||
|
item = "nproc";
|
||||||
|
value = "0";
|
||||||
|
}
|
||||||
|
{ domain = "@student";
|
||||||
|
type = "-";
|
||||||
|
item = "maxlogins";
|
||||||
|
value = "4";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
description =
|
||||||
|
'' Define resource limits that should apply to users or groups.
|
||||||
|
Each item in the list should be an attribute set with a
|
||||||
|
<varname>domain</varname>, <varname>type</varname>,
|
||||||
|
<varname>item</varname>, and <varname>value</varname>
|
||||||
|
attribute. The syntax and semantics of these attributes
|
||||||
|
must be that described in the limits.conf(5) man page.
|
||||||
|
|
||||||
|
Note that these limits do not apply to systemd services,
|
||||||
|
whose limits can be changed via <option>systemd.extraConfig</option>
|
||||||
|
instead.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
security.pam.services = mkOption {
|
||||||
|
default = [];
|
||||||
|
type = with types; loaOf (submodule pamOpts);
|
||||||
|
description =
|
||||||
|
''
|
||||||
|
This option defines the PAM services. A service typically
|
||||||
|
corresponds to a program that uses PAM,
|
||||||
|
e.g. <command>login</command> or <command>passwd</command>.
|
||||||
|
Each attribute of this set defines a PAM service, with the attribute name
|
||||||
|
defining the name of the service.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
security.pam.makeHomeDir.skelDirectory = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "/var/empty";
|
||||||
|
example = "/etc/skel";
|
||||||
|
description = ''
|
||||||
|
Path to skeleton directory whose contents are copied to home
|
||||||
|
directories newly created by <literal>pam_mkhomedir</literal>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
security.pam.enableSSHAgentAuth = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description =
|
||||||
|
''
|
||||||
|
Enable sudo logins if the user's SSH agent provides a key
|
||||||
|
present in <filename>~/.ssh/authorized_keys</filename>.
|
||||||
|
This allows machines to exclusively use SSH keys instead of
|
||||||
|
passwords.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
security.pam.enableOTPW = mkEnableOption "the OTPW (one-time password) PAM module";
|
||||||
|
|
||||||
|
security.pam.p11 = {
|
||||||
|
enable = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
Enables P11 PAM (<literal>pam_p11</literal>) module.
|
||||||
|
|
||||||
|
If set, users can log in with SSH keys and PKCS#11 tokens.
|
||||||
|
|
||||||
|
More information can be found <link
|
||||||
|
xlink:href="https://github.com/OpenSC/pam_p11">here</link>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
control = mkOption {
|
||||||
|
default = "sufficient";
|
||||||
|
type = types.enum [ "required" "requisite" "sufficient" "optional" ];
|
||||||
|
description = ''
|
||||||
|
This option sets pam "control".
|
||||||
|
If you want to have multi factor authentication, use "required".
|
||||||
|
If you want to use the PKCS#11 device instead of the regular password,
|
||||||
|
use "sufficient".
|
||||||
|
|
||||||
|
Read
|
||||||
|
<citerefentry>
|
||||||
|
<refentrytitle>pam.conf</refentrytitle>
|
||||||
|
<manvolnum>5</manvolnum>
|
||||||
|
</citerefentry>
|
||||||
|
for better understanding of this option.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
security.pam.u2f = {
|
||||||
|
enable = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
Enables U2F PAM (<literal>pam-u2f</literal>) module.
|
||||||
|
|
||||||
|
If set, users listed in
|
||||||
|
<filename>$XDG_CONFIG_HOME/Yubico/u2f_keys</filename> (or
|
||||||
|
<filename>$HOME/.config/Yubico/u2f_keys</filename> if XDG variable is
|
||||||
|
not set) are able to log in with the associated U2F key. The path can
|
||||||
|
be changed using <option>security.pam.u2f.authFile</option> option.
|
||||||
|
|
||||||
|
File format is:
|
||||||
|
<literal>username:first_keyHandle,first_public_key: second_keyHandle,second_public_key</literal>
|
||||||
|
This file can be generated using <command>pamu2fcfg</command> command.
|
||||||
|
|
||||||
|
More information can be found <link
|
||||||
|
xlink:href="https://developers.yubico.com/pam-u2f/">here</link>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
authFile = mkOption {
|
||||||
|
default = null;
|
||||||
|
type = with types; nullOr path;
|
||||||
|
description = ''
|
||||||
|
By default <literal>pam-u2f</literal> module reads the keys from
|
||||||
|
<filename>$XDG_CONFIG_HOME/Yubico/u2f_keys</filename> (or
|
||||||
|
<filename>$HOME/.config/Yubico/u2f_keys</filename> if XDG variable is
|
||||||
|
not set).
|
||||||
|
|
||||||
|
If you want to change auth file locations or centralize database (for
|
||||||
|
example use <filename>/etc/u2f-mappings</filename>) you can set this
|
||||||
|
option.
|
||||||
|
|
||||||
|
File format is:
|
||||||
|
<literal>username:first_keyHandle,first_public_key: second_keyHandle,second_public_key</literal>
|
||||||
|
This file can be generated using <command>pamu2fcfg</command> command.
|
||||||
|
|
||||||
|
More information can be found <link
|
||||||
|
xlink:href="https://developers.yubico.com/pam-u2f/">here</link>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
control = mkOption {
|
||||||
|
default = "sufficient";
|
||||||
|
type = types.enum [ "required" "requisite" "sufficient" "optional" ];
|
||||||
|
description = ''
|
||||||
|
This option sets pam "control".
|
||||||
|
If you want to have multi factor authentication, use "required".
|
||||||
|
If you want to use U2F device instead of regular password, use "sufficient".
|
||||||
|
|
||||||
|
Read
|
||||||
|
<citerefentry>
|
||||||
|
<refentrytitle>pam.conf</refentrytitle>
|
||||||
|
<manvolnum>5</manvolnum>
|
||||||
|
</citerefentry>
|
||||||
|
for better understanding of this option.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
debug = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
Debug output to stderr.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
interactive = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
Set to prompt a message and wait before testing the presence of a U2F device.
|
||||||
|
Recommended if your device doesn’t have a tactile trigger.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
cue = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
By default <literal>pam-u2f</literal> module does not inform user
|
||||||
|
that he needs to use the u2f device, it just waits without a prompt.
|
||||||
|
|
||||||
|
If you set this option to <literal>true</literal>,
|
||||||
|
<literal>cue</literal> option is added to <literal>pam-u2f</literal>
|
||||||
|
module and reminder message will be displayed.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
security.pam.yubico = {
|
||||||
|
enable = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
Enables Yubico PAM (<literal>yubico-pam</literal>) module.
|
||||||
|
|
||||||
|
If set, users listed in
|
||||||
|
<filename>~/.yubico/authorized_yubikeys</filename>
|
||||||
|
are able to log in with the associated Yubikey tokens.
|
||||||
|
|
||||||
|
The file must have only one line:
|
||||||
|
<literal>username:yubikey_token_id1:yubikey_token_id2</literal>
|
||||||
|
More information can be found <link
|
||||||
|
xlink:href="https://developers.yubico.com/yubico-pam/">here</link>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
control = mkOption {
|
||||||
|
default = "sufficient";
|
||||||
|
type = types.enum [ "required" "requisite" "sufficient" "optional" ];
|
||||||
|
description = ''
|
||||||
|
This option sets pam "control".
|
||||||
|
If you want to have multi factor authentication, use "required".
|
||||||
|
If you want to use Yubikey instead of regular password, use "sufficient".
|
||||||
|
|
||||||
|
Read
|
||||||
|
<citerefentry>
|
||||||
|
<refentrytitle>pam.conf</refentrytitle>
|
||||||
|
<manvolnum>5</manvolnum>
|
||||||
|
</citerefentry>
|
||||||
|
for better understanding of this option.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
id = mkOption {
|
||||||
|
example = "42";
|
||||||
|
type = types.str;
|
||||||
|
description = "client id";
|
||||||
|
};
|
||||||
|
|
||||||
|
debug = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
Debug output to stderr.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
mode = mkOption {
|
||||||
|
default = "client";
|
||||||
|
type = types.enum [ "client" "challenge-response" ];
|
||||||
|
description = ''
|
||||||
|
Mode of operation.
|
||||||
|
|
||||||
|
Use "client" for online validation with a YubiKey validation service such as
|
||||||
|
the YubiCloud.
|
||||||
|
|
||||||
|
Use "challenge-response" for offline validation using YubiKeys with HMAC-SHA-1
|
||||||
|
Challenge-Response configurations. See the man-page ykpamcfg(1) for further
|
||||||
|
details on how to configure offline Challenge-Response validation.
|
||||||
|
|
||||||
|
More information can be found <link
|
||||||
|
xlink:href="https://developers.yubico.com/yubico-pam/Authentication_Using_Challenge-Response.html">here</link>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
security.pam.enableEcryptfs = mkEnableOption "eCryptfs PAM module (mounting ecryptfs home directory on login)";
|
||||||
|
|
||||||
|
users.motd = mkOption {
|
||||||
|
default = null;
|
||||||
|
example = "Today is Sweetmorn, the 4th day of The Aftermath in the YOLD 3178.";
|
||||||
|
type = types.nullOr types.lines;
|
||||||
|
description = "Message of the day shown to users when they log in.";
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
###### implementation
|
||||||
|
|
||||||
|
config = {
|
||||||
|
|
||||||
|
environment.systemPackages =
|
||||||
|
# Include the PAM modules in the system path mostly for the manpages.
|
||||||
|
[ pkgs.pam ]
|
||||||
|
++ optional config.users.ldap.enable pam_ldap
|
||||||
|
++ optional config.services.sssd.enable pkgs.sssd
|
||||||
|
++ optionals config.krb5.enable [pam_krb5 pam_ccreds]
|
||||||
|
++ optionals config.security.pam.enableOTPW [ pkgs.otpw ]
|
||||||
|
++ optionals config.security.pam.oath.enable [ pkgs.oathToolkit ]
|
||||||
|
++ optionals config.security.pam.p11.enable [ pam_p11 ]
|
||||||
|
++ optionals config.security.pam.u2f.enable [ pkgs.pam_u2f ];
|
||||||
|
|
||||||
|
boot.supportedFilesystems = optionals config.security.pam.enableEcryptfs [ "ecryptfs" ];
|
||||||
|
|
||||||
|
security.wrappers = {
|
||||||
|
unix_chkpwd = {
|
||||||
|
source = "${pkgs.pam}/sbin/unix_chkpwd.orig";
|
||||||
|
owner = "root";
|
||||||
|
setuid = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.etc = mapAttrs' makePAMService config.security.pam.services;
|
||||||
|
|
||||||
|
security.pam.services =
|
||||||
|
{ other.text =
|
||||||
|
''
|
||||||
|
auth required pam_warn.so
|
||||||
|
auth required pam_deny.so
|
||||||
|
account required pam_warn.so
|
||||||
|
account required pam_deny.so
|
||||||
|
password required pam_warn.so
|
||||||
|
password required pam_deny.so
|
||||||
|
session required pam_warn.so
|
||||||
|
session required pam_deny.so
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Most of these should be moved to specific modules.
|
||||||
|
i3lock = {};
|
||||||
|
i3lock-color = {};
|
||||||
|
vlock = {};
|
||||||
|
xlock = {};
|
||||||
|
xscreensaver = {};
|
||||||
|
|
||||||
|
runuser = { rootOK = true; unixAuth = false; setEnvironment = false; };
|
||||||
|
|
||||||
|
/* FIXME: should runuser -l start a systemd session? Currently
|
||||||
|
it complains "Cannot create session: Already running in a
|
||||||
|
session". */
|
||||||
|
runuser-l = { rootOK = true; unixAuth = false; };
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
{ stdenv, fetchFromGitHub, autoreconfHook, pkg-config, openssl, libp11, pam }:
|
||||||
|
|
||||||
|
stdenv.mkDerivation rec {
|
||||||
|
pname = "pam_p11";
|
||||||
|
version = "0.3.1";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "OpenSC";
|
||||||
|
repo = "pam_p11";
|
||||||
|
rev = "pam_p11-${version}";
|
||||||
|
sha256 = "1caidy18rq5zk82d51x8vwidmkhwmanf3qm25x1yrdlbhxv6m7lk";
|
||||||
|
};
|
||||||
|
|
||||||
|
patchPhase =
|
||||||
|
''
|
||||||
|
substituteInPlace src/match_openssh.c --replace \
|
||||||
|
'"%s/.ssh/authorized_keys", pw->pw_dir)' \
|
||||||
|
'"/etc/ssh/authorized_keys.d/%s", pw->pw_name)'
|
||||||
|
'';
|
||||||
|
|
||||||
|
nativeBuildInputs = [ autoreconfHook pkg-config ];
|
||||||
|
buildInputs = [ pam openssl libp11 ];
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
{ host, rpi4 }:
|
||||||
|
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
let
|
||||||
|
m-labs = import (fetchTarball https://nixbld.m-labs.hk/channel/custom/artiq/full/artiq-full/nixexprs.tar.xz) { inherit pkgs; };
|
||||||
|
in
|
||||||
|
{
|
||||||
|
deployment.targetHost = host;
|
||||||
|
nixpkgs.system = "aarch64-linux";
|
||||||
|
|
||||||
|
boot.loader.grub.enable = false;
|
||||||
|
|
||||||
|
boot.loader.generic-extlinux-compatible.enable = !rpi4;
|
||||||
|
boot.loader.raspberryPi = pkgs.lib.mkIf rpi4 {
|
||||||
|
enable = true;
|
||||||
|
version = 4;
|
||||||
|
};
|
||||||
|
boot.kernelPackages = pkgs.lib.mkIf rpi4 pkgs.linuxPackages_latest;
|
||||||
|
|
||||||
|
fileSystems = if rpi4 then {
|
||||||
|
"/boot" = {
|
||||||
|
device = "/dev/disk/by-label/FIRMWARE";
|
||||||
|
fsType = "vfat";
|
||||||
|
};
|
||||||
|
"/" = {
|
||||||
|
device = "/dev/disk/by-label/NIXOS_SD";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
"/" = {
|
||||||
|
device = "/dev/disk/by-label/NIXOS_SD";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.openssh.enable = true;
|
||||||
|
services.openssh.passwordAuthentication = false;
|
||||||
|
|
||||||
|
networking.hostName = host;
|
||||||
|
time.timeZone = "Asia/Hong_Kong";
|
||||||
|
|
||||||
|
users.extraGroups.plugdev = { };
|
||||||
|
users.mutableUsers = false;
|
||||||
|
users.defaultUserShell = pkgs.fish;
|
||||||
|
users.extraUsers = (import ./common-users.nix { inherit pkgs; }) // {
|
||||||
|
nix = {
|
||||||
|
isNormalUser = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
security.sudo.wheelNeedsPassword = false;
|
||||||
|
services.udev.packages = [ m-labs.openocd ];
|
||||||
|
|
||||||
|
documentation.enable = false;
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
psmisc wget vim git usbutils lm_sensors file telnet mosh tmux xc3sprog m-labs.openocd screen gdb minicom picocom
|
||||||
|
];
|
||||||
|
programs.fish.enable = true;
|
||||||
|
programs.wireshark.enable = true;
|
||||||
|
|
||||||
|
nix.binaryCachePublicKeys = ["nixbld.m-labs.hk-1:5aSRVA5b320xbNvu30tqxVPXpld73bhtOeH6uAjRyHc="];
|
||||||
|
nix.binaryCaches = ["https://cache.nixos.org" "https://nixbld.m-labs.hk"];
|
||||||
|
nix.trustedUsers = ["root" "nix"];
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
# 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, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports =
|
||||||
|
[ <nixpkgs/nixos/modules/installer/scan/not-detected.nix>
|
||||||
|
];
|
||||||
|
|
||||||
|
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod" ];
|
||||||
|
boot.initrd.kernelModules = [ ];
|
||||||
|
boot.kernelModules = [ "kvm-intel" ];
|
||||||
|
boot.extraModulePackages = [ ];
|
||||||
|
|
||||||
|
fileSystems."/" =
|
||||||
|
{ device = "/dev/disk/by-uuid/890b20a2-08d5-4635-b3a7-003ad4a11a19";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/boot" =
|
||||||
|
{ device = "/dev/disk/by-uuid/91B4-E546";
|
||||||
|
fsType = "vfat";
|
||||||
|
};
|
||||||
|
|
||||||
|
swapDevices = [ ];
|
||||||
|
|
||||||
|
nix.maxJobs = lib.mkDefault 16;
|
||||||
|
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
|
||||||
|
|
||||||
|
boot.loader.systemd-boot.enable = true;
|
||||||
|
boot.loader.efi.canTouchEfiVariables = true;
|
||||||
|
}
|
Loading…
Reference in New Issue