signer
Signer service provides REST API for creating Verifiable Credentials (VC) and
Verifiable Presentations (VP) in the W3C 1.0 credential format.
It also provides more generic endpoints for signing arbitrary data, for adding
cryptographic proofs to existing VC/VP and for fetching public keys necessary
for signature verification.
It is developed using the Goa v3 framework.
A helper script named goagen.sh
can be found inside the root directory of
the service. It can be used to generate the transport layer code from the
Goa DSL definitions in the design directory. The script should
be executed everytime the design definitions are updated. It also generates
updated OpenAPI documentation from the DSL.
OpenAPI Documentation
Swagger Web UI
In the local docker-compose environment a live Swagger UI is exposed at http://localhost:8085/swagger-ui/.
High-level Overview
flowchart LR
A([client]) -- HTTP --> B[Signer API]
subgraph signer
B --HTTP--> C[Vault\nTransit API]
C --> D[(Vault)]
end
Configuration
The signer service is configured using the Configuration File.
All configurations are expected as Environment variables specified in the
configuration file. For managing the configuration data from ENV variables,
envconfig library is used.
Hashicorp Vault
The service uses Hashicorp Vault for crypto operations and storage of key material. The
Vault client is defined as Go interface, so an implementer can provide different
crypto engine implementations for crypto operations and key storage.
Vault setup is described here.
When it's up and running, the Vault Transit Engine
must be enabled and at least one asymmetric key should be created inside for use
by the Signer service. The Vault provides Web UI interface and a terminal CLI
application which can be used to manage Vault Engines and keys.
Signing Key
When a client requests a proof or creates a VC, it must specify the name of the transit
engine and signing key to be used. The key must be of a supported type, as not all key
types can be used for generating signatures.
Supported key types
Supported key types are defined as ENV variable VAULT_SUPPORTED_KEYS
. This
configuration exists because the Vault can contain different types of keys
some of which may not be supported by the codebase of the Signer service for
generating proofs. Example values:
VAULT_SUPPORTED_KEYS="ed25519,ecdsa-p256,ecdsa-p384,ecdsa-p521"
Check out Hashicorp Vault docs for all supported key types
by Vault Transit Engine. Keep in mind, that not all Vault key types are supported
by the Aries framework signature suites and the Signer service (for example RSA).
Keys we have tested with are ECDSA and ED25519 for VC/VP, while for signing arbitrary
data used for policy bundles signing, all asymmetric key types are supported
(including RSA).
Public Keys
The service exposes two endpoints for getting public keys - one for getting
a single key by name and the other for getting all possible public keys of
the signer service.
The keys are returned in JWK format and are wrapped in a DID Verification Method
envelope, so that the response can be used more easily during DID proofs verification
process. Example key response:
{
"id": "key1",
"publicKeyJwk": {
"crv": "P-256",
"kid": "key1",
"kty": "EC",
"x": "RTx_2cyYcGVSIRP_826S32BiZxSgnzyXgRYmKP8N2l0",
"y": "unnPzMAnbByBMq2l9WWKsDFE-MDvX6hYhrESsjAaT50"
},
"type": "JsonWebKey2020"
}
Build
Local binary
To make the service binary locally, you can run the following command from the root
directory (you must have Go installed):
go build -o signer ./cmd/signer/...
Docker image
You can see the Dockerfile of the service under the deployment directory.
There is one Dockerfile for use during local development with docker-compose and one for
building an optimized production image: deployment/docker/Dockerfile.
Versioning
There is one global exported variable named Version
in main.go
This variable is set to the latest tag or commit hash during the build process. You can
look in the production Dockerfile to see how the Version is set during build. The version
is printed in the service log on startup and can be checked to verify which specific version
of the code is deployed.
Version should not be set or modified manually in the source code.
VC/VP verification
When given a VC/VP for verification, the service checks the validity of the JSON structure
against the included schemas (context
), and verifies all proofs inside. Additional custom
verifiers could be written to extend the verification process. Currently, there is one such
extended verification component named train
. It can be used as an example for how to write
more verifications if needed.
Extended verification modules are enabled by a configuration variable and the corresponding
implementation. The ENV variable that specifies extended verifiers is named CREDENTIAL_VERIFIERS
and holds comma-separated strings which denote a particular verifier implementation. Inside the
service all listed verifiers are constructed and used during the VC verification process.
CREDENTIAL_VERIFIERS="train,mynewverifier"
Of course, for mynewverifier
to be a usable option, it must have been implemented inside
the service and created when its name is given in the config.
All extended verifiers implement a common interface and provide two methods.
type Verifier interface {
VerifyCredential(ctx context.Context, vc *verifiable.Credential) error
VerifyPresentation(ctx context.Context, vp *verifiable.Presentation) error
}
Logging
The service outputs all logs to stdout
as defined by the best practices in the Cloud Native
community. See here for more details 12 Factor App.
From there logs could be processed as needed in the specific running environment.
The standard log levels are [debug,info,warn,error,fatal
] and info
is the default level.
If you want to set another log level, use the ENV configuration variable LOG_LEVEL
to set it.
Dependencies and Vendor
The project uses Go modules for managing dependencies and we commit the vendor directory.
When you add/change dependencies, be sure to clean and update the vendor directory before
submitting your Merge Request for review.
go mod tidy
go mod vendor
Tests and Linters
To execute the units tests for the service go to the root project directory and run:
go test -race $(go list ./... | grep -v /integration)
To run the linters go to the root project directory and run:
golangci-lint run
Integration Tests
Integration tests are inside the integration directory.
The only configuration option they need is the base URL of the signer service.
It must be specified in the SIGNER_ADDR
environment variable.
The tests can be executed against different environments by setting the
value for SIGNER_ADDR
.
SIGNER_ADDR=https://{{SIGNER_ADDRESS}} go test
Note: these tests are not executed in the CI pipeline currently.
Dependencies
Dependencies
Deployment
Helm
Link to Helm README
License
Apache 2.0 license