Skip to content

tkeeper-org/firekeeper

What is it

Firekeeper is a bridge between Fireblocks Agent and TKeeper.

It accepts signing requests from Fireblocks Agent, validates the shared secret in the Authorization header, and forwards signing operations to TKeeper.

What it does

  • accepts Fireblocks Agent requests
  • authenticates the agent with fireblocks.secret
  • forwards signing to TKeeper
  • supports two TKeeper auth modes:
    • DEV
    • OIDC
  • supports optional custom trust store for outgoing TLS to TKeeper
  • uses PostgreSQL for persistence

Requirements

  • Java 21
  • PostgreSQL
  • TKeeper reachable from Firekeeper
  • Fireblocks Agent configured to call Firekeeper

Database migrations

Firekeeper uses Liquibase migrations from:

src/main/db/changelog/changelog.yaml

Apply these migrations before running the service in any environment where the database is not already initialized.

If your deployment applies Liquibase migrations externally, make sure the full changelog is executed before Firekeeper starts processing requests.

Build

Generate jOOQ sources first:

./gradlew jooqCodegen

Build the application:

./gradlew build

Run it:

java -jar build/quarkus-app/quarkus-run.jar

Docker

The project ships with a standard Quarkus JVM image based on UBI9/OpenJDK 21.

Build the jar first:

./gradlew build

Then build the image from the project root:

docker build -f src/main/docker/Dockerfile.jvm -t firekeeper:latest .

Core configuration

application.properties example:

# -----------------------------
# Fireblocks Agent authentication
# -----------------------------
fireblocks.secret=change-me

# -----------------------------
# TKeeper connection
# -----------------------------
keeper.url=https://tkeeper.example.com
keeper.auth.type=DEV
keeper.auth.dev.token=change-me

# Optional trust store for TKeeper TLS
# keeper.trust-store.path=/app/truststore.p12
# keeper.trust-store.password=change-me

# -----------------------------
# Signing processor tuning
# -----------------------------
keeper.signature.max-attempts=3

keeper.signature.ecdsa.batch-size=8
keeper.signature.ecdsa.interval-ms=250
keeper.signature.ecdsa.timeout-ms=60000

keeper.signature.eddsa.batch-size=20
keeper.signature.eddsa.interval-ms=75
keeper.signature.eddsa.timeout-ms=10000

# -----------------------------
# PostgreSQL datasource
# -----------------------------
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=firekeeper
quarkus.datasource.password=change-me
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/firekeeper
quarkus.datasource.jdbc.max-size=16
quarkus.datasource.jdbc.min-size=2

# -----------------------------
# Liquibase
# -----------------------------
quarkus.liquibase.migrate-at-start=true
quarkus.liquibase.change-log=src/main/db/changelog/changelog.yaml

Configuration reference

Fireblocks

Property Required Description
fireblocks.secret yes Exact value expected in the incoming Authorization header from Fireblocks Agent. Fireblocks Agent forwards whatever you set in CUSTOMER_SERVER_AUTHORIZATION, so keep the full scheme here if you use one, for example Bearer ....

TKeeper

Property Required Description
keeper.url yes Public base URL of TKeeper.
keeper.auth.type yes DEV or OIDC.
keeper.auth.dev.token when DEV Token used by DevTokenAuth.
keeper.trust-store.path optional Trust store path for TLS to TKeeper.
keeper.trust-store.password optional Trust store password.

Signing processor

Property Default Description
keeper.signature.max-attempts 3 Maximum retries before the item is marked failed.
keeper.signature.ecdsa.batch-size 8 Number of ECDSA items claimed from the database per tick.
keeper.signature.ecdsa.interval-ms 250 Delay between ECDSA scheduler runs.
keeper.signature.ecdsa.timeout-ms 60000 Processing timeout for ECDSA items before they can be reclaimed.
keeper.signature.eddsa.batch-size 20 Number of EdDSA items claimed from the database per tick.
keeper.signature.eddsa.interval-ms 75 Delay between EdDSA scheduler runs.
keeper.signature.eddsa.timeout-ms 10000 Processing timeout for EdDSA items before they can be reclaimed.

PostgreSQL datasource

Firekeeper uses the standard Quarkus JDBC datasource.

Minimum setup:

quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=firekeeper
quarkus.datasource.password=change-me
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/firekeeper

A practical starting point for the pool:

quarkus.datasource.jdbc.max-size=16
quarkus.datasource.jdbc.min-size=2

OIDC setup for TKeeper

When keeper.auth.type=OIDC, configure a named OIDC client called keeper.

keeper.auth.type=OIDC
keeper.url=https://tkeeper.example.com

quarkus.oidc-client.keeper.auth-server-url=https://id.example.com/realms/main
quarkus.oidc-client.keeper.client-id=firekeeper
quarkus.oidc-client.keeper.grant.type=client
quarkus.oidc-client.keeper.credentials.secret=change-me

Optional: Vault config source

If you want secrets to come from HashiCorp Vault instead of plain properties, configure Vault as a config source.

Example:

quarkus.vault.url=http://localhost:8200
quarkus.vault.authentication.client-token=change-me
quarkus.vault.secret-config-kv-path=myapps/firekeeper

Then values such as fireblocks.secret, keeper.auth.dev.token, database credentials, or OIDC secrets can be provided by Vault.

Environment variables still override Vault values.

Optional: Sentry

If you use Sentry for error logging, add the extension and set the DSN.

quarkus.log.sentry=true
quarkus.log.sentry.dsn=https://examplePublicKey@o0.ingest.sentry.io/0
quarkus.log.sentry.minimum-event-level=ERROR

About

Use TKeeper as a signing backend in Fireblocks

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages