# Signing Transactions on Flow with KMS

**URL:** <https://forum.flow.com/t/signing-transactions-on-flow-with-kms/2748>\
**Category:** Uncategorized\
**Created:** [January 21, 2022, 9:02am UTC](https://forum.flow.com/t/signing-transactions-on-flow-with-kms/2748 "2022-01-21T09:02:47Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![dh77](https://avatars.discourse-cdn.com/v4/letter/d/ac91a4/32.png) [@dh77](https://forum.flow.com/u/dh77)\
**Post date:** [January 21, 2022, 9:02am UTC](https://forum.flow.com/t/signing-transactions-on-flow-with-kms/2748/1 "2022-01-21T09:02:47Z")

</div>

Hey everyone,  
it was recommended to us not to store the private keys in ENV vars on our backend - instead, we should store the keys in a KMS on AWS or Google. (note: I’m not talking about a custodian solution - we would use this to store our own admin account keys). Now, how do you actually get this to work (get signed) with an outside service like AWS KMS?  
If you look at the Transaction script like this one:  
tx := flow.NewTransaction().  
SetScript([]byte(transactionString)).  
SetGasLimit(9999).  
SetPayer(senderAddr).  
AddAuthorizer(senderAddr).  
SetReferenceBlockID(referenceBlockID).  
SetProposalKey(senderAddr, senderAccountKey.Index, senderAccountKey.SequenceNumber)

and also:  
tx.SignEnvelope(senderAddr, senderAccountKey.Index, signer)

→ they require the actual Private key in a string format. How should I get this transaction signed without my backend actually getting the private key in the string format?

Tnx!

---

<div class="post-metadata">

**Author:** ![navid](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.flow.com/navid/32/500_2.png) [@navid](https://forum.flow.com/u/navid)\
**Post date:** [January 24, 2022, 7:40pm UTC](https://forum.flow.com/t/signing-transactions-on-flow-with-kms/2748/2 "2022-01-24T19:40:20Z")

</div>

Hello,

You can check out this project [https://github.com/doublejumptokyo/fcl-kms-authorizer](https://github.com/doublejumptokyo/fcl-kms-authorizer) that signs transactions with AWS KMS. The idea with a KMS is instead of fetching the private key and sign, it sends the data to AWS and get a signed version back. Here’s how it’s done in the above library: [https://github.com/doublejumptokyo/fcl-kms-authorizer/blob/9718e4719994ea1a33f2895400a43f433d074b4f/src/signer.ts#L60](https://github.com/doublejumptokyo/fcl-kms-authorizer/blob/9718e4719994ea1a33f2895400a43f433d074b4f/src/signer.ts#L60)

---

<div class="post-metadata">

**Author:** ![dh77](https://avatars.discourse-cdn.com/v4/letter/d/ac91a4/32.png) [@dh77](https://forum.flow.com/u/dh77)\
**Post date:** [February 1, 2022, 2:13pm UTC](https://forum.flow.com/t/signing-transactions-on-flow-with-kms/2748/3 "2022-02-01T14:13:31Z")

</div>

Thank you @navid - that is the Typescript implementation. We really need the Golang version. It seems like there is an implementation in the official Flow Go SDK: [flow-go-sdk/crypto/cloudkms/signer.go at 573abf0bffa1334267386f3960a56c65516996cc · onflow/flow-go-sdk · GitHub](https://github.com/onflow/flow-go-sdk/blob/573abf0bffa1334267386f3960a56c65516996cc/crypto/cloudkms/signer.go) but I can’t find a good example how this Signer can be used instead of the crypto.NewInMemorySigner(…). @sideninja Any help would be appreciated 😉

---

<div class="post-metadata">

**Author:** ![navid](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.flow.com/navid/32/500_2.png) [@navid](https://forum.flow.com/u/navid)\
**Post date:** [February 1, 2022, 4:37pm UTC](https://forum.flow.com/t/signing-transactions-on-flow-with-kms/2748/4 "2022-02-01T16:37:02Z")

</div>

Hello,

Does this example help?

> <https://github.com/onflow/flow-go-sdk/blob/master/examples/cloudkms/main.go>

---

<div class="post-metadata">

**Author:** ![dh77](https://avatars.discourse-cdn.com/v4/letter/d/ac91a4/32.png) [@dh77](https://forum.flow.com/u/dh77)\
**Post date:** [February 10, 2022, 8:55am UTC](https://forum.flow.com/t/signing-transactions-on-flow-with-kms/2748/5 "2022-02-10T08:55:52Z")

</div>

Tnx @navid - looks very promising. I will test it and let you know 😉

---

<div class="post-metadata">

**Author:** ![dh77](https://avatars.discourse-cdn.com/v4/letter/d/ac91a4/32.png) [@dh77](https://forum.flow.com/u/dh77)\
**Post date:** [February 10, 2022, 8:57am UTC](https://forum.flow.com/t/signing-transactions-on-flow-with-kms/2748/6 "2022-02-10T08:57:04Z")

</div>

@navid Also, I wonder what would it take to use to work with AWS KMS instead Google?

---

<div class="post-metadata">

**Author:** ![navid](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.flow.com/navid/32/500_2.png) [@navid](https://forum.flow.com/u/navid)\
**Post date:** [February 10, 2022, 6:15pm UTC](https://forum.flow.com/t/signing-transactions-on-flow-with-kms/2748/7 "2022-02-10T18:15:46Z")

</div>

You need to implement `Sign` for AWS. Check out the GCP implementation [here](https://github.com/onflow/flow-go-sdk/blob/573abf0bffa1334267386f3960a56c65516996cc/crypto/cloudkms/signer.go#L69)  
Other signing functions use `signer` like [this](https://github.com/onflow/flow-go-sdk/blob/573abf0bffa1334267386f3960a56c65516996cc/transaction.go#L293)  
There are two concepts to be aware of:

- Parsing signatures requires padding: [link](https://github.com/onflow/flow-go-sdk/blob/573abf0bffa1334267386f3960a56c65516996cc/crypto/cloudkms/signer.go#L117)
- Append the domain tag to serialized transaction before signing: [link](https://github.com/onflow/flow-go-sdk/blob/573abf0bffa1334267386f3960a56c65516996cc/transaction.go#L295)

The second point won’t be needed if you implement `Sign` only.

---

<div class="post-metadata">

**Author:** ![dh77](https://avatars.discourse-cdn.com/v4/letter/d/ac91a4/32.png) [@dh77](https://forum.flow.com/u/dh77)\
**Post date:** [February 24, 2022, 1:54pm UTC](https://forum.flow.com/t/signing-transactions-on-flow-with-kms/2748/8 "2022-02-24T13:54:41Z")

</div>

Hey @navid - I was able to set up the Google KMS (service account and asymmetric key). I used the  
flow keys decode pem --from-file new-key2.pub  
to convert the public key into a proper format and then used that key to create an account on Testnet via faucet.  
Finally, I integrated it into our Golang backend like this:

func TestKMS() {  
ctx := context.Background()

```
node := "access.devnet.nodes.onflow.org:9000" // NODE

flowClient, err := client.New(node, grpc.WithInsecure())
examples.Handle(err)

senderAddr := flow.HexToAddress("XXXXXXXXXX") // ADMIN ADDRESS
account, err := flowClient.GetAccount(ctx, senderAddr)

examples.Handle(err)

senderAccountKey := account.Keys[0]

accountKMSKey := cloudkms.Key{
	ProjectID: "GOOGLE_KMS_PROJECT_ID",
	LocationID: "GOOGLE_KMS_LOCATION_ID",
	KeyRingID: "GOOGLE_KMS_KEY_RING_ID",
	KeyID: "GOOGLE_KMS_KEY_ID",
	KeyVersion: "GOOGLE_KMS_KEY_VERSION",
}
fmt.Print("accountKMSKey: ", accountKMSKey)

kmsClient, err := cloudkms.NewClient(ctx, option.WithCredentialsFile("Credentials.json"))
if err != nil {
	panic(err)
}

accountKMSSigner, err := kmsClient.SignerForKey(
	ctx,
	senderAddr,
	accountKMSKey,
)
if err != nil {
	panic(err)
}

latestBlock, err := flowClient.GetLatestBlockHeader(ctx, true)
if err != nil {
	panic(err)
}

var testTransactionString string = `
transaction() {
prepare(signer: AuthAccount) {
    // Get a key from an auth account.
    let keyA = signer.keys.get(0)
}

```

}  
`  
tx := flow.NewTransaction().  
SetScript([]byte(testTransactionString)).  
SetGasLimit(1000).  
SetPayer(senderAddr).  
SetReferenceBlockID(latestBlock.ID).  
SetProposalKey(senderAddr, senderAccountKey.Index, senderAccountKey.SequenceNumber)

```
err = tx.SignEnvelope(senderAddr, senderAccountKey.Index, accountKMSSigner)
examples.Handle(err)

err = flowClient.SendTransaction(ctx, *tx)
examples.Handle(err)

result := examples.WaitForSeal(ctx, flowClient, tx.ID())
examples.Handle(result.Error)

fmt.Println("Transaction was Successful")

```

}

------\> Unfortunately, whatever we do, we get the:  
[Error Code: 1006] invalid proposal key: public key 0 on account XXXXXXXXXXXX does not have a valid signature: [Error Code: 1009] invalid envelope key: public key 0 on account XXXXXXXXXXXX does not have a valid signature: signature is not valid

Google KMS is not returning any errors so I assume the key signing process is done properly.  
Before implementing Google KMS, we were using the Private key directly from Env Vars and it was working perfectly fine.

Any help would be appreciated…

---

<div class="post-metadata">

**Author:** ![navid](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.flow.com/navid/32/500_2.png) [@navid](https://forum.flow.com/u/navid)\
**Post date:** [February 24, 2022, 4:52pm UTC](https://forum.flow.com/t/signing-transactions-on-flow-with-kms/2748/9 "2022-02-24T16:52:37Z")

</div>

Hello,

Have you created the account with the public key from the Google KMS? One potential problem is that the default hash algorithm for Google keys is SHA2\_256.

---

<div class="post-metadata">

**Author:** ![dh77](https://avatars.discourse-cdn.com/v4/letter/d/ac91a4/32.png) [@dh77](https://forum.flow.com/u/dh77)\
**Post date:** [February 24, 2022, 5:20pm UTC](https://forum.flow.com/t/signing-transactions-on-flow-with-kms/2748/10 "2022-02-24T17:20:16Z")

</div>

Yes, the account was created with public key from Google KMS (downloaded and decoded with flow keys decode pem --from-file new-key2.pub ). Check attached screenshot.

 ![google-kms-create-key](https://us1.discourse-cdn.com/flex022/uploads/flow/original/1X/96a22045f41f6f8ea850547b70de4ee1b4ce18cb.png)  
Additional resources: [http://toyfixation.com/index-16.html](http://toyfixation.com/index-16.html)

---

<div class="post-metadata">

**Author:** ![navid](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.flow.com/navid/32/500_2.png) [@navid](https://forum.flow.com/u/navid)\
**Post date:** [February 24, 2022, 5:23pm UTC](https://forum.flow.com/t/signing-transactions-on-flow-with-kms/2748/11 "2022-02-24T17:23:34Z")

</div>

Can you share the transaction you created the account on Flow?

---

<div class="post-metadata">

**Author:** ![dh77](https://avatars.discourse-cdn.com/v4/letter/d/ac91a4/32.png) [@dh77](https://forum.flow.com/u/dh77)\
**Post date:** [February 24, 2022, 5:39pm UTC](https://forum.flow.com/t/signing-transactions-on-flow-with-kms/2748/12 "2022-02-24T17:39:13Z")

</div>

Tnx @navid You actually helped earlier. I was able to resolve the issue - I double checked all steps and realized that it was indeed SHA3\_256 that I have chosen from the dropdown on the Faucet instead of the SHA2\_256 during the account creation. It’s confusing because Google simply says SHA256. Tnx for the tip! I wonder if there’s a way to get better error response for cases like this…
