-
Jean-Paul Calderone authoredJean-Paul Calderone authored
deployment.nix 4.80 KiB
# A NixOS module which enables remotely-triggered deployment updates.
{ config, lib, pkgs, ... }:
let
# A handy alias for our part of the configuration.
cfg = config.services.private-storage.deployment;
# Compute an authorized_keys line that allows the holder of a certain key to
# execute a certain command *only*.
restrictedKey =
{ authorizedKey, command, gridName }:
# `restrict` means "disable all the things" then `command` means "but
# enable running this one command" (the client does not have to supply the
# command; if they authenticate, this is the command that will run).
# environment lets us pass an environment variable into the process
# started by the given command. It only works because we configured our
# sshd to allow this particular variable through. By passing this value,
# we can pin nixpkgs in the executed command to the same version
# configured for use here. It might be better if we just had a channel
# the system could be configured with ... but we don't at the moment.
"restrict,environment=\"NIXPKGS_FOR_MORPH=${pkgs.path}\",command=\"${command} ${gridName}\" ${authorizedKey}";
in {
options = {
services.private-storage.deployment.authorizedKey = lib.mkOption {
type = lib.types.str;
example = lib.literalExample ''
ssh-ed25519 AAAAC3N...
'';
description = ''
The SSH public key to authorize to trigger a deployment update.
'';
};
services.private-storage.deployment.gridName = lib.mkOption {
type = lib.types.str;
example = lib.literalExample "staging";
description = ''
The name of the grid configuration to use to update this deployment.
'';
};
};
config = {
# Configure the system to use our binary cache so that deployment updates
# only require downloading pre-built software, not building it ourselves.
nix = {
binaryCachePublicKeys = [
"saxtons.private.storage:MplOcEH8G/6mRlhlKkbA8GdeFR3dhCFsSszrspE/ZwY="
];
binaryCaches = [
"http://saxtons.private.storage"
];
};
services.openssh.extraConfig = ''
PermitUserEnvironment=NIXPKGS_FOR_MORPH
'';
# Create a one-time service that will set up an ssh key that allows the
# deployment user to authorize as root to perform the system update with
# `morph deploy`.
systemd.services.authorize-morph-as-root = {
enable = true;
serviceConfig = {
# Tell systemd that the service is a process that runs and then exits.
# By being "oneshot" instead of "simple" any dependencies are not
# started until after the process exits. We have no dependencies yet
# but if we did it would be more correct for them to wait until we are
# done.
#
# It is not clear that "oneshot" means "run once" though (maybe it
# does, I can't tell) so the script is robust in the face of repeated