We are excited to announce a new major release of Veramo
!
This new release brings together a bunch of fixes and features that we've been working on recently, including some from the community (thank you for your contributions!).
You can get a detailed list of changes in
the release description. Depending on how you're
using Veramo
you might be impacted by some breaking changes that had to be added in this release.
In Veramo 3.0 we've separated some responsibilities of different plugins that deal with key management. This enables people to create new kinds of key management systems for Veramo in a way that makes it clearer where private data is stored and reduces the risk of leaking.
As you may already be aware, Veramo has a 2 layer approach to plugins. On the first layer there are top-level agent
plugins that can register for events and that export methods to be directly callable on the agent
object. These
plugin methods can also call each other in the same execution context.
In many cases these agent plugins provide some common API for interacting with different protocols or standards implementations. This is where the second level plugins come in. These provide specific implementations that plug-into the top-level ones. These implementations aren't expected to be aware of each-other, so they don't directly interact.
Examples of this pattern include DIDResolver
with implementations for various DID methods, DIDManager
with IDIDProvider
implementations, and of course KeyManager
with implementations of AbstractKeyManagementSystem
(
We sometimes refer to these as KMS).
What's new about key management?
The @veramo/kms-local
is an implementation of AbstractKeyManagementSystem
. In the previous versions it was
responsible for implementing some crypto algorithms, but it would rely on the top-level @veramo/key-manager
to provide
the actual private key material.
In Veramo 3.0 @veramo/key-manager
no longer stores any private key material.
Instead, @veramo/kms-local
now uses a PrivateKeyStore
for hosting the key data. The @veramo/data-store
package
provides an implementation that uses a database for storing these keys encrypted by a SecretBox
.
This means there will be some changes for the initial setup of these plugins, and also some changes related to how the database connection is made.
This also means that keyManagerGet()
no longer returns private keys**. If your use-case requires that you export
keys from Veramo, please raise an issue, or contact us on the
github discussions page.
Ok, so how does it affect me?
If you're just starting out, simply follow one of the getting started guides. Easy-peasy.
If you're already working with Veramo and wish to upgrade existing agents to 3.0, you'll have to make some changes to your configuration, depending on how you're using the framework.
It boils down to these 3 steps, but keep reading for more details:
- Update your database connection to use
migrations
- Remove the
SecretBox
parameter fromKeyManager
- Add a
PrivateKeyStore
parameter toKeyManagementSystem
with aSecretBox
that you were using before withKeyManager
(and keep the same encryption key)
Typescript app config changes
If your agents are part of a typescript app, these changes will look like this:
import {
// ...
migrations, // 0. import default veramo migrations
PrivateKeyStore,
} from '@veramo/data-store'
// 1. update your connection config to use migrations
dbConnection = createConnection({
// ...
synchronize: false, // switch this to false
migrations, // add default veramo migrations
migrationsRun: true, // add this flag
})
const agent = createAgent<>({
// ...
plugins: [
// 2. key manager: remove SecretBox param
new KeyManager({
store: new KeyStore(dbConnection),
kms: {
// 3. kms-local: add PrivateKeyStore with SecretBox
local: new KeyManagementSystem(new PrivateKeyStore(dbConnection, new SecretBox(secretKey))),
},
}),
// ...
],
})
CLI config changes
# 0. update the version for your config file
version: 3.0
# ...
# 1. update your database connection to use migrations
dbConnection:
$require: typeorm?t=function#createConnection
$args:
- type: sqlite
database:
$ref: /constants/databaseFile
synchronize: false # switch off synchronize
migrationsRun: true # turn on migrations
migrations: # start with veramo default migrations
$require: '@veramo/data-store?t=object#migrations'
logging: false
entities:
$require: '@veramo/data-store?t=object#Entities'
# then update your keyManager config:
keyManager:
$require: '@veramo/key-manager#KeyManager'
$args:
- store:
$require: '@veramo/data-store#KeyStore'
$args:
- $ref: /dbConnection
# 2. remove the SecretBox argument from KeyManager
kms:
local:
$require: '@veramo/kms-local#KeyManagementSystem'
$args:
- $require: '@veramo/data-store#PrivateKeyStore'
$args:
- $ref: /dbConnection
# 3. add the SecretBox argument from KeyManager to your PrivateKeyStore
- $require: '@veramo/kms-local#SecretBox'
$args:
- $ref: /constants/secretKey
Easy, right?
The default migrations
that we bundle with @veramo/data-store
also take care of moving the encrypted keys to the new
table. Make sure to use the same encryption key with SecretBox
that you were using before to be able to decrypt the
keys in their new location.
I was using my own AbstractKeyManagementSystem
, what do I do now?
In that case, congrats! Let us know about it.
The most important thing to keep in mind is that KeyManager
no longer holds any private key material. It only
knows about which AbstractKeyManagementSystem
holds the key.
This means that when a method like sign()
is called on your KMS, you should only care about the kid
property of
the IKey
param and nothing else.
Also, it is now the responsibility of the KMS implementation to compute publicKeyHex
and to decorate a key with
meta-data when it creates or imports it, before returning the descriptor to the calling KeyManager
.
As always, if there are any issues, let us know abut them, and if there are questions, please use the discussions page to get them answered and stay tuned for more.