PIV keys support

Introduction

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)':
---the-bastion.example.org--------------------------------the-bastion-3.01.03---
=> 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-----':
~
-----BEGIN CERTIFICATE-----
MIIDIDCCAgigAwIBAgIQAajpKeFbM+X1Yfk8GaH9dzANBgkqhkiG9w0BAQsFADAh
MR8wHQYDVQQDDBZZdWJpY28gUElWIEF0dGVzdGF0aW9uMCAXDTE2MDMxNDAwMDAw
MFoYDzIwNTIwNDE3MDAwMDAwWjAlMSMwIQYDVQQDDBpZdWJpS2V5IFBJViBBdHRl
c3RhdGlvbiA5YTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALIAy3EZ
P9G/MFleJiWsKzBkyu5G2gG042tUlNncKPlmmNpnIJGND8RPNlddu+70qIGxnKFV
v/kf0XsJIaL4PkGVxEAqtP0/wyxPsEdZTXgaEl12EcPLisyddqkT3ejFudAiNBPf
ijO9MqVvSo6hH9KVPXguWW9BLpqNpcHsWbhsAkb+BgZccSzaeZmfftGWXq++lngT
Ezb1SupTeECNg7Qdr6QvkbxOv586FX/lmbM2xiKB1bsW3sKjhOmV30PQ+pWEM8rs
XXMcgVRe6cWx7Aa0HchDEt0sYNoIzOtGLXVXqr+kHM3/vlixbqelF07MkqOfDEbX
2VO1UKYJjcQ9EXMCAwEAAaNOMEwwEQYKKwYBBAGCxAoDAwQDBQIEMBQGCisGAQQB
gsQKAwcEBgIEALeG1jAQBgorBgEEAYLECgMIBAIDATAPBgorBgEEAYLECgMJBAEB
MA0GCSqGSIb3DQEBCwUAA4IBAQAq9O6H02KRvSmBYsz23r6cNTNS/fr5lSPYMHz/
fX+D5B1thKKGstsfZVzoopwIjj86cIWpCYuNfEje+a5HrELL8ClV88JutJR2Nihs
NxU3BbsSUqnwi2rQHcmtHJcC8rjfDzpYDlW1yR+SxVenbVxuRy0v8sbleHSPYaXG
EhjupEAuhq7n0TjZMF1X7KElx9FZZM9HeuxUJvzV7XWiUgA4Zm05+4/zKW01n2kt
+aMaQk7T1oiE0oOK51wJX6J80GzF51pM00oPlh4iDvnnNXYN2KvkNuNwPoceDDE/
8K23ZfJyTN5nibk13UbxEWSHMUue1zcnFp0KdhqxbJYSS/9q
-----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-----':
~
-----BEGIN CERTIFICATE-----
MIIC5jCCAc6gAwIBAgIJAKT/dqaxohbiMA0GCSqGSIb3DQEBCwUAMCsxKTAnBgNV
BAMMIFl1YmljbyBQSVYgUm9vdCBDQSBTZXJpYWwgMjYzNzUxMCAXDTE2MDMxNDAw
MDAwMFoYDzIwNTIwNDE3MDAwMDAwWjAhMR8wHQYDVQQDDBZZdWJpY28gUElWIEF0
dGVzdGF0aW9uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwDhP3YUI
yLWSjseIKNzMscqCdicslrdkxPgMoK8Ocxu0err4yvFXiSZZL32BTZYLD8N7Y+d1
cww6VVsFYdwn01Kc6YLrwM5FIN/msXkGTPdPVhVeqNMHh4QyYrYixwWaTbDCGoQD
axVlifVmPS02Mvm8NDjC17X3LhsV1OiS/wOScsI8HHGgQXQIQEDMnt6cwZ83QK73
7Wuu5uhSzT3jVOz28Rnij1p/8PcVWcGKWCPVYNbCmCdcm/sQeJB8y5aERDaePIIZ
v9axnDT0DnUO7aDpzXA7i7XPbrkiSBEp7RCqXGs5cBqGCbq//xGh+/AGtCCV/sQM
nTjl0d2k2Q8XTwIDAQABoxUwEzARBgorBgEEAYLECgMDBAMFAgQwDQYJKoZIhvcN
AQELBQADggEBAHCnp3k5kQaBwYmR9nUHKGY1dgCvhJUlX2SAyY2fUeaMuURcRRlW
BFw6CvLAjvSs5Dy3O6JWDmk+1WFZo0UMr15WZFiS5Fpy0M+GWvBCRP3YmbSw+J2t
kyWypCIIu7cMtLpRYkL5SAlWmUCAz8dZPk5FLPpeqmxgQnRoSSe67IXiv3bNyPA1
3NoXI2xw0hWQU1+85tfTxoTxOiAzY8UpAT2GggtSmCwO3sHsHJUYXRyCf8e6jtJL
OFBx/uz+VJoRH7hUVOY+sbP5JJ83dRrWZkS57Hf3q0LOtbn27vM+fmL0y7z4vgDo
DedmrmsbPtsRc3t7RWoqCa80Iq1jPvdm5gw=
-----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]
---------------------------------------------------------</selfAddIngressKey>---

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 ingressRequiresPIV 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
---the-bastion.example.org--------------------------------the-bastion-3.01.03---
=> 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
----------------------------------------------------------------</accountPIV>---

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.