Tenho os seguintes requisitos:
- Se um pendrive USB específico for inserido, ele deve ser detectado e montado automaticamente. As informações sobre onde ele deve ser montado estarão em
/etc/fstab
(claro). - Se o pendrive for danificado, uma limpeza completa deverá ocorrer automaticamente, resultando na ausência de vestígios de que ele foi montado (ou ainda está montado) e/ou de quaisquer unidades systemd não finalizadas.
- Se a(s) partição(ões) em questão forem
umount
editadas manualmente, tudo também deverá ser limpo, mesmo que o stick ainda esteja presente; removê-lo do plugue deverá limpar apenas o que não pôde ser limpo antes (provavelmente as.device
unidades).
Para conseguir isso de forma limpa, a inserção do pendrive deve causar o início de uma unidade systemd personalizada, que então configuraremos para fazer o resto.
O que é necessário para escrever isso?
Vamos supor que temos um pendrive com três partições:
/dev/sdc1
e /dev/sdc2
- que são criptografadas com LUKS, e /dev/sdc3
- que não é criptografada.
Por exemplo,
>sudo blkid /dev/sdc{1,2,3}
/dev/sdc1: UUID="de9a000f-fa60-4050-8d11-864e97829b8a" TYPE="crypto_LUKS" PARTUUID="219578f5-5905-41cd-895d-7b937ac0756a"
/dev/sdc2: UUID="012059c1-6b88-4937-889a-a21448740492" TYPE="crypto_LUKS" PARTUUID="59c7f6f3-a5cb-41af-82fa-b515031d85d5"
/dev/sdc3: LABEL="README" UUID="9d262deb-2343-4096-bccf-bb26ed4415ad" BLOCK_SIZE="1024" TYPE="ext2" PARTUUID="165db3da-4ebb-4f59-ab09-ee5e5b26ed43"
Aqui UUID
está o que é usado em /dev/disk/by-uuid
:
>ls -l /dev/disk/by-uuid | grep sdc
lrwxrwxrwx 1 root root 10 Dec 22 18:27 012059c1-6b88-4937-889a-a21448740492 -> ../../sdc2
lrwxrwxrwx 1 root root 10 Dec 22 18:27 9d262deb-2343-4096-bccf-bb26ed4415ad -> ../../sdc3
lrwxrwxrwx 1 root root 10 Dec 22 18:27 de9a000f-fa60-4050-8d11-864e97829b8a -> ../../sdc1
Como o nome do dispositivo /dev/sdc
é bastante aleatório, devemos usar apenas o UUID de agora em diante.
Para montar manualmente a partição não criptografada, precisamos executar (certifique-se de que nada esteja montado em /mnt e/ou /mnt/usb!):
UUID=9d262deb-2343-4096-bccf-bb26ed4415ad
SERIAL=408D5CBECAC3E7C0E9170AEC
sudo /bin/mkdir -p /mnt/usb/$SERIAL/part3
sudo mount -t ext2 /dev/disk/by-uuid/$UUID /mnt/usb/$SERIAL/part3
Onde eu escolhi usar o valor ID_SERIAL_SHORT
do dispositivo USB, que pode ser obtido com, por exemplo:
>udevadm info -n /dev/sdc3 | grep -E '(ID_SERIAL_SHORT|ID_FS_UUID)='
E: ID_SERIAL_SHORT=408D5CBECAC3E7C0E9170AEC
E: ID_FS_UUID=9d262deb-2343-4096-bccf-bb26ed4415ad
Vamos armazenar o ponto de montagem /etc/fstab
adicionando-o a esse arquivo:
UUID=9d262deb-2343-4096-bccf-bb26ed4415ad /mnt/usb/408D5CBECAC3E7C0E9170AEC/part3 ext2 rw,noauto 0 0
Note que depois disso, podemos fazer :
sudo mount /dev/sdc3
e ele fará a montagem perfeitamente, desde que o dispositivo de bloco tenha o UUID esperado.
As outras duas partições /dev/sdc{1,2}
são criptografadas e precisam primeiro
UUID1=573bfda0-69f5-4fb9-9d7e-333a70a51710
UUID2=6d7bdc1d-3eb0-4774-a9fb-3d1ac1027010
echo $LUKS_PASS | sudo cryptsetup -q luksOpen /dev/disk/by-uuid/$UUID1 usb-$UUID1
echo $LUKS_PASS | sudo cryptsetup -q luksOpen /dev/disk/by-uuid/$UUID2 usb-$UUID2
para ser executado, onde eu assumo que a variável de ambiente LUKS_PASS
contém a frase-senha necessária para descriptografar a partição LUKS. Os UUIDs aqui são aqueles que blkid retorna:
>sudo blkid /dev/sdc{1,2}
/dev/sdc1: UUID="573bfda0-69f5-4fb9-9d7e-333a70a51710" TYPE="crypto_LUKS" PARTUUID="caa57a9d-7389-4990-a243-34b19a179368"
/dev/sdc2: UUID="6d7bdc1d-3eb0-4774-a9fb-3d1ac1027010" TYPE="crypto_LUKS" PARTUUID="10813450-6dcc-4700-9e88-d0577c0c9aeb"
Isso cria um /dev/mapper/usb-$UUID
dispositivo (para cada partição), cada um com seu próprio UUID:
>sudo blkid /dev/mapper/usb*
/dev/mapper/usb-573bfda0-69f5-4fb9-9d7e-333a70a51710: LABEL="gold1-2024-12-21" UUID="67f056be-dbbc-4f7a-979d-6ff077d16e93" BLOCK_SIZE="4096" TYPE="ext2"
/dev/mapper/usb-6d7bdc1d-3eb0-4774-a9fb-3d1ac1027010: LABEL="gold2-2024-12-21" UUID="94bfcc55-6b52-431f-bc76-3aa198c107c7" BLOCK_SIZE="4096" TYPE="ext2"
E são esses UUIDs que queremos adicionar /etc/fstab
.
Para facilitar a vida, escrevi o seguinte script que imprime a /etc/fstab
configuração necessária quando executado após inserir um USB (para o meu caso específico):
# Get the device path.
DEVPATH=$(/bin/ls /dev/disk/by-id/usb-Kingston_DataTraveler* | grep -E -v -- '-part[0-9]+$')
# Get the serial of the USB stick.
ID_SERIAL_SHORT=$(udevadm info -n $DEVPATH | grep ID_SERIAL_SHORT | sed -e 's/.*ID_SERIAL_SHORT=//')
# Run over all existing partitions.
for p in $(/bin/ls $DEVPATH-part*); do
# Extract the "part?" string.
PART=$(echo $p | sed -r -e 's/.*-(part[0-9]+)$/\1/')
# Get the UUID of the block device of this partition iff it is a LUKS encrypted partition.
UUID=$(blkid --match-token TYPE=crypto_LUKS $p | sed -e 's/.* UUID="\([^ ]*\)".*/\1/' || true)
if [ -n "$UUID" ]; then
# Decrypt the partition.
echo $LUKS_PASS | sudo cryptsetup -q luksOpen /dev/disk/by-uuid/$UUID usb-$UUID
# Get the UUID of the encrypted partition.
UUID2=$(blkid /dev/mapper/usb-$UUID | sed -e 's/.* UUID="\([^ ]*\)".*/\1/')
echo -e "UUID=$UUID2\t/mnt/usb/$ID_SERIAL_SHORT/$PART\text2\trw,noauto\t0 0"
sudo cryptsetup luksClose usb-$UUID
else
# Get UUID of non-encrypted partition.
UUID=$(blkid $p | sed -e 's/.* UUID="\([^ ]*\)".*/\1/')
echo -e "UUID=$UUID\t/mnt/usb/$ID_SERIAL_SHORT/$PART\text2\trw,noauto\t0 0"
fi
done
Após exportar, LUKS_PASS
certifique-se de executar o script acima usando sudo -E
para preservar o ambiente. Exemplo de saída:
>sudo -E ./foo.sh
UUID=db97c4b0-8f92-4edc-bacb-dc90e62de2e2 /mnt/usb/408D5CBECAC3E7C0E9170AEC/part1 ext2 rw,noauto 0 0
UUID=c45c6a7a-1c0f-49c4-bcfb-15766114daa1 /mnt/usb/408D5CBECAC3E7C0E9170AEC/part2 ext2 rw,noauto 0 0
UUID=9d262deb-2343-4096-bccf-bb26ed4415ad /mnt/usb/408D5CBECAC3E7C0E9170AEC/part3 ext2 rw,noauto 0 0
Com /etc/fstab
a configuração feita e sabendo exatamente quais comandos são necessários, o que resta é automatizar isso com udev
e systemd units
.
A questão é: como?
EDIT: TLDR; você precisa ler minha outra resposta primeiro.
Aqui está um relatório passo a passo da minha pesquisa.
Registro de depuração
Pode haver uma maneira melhor, mas a seguinte funciona: criei um script executável com
/usr/local/sbin/log_service
o seguinte conteúdo:Quando isso for executado,
/bin/systemd-cat -t usbtest
a saída escrita pelo script na saída padrão será gravada no diário.Para monitorar a saída, executamos, em uma janela de terminal separada:
para monitorar a saída em tempo real.
Dispositivo falso
Primeiro criei um serviço falso que usarei como um ".device" falso (embora este seja um .service).
Crie o seguinte arquivo como
/etc/systemd/system/A.service
:e então execute
sudo systemctl daemon-reload
para que o sistema em execução fique ciente disso.Tente iniciar o novo serviço:
Isso resulta na saída de log imediata:
A razão é que o script que está sendo executado (
/usr/local/sbin/log_service
) retorna imediatamente. Como em vez disso queremos imitar um serviço que podemos iniciar e parar por meio do systemctl, adicionamos a linhaRemainAfterExit=yes
:Agora podemos
sudo systemctl start A
e separadamentesudo systemctl stop A
.Montagem falsa .service
Vamos fazer isso novamente para um novo serviço
B
. A ideia é que queremos que eleB
seja iniciado automaticamente quandoA
for iniciado, e pararA
deve causarB
a parada. PararB
manualmente, no entanto, não deve pararA
.Como B será dependente de A e ambos fazem log, queremos que B seja iniciado após A terminar o log (o ExecStart de A terminou), portanto, altere
A.service
novamente e adicioneType=oneshot
; queremos garantir que todos os ExecStarts sejam feitos antes que qualquer serviço dependente comece. Observe que outra diferença é que com o tipooneshot
, se houver váriasExecStart
linhas, elas serão feitas sequencialmente e a próxima só será iniciada após a anterior terminar, ao contrário deType=simple
, o padrão, que inicia todasExecStart
as linhas em paralelo (porque não se espera que elas terminem rapidamente, ou de jeito nenhum). No entanto, isso não nos preocupa: temos apenas uma únicaExecStart
(uma que retorna "imediatamente", caso contrário, você não pode usaroneshot
).Não vou repetir tudo o que tentei aqui; apenas o resultado final que funciona:
(não se esqueça de executar novamente
sudo systemctl daemon-reload
).O que precisamos
After=A.service
fala por si: você não pode montar um dispositivo se ele não existir (ou seja, se a unidade .device estiver ativa); portanto, não queremos iniciar B até que A tenha sido iniciado.Para que B seja iniciado sempre que A for iniciado, não é suficiente ter o
WantedBy=A.service
, precisamos adicionarWants=B.service
à[Unit]
seção deA.service
!Com isso, B é iniciado se iniciarmos A. Não queremos que A seja iniciado se tentarmos iniciar B: isso não faz sentido. Portanto, usamos
Requisite=A.service
as opposite toRequires=A.service
(orBindsTo=A.service
). Como resultado, isso simplesmente se recusa a iniciar B se A não estiver ativo (conforme a documentação):em vez de começar A.
Também podemos parar B quando ambos estiverem ativos; isso só para B ( não podemos nem parar o .device, pois isso não faria sentido: ele ainda está conectado). Executar
systemctl start A
depois disso (mesmo que A já esteja ativo) inicia B novamente, o que é provavelmente o que queremos.Finalmente, parar A enquanto ambos estão ativos para primeiro B e depois A - exatamente como queremos. Isso é estranho, no entanto, porque, pela documentação, entendo que esse é um recurso
BindsTo=
que tem a seguinte descrição:que descreve exatamente o que precisamos ("uma unidade de dispositivo pode estar desconectada"). Enquanto a documentação de
Requisite=
éEntão, queremos isso (iniciar B falhará se A ainda não tiver sido iniciado em vez de tentar iniciar B), mas não menciona a parte que
BindsTo
também precisamos (parar A interromperá B).No entanto, se eu adicionar
BindsTo=A.service
a função deRequisite=
é anulado e iniciar B simplesmente inicia A (primeiro). Um bug no systemd (testado com a versão 257-1 no Arch)?Usando um dispositivo real (udev)
Podemos adicionar uma
udev
regra para detectar a inserção de um dos pendrives que eu quero detectar. Note que mesmo sem tal regra, inserir um pendrive já faz com que.device
unidades sejam criadas:mas como os nomes dessas
.device
unidades podem mudar (mesmo que apenas com base no local em que eu as conecto), não podemos usar seus nomes da maneira que usamosA.service
em todos os lugares. Além disso, precisamos adicionar umWants=B.service
a esses dispositivos - o que estes não têm. E, finalmente, não queremos dispararB.service
para qualquer dispositivo USB suas partições e sua mãe, mas apenas para as partições que listei acima.Tudo isso pode ser alcançado criando uma nova regra udev.
Enquanto o pendrive estiver conectado (que tem uma terceira partição /dev/sdc3) podemos executar por exemplo:
Observe como isso nos diz que udev está ciente de tudo (UUID e ID_SERIAL_SHORT em particular), mas SYSTEMD_WANTS não está definido. Precisamos que seja definido como
B.service
.Em seguida, criamos uma nova regra udev criando o arquivo
/etc/udev/rules.d/69-gold-usb.rules
com o conteúdo:E recarregue com
sudo udevadm control --reload-rules
. Ao executarsudo udevadm test /sys/class/block/sdc3
novamente (como acima) obtemos o mesmo resultado, mas com uma linha extra:indicando que a regra funciona.
Podemos testar a mesma coisa conectando e desconectando o pendrive enquanto estiver em execução
Isso dá, ao adicionar o pendrive:
e o mesmo acontece
remove
ao desligar.Observe como a regra é acionada para ambos,
/dev/sdc
assim como para cada uma das três partições. Como estamos interessados apenas nas partições, vamos adicionarENV{DEVTYPE}=="partition"
à regra udev:Agora temos uma
udev
regra que detecta a inserção de um dos três pendrives USB e, como resultado, iniciaB.service
. No entanto,B.service
falta oAfter=
,Requisite=
eWantedBy=
, de modo que desconectar o pendrive USB ainda não tem o efeito desejado.Adicionando a dependência do .device ao B.service
Se tivéssemos apenas uma partição para lidar (digamos, /dev/sdc3 deste pendrive em particular), então uma maneira direta de adicionar a dependência parece ser usar um dos
DEVLINKS
- mais notavelmente,que é, claro, totalmente fixo para uma partição dada. No entanto, esses nomes de caminho devem ser escapados: todas as barras devem ser substituídas por traços (
-
), e se tentarmos:Então obtemos o seguinte erro interessante quando
B.service
é iniciado:Observe como também o
-
que faz parte do UUID foi convertido para/
. A maneira correta de gerar esta string é comMas, usar essa string em
B.service
vez da stringA.service
revela que nãoB
é parado se desconectarmos o pendrive USB (como esperado apenas olhando a documentação). Portanto, precisamos também adicionar uma linha.BindsTo=
B.service
então se torna:Curiosamente, agora a tentativa de iniciar
sudo systemctl start B
não falha, mas trava se o USB não estiver conectado, até que você o conecte. Isso é bem legal, eu acho.Conectar o USB inicia automaticamente
B
de qualquer maneira. Nesse ponto, podemos parar manualmenteB
como antes, em que pontoB
é parado enquanto o stick está conectado e então podemos simplesmente (re)iniciarB
manualmente sem que ele trave.Podemos passar apenas o UUID (dinâmico) para o serviço, como um hack, fazendo:
and then use
%i
in the .service to access the UUID. I call this a "hack" because it only works because an UUID doesn't contain illegal character for an escaped string: you SHOULD pass a systemd escaped string here; in that case %i would be that escaped string and %I would be the original, unescaped string.However, this is not usable: we NEED the escaped string for
After=
,Requisite=
,BindsTo=
andWantedBy=
because there is no way to manipulate %i: it must be used as-is.There is a way to create the escaped string during the udev rule, but due to a bug in udev it is impossible to actually use that if it contains any backslashes (it is beyond me how such a horrible bug can exist for years without anyone fixing it).
The only remaining option therefore is to use
SYMLINK
with a path that doesn't contain any characters that need to be escaped with a backslash (aka, no '-' characters). In fact, we can pass any information using this trick!This way we can pass (any) information (in this case only ID_FS_UUID) while still using %i for the dependency stuff in the
@.service
template! We only have to make sure that the%c
, the output ofPROGRAM
(and thus the SYMLINK) does not contain any characters that need to be escaped or are escaped with a backslash.The
/usr/local/sbin/udev-escape
that I use contains:Simple, but you have to admit, brilliant.
The counter part is
/usr/local/sbin/udev-unescape
:Warning: the output of this program can contain ANYTHING, including newline characters. So you should be very careful how to use it in a service, that is being run by root and stuff. Probably best to apply some filtering.
Using the above,
%i
is going to have a value likeMDQ2YmE4MWItN2Q5Yy00YTU0LWE2OWYtNmZiYTA2YWM3NzU0Cg__
. The device path then is/dev/%I
, or/dev/usb/MDQ2YmE4MWItN2Q5Yy00YTU0LWE2OWYtNmZiYTA2YWM3NzU0Cg__
, which will be a symlink to for example/dev/sdc3
. And inside the service scripts we can retrieve our information by passing%i
toudev-unescape
:Hence,
[email protected]
now becomes:Passing arbitrary information from udev to a service.
Udev has a lot of information available, it would be a waste not to pass that. With the USB stick inserted, you can now easily see which partitions are available:
Lets say we want to investigate what information is available for sdc1. We can list the
ATTR
values with:And we can inspect the udev environment variables using - say:
Note that
SYSTEMD_WANTS
has an empty%i
because we never really did runudev-escape
in this case.We're going to need the value of
ID_FS_TYPE
too, so lets change the udev rule to its FINAL VERSION:Here I added
$env{ID_FS_TYPE}
to the encoding of the symlink.Adding auto-mounting
We're now done with udev.
[email protected]
is started properly and we can pass any information (from udev) to it that we need.To finish this project, lets rename
[email protected]
to something normal and change it to call some real scripts.What I did was create the file
/etc/systemd/system/[email protected]
with the following content:This incorporates everything we learned about the unit file leaving us only with the task of writing the scripts.
TODO
This answer is getting so long that I decided to post it already. I'll make updates to the remaining parts once I got it fully working.
My current files are:
/usr/local/sbin/usb-gold-start
:/usr/local/sbin/usb-gold-stop
:EDIT (28 December 2024):
It turned out that also the
SYMLINK
trick can't be used, because that ".device" is killed during thecryptsetup
, causing the .service to be terminated beforecryptsetup
returns. The latter still gets the chance to finish what it is doing, but mounting afterwards is a no-go.Therefore, we need(ed) another method: One can use
IMPORT{program}
which preserves backslashes. For example:IMPORT{program}="/usr/local/sbin/udev-gold-usb-systemd_wants.sh $env{ID_SERIAL_SHORT}-part$env{PARTN}"
, in which case it is theoretically possible to write double backslashes to the output ofudev-gold-usb-systemd_wants.sh
which then become single backslashes. However, this is deprecated because it has been decided (I think) that this 8-year-old bug just has to be fixed (see the previous link to the systemd issue; which has considerably grown since I added it). For the time being, it is best to stay away from trying to pass backslashes completely.This answer is written after I solved the problem (as opposed to writing it while I was doing all the research).
systemd already supports mounting encrypted filesystems out of the box. The following points are required:
/etc/fstab
for each partition, from which systemd-fstab-generator will generate the required mount unit./etc/crypttab
for each partition that is encrypted, from which systemd-cryptsetup-generator will generate the required[email protected]
template unit.While implementing this we have to take into account that udev rules and systemd escape functionality do not play well together. We need to avoid the use of backslashes or it either won't work or will break in the near future when these bugs are fixed.
The custom service is only required because a mount unit can not be a template.
The udev rule
The udev rule can contain tests like
ATTR{removable}=="1"
. To get a full list of possibleATTR
tests, run:where
/dev/sdc1
is the device path of a currently inserted USB stick partition.Likewise, one can get a list of possible
ENV{<property name>}=="<regular expression>"
values with:which will list lines as
ID_SERIAL_SHORT='408D5CBF5F0AE7C0E9150B70'
. For example, my/etc/udev/rules.d/69-gold-usb.rules
contains:And yes, you can use backslashes to split up long lines. Just don't forget to use
==
(not=
) and don't forget the comma's.Note that this rule uses
IMPORT{program}
which is currently (December 2024) the only way to pass double backslashes to aSYSTEMD_WANTS
property, but as the behavior of systemd is going to change in that regard (no longer requiring double backslashes), we shouldn't be using backslashes. This means that we can use slashes ('/' for paths) which are converted to a hyphen ('-'), but we can't use a hypen ('-' as appear in UUIDs) which would be escaped as '\x2d'.The script
/usr/local/sbin/udev-gold-usb-systemd_wants.sh
contains:and we are passing to it something like
408D5CBF5F0AE7C0E9150B70-part1
where the hypen is an escaped '/'! This string therefore must be used as, and thus exist, as part of a path that contains"408D5CBF5F0AE7C0E9150B70/part1"
or it can't work.Don't forget to run
to re-read all udev rules after you made changes.
The template service
[email protected]
As said before, this custom service is only required to allow the udev rule to have a variable path (although, I copied the idea from here without really testing if we can't specify the .mount directly).
For the rest is does nothing, but a
StartExec
is required. Therefore this unit file contains:And as
.mount
unit files use their mount point as name, this means that this specifies the mount point as/mnt/usb/408D5CBF5F0AE7C0E9150B70/part1
! Fortunately we don't have to create that directory ourselves, see below.The
/etc/fstab
entry./etc/fstab
can contain entries that will causesystemd
to generate.mount
unit files, normally at boot time, but you can re-trigger this by running:Here is an example of what is in my
/etc/fstab
:Note how this contains the same mount point path
/mnt/usb/408D5CBF5F0AE7C0E9150B70/part1
, otherwise it wouldn't cause the generation of themnt-usb-408D5CBF5F0AE7C0E9150B70-part1.mount
unit.The first column,
UUID=5b214986-7db3-439c-99ba-f4da0cebdf34
, contains the UUID of the partition that must be mounted: the decrypted/dev/mapper/usba52ee8f0a8fa42008c19d798303ac118
, not the encrypted/dev/sdc1
partition.x-mount.mkdir
causes the mount point path to be automatically created if it doesn't exist. Andx-systemd.requires=systemd-cryptsetup@usba52ee8f0a8fa42008c19d798303ac118.service
makes sure thatcryptsetup
is being run first in order to create that decrypted/dev/mapper/usba52ee8f0a8fa42008c19d798303ac118
that we want to mount.Also note that partition 3 is not encrypted, so
046ba81b-7d9c-4a54-a69f-6fba06ac7754
is the UUID of/dev/sdc3
and that line doesn't have ax-systemd.requires=
.The
/etc/crypttab
entry.For the encrypted partitions to work, we also need an entry in
/etc/crypttab
:Here
/dev/disk/by-uuid/a52ee8f0-a8fa-4200-8c19-d798303ac118
is the encrypted partition (it points to/dev/sdc1
) andusba52ee8f0a8fa42008c19d798303ac118
is a random id, which as it turns out, can not contain backslashes [...]. In order to avoid collisions I used the UUID, but had to remove the hypens from it.Entering the pass phrase to unlock the LUKS partitions.
With the above in place and having reloaded the configs (see above), inserting the USB stick will send a broadcast message to all tty's with something like:
Just hit Enter to see your prompt again (assuming it was still empty and your weren't in the middle of typing), and run:
This will then allow you to enter whatever secret is required. If the USB contains more than one partition, but have the same pass phrase, then you only have to enter it once (the second one will try the last entered pass phrase first and since that works won't require you to enter it again). I didn't test what happens if they have a different pass phrase, I can imagine that in that case you have a problem; maybe need to run
sudo systemd-tty-ask-password-agent
again after a failure or something like that.Using a YubiKey
Install the package
libfido2
. Then, with your YubiKey inserted, run:(and afterwards for all other encrypted partitions, of course). This will ask you to enter the passphrase of
/dev/sdc1
, then it will ask for the FIDO2 PIN. If you didn't change that yet, it will be the default123456
.You can change this PIN with the following command:
Doesn't matter if you do this before or after. It has no effect on the FIDO credentials.
You can inspect the result with
This now should show one more key under
Keyslots:
, at the very least the one containing your pass phrase, but also a new one. UnderTokens:
you will see an entry withsystemd-fido2
, and a reference to the Keyslot that it uses.To make the system use the YubiKey, change the entries in your
/etc/crypttab
to containfido2-device=auto
. For example,and rerun
sudo systemctl daemon-reload
.If now you insert the USB key it should do a broadcast message as before, but if then you run
sudo systemd-tty-ask-password-agent
it will ask forPlease enter LUKS2 token PIN:
. Enter the PIN that you set (or still 123456) and then tap your YubiKey once for every partition that needs to be decrypted.Now your partitions should be mounted. If they are not mounted then you are in deep shit because I didn't explain anything, I just hand-held you with the final answer :(. Expect many days of reading documents and learning all kinds of commands to find out intermediate results and debug output (e.g.
journalctl -b -t systemd
). Asking an A.I. for help with learning these commands actually helps here.Finally, here is a little script that I used to print the required entries for
/etc/fstab
and/etc/crypttab
, because that is a lot of work and I had three of these USB sticks (in case of failure of one in the future):