Samples in golang that enables the following where the private key or hmac secret is embedded with a TPM (Trusted Platform Module)
this repository is not supported by Google
You can find the source here
AWS v4 Signer for embedding Access Secrets to PKCS11 and TPMs
TPM TokenSource for GoogleCloud
golang TokenSource
which derives GCP Oauth2 and JWTAccessTokens from a TPM for use with GCP Client libraries
TPM AccessTokens using Openssl TPM library Create oauth2 and jwtaccess tokens using TPM support with openssl
Generate key on TPM and export public X509 certificate to GCP
TPM to TPM secret Transfers: Use to transfer a wrapped HMAC or RSA key from one TPM to another
Examples of the complete Signature Version 4 signing process (Python)
Create GCS Bucket, object and Service Account and HMAC key to test with
export PROJECT_ID=`gcloud config get-value core/project`
export PROJECT_NUMBER=`gcloud projects describe $PROJECT_ID --format='value(projectNumber)'`
# create a gcs bucket and object
gsutil mb gs://$PROJECT_ID-tpm
echo -n "some text" > somefile.txt
gsutil cp somefile.txt gs://$PROJECT_ID-tpm
# create a service account that has access to a bucket
# the private key on the TPM will be associated with this service account
gcloud iam service-accounts create tpm-svc-account --project $PROJECT_ID
gcloud iam service-accounts keys list --iam-account tpm-svc-account@$PROJECT_ID.iam.gserviceaccount.com
# allow the service account access to the bucket
gsutil iam ch serviceAccount:tpm-svc-account@$PROJECT_ID.iam.gserviceaccount.com:objectViewer gs://$PROJECT_ID-tpm
# remember the hmac key and secret
gsutil hmac create tpm-svc-account@$PROJECT_ID.iam.gserviceaccount.com
Access ID: GOOG1EJBAWIATBBMPW5SNXGTKD6QTQPNJ3MDJXGGGQTJ6PYQQ3I4UGWIZYHBQ
Secret: ...redacted...
gsutil hmac list -p $PROJECT_ID
# Create a VM with a TPM
gcloud compute instances create tpm-test \
--image=debian-10-buster-v20210701 --image-project=debian-cloud \
--machine-type "n1-standard-1" \
--shielded-secure-boot --shielded-vtpm --shielded-integrity-monitoring \
--zone us-central1-a
# ssh to the VM
gcloud compute ssh tpm-test --zone us-central1-a
On VM:
sudo su -
apt-get update -y
apt-get install wget curl git -y
# install golang 1.15 https://golang.org/doc/install
wget https://golang.org/dl/go1.15.14.linux-amd64.tar.gz
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.15.14.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
## *optionally* install tpm2_tools https://tpm2-tools.readthedocs.io/en/latest/INSTALL/
# get the source
git clone https://github.com/salrashid123/gcs_tpm.git
cd gcs_tpm
Embed the HMAC key into the TPM
# first import the hmac secret to the TPM
go run main.go --mode=import --hmacSecret="hmac_secret_from_setup"
# now use the TPM to generate a signedURL and download the file
go run main.go --mode=sign \
--hmacKey="GOOG1EJBAWIATBBMPW5SNXGTKD6QTQPNJ3MDJXGGGQTJ6PYQQ3I4UGWIZYHBQ" \
--bucketName="$PROJECT_ID-tpm" --objectName="somefile.txt"
At this point the hmac key is embedded into the TPM with set TPM attributes
public := tpm2.Public{
Type: tpm2.AlgKeyedHash,
NameAlg: tpm2.AlgSHA256,
AuthPolicy: []byte(defaultPassword),
Attributes: tpm2.FlagFixedTPM | tpm2.FlagFixedParent | tpm2.FlagUserWithAuth | tpm2.FlagSign, // | tpm2.FlagSensitiveDataOrigin
KeyedHashParameters: &tpm2.KeyedHashParams{
Alg: tpm2.AlgHMAC,
Hash: tpm2.AlgSHA1,
},
}
You can also set TPM Policies that govern how to access the key (eg, passwordPolicy, PCR Policy, etc)
If you want to use tpm2_tools, note that tpm support was added in with Issue 1597
The following will create an RSA private key on the tpm and then use that to create a Certificate Signing Request (CSR) and a self-signed x509 Certificate. The CSR is NOT used in this sample but could be used by an external CA to sign. For this repo, we will use the TPM based RSA key to self-sign a certificate.
Since this procedure uploads a key, your organization policy should allow type: constraints/iam.disableServiceAccountKeyUpload
# generate the 509
go run svcaccount/main.go --mode=gencert --cn=tpm-svc-account@$PROJECT_ID.iam.gserviceaccount.com
# this will generate the cert file at `x509cert.pem`
# copy x509cert.pem to laptop
# on LAPTOP, upload the 509 cert and associate it with a service account
gcloud beta iam service-accounts keys upload x509cert.pem --iam-account=tpm-svc-account@$PROJECT_ID.iam.gserviceaccount.com
gcloud iam service-accounts keys list --iam-account tpm-svc-account@$PROJECT_ID.iam.gserviceaccount.com
KEY_ID CREATED_AT EXPIRES_AT
4909a11e0a0793f7daba01958a93e67c34cddff6 2021-08-02T12:52:00Z 2022-08-02T12:52:00Z <<< TPM based service account
1155f398f6bf840e84a9e16effa35aceca6f45a8 2021-08-02T12:26:22Z 2023-08-25T01:58:04Z
# on VM
# A) generate a signedURL and access the object
go run svcaccount/main.go --mode=genurl --cn=tpm-svc-account@$PROJECT_ID.iam.gserviceaccount.com --bucketName=$PROJECT_ID-tpm --objectName=somefile.txt
# B) use the TPM's private key to generate a GCP oauth access_token
go run svcaccount/main.go --mode=useclient --cn=tpm-svc-account@$PROJECT_ID.iam.gserviceaccount.com --bucketName=$PROJECT_ID-tpm --objectName=somefile.txt
with SignedURL
with oauth2 token
You can also use the Attestation Signing Key to sign the url or for an auth token.
// note this key is on OWNER
kk, err = client.AttestationKeyRSA(rwc)
if err != nil {
fmt.Fprintf(os.Stderr, "can't AK %q: %v", tpmPath, err)
os.Exit(1)
}
// GceAttestationKeyRSA generates and loads the GCE RSA AK. Note that this function will only work on a GCE VM. Unlike AttestationKeyRSA, this key uses the Endorsement Hierarchy and its template loaded from GceAKTemplateNVIndexRSA.
// ```bash
// gcloud compute instances get-shielded-identity tpm-test --zone us-central1-a --format="value(signingKey.ekPub)"
// ```
kk, err = client.GceAttestationKeyRSA(rwc)
if err != nil {
fmt.Fprintf(os.Stderr, "can't AK %q: %v", tpmPath, err)
os.Exit(1)
}
pubKey := kk.PublicKey().(*rsa.PublicKey)
akBytes, err := x509.MarshalPKIXPublicKey(pubKey)
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR: could not get MarshalPKIXPublicKey: %v", err)
os.Exit(1)
}
akPubPEM := pem.EncodeToMemory(
&pem.Block{
Type: "PUBLIC KEY",
Bytes: akBytes,
},
)
Either way, you should have a go-tpm-tools Key object which you should persist. Later on, you will load this Key and use it for Signing.
The equivalent commands using openssl-tss engine to that will generate and embed hmac and RSA keys are
# verify TPM support
openssl engine -t -c tpm2tss
# generate a private key on TPM
tpm2tss-genkey -a rsa private.tss
# generate CSR
openssl req -new -out csr.pem -engine tpm2tss -keyform engine -key private.tss
# generate self-signed certificate
openssl req -new -x509 -engine tpm2tss -key private.tss -keyform engine -out public.crt -subj "/C=US/ST=California/L=Mountain View/O=Acme Co/OU=Enterprise/CN=OURServiceAccountName@PROJECT_ID.iam.gserviceaccount.com"
# extract RSA publickey from certificate
openssl x509 -pubkey -noout -in public.crt > public.pem
# print certificate
openssl x509 -in public.crt -text -noout
# start SSL listener using TPM-based private key
openssl s_server -cert public.crt -key private.tss -keyform engine -engine tpm2tss -accept 50051
export secret="key"
export plain="The quick brown fox jumps over the lazy dog"
echo -n $secret > hmac.key
hexkey=$(xxd -p -c 256 < hmac.key)
echo $hexkey
echo -n $plain > data.in
openssl dgst -sha256 -mac hmac -macopt hexkey:$hexkey data.in
HMAC-SHA256(data.in)= f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8
tpm2 createprimary -Q -G rsa -g sha256 -C e -c primary.ctx
tpm2 import -C primary.ctx -G hmac -i hmac.key -u hmac.pub -r hmac.priv
tpm2 load -C primary.ctx -u hmac.pub -r hmac.priv -c hmac.ctx
echo -n $plain | tpm2_hmac -g sha256 -c hmac.ctx | xxd -p -c 256
f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8
This site supports webmentions. Send me a mention via this form.