PIV keys support


The Bastion supports enabling a policy forcing accounts SSH ingress keys to originate from a known hardware token, ensuring that the private SSH key is only stored on this hardware token, and not on the filesystem.

Currently, only Yubico keys implementing PIV can be verified this way. In that case, each individual hardware token has a builtin Certificate Authority, signed by a well-known Yubico certificate, hence proving that the hardware token is known and legit.

This builtin CA, in turn, emits an attestation certificate each time a new PIV key is generated on the hardware token, hence proving that the bikey (private and public) has been generated by this individual hardware token. Other metadata is included in the attestation, such as the firmware version, the serial number of the token, the TouchPolicy and PinPolicy. Note that you may decide to overwrite the builtin CA by a one of your own, possibly signed by a CA of your company. This would ensure not only that the SSH key is provided by the device, but also that the device has been provided by your company.

Please refer to the Yubico PIV attestation page and the Yubico PIV tool page for more information.

Without a policy

If you want to support PIV keys without making those mandatory, you don't have anything to do: those keys are just regular RSA/ECDSA keys and they just work with The Bastion. In that case, after having properly configured your hardware token with a key in slot 9a, you can just use selfAddIngressKey to add the key to your bastion account, and call it a day. As a quick guidance, on a Yubikey you can usually generate a key in the proper slot this way, after you've setup a management key:

yubico-piv-tool --key=YOUR_MGMT_KEY --action generate --pin-policy always --touch-policy never --slot 9a -o -

Now, if you want the bastion to be aware that this key is from a hardware token, you shall use the --piv option to selfAddIngressKey. This won't do anything special per-se, except storing the certificates information, and showing the details of the PIV key in command outputs such as selfListIngressKeys. Note however that if in the future you enable the PIV enforcing policy either on your account or globally, this key will be considered valid, contrary to all the keys added without the --piv option, even if these keys happen to be PIV ones. To add a key with the --piv option, you'll need the SSH public key as usual, but also the attestation certificate and the key certificate. Step by step details on how to get those are out of the scope of this document, but again as a quick guidance, on a Yubikey you can usually get those this way:

yubico-piv-tool --action=read-certificate --slot=9a --key-format=SSH
yubico-piv-tool --action=attest --slot=9a
yubico-piv-tool --action=read-certificate --slot=f9

When you'll have added your key, you'll see a few more details than usual:

bssh --osh selfAddIngressKey --piv
Enter PIN for 'PIV Card Holder pin (PIV_II)':
=> add a new public key to your account
~ Please paste the SSH key you want to add. This bastion supports the following algorithms:
~ ED25519: strongness[#####] speed[#####], use `ssh-keygen -t ed25519' to generate one
~ ECDSA  : strongness[####.] speed[#####], use `ssh-keygen -t ecdsa -b 521' to generate one
~ RSA    : strongness[###..] speed[#....], use `ssh-keygen -t rsa -b 4096' to generate one
~ In any case, don't save it without a passphrase.
~ You can prepend your key with a from="IP1,IP2,..." as this bastion policy allows ingress keys "from" override by users
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCyAMtxGT/RvzBZXiYlrCswZMruRtoBtONrVJTZ3Cj5ZpjaZyCRjQ/ETzZXXbvu9KiBsZyhVb/5H9F7CSGi+D5BlcRAKrT9P8MsT7BHWU14GhJddhHDy4rMnXapE93oxbnQIjQT34ozvTKlb0qOoR/SlT14LllvQS6ajaXB7Fm4bAJG/gYGXHEs2nmZn37Rll6vvpZ4ExM29UrqU3hAjYO0Ha+kL5G8Tr+fOhV/5ZmzNsYigdW7Ft7Co4Tpld9D0PqVhDPK7F1zHIFUXunFsewGtB3IQxLdLGDaCMzrRi11V6q/pBzN/75YsW6npRdOzJKjnwxG19lTtVCmCY3EPRFz
~ You have requested to add a PIV-enabled SSH key.
~ Please paste the PIV attestation certificate of your hardware key in PEM format.
~ This snippet should start with '-----BEGIN CERTIFICATE-----' and end with '-----END CERTIFICATE-----':
~ Thanks, now please paste the PIV key certificate of your generated key in PEM format.
~ This snippet should also start with '-----BEGIN CERTIFICATE-----' and end with '-----END CERTIFICATE-----':
~ Public key successfully added:
~ info: ADDED_BY=jdoe USING=selfAddIngressKey UNIQID=2993de2bb014 TIMESTAMP=1609427402 DATETIME=2020-12-31T15:10:02 VERSION=3.01.03
~ PIV: TouchPolicy=Never, PinPolicy=Always, SerialNo=12345678, Firmware=5.2.4
~ fingerprint: SHA256:8B0T6174KUPL1iTSyC0UpnDOvuaCgyKpu8zo9rb2lco (RSA-2048) [2020/12/17]

As you can see, we added the public key as usual but were also asked for the two certificates. On the bastion answer, right before the fingerprint of the key, we have a line starting with PIV:, with some metadata extracted from the certificate.

Per-account policy

If you want to force several accounts to only use certified PIV keys, you can set the option per-account using the accountPIV command, see its documentation page for all the possible options. The main takeaways are:

  • If you want an account to only have PIV keys, set the enforce policy for this account

  • If you want an account to never require PIV keys, even if the global policy would require it, set the never policy (useful for accounts used by automated workflows)

Global policy

If you want to apply a policy bastion-wide, please refer to the ingressRequirePIV option. This policy can still be overridden per-account if needed, see above.

Temporary grace period

If you enable the PIV policy globally or on several accounts, you'll soon find out that sometimes people forget or lose their PIV-enabled hardware tokens, effectively locking them out of the bastion. There is a temporary grace period feature you can use to handle such cases nicely:

bssh --osh accountPIV --account lechuck --policy grace --ttl 48h
=> modify the PIV policy of an account
~ Changing account configuration...

~ PIV grace up to 2d+00:00:00 (Wed 2021-01-13 09:22:29 UTC) has been set for this account
~ Applying change to keys...

~ Non-PIV account's ingress keys, if any, have been restored

What happens here is that, for a duration of 48 hours, this account will behave as if no PIV policy was enforced: non-PIV keys are allowed again. If this account had non-PIV keys before its policy was set to enforce, those keys are even restored (can be viewed using selfListIngressKeys as usual), so that they can easily connect again. However, after the grace period expires, their policy will go back to what it was previously, and all the non-PIV keys will be disabled again. This event is logged, so you can easily link this event from your SIEM to a potential ticket to your Helpdesk for a hardware key replacement, or such.

This mechanism allows some flexibility (avoiding sending people back home just because they forgot their hardware key), while still enforcing a high-level security policy with the proper processes in place.