or “SSH with Google Cloud OS-Login with YubiKey OpenSC-PKCS11 and Trusted Platform Module (TPM) based keys”.
First off, this is nothing new; its a rehash of decade old tech that i decided to try out since i happens to have a YubiKey Neo and familiarity with Trusted Platform Module on a GCP Shielded VM.
Both the Yubikey Neo and TPM have one common capability here which this tutorial covers: embedding an RSA private key inextricably into a hardware device and provide an interface to sign arbitrary data using that key. By inextricably i mean once its on the device, it can be configured to never leave in its raw form and can only be made to do specific crypto operations (sign, decrypt, etc).
The application to public-key based SSH is straightforward: instead of SSH using the private keys normally saved under ~/.ssh/, the keys are saved on the device itself. For the yubikey, you need to insert the token while for the TPM you need to execute the command only on that specific VM that was configured.
For Google Compute Engine, OS-Login allows administrators to define external RSA keys for access to specific VMs as declared through IAM policies. This tutorial embeds RSA keys for use with GCP OS Login but ofcourse this procedure is applicable to any SSH system utilizing RSA keypairs.
This is NOT supported by Google Cloud. caveat emptor
To embed certificates, you first neeed a PIV-enabled Yubikey such as a Yubikey Neo. These advanced (and more expensive) Yubikeys allows you to (among other things) save keys into the device and execute crypto operations against it.
You can use either YubiKey Neo or YubiKey 4 or 5 as those keys support embedded keys.
note, Google Titan keys do not allow saving arbitrary data into it; its just U2F.
On any, first install Yubikey tools to help embed the RSA key. This step can be done on any system: all we are doing here is provisioning the RSA key into the Yubikey
Plug in the Yubikey and verify you’ve got a YubiKey Neo:
Check Yubikey is plugged in
$ lsusb | grep -i yubikey
Bus 001 Device 013: ID 1050:0111 Yubico.com Yubikey NEO(-N) OTP+CCID
Install PKCS11 OpenSC support
sudo apt-get install opensc opensc-pkcs11
Confirm the OpenSC PKCS Library is installed. eg:
/usr/lib/x86_64-linux-gnu/opensc-pkcs11.so
You will need to install OpenSC on any system you wish to use the Yubikey. You do not ofcourse need ot install the yubico toolsets anywhere else other than the system where you embed the key.
You can either generate an RSA keypair directly on the Yubikey or import one externally. In the following, we will generate a keypair externally and then import. (note, its better to generate on the device vs import…i’m just lazy here)
more more info sss Yubico SSH Certificates
echo OS_LOGIN_USER=user_esodemoapp2_com
openssl genrsa -out private.pem 2048
openssl rsa -in private.pem -outform PEM -pubout -out public.pem
openssl req -new -x509 -key private.pem -out public.crt -subj "/CN=$OS_LOGIN_USER/"
openssl x509 -in public.crt -text -noout
yubico-piv-tool -s 9a -a import-key -i private.pem
yubico-piv-tool -a import-certificate -s 9a -i public.crt
if you launch yubikey-manager-qt
, you should see your certificate now in slot 9a
Note, at this moment, you can *DELETE the keys you just created (private.pem)…it now exists on the Yubikey
echo `ssh-keygen -D /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so` | tee my.pub
Now edit my.pub
to remove any extra certificates that mybe there. That is opensc-pkcs11.so
outputs all public keys from the yubkey in numeric order; we just need slot 9a
which is the first one so edit my.pub and keep the first ssh-rsa
entry. If you didn’t embed any other certificates prior to this, then you should only see one key.
$ gcloud compute os-login ssh-keys add --key-file my.pub
loginProfile:
name: '108157913093274845548'
posixAccounts:
- accountId: your_project
gid: '1074457818'
homeDirectory: /home/user1_esodemoapp2_com
name: users/user1@esodemoapp2.com/projects/yourproject
operatingSystemType: LINUX
primary: true
uid: '1074457818'
username: user1_esodemoapp2_com
sshPublicKeys:
722a2d7dec12c037cecda888013656a420937662be643a4e375b7d5bfe62997f:
fingerprint: 722a2d7dec12c037cecda888013656a420937662be643a4e375b7d5bfe62997f
key: |
ssh-rsa AAAAB3NzaC1yc2EAredacted
name: users/user1@esodemoapp2.com/sshPublicKeys/722a2d7dec12c037cecda888013656a420937662be643a4e375b7d5bfe62997f
Create a GCP OS-Login enabled VM and then set IAM Permission to allow access:
Get the public IP of the VM you have enabled OS login and IAM permissions, then SSH in while specifying the opensc-pkcs11 library:
ssh -I /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so user1_esodemoapp2_com@35.225.191.
If you enable -vvv
in the SSH command, you should see indication that keys are read from opensc-pkcs11.so
.
If you are prompted for a PIN, enter the one you setup on the Yubikey default. The default code is 123456
debug1: provider /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so: manufacturerID <OpenSC Project> cryptokiVersion 2.20 libraryDescription <OpenSC smartcard framework> libraryVersion 0.19
debug1: provider /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so slot 0: label <srashid_google_com> manufacturerID <piv_II> model <PKCS#15 emulate> serial <295a1be28d916b2> flags 0x40d
debug1: Offering public key: /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so RSA SHA256:f8SYSZMBH3FjwgredgZx6YVuxHJGS+nN0GcYscA82lc token
debug3: send packet: type 50
debug2: we sent a publickey packet, wait for reply
debug3: receive packet: type 60
debug1: Server accepts key: /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so RSA SHA256:f8SYSZMBH3FjwgredgZx6YVuxHJGS+nN0GcYscA82lc token
debug3: sign_and_send_pubkey: RSA SHA256:f8SYSZMBH3FjwgredgZx6YVuxHJGS+nN0GcYscA82lc
debug3: sign_and_send_pubkey: signing using ssh-rsa
Enter PIN for 'user1_esodemoapp2_com':
If everything went allright, you should be logged into the VM!
Embedding RSA keyapair into a TPM ofcourse requires a machine with a TPM!. Fortunately, Google Cloud Shielded VMs hav one enabled so you can use this to test:
gcloud compute instances create shielded-6 --zone=us-central1-a --machine-type=n1-standard-1 --no-service-account --no-scopes --image=ubuntu-1804-bionic-v20191002 --image-project=gce-uefi-images --no-shielded-secure-boot --shielded-vtpm --shielded-integrity-monitoring
SSH to the VM and install tpm2-pkcs11 package. This library uses tpm2_tools
, tpm2-tss
internally to provide the PKCS11 interface to the TPM and from there SSH support
Note the disclaimer on the tpm2-pkcs11 package; at the time of writing
11/3/19
, it is NOT recommended for production us
apt-get update
apt -y install autoconf-archive libcmocka0 libcmocka-dev procps iproute2 build-essential git pkg-config gcc libtool automake libssl-dev uthash-dev autoconf doxygen libcurl4-openssl-dev dbus-x11 libglib2.0-dev libcurl4-openssl-dev libsqlite3-dev python python-yaml python-pip
Then install the components
cd
git clone https://github.com/tpm2-software/tpm2-tss.git
cd tpm2-tss
./bootstrap
./configure --with-udevrulesdir=/etc/udev/rules.d
make -j$(nproc)
make install
udevadm control --reload-rules && sudo udevadm trigger
ldconfig
cd
git clone https://github.com/tpm2-software/tpm2-tools.git
cd tpm2-tools
./bootstrap
./configure
make check
make install
cd
git clone https://github.com/tpm2-software/tpm2-pkcs11
cd tpm2-pkcs11
./bootstrap
./configure
make
make install
Once installed, you should see libtpm2_pkcs11.so
library available for use. On debian, its at /usr/local/lib/libtpm2_pkcs11.so
Now use the tpm2_tool
wrapper client for tpm2_tools
to generate a primary object and import the RSA key.
In the following, we will use the same RSA key for the Yubikey sample defined in Generate or Import RSA Key
above (i.,e you should have private.pem file handy and in the folder below where it is specified)
echo OS_LOGIN_USER=user1_esodemoapp2_com
cd /root/tpm2-pkcs11/tools
./tpm2_ptool init
Created a primary object of id: 1
./tpm2_ptool addtoken --pid=1 --sopin=mysopin --userpin=123456 --label $OS_LOGIN_USER
Created token label: user1_esodemoapp2_com
./tpm2_ptool import --userpin 123456 --privkey /path/to/private.pem --label $OS_LOGIN_USER --algorithm rsa
Imported key as label: "1"
Note: internally, i belive the above does something like the following:
tpm2_createprimary -C o -g sha256 -G rsa -c primary.ctx
tpm2_import -C primary.ctx -G rsa -i private.pem \
-u key.pub -r key.prv
tpm2_load -C primary.ctx -u key.pub -r key.prv -c key.ctx
The follwing will extract the public SSH-formatted public key from the TPM. Note, if we used the same private key as in the Yubikey setup, the public portion will ofcourse be the same
ssh-keygen -D /usr/local/lib/libtpm2_pkcs11.so | tee my.pub
my.pub
should look something like
ssh-rsa AAAAB3redacted...
$ gcloud compute os-login ssh-keys add --key-file my.pub
Use the public IP of the OS Login VM you geneated in the Yubikey Setup stage. The PIN is 123456
as specified in the setup
ssh -I /usr/local/lib/libtpm2_pkcs11.so $OS_LOGIN_USER@35.225.191.58
Enter PIN for 'user1_esodemoapp2_com':
To restate, this is nothing new…the Yubikey stuff is just PIV-smartcard stuff thats been around for a long time.
TPM based PKCS is still in development; DO NOT use this is production.
TPM setup for PKCS11 uses some sort of sqlite3 datastore which i need to understand more. I’d rather just manually provision the TPM and have a persistent handle plus custom authorization policies (PCR values, etc) as available restricts. They maybe somewher in the tool but i didn’t see it readily.
This is just for amusement only.
This site supports webmentions. Send me a mention via this form.