This article focuses on replacing the default BCCSP (Blockchain Cryptographic Service Provider) security provider in Go SDK for Hyperledger Fabric with the Transit engine provided by HashiCorp’s Vault.
You might be asking yourself the question, why is it beneficial to replace a built-in feature of the Go SDK? Each transaction sent to Hyperledger Fabric needs to be signed with a private key of the user who invokes the transaction. The Go SDK uses the BCCSP which does the signing for you. The BCCSP uses encryption keys and certificates loaded from the MSP directory on a local filesystem.
This is where the problem lies, a local filesystem. Usually, the app which is connecting to blockchain using the Go SDK runs on some remote server. This means it’s necessary to store all user’s private keys on the filesystem of the remote server in plain text which is totally not recommended in production environments.
First of all, each user should have his private key securely stored on his location if storing it in plain text. Secondly, storing any private key in plain text is a huge security vulnerability because the plain text file may be read by an attacker or malicious code.
Vault from HashiCorp is a highly secured secret management system. It stores secrets such as passwords, certificates, API keys, etc. in a strongly encrypted way. It also manages and enforces access to them based on trusted sources of application and user identity.
Another feature of Vault is the ability to encrypt or sign the data in transit and at rest across applications. The transit engine generates and stores private keys for users in encrypted storage without the need to export them for usage. The encrypt and sign operations with the user’s private key are done based on the user’s authentication. That means the keys are protected in the best possible way, and if the authentication information is compromised it’s easy to revoke it and grant access to the key with different authentication without changing the private key itself.
This feature is desired in systems like Hyperledger Fabric where changing the admin certificates in channel configuration can be a difficult and time-consuming process when there’s a need to change the private keys which those certificates were issued for.
The request originates from the client machine. It’s processed on the SDK server where it needs to be signed. The server uses the Vault to sign the request using the authentication from the original request. Vault returns the signature which is added to the final request that is sent to the Hyperledger Fabric network.
Hyperledger Fabric request flow using HashiCorp Vault
First, we need to have the Vault instance deployed and configured. This process is beyond the scope of this article. The next steps of this article can be achieved using Vault CLI or UI. If you prefer the CLI make sure you have it installed on your system and properly configured. For using UI navigate to http(s)://[VAULT_ADDR]:8200/ui and log in. This article also assumes that you have the Go language installed and properly configured.
Let’s start by enabling the transit engine.
vault secrets enable transit
Then, we need to create the user’s key in the Transit engine.
vault write -f transit/keys/username
We also need to create the CSR to be able to issue a certificate from CA. Since our private key is in Vault we can’t do it by Open SSL. I’ve made a simple program in Go to achieve this. So let’s install it.
go install github.com/richardfelkl/vault-tools-go/cmd/vault-tools
Make sure you have your GOBIN environment variable in your path. You’ll then be able to execute the vault-tools command.
Let’s prepare the arguments for the CSR. In the example below there’s a JSON file with the minimum arguments you’ll need to place in the certificate. The common name should be the name of your user and Organization should be the name of your organization.
Now let’s execute vault-tools. It is able to read the Vault environment variables used for Vault CLI: VAULT_ADDR and VAULT_TOKEN . Make sure those variables are set or pass them in --address and --token parameters of the following command. The --names parameter is a path to JSON file created above. The --name parameter is the transit name.
vault-tools csr --name username --names ./names.json
This command will print the CSR in PEM format. Now you can use the CSR to issue the certificate from your CA. It could either be Fabric CA or another system you’re using. This process is beyond the scope of this article. The certificate is needed in the last step to make the example work.
Let’s take a look at all the code you’ll need to make the integration work. Let’s assume the following package structure of the Go code:
We’re going to start with the code for the vault package. It will contain a Manager struct that is able to do sign and verify operations using the Vault Transit engine.
Now we need to define custom identity implementation that will use the Vault Transit engine to sign and verify transactions. It needs to be serializable into the Protobuf format. We also define a key which is a type of core.Key.
The last package is cryptosuite. We need to define a custom cryptosuite implementation that is able to import public keys and verify signatures with them. We’ll make use of the VaultKey we defined in the identity package.
The last thing is the provider factory which manages the cryptosuite we created in the previous step.
Now we have all necessary structures prepared and we can put it all together in a sample main application. Pay attention to variables with comments. Additional settings are needed.
And that’s it. It’s quite a lot of code to be defined for replacing the key components for signing, and that’s just a sample. There is still a lot of code missing to make it production-ready, but it gives you a strong and secure mechanism for signing the Fabric transactions. The code for other SDKs like Node and Java may look similar.