Yubikey In Containers¶
pcscd
must not be running on the host. The daemon takes exclusive control of
smart card devices, so they will not be able to be accessed inside containers.
Stopping the systemd pcscd.socket
is generally all that needs to be done. If
you use smart cards for other purposes, be sure to re-enable it when you're
done.
sudo systemctl stop pcscd.socket
SELinux¶
On SELinux-enforcing systems, a policy needs to be created to allow container
applications (Docker & Podman) access to USB devices that mount as character
devices. This will allow a yubikey to be passed in as a --device
.
Compile Module¶
Using the classic Type Enforcement (te
) format, the policy can be compiled
with the following:
module container_usb_chr 1.0;
require {
type container_t;
type usb_device_t;
class chr_file { getattr ioctl open read write };
}
allow container_t usb_device_t:chr_file { getattr ioctl open read write };
If you're unfamiliar with writing custom SELinux policies, te
files must be
compiled into a module (mod
) first, then bundled into a Policy Package (pp
).
checkmodule -M -m -o container_usb_chr.mod container_usb_chr.te
semodule_package -o container_usb_chr.pp -m container_usb_chr.mod
Finally, install the Policy Package:
semodule -i container_usb_chr.pp
Common Intermediate Language (CIL)¶
An alternative to the Type Enforcement compilation workflow is the Common
Intermediate Language (CIL). The syntax is a bit more convoluted, but cil
files can be installed directly without transatory compilation.
(typeattributeset cil_gen_require container_t)
(typeattributeset cil_gen_require usb_device_t)
(allow container_t usb_device_t (chr_file (getattr ioctl open read write)))
Install the cil
file.
semodule -i container_usb_chr.cil
Note
Policies installed using CIL are named after the file, in this case
container_usb_chr
. This differs from Type Enforcement syntax where the
policy name is derived from the module
declaration.
This is important if you want to remove the policy in the future since
modules are removed by name (ie. semodule -r container_usb_chr
).
FCOS Butane
Installing the policy in Fedora CoreOS utilizes the CIL format and a
systemd
one-shot unit.
storage:
files:
- path: /etc/policies/container_usb_chr.cil
mode: 0644
contents:
inline: |
(typeattributeset cil_gen_require container_t)
(typeattributeset cil_gen_require usb_device_t)
(allow container_t usb_device_t (chr_file (getattr ioctl open read write)))
systemd:
units:
- name: yubikey-container-selinux-policy.service
enabled: true
contents: |
[Service]
Type=oneshot
ExecStart=/usr/sbin/semodule -i /etc/policies/container_usb_chr.cil
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
PIV udev Rule¶
Udev rules aren't strictly necessary, but they ensure a predictable name to pass to the container engine.
Without this rule, the PIV device would be (for example) /dev/bus/usb/001/001
.
This last number increments for every device inserted on that bus and does not
reset until your computer is restarted.
The following rule mounts the PIV device as /dev/yubipiv
with the serial
number appended if serial numbers are visible over USB (ie.
/dev/yubipiv0123456789
).
Notice
It is strongly recommended to enable serial numbers if you use multiple
Yubikeys. Without serial numbers enabled, subsequent Yubikeys will overide
any existing /dev/yubikey
links.
Toggling Yubikey Serial Number Visibility
To enable:
ykpersonalize -vu1y -o serial-usb-visible -o serial-api-visible
To disable:
ykpersonalize -vu1y -o -serial-usb-visible -o -serial-api-visible
SUBSYSTEM=="usb", \
ATTRS{idVendor}=="1050", \
ATTRS{idProduct}=="0401|0402|0403|0404|0405|0406|0407", \
SYMLINK+="yubipiv$attr{serial}", \
TAG+="uaccess"
Note
The idProduct
values here match Yubikey 4 and 5 devices. If you use a
different device, refer to the
Yubikey Product Codes.
Refresh and load the rules:
sudo udevadm control --reload-rules && sudo udevadm trigger
FCOS Butane
storage:
files:
- path: /etc/udev/rules.d/99-yubikey-piv.rules
mode: 0644
contents:
inline: |
SUBSYSTEM=="usb", \
ATTRS{idVendor}=="1050", \
ATTRS{idProduct}=="0401|0402|0403|0404|0405|0406|0407", \
SYMLINK+="yubipiv$attr{serial}", \
TAG+="uaccess"
FIDO udev Rule¶
This udev rule operates simliarly to the PIV rule. It maps the appropriate
hidraw
device to /dev/yubifido
with the serial number appended if serial
numbers are visible over USB (ie. /dev/yubifido0123456789
).
Notice
It is strongly recommended to enable serial numbers if you use multiple
Yubikeys. Without serial numbers enabled, subsequent Yubikeys will overide
any existing /dev/yubikey
links.
Toggling Yubikey Serial Number Visibility
To enable:
ykpersonalize -vu1y -o serial-usb-visible -o serial-api-visible
To disable:
ykpersonalize -vu1y -o -serial-usb-visible -o -serial-api-visible
SUBSYSTEM=="hidraw", \
ATTRS{idVendor}=="1050", \
ATTRS{idProduct}=="0401|0402|0403|0404|0405|0406|0407", \
SYMLINK+="yubifido$attr{serial}", \
TAG+="uaccess"
Note
The idProduct
values here match Yubikey 4 and 5 devices. If you use a
different device, refer to the
Yubikey Product Codes.
Refresh and load the rules:
sudo udevadm control --reload-rules && sudo udevadm trigger
FCOS Butane
storage:
files:
- path: /etc/udev/rules.d/99-yubikey-fido.rules
mode: 0644
contents:
inline: |
SUBSYSTEM=="hidraw", \
ATTRS{idVendor}=="1050", \
ATTRS{idProduct}=="0401|0402|0403|0404|0405|0406|0407", \
SYMLINK+="yubifido$attr{serial}", \
TAG+="uaccess"
Yubikey Product Codes¶
YubiKey Series | USB Interfaces | idProduct |
iProduct String |
---|---|---|---|
YubiKey Gen 1 | OTP | 0010 |
N/A |
YubiKey Gen 2 | OTP | 0010 |
N/A |
YubiKey NEO | OTP | 0110 |
YubiKey OTP |
YubiKey NEO | FIDO | 0111 |
YubiKey FIDO |
YubiKey NEO | CCID | 0112 |
YubiKey CCID |
YubiKey NEO | OTP, FIDO | 0113 |
YubiKey OTP+FIDO |
YubiKey NEO | OTP, CCID | 0114 |
YubiKey OTP+CCID |
YubiKey NEO | FIDO, CCID | 0115 |
YubiKey FIDO+CCID |
YubiKey NEO | OTP, FIDO, CCID | 0116 |
YubiKey OTP+FIDO+CCID |
YubiKey 4 | OTP | 0401 |
YubiKey OTP |
YubiKey 4 | FIDO | 0402 |
YubiKey FIDO |
YubiKey 4 | CCID | 0404 |
YubiKey CCID |
YubiKey 4 | OTP, FIDO | 0403 |
YubiKey OTP+FIDO |
YubiKey 4 | OTP, CCID | 0405 |
YubiKey OTP+CCID |
YubiKey 4 | FIDO, CCID | 0406 |
YubiKey FIDO+CCID |
YubiKey 4 | OTP, FIDO, CCID | 0407 |
YubiKey OTP+FIDO+CCID |
YubiKey FIPS (4 Series) † | OTP, FIDO, CCID | 0407 |
YubiKey OTP+FIDO+CCID |
YubiKey 5 | OTP | 0401 |
YubiKey OTP |
YubiKey 5 | FIDO | 0402 |
YubiKey FIDO |
YubiKey 5 | CCID | 0404 |
YubiKey CCID |
YubiKey 5 | OTP, FIDO | 0403 |
YubiKey OTP+FIDO |
YubiKey 5 | OTP, CCID | 0405 |
YubiKey OTP+CCID |
YubiKey 5 | FIDO, CCID | 0406 |
YubiKey FIDO+CCID |
YubiKey 5 | OTP, FIDO, CCID | 0407 |
YubiKey OTP+FIDO+CCID |
YubiKey 5 FIPS Series † | OTP, FIDO, CCID | 0407 |
YubiKey OTP+FIDO+CCID |
Security Key Series (firmware <5.2.7) | FIDO | 0120 |
Security Key by Yubico |
Security Key Series (firmware 5.2.7+) | FIDO | 0420 |
YubiKey FIDO |
YubiKey Bio Series | FIDO | 0420 |
YubiKey FIDO |
† The YubiKey FIPS (4 Series) and YubiKey 5 FIPS Series devices, when
deployed in a FIPS-approved mode, will have all USB interfaces enabled.
Should an exemption be obtained to deploy these devices with some interfaces
disabled, the idProduct
and iProduct values will be identical to the
YubiKey 4 / 5 Series.
Source: Yubico
Using Fedora Base¶
#!/bin/bash
init() {
local pcscd_running=$(pc aux | grep [p]cscd)
if [ -z "$pcscd_running" ]; then
echo "starting pcscd"
pcscd --debug --apdu
pcscd --hotplug
else
echo "pcscd is running: ${pscsd_running}"
fi
local dbus_daemon_running=$(ps aux | grep [d]bus-daemon)
if [ -z "$dbus_daemon_running" ]; then
echo "starting dbus-daemon"
mkdir -p /run/dbus
dbus-daemon --config-file=/usr/share/dbus-1/system.conf
else
echo "dbus-daemon is running: ${dbus-daemon}"
fi
}
init
"$@"
Fedora images do not contain dbus
by default, which is used by pcscd
to
locate and communicate with smart cards. It will need to be installed.
FROM registry.fedoraproject.org/fedora:37
RUN dnf install -y --setopt=install_weak_deps=False --nodocs \
dbus-daemon procps yubico-piv-tool && \
dnf clean all
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
WORKDIR /root/
ENTRYPOINT [ "/usr/local/bin/entrypoint.sh" ]
CMD [ "yubico-piv-tool", "--help" ]
podman build -t localhost/fedora-yubikey:latest fedora/
podman run --rm -it --device=/dev/yubikey0123456789 \
localhost/fedora-yubikey:latest yubico-piv-tool -a status
Using Ubuntu Base¶
#!/bin/bash
init() {
local pcscd_running=$(ps aux | grep [p]cscd)
if [ -z "$pcscd_running" ]; then
echo "starting pcscd in background"
pcscd --debug --apdu
pcscd --hotplug
else
echo "pcscd is running: ${pscsd_running}"
fi
}
init
"$@"
FROM docker.io/library/ubuntu:latest
RUN apt update && \
apt install -y --no-install-recommends software-properties-common && \
add-apt-repositry -y ppa:yubico/stable && \
apt update && \
apt install -y --no-install-recommends pcscd usbutils yubico-piv-tool && \
apt clean
WORKDIR /root/
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
ENTRYPOINT [ "/usr/local/bin/entrypoint.sh" ]
CMD [ "yubico-piv-tool", "--help" ]
podman build -t localhost/ubuntu-yubikey:latest ubuntu/
podman run --rm -it --device=/dev/yubikey \
localhost/ubuntu-yubikey:latest yubico-piv-tool -a status
Created: March 26, 2022