yubikey-agent: init at 0.1.3

This adds yubikey-agent as a package and a nixos module.

On macOS, we use `wrapProgram` to set pinentry_mac as default in PATH;
on Linux we rely on the user to set their preferred pinentry in PATH.
In particular, we use a systemd override to prefix PATH to select a
chosen pinentry program if specified.

On Linux, we need libnotify to provide the notify-send utility for
desktop notifications (such as "Waiting for Yubikey touch...").

This might work on other flavors of unix, but I haven't tested.

We reuse the programs.gnupg.agent.pinentryFlavor option for
yubikey-agent, but in doing so I hit a problem: pinentryFlavour's
default value is specified in a mkDefault, but only conditionally. We
ought to be able to pick up the pinentryFlavour whether or not gpg-agent
is running. As a result, this commit moves the default value to the
definition of programs.gnupg.agent.enable.

Changed files
+178 -2
nixos
modules
programs
services
pkgs
+1
nixos/modules/module-list.nix
···
./services/security/torsocks.nix
./services/security/usbguard.nix
./services/security/vault.nix
./services/system/cloud-init.nix
./services/system/dbus.nix
./services/system/earlyoom.nix
···
./services/security/torsocks.nix
./services/security/usbguard.nix
./services/security/vault.nix
+
./services/security/yubikey-agent.nix
./services/system/cloud-init.nix
./services/system/dbus.nix
./services/system/earlyoom.nix
+1 -2
nixos/modules/programs/gnupg.nix
···
agent.pinentryFlavor = mkOption {
type = types.nullOr (types.enum pkgs.pinentry.flavors);
example = "gnome3";
description = ''
Which pinentry interface to use. If not null, the path to the
pinentry binary will be passed to gpg-agent via commandline and
···
};
config = mkIf cfg.agent.enable {
-
programs.gnupg.agent.pinentryFlavor = mkDefault defaultPinentryFlavor;
-
# This overrides the systemd user unit shipped with the gnupg package
systemd.user.services.gpg-agent = mkIf (cfg.agent.pinentryFlavor != null) {
serviceConfig.ExecStart = [ "" ''
···
agent.pinentryFlavor = mkOption {
type = types.nullOr (types.enum pkgs.pinentry.flavors);
example = "gnome3";
+
default = defaultPinentryFlavor;
description = ''
Which pinentry interface to use. If not null, the path to the
pinentry binary will be passed to gpg-agent via commandline and
···
};
config = mkIf cfg.agent.enable {
# This overrides the systemd user unit shipped with the gnupg package
systemd.user.services.gpg-agent = mkIf (cfg.agent.pinentryFlavor != null) {
serviceConfig.ExecStart = [ "" ''
+61
nixos/modules/services/security/yubikey-agent.nix
···
···
+
# Global configuration for yubikey-agent.
+
+
{ config, lib, pkgs, ... }:
+
+
with lib;
+
+
let
+
cfg = config.services.yubikey-agent;
+
+
# reuse the pinentryFlavor option from the gnupg module
+
pinentryFlavor = config.programs.gnupg.agent.pinentryFlavor;
+
in
+
{
+
###### interface
+
+
meta.maintainers = with maintainers; [ philandstuff rawkode ];
+
+
options = {
+
+
services.yubikey-agent = {
+
enable = mkOption {
+
type = types.bool;
+
default = false;
+
description = ''
+
Whether to start yubikey-agent when you log in. Also sets
+
SSH_AUTH_SOCK to point at yubikey-agent.
+
+
Note that yubikey-agent will use whatever pinentry is
+
specified in programs.gnupg.agent.pinentryFlavor.
+
'';
+
};
+
+
package = mkOption {
+
type = types.package;
+
default = pkgs.yubikey-agent;
+
defaultText = "pkgs.yubikey-agent";
+
description = ''
+
The package used for the yubikey-agent daemon.
+
'';
+
};
+
};
+
};
+
+
config = {
+
environment.systemPackages = [ cfg.package ];
+
systemd.packages = [ cfg.package ];
+
+
# This overrides the systemd user unit shipped with the
+
# yubikey-agent package
+
systemd.user.services.yubikey-agent = mkIf (pinentryFlavor != null) {
+
path = [ pkgs.pinentry.${pinentryFlavor} ];
+
};
+
+
environment.extraInit = optionalString cfg.enable
+
''
+
if [ -z "$SSH_AUTH_SOCK" -a -n "$XDG_RUNTIME_DIR" ]; then
+
export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/yubikey-agent/yubikey-agent.sock"
+
fi
+
'';
+
};
+
}
+54
pkgs/tools/security/yubikey-agent/default.nix
···
···
+
{ stdenv, lib, fetchFromGitHub, buildGoModule, libnotify, makeWrapper, pcsclite, pinentry_mac, pkgconfig, darwin }:
+
+
buildGoModule rec {
+
pname = "yubikey-agent";
+
version = "0.1.3";
+
+
src = fetchFromGitHub {
+
owner = "FiloSottile";
+
repo = pname;
+
rev = "v${version}";
+
sha256 = "07gix5wrakn4z846zhvl66lzwx58djrfnn6m8v7vc69l9jr3kihr";
+
};
+
+
buildInputs =
+
lib.optional stdenv.isLinux (lib.getDev pcsclite)
+
++ lib.optional stdenv.isDarwin (darwin.apple_sdk.frameworks.PCSC);
+
+
nativeBuildInputs = [ makeWrapper pkgconfig ];
+
+
# pull in go-piv/piv-go#75
+
# once go-piv/piv-go#75 is merged and released, we should
+
# use the released version (and push upstream to do the same)
+
patches = [ ./use-piv-go-75.patch ];
+
postPatch = lib.optionalString stdenv.isLinux ''
+
substituteInPlace main.go --replace 'notify-send' ${libnotify}/bin/notify-send
+
'';
+
+
vendorSha256 = "1x7934p6522i0yyv08xzb4134d0kr5x6igsrp26vh79d8fndbywr";
+
+
subPackages = [ "." ];
+
+
# On macOS, there isn't a choice of pinentry program, so let's
+
# ensure the nixpkgs-provided one is available
+
postInstall = lib.optionalString stdenv.isDarwin ''
+
wrapProgram $out/bin/yubikey-agent --suffix PATH : $(dirname ${pinentry_mac}/${pinentry_mac.binaryPath})
+
''
+
# Note: in the next release, upstream provides
+
# contrib/systemd/user/yubikey-agent.service, which we should use
+
# instead
+
# See https://github.com/FiloSottile/yubikey-agent/pull/43
+
+ lib.optionalString stdenv.isLinux ''
+
mkdir -p $out/lib/systemd/user
+
substitute ${./yubikey-agent.service} $out/lib/systemd/user/yubikey-agent.service \
+
--replace 'ExecStart=yubikey-agent' "ExecStart=$out/bin/yubikey-agent"
+
'';
+
+
meta = with lib; {
+
description = "A seamless ssh-agent for YubiKeys";
+
license = licenses.bsd3;
+
homepage = "https://filippo.io/yubikey-agent";
+
maintainers = with lib.maintainers; [ philandstuff rawkode ];
+
platforms = platforms.darwin ++ platforms.linux;
+
};
+
}
+24
pkgs/tools/security/yubikey-agent/use-piv-go-75.patch
···
···
+
From 56a465d463273b2a2a24cf668c4c33938b198b16 Mon Sep 17 00:00:00 2001
+
From: Philip Potter <philip.g.potter@gmail.com>
+
Date: Sun, 12 Jul 2020 16:54:57 +0100
+
Subject: [PATCH] Pull in go-piv/piv-go#75
+
+
---
+
go.mod | 1 +
+
1 file changed, 1 insertion(+)
+
+
diff --git a/go.mod b/go.mod
+
index d4d13c8..e24d53d 100644
+
--- a/go.mod
+
+++ b/go.mod
+
@@ -2,6 +2,7 @@ module filippo.io/yubikey-agent
+
+
go 1.14
+
+
+replace github.com/go-piv/piv-go => github.com/rawkode/piv-go v1.5.1-0.20200711221619-a4158f9b8204
+
require (
+
github.com/go-piv/piv-go v1.5.1-0.20200523071327-a3e5767e8b72
+
github.com/gopasspw/gopass v1.9.1
+
--
+
2.27.0
+
+35
pkgs/tools/security/yubikey-agent/yubikey-agent.service
···
···
+
[Unit]
+
Description=Seamless ssh-agent for YubiKeys
+
Documentation=https://filippo.io/yubikey-agent
+
+
[Service]
+
ExecStart=yubikey-agent -l %t/yubikey-agent/yubikey-agent.sock
+
ExecReload=/bin/kill -HUP $MAINPID
+
ProtectSystem=strict
+
ProtectKernelLogs=yes
+
ProtectKernelModules=yes
+
ProtectKernelTunables=yes
+
ProtectControlGroups=yes
+
ProtectClock=yes
+
ProtectHostname=yes
+
PrivateTmp=yes
+
PrivateDevices=yes
+
PrivateUsers=yes
+
IPAddressDeny=any
+
RestrictAddressFamilies=AF_UNIX
+
RestrictNamespaces=yes
+
RestrictRealtime=yes
+
RestrictSUIDSGID=yes
+
LockPersonality=yes
+
CapabilityBoundingSet=
+
SystemCallFilter=@system-service
+
SystemCallFilter=~@privileged @resources
+
SystemCallErrorNumber=EPERM
+
SystemCallArchitectures=native
+
NoNewPrivileges=yes
+
KeyringMode=private
+
UMask=0177
+
RuntimeDirectory=yubikey-agent
+
+
[Install]
+
WantedBy=default.target
+2
pkgs/top-level/all-packages.nix
···
yubikey-personalization-gui = libsForQt5.callPackage ../tools/misc/yubikey-personalization-gui { };
zchunk = callPackage ../development/libraries/zchunk { };
zeitgeist = callPackage ../development/libraries/zeitgeist { };
···
yubikey-personalization-gui = libsForQt5.callPackage ../tools/misc/yubikey-personalization-gui { };
+
yubikey-agent = callPackage ../tools/security/yubikey-agent { };
+
zchunk = callPackage ../development/libraries/zchunk { };
zeitgeist = callPackage ../development/libraries/zeitgeist { };