AWS Process Credential source where the AWS_SECRET_ACCESS_KEY
is embedded into a Trusted Platform Module (TPM)
.
Use the binary as a way to use aws cli and any sdk library where after setup, you don't actually need to know the source AWS_SECRET_ACCESS_KEY.
To use this, you need to save the AWS_SECRET_ACCESS_KEY
into the TPM:
-
Directly load
AWS_SECRET_ACCESS_KEY
With this, you "load" the
AWS_SECRET_ACCESS_KEY
into a TPM's persistentHandle or a TPM encrypted PEM that it can only be used on that TPM alone. -
Securely Transfer
AWS_SECRET_ACCESS_KEY
from one hose to anotherThis flow is not shown in this repo but is describe in: Duplicate an externally loaded HMAC key
This repo shows how to do 1
If you're curious how all this works, see
You can set the following options on usage:
Option | Description |
---|---|
--tpm-path |
path to the TPM device (default: /dev/tpm0 ) |
--aws-access-key-id |
(required) The value for AWS_ACCESS_KEY_ID |
--persistentHandle |
Persistent Handle for the HMAC key (default: 0x81008003 ) |
--credential-file |
Path to the TPM HMAC credential file (default: ``) |
--keypass |
Passphrase for the key handle (will use TPM_KEY_AUTH env var) |
--parentPass |
Passphrase for the key handle (will use TPM_KEY_AUTH env var) |
--pcrs |
PCR Bound value (increasing order, comma separated) |
--aws-arn |
AWS ARN value to use (default: ``) |
--aws-session-name |
Session Name to use (default: ``) |
--aws-region |
AWS Region to use (default: ``) |
--assumeRole |
Boolean flag to switch the token type returned (default: false ) |
--duration |
Lifetime for the AWS token (default: 3600s ) |
--timeout |
Timeout waiting for HMAC signature from the TPM (default: 2s ) |
--tpm-session-encrypt-with-name |
hex encoded TPM object 'name' to use with an encrypted session |
On a system which has the TPM, install go, then run the following which seals the key to persistentHandle
$ export AWS_ACCESS_KEY_ID=AKIAUH3H6EGK-redacted
$ export AWS_SECRET_ACCESS_KEY=--redacted--
## add the AWS4 prefix to the raw hmac secret access key prior to import
export secret="AWS4$AWS_SECRET_ACCESS_KEY"
echo -n $secret > hmac.key
hexkey=$(xxd -p -c 256 < hmac.key)
## create the primary
### the specific primary here happens to be the h2 template described later on but you are free to define any template and policy
### this is the "H2" profile from https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html#name-parent
printf '\x00\x00' > unique.dat
tpm2_createprimary -C o -G ecc -g sha256 -c primary.ctx -a "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda|restricted|decrypt" -u unique.dat
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
tpm2_evictcontrol -C o -c hmac.ctx 0x81010002
# nif you have tpm2-tss openssl installed,
## export the keys using https://github.com/tpm2-software/tpm2-tss-engine/blob/master/man/tpm2tss-genkey.1.md
tpm2tss-genkey -u hmac.pub -r hmac.priv private.pem
## or golang:
# $ git clone https://github.com/salrashid123/aws_hmac.git
# $ cd aws_hmac/example/tpm
# $ go run create/main.go --accessKeyID $AWS_ACCESS_KEY_ID \
# --secretAccessKey $AWS_SECRET_ACCESS_KEY \
# --persistentHandle=0x81010002 --out=private.pem
At this point the hmac key is saved to both a persistent handle and an encrypted representation as PEM (see tpm2 primary key for (eg TCG EK Credential Profile H-2 profile)
-----BEGIN TSS2 PRIVATE KEY-----
MIHyBgZngQUKAQMCBQCAAAAABDIAMAAIAAsABABSAAAABQALACBkiLm1axCgdEJd
x2/m1J3k070HR2AY7fPXJ+ebWLciPQSBrACqACBcyk0W0lW71RgcPEeFJmOCmmOZ
Ww98+HwktElq9tPMWgAQRKX1ES2lUlg1h3psbVKbI38kuUWjFu1/27R/8r4cnGHx
K/2tVabz5qHl5T7UvnBJ8Cka1joTVmVugt9aNqHSlgovvnjwxWtok4rgyHPxPjly
CqYYr6ZsALXv/mmvs6dyeuz3Xo9YPFmzTxnvEfqZHhpNAOe8fB8HzouLczT2vRLl
nwb+VkA=
-----END TSS2 PRIVATE KEY-----
You can use either way. With files you can dynamically specify the credentials to use while with persistent handles, you need to load them first and have limited ability capacity.
To run this directly
go build -o aws-tpm-process-credential main.go
## using persistent handle
./aws-tpm-process-credential --aws-region=us-east-1 \
--aws-session-name=mysession --assumeRole=false --persistentHandle=0x81010002 \
--aws-access-key-id=$AWS_ACCESS_KEY_ID --duration=3600
# using encrypted file
./aws-tpm-process-credential --aws-region=us-east-1 \
--aws-session-name=mysession --assumeRole=false --credential-file=/path/to/private.pem \
--aws-access-key-id=$AWS_ACCESS_KEY_ID --duration=3600
To test the process credential API and persistent handle, first download aws-tpm-process-credential
from the Releases section or build it on your own
This repo will assume a role "arn:aws:iam::291738886548:user/svcacct1"
has access to AssumeRole on arn:aws:iam::291738886548:role/gcpsts
and both the user and role has access to an s3 bucket
Edit ~/.aws/config
and set the process credential parameters
if you want to use persistentHandle
:
[profile sessiontoken]
credential_process = /path/to/aws-tpm-process-credential --aws-region=us-east-1 --aws-session-name=mysession --assumeRole=false --persistentHandle=0x81010002 --aws-access-key-id=AKIAUH3H6EGK-redacted --duration=3600
[profile assumerole]
credential_process = /path/to/aws-tpm-process-credential --aws-arn="arn:aws:iam::291738886548:role/gcpsts" --aws-region=us-east-1 --aws-session-name=mysession --assumeRole=true --persistentHandle=0x81010002 --aws-access-key-id=AKIAUH3H6EGK-redacted --duration=3600
or credential file:
[profile sessiontokenfile]
credential_process = /path/to/aws-tpm-process-credential --aws-region=us-east-1 --aws-session-name=mysession --assumeRole=false --credential-file=/path/to/private.pem --aws-access-key-id=AKIAUH3H6EGK-redacted --duration=3600
[profile assumerolefile]
credential_process = /path/to/aws-tpm-process-credential --aws-arn="arn:aws:iam::291738886548:role/gcpsts" --aws-region=us-east-1 --aws-session-name=mysession --assumeRole=true --credential-file=/path/to/private.pem --aws-access-key-id=AKIAUH3H6EGK-redacted --duration=3600
To verify AssumeRole
first just run aws-tpm-process-credential
directly
$ /path/to/aws-tpm-process-credential \
--aws-arn="arn:aws:iam::291738886548:role/gcpsts" --aws-region=us-east-1 --aws-session-name=mysession --assumeRole=true --persistentHandle=0x81010002 --aws-access-key-id=$AWS_ACCESS_KEY_ID --duration=3600
{
"Version": 1,
"AccessKeyId": "ASIAUH3H6EGKIA6WLCJG",
"SecretAccessKey": "h7anawgBS5xNPlUcJ2P7x9YED5iltredacted",
"SessionToken": "FwoGZXIvYXdzEKz//////////wEaDK+OR7VuQewac2+redacted",
"Expiration": "2023-10-29T19:33:27+0000"
}
if that works, verify the aws cli
$ aws sts get-caller-identity --profile assumerole
{
"UserId": "AROAUH3H6EGKHZUSB4BC5:mysession",
"Account": "291738886548",
"Arn": "arn:aws:sts::291738886548:assumed-role/gcpsts/mysession"
}
# then finally s3
$ aws s3 ls mineral-minutia --region us-east-2 --profile sessiontoken
2020-08-10 02:52:08 411 README.md
2020-11-03 00:16:00 3 foo.txt
To verify the session token, first just run aws-tpm-process-credential
directly
$ sudo /path/to/aws-tpm-process-credential \
--aws-region=us-east-1 --aws-session-name=mysession --assumeRole=false --persistentHandle=0x81010002 --aws-access-key-id=$AWS_ACCESS_KEY_ID --duration=3600
{
"Version": 1,
"AccessKeyId": "ASIAUH3H6EGKFOX7G5XU",
"SecretAccessKey": "lwfjGGh41y/3RI0HUlYJFCK5LWxredacted",
"SessionToken": "FwoGZXIvYXdzEKv//////////wEaDOrG0ZqGoVCnU89juyKBredacted",
"Expiration": "2023-10-29T18:59:58+0000"
}
if that works, verify the aws cli
$ aws sts get-caller-identity --profile sessiontoken
{
"UserId": "AIDAUH3H6EGKDO36JYJH3",
"Account": "291738886548",
"Arn": "arn:aws:iam::291738886548:user/svcacct1"
}
# then finally s3
$ aws s3 ls mineral-minutia --region us-east-2 --profile sessiontoken
2020-08-10 02:52:08 411 README.md
2020-11-03 00:16:00 3 foo.txt
The TPM encrypted file is not decodable in userspace (it must be used inside the TPM by the TPM). The default format used here is compatible with openssl as described in ASN.1 Specification for TPM 2.0 Key Files where the template h-2 is described in pg 43 TCG EK Credential Profile
Of course the encrypted key can ONLY be used ont that TPM.
If you want to setup access to the key using a TPM PCR policy (eg, pcr values you specified during key creation must be met during signing), then configure it first during key creation:
In the following PCR 23 is used:
export secret="AWS4$AWS_SECRET_ACCESS_KEY"
echo -n $secret > hmac.key
hexkey=$(xxd -p -c 256 < hmac.key)
tpm2_startauthsession -S session.dat
tpm2_policypcr -S session.dat -l sha256:23 -L policy.dat
tpm2_flushcontext session.dat
printf '\x00\x00' > unique.dat
tpm2_createprimary -C o -G ecc -g sha256 -c primary.ctx -a "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda|restricted|decrypt" -u unique.dat
tpm2_import -C primary.ctx -G hmac -i hmac.key -u hmac.pub -r hmac.priv -L policy.dat
tpm2_load -C primary.ctx -u hmac.pub -r hmac.priv -c hmac.ctx
tpm2_evictcontrol -C o -c hmac.ctx 0x81010003
# tpm2tss-genkey -u hmac.pub -r hmac.priv private.pem
And then again by passing through the --pcrs=
parameter
./aws-tpm-process-credential \
--aws-arn="arn:aws:iam::291738886548:role/gcpsts" --aws-region=us-east-1 \
--aws-session-name=mysession --assumeRole=true --persistentHandle=0x81010003 \
--aws-access-key-id=$AWS_ACCESS_KEY_ID --duration=3600 --pcrs=23
ofcourse if you alter the value, the key can't be used for signing again
$ tpm2_pcrread sha256:23
sha256:
23: 0xC78009FDF07FC56A11F122370658A353AAA542ED63E44C4BC15FF4CD105AB33C
$ tpm2_pcrextend 23:sha256=0xC78009FDF07FC56A11F122370658A353AAA542ED63E44C4BC15FF4CD105AB33C
If you want to setup access to the key using a TPM Password policy (eg, you have to supply a passphrase first), then configure it first during key creation:
export passphrase="testpwd"
export secret="AWS4$AWS_SECRET_ACCESS_KEY"
echo -n $secret > hmac.key
hexkey=$(xxd -p -c 256 < hmac.key)
printf '\x00\x00' > unique.dat
tpm2_createprimary -C o -G ecc -g sha256 -c primary.ctx -a "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda|restricted|decrypt" -u unique.dat
tpm2_import -C primary.ctx -G hmac -i hmac.key -u hmac.pub -r hmac.priv -p $passphrase
tpm2_load -C primary.ctx -u hmac.pub -r hmac.priv -c hmac.ctx
tpm2_evictcontrol -C o -c hmac.ctx 0x81010004
# tpm2tss-genkey -u hmac.pub -r hmac.priv private.pem
And then again by passing through the --keyPass=
parameter
./aws-tpm-process-credential \
--aws-arn="arn:aws:iam::291738886548:role/gcpsts" --aws-region=us-east-1 \
--aws-session-name=mysession --assumeRole=true --persistentHandle=0x81010004 \
--aws-access-key-id=$AWS_ACCESS_KEY_ID --duration=3600 --keyPass=$passphrase
If you want to create a custom policy, you need to modify the code as described here
If you want to enable TPM Encrypted sessions, you should provide the "name" of a trusted key on the TPM for each call.
A trusted key can be the EK Key. You can get the name using tpm2_tools
:
tpm2_createek -c primary.ctx -G rsa -u ek.pub -Q
tpm2_readpublic -c primary.ctx -o ek.pem -n name.bin -f pem -Q
xxd -p -c 100 name.bin
000bb50d34f6377bb3c2f41a1b4b6094ed6efcd7032d28054566db0766879dad1ee0
Then use the hex value returned in the --tpm-session-encrypt-with-name=
argument.
For example:
--tpm-session-encrypt-with-name=000bb50d34f6377bb3c2f41a1b4b6094ed6efcd7032d28054566db0766879dad1ee0
You can also derive the "name" from a public key of a known template: