Compare commits

...

5 commits

10 changed files with 436 additions and 21 deletions

1
.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
tailscale-client-secret filter=git-agecrypt diff=git-agecrypt

View file

@ -12,8 +12,6 @@
boot.tmp.cleanOnBoot = true; boot.tmp.cleanOnBoot = true;
boot.loader.generic-extlinux-compatible.enable = false;
# Set root password to a secure password # Set root password to a secure password
users.users.root.password = "asecurepassword"; users.users.root.password = "asecurepassword";
@ -36,12 +34,20 @@
networking.hostName = "kiosk"; networking.hostName = "kiosk";
time.timeZone = "America/New_York"; time.timeZone = "America/New_York";
raspberry-pi-nix.board = "bcm2711";
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
vim vim
git git
]; ];
environment.defaultPackages = lib.mkForce [ ];
documentation = {
enable = false;
nixos.enable = false;
man.enable = false;
info.enable = false;
doc.enable = false;
dev.enable = false;
};
nix.settings = { nix.settings = {
substituters = [ "https://hydra.inx.moe?priority=10" ]; substituters = [ "https://hydra.inx.moe?priority=10" ];

View file

@ -7,24 +7,27 @@
nixos-hardware.url = "github:NixOS/nixos-hardware"; nixos-hardware.url = "github:NixOS/nixos-hardware";
}; };
outputs = { nixpkgs, rpi-nix, nixos-hardware, ... }: { outputs = inputs@{ nixpkgs, rpi-nix, nixos-hardware, ... }:
let
nixosConfigurations.kiosk = nixpkgs.lib.nixosSystem { rpi = [
system = "aarch64-linux"; ./sd-image
modules = [ rpi-nix.nixosModules.raspberry-pi
];
mkKiosk = system: modules: nixpkgs.lib.nixosSystem {
inherit system;
specialArgs = { inherit inputs; };
modules = nixpkgs.lib.flatten modules ++ [
./base.nix ./base.nix
./kiosk.nix ./kiosk.nix
rpi-nix.nixosModules.raspberry-pi
rpi-nix.nixosModules.sd-image
nixos-hardware.nixosModules.raspberry-pi-4
({ lib, pkgs, ... }: {
sdImage.compressImage = false;
nixpkgs.buildPlatform = "x86_64-linux";
boot.kernelPackages = lib.mkForce pkgs.linuxKernel.packages.linux_rpi4;
})
]; ];
};
in
{
nixosConfigurations = {
kiosk-rpi3 = mkKiosk "aarch64-linux" [ rpi ./rpi3.nix ];
kiosk-rpi4 = mkKiosk "aarch64-linux" [ rpi ./rpi4.nix ];
pc = mkKiosk "x86_64-linux" [ ./pc.nix ];
}; };
}; };
} }

5
git-agecrypt.toml Normal file
View file

@ -0,0 +1,5 @@
[config]
tailscale-client-secret = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINwo8TGBe91mmkc/QonsXtTBKCJtsAGz3YzphDZlzmaO infinidoge@Infini-FRAMEWORK",
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIUIcQljnMxXsLU8RO33kqFRqEOgQi7U0x+UFG4Caskk infinidoge@Infini-DL360",
]

View file

@ -26,6 +26,7 @@ in
# Set firefox autoplay policy to always allow autoplay for dashboard # Set firefox autoplay policy to always allow autoplay for dashboard
programs.firefox.policies = { programs.firefox.policies = {
Permissions.Autoplay.Allow = [ dashboardUrl ]; Permissions.Autoplay.Allow = [ dashboardUrl ];
DontCheckDefaultBrowser = true;
}; };
# Enable pipewire/pipewire-pulse for audio # Enable pipewire/pipewire-pulse for audio
@ -34,4 +35,20 @@ in
enable = true; enable = true;
pulse.enable = true; pulse.enable = true;
}; };
services.tailscale = {
enable = true;
extraUpFlags = [ "--advertise-tags" "tag:kiosk" ];
authKeyFile = ./tailscale-client-secret;
authKeyParameters.ephemeral = false;
openFirewall = true;
};
networking.firewall.trustedInterfaces = [ "tailscale0" ];
services.openssh = {
enable = true;
settings = {
PermitRootLogin = "yes";
};
};
} }

13
rpi3.nix Normal file
View file

@ -0,0 +1,13 @@
{ inputs, lib, pkgs, ... }:
{
imports = [
inputs.nixos-hardware.nixosModules.raspberry-pi-3
];
nixpkgs.buildPlatform = "x86_64-linux";
boot.kernelPackages = lib.mkForce pkgs.linuxKernel.packages.linux_rpi3;
raspberry-pi-nix.board = "bcm2711";
raspberry-pi-nix.uboot.enable = true;
}

30
rpi4.nix Normal file
View file

@ -0,0 +1,30 @@
{ inputs, lib, pkgs, ... }:
{
imports = [
inputs.nixos-hardware.nixosModules.raspberry-pi-4
];
nixpkgs.buildPlatform = "x86_64-linux";
raspberry-pi-nix.board = "bcm2711";
boot.kernelPackages = lib.mkForce pkgs.linuxKernel.packages.linux_rpi4;
# nixos-hardware and raspberry-pi-nix conflict, set explicitly
boot.loader.generic-extlinux-compatible.enable = false;
boot.extraModprobeConfig = ''
options snd_bcm2835 enable_headphones=1 enable_hdmi=1 enable_compat_alsa=0
'';
hardware.raspberry-pi."4" = {
fkms-3d.enable = true;
};
hardware.raspberry-pi.config.all.base-dt-params = {
audio = {
enable = true;
value = true;
};
};
}

69
sd-image/default.nix Normal file
View file

@ -0,0 +1,69 @@
{ config, lib, pkgs, ... }:
{
imports = [ ./sd-image.nix ];
config = {
boot.loader.grub.enable = false;
boot.consoleLogLevel = lib.mkDefault 7;
boot.kernelParams = [
# This is ugly and fragile, but the sdImage image has an msdos
# table, so the partition table id is a 1-indexed hex
# number. So, we drop the hex prefix and stick on a "02" to
# refer to the root partition.
"root=PARTUUID=${lib.strings.removePrefix "0x" config.sdImage.firmwarePartitionID}-02"
"rootfstype=ext4"
"fsck.repair=yes"
"rootwait"
];
sdImage =
let
kernel-params = pkgs.writeTextFile {
name = "cmdline.txt";
text = ''
${lib.strings.concatStringsSep " " config.boot.kernelParams}
'';
};
cfg = config.raspberry-pi-nix;
version = cfg.kernel-version;
board = cfg.board;
kernel = "${config.system.build.kernel}/${config.system.boot.loader.kernelFile}";
initrd = "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}";
populate-kernel =
if cfg.uboot.enable
then ''
cp ${cfg.uboot.package}/u-boot.bin firmware/u-boot-rpi-arm64.bin
''
else ''
cp "${kernel}" firmware/kernel.img
cp "${initrd}" firmware/initrd
cp "${kernel-params}" firmware/cmdline.txt
'';
in
{
populateFirmwareCommands = ''
${populate-kernel}
cp -r ${pkgs.raspberrypifw}/share/raspberrypi/boot/{start*.elf,*.dtb,bootcode.bin,fixup*.dat,overlays} firmware
cp ${config.hardware.raspberry-pi.config-output} firmware/config.txt
'';
populateRootCommands =
if cfg.uboot.enable
then ''
mkdir -p ./files/boot
${config.boot.loader.generic-extlinux-compatible.populateCmd} -c ${config.system.build.toplevel} -d ./files/boot
''
else ''
mkdir -p ./files/sbin
content="$(
echo "#!${pkgs.bash}/bin/bash"
echo "exec ${config.system.build.toplevel}/init"
)"
echo "$content" > ./files/sbin/init
chmod 744 ./files/sbin/init
'';
};
};
}

270
sd-image/sd-image.nix Normal file
View file

@ -0,0 +1,270 @@
# This module was lifted from nixpkgs installer code. It is modified
# so as to not import all-hardware. The goal here is to write the
# nixos image for a raspberry pi to an sd-card in a way so that we can
# pop it in and go. We don't need to support many possible hardware
# targets since we know we are targeting raspberry pi products.
# This module creates a bootable SD card image containing the given NixOS
# configuration. The generated image is MBR partitioned, with a FAT
# /boot/firmware partition, and ext4 root partition. The generated image
# is sized to fit its contents, and a boot script automatically resizes
# the root partition to fit the device on the first boot.
#
# The firmware partition is built with expectation to hold the Raspberry
# Pi firmware and bootloader, and be removed and replaced with a firmware
# build for the target SoC for other board families.
#
# The derivation for the SD image will be placed in
# config.system.build.sdImage
{ modulesPath, config, lib, pkgs, ... }:
with lib;
let
rootfsImage = pkgs.callPackage "${modulesPath}/../lib/make-ext4-fs.nix" ({
inherit (config.sdImage) storePaths;
compressImage = false;
populateImageCommands = config.sdImage.populateRootCommands;
volumeLabel = "NIXOS_SD";
} // optionalAttrs (config.sdImage.rootPartitionUUID != null) {
uuid = config.sdImage.rootPartitionUUID;
});
in
{
imports = [ ];
options.sdImage = {
imageName = mkOption {
default =
"${config.sdImage.imageBaseName}-${config.system.nixos.label}-${pkgs.stdenv.hostPlatform.system}.img";
description = ''
Name of the generated image file.
'';
};
imageBaseName = mkOption {
default = "nixos-sd-image";
description = ''
Prefix of the name of the generated image file.
'';
};
storePaths = mkOption {
type = with types; listOf package;
example = literalExpression "[ pkgs.stdenv ]";
description = ''
Derivations to be included in the Nix store in the generated SD image.
'';
};
firmwarePartitionOffset = mkOption {
type = types.int;
default = 8;
description = ''
Gap in front of the /boot/firmware partition, in mebibytes (1024×1024
bytes).
Can be increased to make more space for boards requiring to dd u-boot
SPL before actual partitions.
Unless you are building your own images pre-configured with an
installed U-Boot, you can instead opt to delete the existing `FIRMWARE`
partition, which is used **only** for the Raspberry Pi family of
hardware.
'';
};
firmwarePartitionID = mkOption {
type = types.str;
default = "0x2178694e";
description = ''
Volume ID for the /boot/firmware partition on the SD card. This value
must be a 32-bit hexadecimal number.
'';
};
rootPartitionUUID = mkOption {
type = types.nullOr types.str;
default = null;
example = "14e19a7b-0ae0-484d-9d54-43bd6fdc20c7";
description = ''
UUID for the filesystem on the main NixOS partition on the SD card.
'';
};
firmwareSize = mkOption {
type = types.int;
# As of 2019-08-18 the Raspberry pi firmware + u-boot takes ~18MiB
default = 128;
description = ''
Size of the /boot/firmware partition, in megabytes.
'';
};
populateFirmwareCommands = mkOption {
example =
literalExpression "'' cp \${pkgs.myBootLoader}/u-boot.bin firmware/ ''";
description = ''
Shell commands to populate the ./firmware directory.
All files in that directory are copied to the
/boot/firmware partition on the SD image.
'';
};
populateRootCommands = mkOption {
example = literalExpression
"''\${config.boot.loader.generic-extlinux-compatible.populateCmd} -c \${config.system.build.toplevel} -d ./files/boot''";
description = ''
Shell commands to populate the ./files directory.
All files in that directory are copied to the
root (/) partition on the SD image. Use this to
populate the ./files/boot (/boot) directory.
'';
};
postBuildCommands = mkOption {
example = literalExpression
"'' dd if=\${pkgs.myBootLoader}/SPL of=$img bs=1024 seek=1 conv=notrunc ''";
default = "";
description = ''
Shell commands to run after the image is built.
Can be used for boards requiring to dd u-boot SPL before actual partitions.
'';
};
compressImage = mkOption {
type = types.bool;
default = false;
description = ''
Whether the SD image should be compressed using
<command>zstd</command>.
'';
};
expandOnBoot = mkOption {
type = types.bool;
default = true;
description = ''
Whether to configure the sd image to expand it's partition on boot.
'';
};
};
config = {
fileSystems = {
"/boot/firmware" = {
device = "/dev/disk/by-label/${config.raspberry-pi-nix.firmware-partition-label}";
fsType = "vfat";
};
"/" = {
device = "/dev/disk/by-label/NIXOS_SD";
fsType = "ext4";
};
};
sdImage.storePaths = [ config.system.build.toplevel ];
system.build.sdImage = pkgs.callPackage
({ stdenv, dosfstools, e2fsprogs, mtools, libfaketime, util-linux, zstd }:
stdenv.mkDerivation {
name = config.sdImage.imageName;
nativeBuildInputs =
[ dosfstools e2fsprogs mtools libfaketime util-linux zstd ];
inherit (config.sdImage) compressImage;
buildCommand = ''
mkdir -p $out/nix-support $out/sd-image
export img=$out/sd-image/${config.sdImage.imageName}
echo "${pkgs.stdenv.buildPlatform.system}" > $out/nix-support/system
if test -n "$compressImage"; then
echo "file sd-image $img.zst" >> $out/nix-support/hydra-build-products
else
echo "file sd-image $img" >> $out/nix-support/hydra-build-products
fi
echo "Decompressing rootfs image"
cp "${rootfsImage}" ./root-fs.img
# Gap in front of the first partition, in MiB
gap=${toString config.sdImage.firmwarePartitionOffset}
# Create the image file sized to fit /boot/firmware and /, plus slack for the gap.
rootSizeBlocks=$(du -B 512 --apparent-size ./root-fs.img | awk '{ print $1 }')
firmwareSizeBlocks=$((${
toString config.sdImage.firmwareSize
} * 1024 * 1024 / 512))
imageSize=$((rootSizeBlocks * 512 + firmwareSizeBlocks * 512 + gap * 1024 * 1024))
truncate -s $imageSize $img
# type=b is 'W95 FAT32', type=83 is 'Linux'.
# The "bootable" partition is where u-boot will look file for the bootloader
# information (dtbs, extlinux.conf file).
sfdisk $img <<EOF
label: dos
label-id: ${config.sdImage.firmwarePartitionID}
start=''${gap}M, size=$firmwareSizeBlocks, type=b
start=$((gap + ${
toString config.sdImage.firmwareSize
}))M, type=83, bootable
EOF
# Copy the rootfs into the SD image
eval $(partx $img -o START,SECTORS --nr 2 --pairs)
dd conv=notrunc if=./root-fs.img of=$img seek=$START count=$SECTORS
# Create a FAT32 /boot/firmware partition of suitable size into firmware_part.img
eval $(partx $img -o START,SECTORS --nr 1 --pairs)
truncate -s $((SECTORS * 512)) firmware_part.img
faketime "1970-01-01 00:00:00" mkfs.vfat -i ${config.sdImage.firmwarePartitionID} -n ${config.raspberry-pi-nix.firmware-partition-label} firmware_part.img
# Populate the files intended for /boot/firmware
mkdir firmware
${config.sdImage.populateFirmwareCommands}
# Copy the populated /boot/firmware into the SD image
(cd firmware; mcopy -psvm -i ../firmware_part.img ./* ::)
# Verify the FAT partition before copying it.
fsck.vfat -vn firmware_part.img
dd conv=notrunc if=firmware_part.img of=$img seek=$START count=$SECTORS
${config.sdImage.postBuildCommands}
if test -n "$compressImage"; then
zstd -T$NIX_BUILD_CORES --rm $img
fi
'';
})
{ };
boot.postBootCommands = lib.mkIf config.sdImage.expandOnBoot ''
# On the first boot do some maintenance tasks
if [ -f /nix-path-registration ]; then
set -euo pipefail
set -x
# Figure out device names for the boot device and root filesystem.
rootPart=$(${pkgs.util-linux}/bin/findmnt -n -o SOURCE /)
bootDevice=$(lsblk -npo PKNAME $rootPart)
partNum=$(lsblk -npo MAJ:MIN $rootPart | ${pkgs.gawk}/bin/awk -F: '{print $2}')
# Resize the root partition and the filesystem to fit the disk
echo ",+," | sfdisk -N$partNum --no-reread $bootDevice
${pkgs.parted}/bin/partprobe
${pkgs.e2fsprogs}/bin/resize2fs $rootPart
# Register the contents of the initial Nix store
${config.nix.package.out}/bin/nix-store --load-db < /nix-path-registration
# nixos-rebuild also requires a "system" profile and an /etc/NIXOS tag.
touch /etc/NIXOS
${config.nix.package.out}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system
# Prevents this from running on later boots.
rm -f /nix-path-registration
fi
'';
};
}

1
tailscale-client-secret Normal file
View file

@ -0,0 +1 @@
tskey-client-kJTcn9TxqB21CNTRL-3wZR8ZywdWHdTXqqNRxSWHSz9wRng25jG