Add --ssh-pubkey FILE argument

This commit is contained in:
Luis Hebendanz 2024-04-23 18:55:00 +02:00
parent 0bf9a566eb
commit 4f6d25160f
15 changed files with 192 additions and 31 deletions

View File

@ -41,7 +41,7 @@
};
testScript = ''
start_all()
machine.succeed("clan --flake ${../..} flash --debug --yes --disk main /dev/vdb test_install_machine")
machine.succeed("clan --debug --flake ${../..} flash --yes --disk main /dev/vdb test_install_machine")
'';
} { inherit pkgs self; };
};

View File

@ -20,6 +20,7 @@
boot = {
size = "1M";
type = "EF02"; # for grub MBR
priority = 1;
};
ESP = {
size = "512M";

View File

@ -15,7 +15,7 @@
"type": "github"
},
"original": {
"owner": "nix-community",
"owner": "Qubasa",
"repo": "disko",
"type": "github"
}
@ -55,6 +55,22 @@
"type": "github"
}
},
"nixos-2311": {
"locked": {
"lastModified": 1713397591,
"narHash": "sha256-1P6Plf9a9KwgERtuijPpET/s4AwIZUYqIu1nuVJqPPU=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "392320f29b07e74131d4e4a7b435e8e9b9b85adf",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "release-23.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixos-generators": {
"inputs": {
"nixlib": "nixlib",
@ -76,6 +92,27 @@
"type": "github"
}
},
"nixos-images": {
"inputs": {
"nixos-2311": "nixos-2311",
"nixos-unstable": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1713523007,
"narHash": "sha256-kEnwogkcBn0omgIsGo3zbfAP9nJTDUhp+Q9QWXxsUd0=",
"owner": "nix-community",
"repo": "nixos-images",
"rev": "f064936faf1d12452212030c38e8c325f5b4dfe5",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixos-images",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1714290118,
@ -97,6 +134,7 @@
"disko": "disko",
"flake-parts": "flake-parts",
"nixos-generators": "nixos-generators",
"nixos-images": "nixos-images",
"nixpkgs": "nixpkgs",
"sops-nix": "sops-nix",
"treefmt-nix": "treefmt-nix"

View File

@ -8,14 +8,15 @@
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable-small";
disko.url = "github:nix-community/disko";
disko.url = "github:Qubasa/disko";
disko.inputs.nixpkgs.follows = "nixpkgs";
sops-nix.url = "github:Mic92/sops-nix";
sops-nix.inputs.nixpkgs.follows = "nixpkgs";
sops-nix.inputs.nixpkgs-stable.follows = "";
nixos-generators.url = "github:nix-community/nixos-generators";
nixos-generators.inputs.nixpkgs.follows = "nixpkgs";
nixos-images.url = "github:nix-community/nixos-images";
nixos-images.inputs.nixos-unstable.follows = "nixpkgs";
flake-parts.url = "github:hercules-ci/flake-parts";
flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs";
treefmt-nix.url = "github:numtide/treefmt-nix";

View File

@ -16,7 +16,7 @@
(modulesPath + "/profiles/installation-device.nix")
(modulesPath + "/profiles/all-hardware.nix")
(modulesPath + "/profiles/base.nix")
(modulesPath + "/installer/cd-dvd/iso-image.nix")
#(modulesPath + "/installer/cd-dvd/iso-image.nix")
];
services.openssh.settings.PermitRootLogin = "yes";
system.activationScripts.root-password = ''
@ -65,5 +65,5 @@
cat /var/shared/qrcode.utf8
fi
'';
isoImage.squashfsCompression = "zstd";
#isoImage.squashfsCompression = "zstd";
}

View File

@ -43,6 +43,7 @@ let
boot = {
size = "1M";
type = "EF02"; # for grub MBR
priority = 1; # Needs to be first partition
};
ESP = {
size = "100M";

View File

@ -58,6 +58,7 @@ def create_parser(prog: str | None = None) -> argparse.ArgumentParser:
"--debug",
help="Enable debug logging",
action="store_true",
default=False,
)
parser.add_argument(

View File

@ -1,8 +1,8 @@
import argparse
import importlib
import json
import logging
import os
import shlex
import shutil
import textwrap
from collections.abc import Sequence
@ -20,8 +20,48 @@ from .nix import nix_shell
log = logging.getLogger(__name__)
def list_available_ssh_keys(ssh_dir: Path = Path("~/.ssh").expanduser()) -> list[Path]:
"""
Function to list all available SSH public keys in the default .ssh directory.
Returns a list of paths to available public key files.
"""
public_key_patterns = ["*.pub"]
available_keys: list[Path] = []
# Check for public key files
for pattern in public_key_patterns:
for key_path in ssh_dir.glob(pattern):
if key_path.is_file():
available_keys.append(key_path)
return available_keys
def read_public_key_contents(public_keys: list[Path]) -> list[str]:
"""
Function to read and return the contents of available SSH public keys.
Returns a list containing the contents of each public key.
"""
public_key_contents = []
for key_path in public_keys:
try:
with open(key_path.expanduser()) as key_file:
public_key_contents.append(key_file.read().strip())
except FileNotFoundError:
log.error(f"Public key file not found: {key_path}")
return public_key_contents
def flash_machine(
machine: Machine, mode: str, disks: dict[str, str], dry_run: bool, debug: bool
machine: Machine,
*,
mode: str,
disks: dict[str, str],
system_config: dict[str, Any],
dry_run: bool,
debug: bool,
) -> None:
secret_facts_module = importlib.import_module(machine.secret_facts_module)
secret_facts_store: SecretStoreBase = secret_facts_module.SecretStore(
@ -58,12 +98,17 @@ def flash_machine(
disko_install.extend(["--extra-files", str(local_dir), upload_dir])
disko_install.extend(["--flake", str(machine.flake) + "#" + machine.name])
disko_install.extend(["--mode", str(mode)])
disko_install.extend(
[
"--system-config",
json.dumps(system_config),
]
)
cmd = nix_shell(
["nixpkgs#disko"],
disko_install,
)
print("$", " ".join(map(shlex.quote, cmd)))
run(cmd, log=Log.BOTH, error_msg=f"Failed to flash {machine}")
@ -72,6 +117,7 @@ class FlashOptions:
flake: Path
machine: str
disks: dict[str, str]
ssh_keys_path: list[Path]
dry_run: bool
confirm: bool
debug: bool
@ -99,11 +145,13 @@ def flash_command(args: argparse.Namespace) -> None:
flake=args.flake,
machine=args.machine,
disks=args.disk,
ssh_keys_path=args.ssh_pubkey,
dry_run=args.dry_run,
confirm=not args.yes,
debug=args.debug,
mode=args.mode,
)
machine = Machine(opts.machine, flake=opts.flake)
if opts.confirm and not opts.dry_run:
disk_str = ", ".join(f"{name}={device}" for name, device in opts.disks.items())
@ -114,8 +162,38 @@ def flash_command(args: argparse.Namespace) -> None:
ask = input(msg)
if ask != "y":
return
root_keys = read_public_key_contents(opts.ssh_keys_path)
if opts.confirm and not root_keys:
msg = "Should we add your SSH public keys to the root user? [y/N] "
ask = input(msg)
if ask == "y":
pubkeys = list_available_ssh_keys()
root_keys.extend(read_public_key_contents(pubkeys))
elif not opts.confirm and not root_keys:
pubkeys = list_available_ssh_keys()
root_keys.extend(read_public_key_contents(pubkeys))
# If ssh-pubkeys set, we don't need to ask for confirmation
elif opts.confirm and root_keys:
pass
elif not opts.confirm and root_keys:
pass
else:
raise ClanError("Invalid state")
user_keys = {
"users": {
"users": {"root": {"openssh": {"authorizedKeys": {"keys": root_keys}}}}
}
}
flash_machine(
machine, opts.mode, disks=opts.disks, dry_run=opts.dry_run, debug=opts.debug
machine,
mode=opts.mode,
disks=opts.disks,
system_config=user_keys,
dry_run=opts.dry_run,
debug=opts.debug,
)
@ -147,7 +225,13 @@ def register_parser(parser: argparse.ArgumentParser) -> None:
choices=["format", "mount"],
default="format",
)
parser.add_argument(
"--ssh-pubkey",
type=Path,
action="append",
default=[],
help="ssh pubkey file to add to the root user. Can be used multiple times",
)
parser.add_argument(
"--yes",
action="store_true",
@ -160,10 +244,4 @@ def register_parser(parser: argparse.ArgumentParser) -> None:
default=False,
action="store_true",
)
parser.add_argument(
"--debug",
help="Print debug information",
default=False,
action="store_true",
)
parser.set_defaults(func=flash_command)

View File

@ -106,13 +106,7 @@ def nix_shell(packages: list[str], cmd: list[str]) -> list[str]:
if os.environ.get("IN_NIX_SANDBOX"):
return cmd
return [
*nix_command(
[
"shell",
"--inputs-from",
f"{nixpkgs_flake()!s}",
]
),
*nix_command(["shell", "--offline", "--inputs-from", f"{nixpkgs_flake()!s}"]),
*packages,
"-c",
*cmd,

View File

@ -23,11 +23,11 @@
zbar,
tor,
git,
nixpkgs,
qemu,
gnupg,
e2fsprogs,
mypy,
nixpkgs,
clan-core-path,
}:
let
@ -95,17 +95,16 @@ let
description = "dependencies for the clan-cli";
inputs = {
nixpkgs.url = "nixpkgs";
nixpkgs.url = "path://${nixpkgs}";
};
outputs = _inputs: { };
}
EOF
ln -s ${nixpkgs} $out/path
nix flake lock $out \
nix flake update $out \
--store ./. \
--extra-experimental-features 'nix-command flakes' \
--override-input nixpkgs ${nixpkgs}
--extra-experimental-features 'nix-command flakes'
'';
in
python3.pkgs.buildPythonApplication {

View File

@ -38,6 +38,7 @@
'';
in
{
devShells.clan-cli = pkgs.callPackage ./shell.nix { inherit (self'.packages) clan-cli; };
packages = {
clan-cli = pkgs.python3.pkgs.callPackage ./default.nix {

View File

@ -12,6 +12,7 @@ let
rope
setuptools
wheel
ipdb
pip
]);
in
@ -21,6 +22,8 @@ mkShell {
ruff
] ++ devshellTestDeps;
PYTHONBREAKPOINT = "ipdb.set_trace";
shellHook = ''
export GIT_ROOT="$(git rev-parse --show-toplevel)"
export PKG_ROOT="$GIT_ROOT/pkgs/clan-cli"

View File

@ -40,6 +40,8 @@ mkShell {
desktop-file-utils # verify desktop files
]);
PYTHONBREAKPOINT = "ipdb.set_trace";
shellHook = ''
export GIT_ROOT=$(git rev-parse --show-toplevel)
export PKG_ROOT=$GIT_ROOT/pkgs/clan-vm-manager

View File

@ -1,4 +1,5 @@
{ ... }:
{
imports = [
./clan-cli/flake-module.nix

View File

@ -1,12 +1,22 @@
{ self, lib, ... }:
let
installerModule =
{ config, ... }:
{
config,
pkgs,
modulesPath,
...
}:
{
imports = [
self.nixosModules.installer
self.inputs.nixos-generators.nixosModules.all-formats
self.inputs.disko.nixosModules.disko
(modulesPath + "/installer/cd-dvd/iso-image.nix")
];
isoImage.squashfsCompression = "zstd";
# Provide convenience for connecting to wifi
networking.wireless.enable = false;
@ -34,9 +44,35 @@ let
{ disko.memSize = 4096; } # FIXME: otherwise the image builder goes OOM
];
};
flashInstallerModule =
{ config, pkgs, ... }:
{
imports = [
self.nixosModules.installer
self.clanModules.diskLayouts
];
# Provide convenience for connecting to wifi
networking.wireless.enable = false;
# Use iwd instead of wpa_supplicant. It has a user friendly CLI
networking.wireless.iwd = {
settings = {
Network = {
EnableIPv6 = true;
RoutePriorityOffset = 300;
};
Settings = {
AutoConnect = true;
};
};
enable = true;
};
system.stateVersion = config.system.nixos.version;
nixpkgs.pkgs = self.inputs.nixpkgs.legacyPackages.x86_64-linux;
};
in
{
clan = {
clanName = "clan-core";
directory = self;
@ -44,6 +80,11 @@ in
imports = [ installerModule ];
fileSystems."/".device = lib.mkDefault "/dev/null";
};
machines.flash-installer = {
imports = [ flashInstallerModule ];
clan.diskLayouts.singleDiskExt4.device = "/dev/sda";
boot.loader.grub.enable = lib.mkForce true;
};
};
flake.packages.x86_64-linux.install-iso = installer.config.formats.iso;
flake.apps.x86_64-linux.install-vm.program = installer.config.formats.vm.outPath;