Hyperledger FireFly is an implementation of a multi-party system that simplifies data orchestration on top of blockchain and other peer-to-peer technologies.
This chart bootstraps a FireFly deployment on a Kubernetes cluster using the Helm package manager. It can be used to deploy a single FireFly node for an individual organization within a multi-party system.
- Prerequisites
- Get Repo Info
- Install Chart
- Uninstall Chart
- Upgrading Chart
- Using as a Dependency
- Deployment Architecture
- Configuration
- Automated Deployments
- Kubernetes 1.18+
- Helm 3.7+
- PV provisioner support in the underlying infrastructure
- Recommended: cert-manager 1.4+
Helm's experimental OCI registry support is used for publishing and retrieving the FireFly Helm chart, as a result one must log into GHCR to download the chart:
export HELM_EXPERIMENTAL_OCI=1
helm registry login ghcr.io
NOTE: you must use a GitHub personal access token when authenticating to the GHCR registry as opposed to using your GitHub password.
helm install [RELEASE_NAME] --version 0.2.0 oci://ghcr.io/hyperledger/helm/firefly
See configuration below.
See helm install for command documentation.
helm uninstall [RELEASE_NAME]
See helm uninstall for command documentation.
helm upgrade [RELEASE_NAME] --install --version 0.2.0 oci://ghcr.io/hyperledger/helm/firefly
See helm upgrade for command documentation.
You can also use the FireFly chart within your own parent chart's Chart.yaml
:
dependencies:
# ...
- name: firefly
repository: "oci://ghcr.io/hyperledger/helm/"
version: 0.2.0
Then download the chart dependency into your parent chart:
helm dep up path/to/parent-chart
See helm dependency for command documentation.
FireFly provides a REST API with an event-driven paradigm that simplifies building multi-party interactions via decentralized applications. In order to do so, FireFly leverages extensible connector plugins that enable swapping out the underlying blockchain and off-chain infrastructure easily.
As a result, a FireFly node has several infrastructural dependencies:
- Blockchain connector (either Fabconnect -> Fabric, or Ethconnect -> Ethereum) for a private blockchain
- A Fabric chaincode or Ethereum smart contract deployed to the underlying blockchain
- Private data exchange (HTTPS + mTLS)
- Database (PostgreSQL)
- Shared storage (IPFS)
- Optional tokens connectors (ERC1155, ERC20, etc.)
As depicted above, the chart only aims to provide a means for deploying the following components:
Component | Status | Optional | Enabled by Default |
---|---|---|---|
FireFly Core | βeta | ❌ | N/A |
FireFly Ethconnect | ⍺lpha |
✅ | ❌ |
FireFly Fabconnect | Unimplemented 🙈 | N/A | N/A |
FireFly DataExchange HTTPS | βeta | ✅ | ✅ |
FireFly Tokens ERC1155 | βeta | ✅ | ❌ |
FireFly Tokens ERC20 / ERC721 | ⍺lpha |
✅ | ❌ |
NOTE: "Status" is meant to indicate the level of stability of the chart's support for the particular component. It is not meant to indicate the maturity of the component itself, though the component's maturity does have an impact on the community's ability to support it via the chart.
All other infrastructural dependencies such as the blockchain, PostgreSQL, and IPFS are considered out of scope for the chart, and must be pre-provisioned in order for FireFly to be fully functioning.
The following describes how to use the chart's values to configure various aspects of the FireFly deployment.
FireFly itself has a robust YAML configuration file (usually named firefly.core
) powered by Viper
that allows one to define all the necessary configuration for the FireFly server, and the underlying
connectors it will use.
The chart provides a top-level config
value which then contains sub-values such as postgresUrl
, ipfsApiUrl
,
organizationName
, adminEnabled
, etc. These sub-values are meant to provide an opinionated, safe way of templating
the firefly.core
file. Based on which values are set, it will correctly configure the various connector plugins as well
as determine if additional ports will be exposed such as the admin, debug, and metrics ports.
The following values are required in order for FireFly to startup correctly:
config.organizationName
config.organizationKey
config.postgresUrl
config.ipfsApiUrl
andconfig.ipfsGatewayUrl
- either:
config.fireflyContractAddress
, and then eitherconfig.ethconnectUrl
orethconnect.enabled
(see Ethereum below for more details)- or,
config.fabconnectUrl
andconfig.fabconnectSigner
You can find documentation regarding each of these values, as well as all the other config
values,
in the comments of the default values.yaml
. You can see how the values are used for
templating the firefly.core
file by looking at the firefly.coreConfig
helper function in _helpers.tpl
.
NOTE: although
config.dataexchangeUrl
is available, by defaultdataexchange.enabled
istrue
which will deploy a DataExchange HTTPS and automatically configure FireFly to use it.
If you would rather customize the templating of the firefly.core
with your own values, you can use config.templateOverride
:
config:
templateOverride: |
org:
name: {{ .Values.global.myOrgNameValue }}
# etc. ...
See config.go
for all available FireFly configuration options.
If there are configurations you want to set via your own ConfigMaps
or Secrets
, it is recommended to do so
via environment variables which can be provided with the core.extraEnv
list value. FireFly will automatically override
its config via environment variables prefixed with FIREFLY_
. For example, if you want to set to the config value
log.level
you would set the env var FIREFLY_LOG_LEVEL
.
For a more detailed example using core.extraEnv
, one could provide basic auth credentials for IPFS from a Secret
like so:
core:
extraEnv:
- name: FIREFLY_PUBLICSTORAGE_IPFS_API_AUTH_USERNAME
valueFrom:
secretKeyRef:
name: my-ipfs-basic-auth
key: username
- name: FIREFLY_PUBLICSTORAGE_IPFS_API_AUTH_PASSWORD
valueFrom:
secretKeyRef:
name: my-ipfs-basic-auth
key: password
In the case of PostgreSQL credentials, environment variables will have to be set for FireFly and its migrations Job
:
# database section of the config needs to be set to indicate Postgres
config:
databaseOverride: |-
type: postgres
postgres:
migrations:
auto: false
# pass Postgres URL as a secret to both FireFly and the migrations job
core:
extraEnv:
- name: FIREFLY_DATABASE_POSTGRES_URL
valueFrom:
secretKeyRef:
name: custom-psql-config
key: url
jobs:
postgresMigrations:
enabled: true
extraEnv:
- name: PSQL_URL
valueFrom:
secretKeyRef:
name: custom-psql-config
key: url
Configuring FireFly to use an Ethereum blockchain such as Geth, Quorum, or Hyperledger Besu requires first having an instance of FireFly Ethconnect deployed and connected to the JSONRPC port of an Ethereum node in the underlying network. You can either configure the chart to use a "remote", pre-provisioned Ethconnect instance, or the chart can create a "local" Ethconnect instance for you alongside your FireFly.
NOTE: Ethconnect itself has two modes: local registry versus remote registry mode. If you are provisioning Ethconnect yourself using the chart or other means, then it will likely be in local registry mode. This means FireFly will interact with contract instances using the
/contracts/{address}
API. However, if you are using Ethconnect provisioned via a cloud provider such as Kaledio then it will be in remote registry mode and FireFly will need use the/instances/{address}
API instead.
Regardless of how you provision Ethconnect, the chart will need the following config to tell FireFly how to submit and sign batch pin transactions via its smart contract (one of the core operations):
config:
organizationKey: "{organizationWalletAddress}"
fireflyContractAddress: "/contracts/{fireflyContractAddress}"
where:
config.organizationKey
: is the Ethereum address of the organization's wallet / key which will be used for signing transactionsconfig.fireflyContractAddress
: the Ethconnect URI representing the deployed FireFly smart contract i.e./contracts/0x965b92929108df1c77c156ba73d00ca851dcd2e1
or/instances/0x965b92929108df1c77c156ba73d00ca851dcd2e1
. See Smart Contract Deployment for how to you can deploy the contract yourself.
Assuming you have an Ethconnect instance ready, the chart will need the following additional configuration to have FireFly (and any enabled tokens connectors) connect to it:
config:
ethconnectUrl: "https://ethconnect.acme.org"
Assuming you have an Ethereum node ready, the chart can be configured to automatically provision Ethconnect for you given the following:
ethconnect:
enabled: true
config:
jsonRpcUrl: "https://eth.acme.org"
jobs:
registerContracts:
enabled: true
Because the chart-managed Ethconnect is in "local registry mode", it will not be aware of any pre-deployed smart contracts
without first registering them. By default, the chart will run a job which will attempt to register the presumably, pre-deployed
FireFly and ERC1155 contracts provided via the config.fireflyContractAdderess
and erc1155.contractAddress
values.
NOTE: With the ongoing work on Custom On-Chain Logic within FireFly, the support around contract registration and deployment is subject to change in the near future.
If you are unable to pre-deploy the contracts, you can disable registration and boot up FireFly in a "pre-init" state instead:
config:
preInit: true
core:
jobs:
registration:
enabled: false
ethconnect:
enabled: true
config:
jsonRpcUrl: "https://eth.acme.org"
jobs:
registerContracts:
enabled: false
This will allow you to install the chart, deploy your smart contracts to the chart-managed Ethconnect, then you can upgrade the chart with pre-init disabled to have FireFly finish its startup and network registration:
config:
preInit: false
core:
jobs:
registration:
enabled: true
Currently, the chart offers no way for one to manage the FireFly smart contract. Instead, the chart assumes it is already pre-provisioned via Ethconnect by one of the organizations.
If you have the contract available as gateway contract on Ethconnect, you can then deploy it via the API:
curl -v \
-X POST \
-H 'Content-Type: application/json' \
-d '{}' \
"${ETHCONNECT_URL/gateways/${FF_CONTRACT_GATEWAY}?ff-from=${ORG_WALLET_ADDRESS}&ff-sync=true"
The JSON returned by the API will have the Ethereum address of the smart contract in the address
field.
NOTE: the FireFly smart contract only needs to be deployed by one organization within the blockchain network. All organizations within a FireFly network must use the same smart contract instance in order for transactions to work properly.
If the contract is not available as a gateway contract on your Ethconnect instance, see the Ethconnect docs for deploying a contract.
Configuring FireFly to use a Hyperledger Fabric blockchain requires first having an instance of FireFly Fabconnect deployed and connected to the gRPC port of a Fabric peer in the underlying network.
As was noted in Deployment Architecture, the chart will eventually include support for deploying Fabconnect. For now, you can either deploy Fabconnect yourself or use a cloud provider like Kaleido which provides Fabconnect alongside its Fabric peer nodes.
Once you have a Fabconnect instance ready, FireFly then needs three pieces of configuration:
config.organizationKey
: the name of the organization's Fabric identity which will be used for signing transactionsconfig.fabconnectUrl
: the HTTP/S URL of the Fabconnect instance FireFly will useconfig.fabconnectSigner
: the name of the organization's Fabric identity which will be used for signing transactions. See Identity Management for how to you can create and enroll the identity using Fabconnect.
These will enable the FireFly deployment to connect to the Fabric blockchain and submit batch pin transactions via its chaincode on behalf of the organization it's representing.
By default, the chart assumes the FireFly chaincode is deployed to the
default-channel
with the name firefly_go
. If the chaincode was deployed to a different channel or with a different
name you can set config.fabconnectChannel
and config.fireflyChaincode
accordingly.
For deploying the chaincode yourself, consult the Fabric documentation.
The Fabric identity FireFly will use for signing transactions on behalf of the organization must be pre-enrolled with
the Fabric CA before deploying FireFly and registration its organization. Fabconnect provides an /identities
REST API
which makes creating an identity and enrolling it easy. For example, the following Bash script performs the necessary
API calls to create and enroll an identity named ${ORG_NAME}
:
identityRegistrationResponse=$(curl --fail -s \
-X POST \
-H 'Content-Type: application/json' \
-d "{ \"name\": \"${ORG_NAME}\", \"type\": \"client\" }" \
"${FABCONNECT_URL}/identities")
enrollmentSecret=$(echo -n $identityRegistrationResponse | jq -r .secret)
curl --fail -s \
-X POST \
-H 'Content-Type: application/json' \
-d "{ \"secret\": \"${enrollmentSecret}\" }" \
"${FABCONNECT_URL}/identities/${ORG_NAME}/enroll" | jq -r
You can use Bash or whatever scripting / programming language you prefer to enroll the identity. If you wish to enroll the identity without having to first deploying Fabconnect, please consult the Fabric CA documentation.
If you have an Ingress
controller deployed
to your cluster, and the chart supports deploying an Ingress
for the FireFly REST API and websocket subscriptions. For example, if you are using the ingress-nginx
controller
alongside cert-manager
you can secure FireFly with TLS and the necessary settings:
core:
ingress:
enabled: true
className: nginx # assuming you are using the default ingressClassName for nginx-ingress
annotations:
# recommended for handling blob data transfers and broadcasts
nginx.ingress.kubernetes.io/proxy-body-size: 128m
# recommended for having websocket connections live longer than the default 60s
nginx.ingress.kubernetes.io/proxy-read-timeout: "1800"
nginx.ingress.kubernetes.io/proxy-send-timeout: "1800"
# example cert-manager ClusterIssuer for Let's Encrypt
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: firefly.acme.org
tls:
- secretName: firefly-tls
hosts:
- firefly.acme.org
The database schema FireFly uses for its state must be configured via migrations.
The chart offers the ability to automatically apply the migrations matching the version of FireFly in use via a Job
:
core:
jobs:
postgresMigrations:
enabled: true
The Job
will be named with the FireFly version in use, and will be automatically replaced and re-run whenever the
version is updated indicating the expected schema could have potentially changed.
Additionally, FireFly itself can apply its own schema migrations. However, this is not recommended for production use where an organization could have multiple FireFly nodes sharing the same database:
config:
postgresAutomigrate: true
It is recommended to use the migrations Job
from above in favor of the automatic migrations.
FireFly requires that the organizations within the multi-party system, as well as the individual FireFly
nodes be registered with
the rest of the network. This can be accomplished using the FireFly REST API,
however the chart offers a registration Job
which will ensure the organization is registered before then
registering the node:
core:
jobs:
registration:
enabled: true
The DataExchange HTTPS uses mTLS to securely send messages to other peers. By default, the
chart assumes an mTLS certificate with the proper subject
and commonName
is provided
via dataexchange.tlsSecret.name
.
However, the chart offers the ability to automatically provision and wire up the DataExchange with an mTLS certificate using cert-manager:
dataexchange:
tlsSecret:
enabled: false
certificate:
enabled: true
issuerRef:
name: selfsigned-ca
kind: ClusterIssuer
NOTE: the certificate cannot be signed by a self-signed or public CA issuer because cert-manager will not set the
subject
andcommonName
properly (see cert-manager/cert-manager#3651). We recommend using an internal CA issuer instead. An example setup of a CA issuer signed by a self-signed issuer can be found here.
If your DataExchange HTTPS is communicating via Ingresses
, you will need to enable TLS passthrough
in order for mTLS to work. For example, when using ingress-nginx an
annotation can be set on the Ingress
:
ingress:
enabled: true
annotations:
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
class: nginx
hosts:
- host: firefly-dx.acme.org
NOTE: the
tls
section of theIngress
does not need to be configured since mTLS is required. Instead, it assumes the providedhosts
must match thetls[0].hosts
and that the secret is either pre-made or provided by cert-manager.
By default, the chart comes with the FireFly Tokens ERC1155 connector disabled.
The ERC1155 connector requires its ERC1155 smart contract to be deployed via Ethconnect. To do so, you can follow the same process for deploying the FireFly smart contract. Once the smart contract is deployed, you can enable the ERC1155 connect and provide the contract address to the chart:
erc1155:
enabled: true
contractAddress: "/instances/0xf778b86fa74e846c4f0a1fbd1335fe81c00a0c91"
By default, the chart comes with the FireFly Tokens ERC20 / ERC721 connector disabled. ERC20 is the token standard used for fungible tokens as part of this connector, whereas ERC721 is used for the non-fungible tokens (NFTs).
Unlike other token connectors, ERC20 / ERC721 is stateless and currently comes with experimental support for automatically deploying its smart contracts to your Ethconnect instance and preparing them to be used by their respective token pools:
erc20Erc721:
enabled: true
erc20:
enabled: true
tokenName: "FF" # enter the symbol / name for your fungible tokens here
erc721:
enabled: false
tokenName: "NFFT" # enter the symbol / name for your NFTs here
job:
deployContracts:
enabled: true
see the values.yaml for more information around configuration options depending on if you are using an Ethconnect instance in local or remote registry mode.
NOTE: With the ongoing work on Custom On-Chain Logic within FireFly, the support around contract deployment is subject to change in the near future.
FireFly comes with an metrics endpoint exposed on a separate HTTP server for Prometheus scraping.
By default, the FireFly Prometheus metrics server is enabled. You can turn the server off, or configure its exposed port and path using the following values:
config:
metricsEnabled: true
metricsPath: /metrics
core:
service:
metricsPort: 5100
Additionally, if you are managing Prometheus via the Prometheus Operator,
you can enable a ServiceMonitor
for FireFly with:
core:
metrics:
serviceMonitor:
enabled: true
Due to Helm's OCI registry support being experimental, below describes how to configure common deployment automation tooling for consuming the FireFly chart.
Flux V2 is a GitOps controller for Kubernetes which currently does not support Helm OCI registries.
Instead, one can use a GitRepository
resource pointed at a specific release tag:
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: GitRepository
metadata:
name: firefly-helm
spec:
interval: 10m
url: "https://github.com/hyperledger/firefly"
ref:
tag: helm-v0.1.0
ignore: |
/*
!/charts/firefly
then within a HelmRelease
resource you can refer to the chart via the GitRepostiory
:
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: firefly
spec:
chart:
spec:
chart: /charts/firefly
sourceRef:
name: firefly-helm
kind: GitRepository
interval: 1m
values: |
# ...
ArgoCD is another GitOps controller for Kubernetes which does support OCI
Helm registries. In order to use the FireFly Helm chart via an ArgoCD Application
,
you must first add the OCI Helm registry for Hyperledger. For example, you can do so using the CLI:
argocd repo add ghcr.io/hyperledger/helm --type helm --name hyperledger --enable-oci --username ${USERNAME} --password ${PAT}
To declaratively add the registry consult the documentation.
Terraform is a CLI tool that enables engineers to "plan" and "apply" infrastructure defined as code in the HCL language. Terraform offers a Helm provider for managing Helm releases and their values declaratively. Terraform does not currently support OCI registries.
As a result, you can configure Terraform to use the FireFly chart by either:
-
Creating a wrapper parent chart with the FireFly chart dependency pre-downloaded and vendored. See Using as a Dependency for more information.
-
Pre-downloading the FireFly chart directly using:
helm pull --version 0.0.1 oci://ghcr.io/hyperledger/helm/firefly
then referring to via its filepath location:
resource "helm_release" "firefly" { name = "firefly" chart = "firefly-0.0.1.tgz" // ... }