Introduction
As a permissioned blockchain platform, Hyperledger Fabric requires all entities, whether it is a network component or a user (client) using the platform, to be identified. This identification is implemented through digital certificates, and an infrastructure for certificate issuance and management is needed.
While one can use third-party to bring up this infrastructure, Fabric CA provides a handy way, and it generates the appropriate format required in Hyperledger Fabric system.
There is a good tutorial in readthedoc, Fabric CA Operation Guide. It creates a typical setup and provides very detailed step-by-step with explanation. I keep hearing from readers saying that there are some challenges when following this guide. As a result, I came up with this companion guide, and rearrange things into clearer steps with illustration. During the lab we make certain observations at various points to get a bigger picture. Meanwhile I also fix some naming inconsistency and update the configuration files in order to work better. Hope this is helpful when you are working on this tutorial.
Tutorial Overview
Organization Setup
The whole setup is summarized in this.
- Three organizations, org0 is the orderer organization, org1 and org2 are the peer organizations
- org0 comes with one orderer (orderer1-org0) serving ordering service in Solo
- In each peer organizations (org1 and org2) there are two peers (peer1-orgx, peer2-orgx)
- There is an admin user (admin-orgx) for each organization
For our reference, here is the overall picture. We will explain the last column immediately in the next part.
Certificate Authority Setup
If we see the setup from CA perspective, there are four CAs in this tutorial
- TLS-CA: the CA issuing TLS server certificates for network components (orderer and peers) for the whole network for. This certification is for TLS communication only, and note related to identity in this fabric network.
- RCA-ORGx (x=0, 1, 2): It is the Root CA for identities in each organization. On one side it issues the required certificates to the components and users. On the other side it represents the organization (in MSP way) when forming a fabric network.
The last column is for quick reference. We will see these directories later in the tutorial.
Once the certificate issuance is complete and fabric network setup is done, these CAs are not required in daily operation. They are not participating in joining channels, deploying chaincode, invoking chaincode functions, etc. They are needed only when new components (add one more orderer or one more peer) or new users (add more client applications) are joining the setup and new certificates are generated.
Tutorial Flow
Here is the overall flow of this tutorial (Note: this just shows a sequence of tasks, and the steps shown here are not the steps shown in the tutorial.)
- Bring up four CAs, each of which as a Fabric-CA-Server running in a container.
- Use Fabric-CA-Client in localhost to interact with these CAs. For each CA, enrol a registrar, and start entity registration of all organizations according to our tutorial design..
- For each organization, use Fabric-CA-Client to enroll entities registered in 2. Now we have all crypto material required.
- Place the resulting crypto material in appropriate directories, which will be mapped in those components (orderer and peer) defined in docker-compose file.
- Prepare the MSP directory for each organization, which is needed when creating fabric networks.
- Bring up the five containers (one orderer, four peers) and two CLI containers.
- Create channel and join peers to channel
- Deploy chaincode and observe the attribute-based access control (ABAC) feature in chaincode.
Configuration Files
There are two configuration files: a docker-compose file (docker-compose.yaml
) and a channel artifacts file (configtx.yaml
).
The docker-compose.yaml
is modified and updated to reflect the change. The original file is here.
Here is the configuration for generating channel artifacts (configtx.yaml
). The original file is here. No change in the file except fixing the indent.
Directory Structure
We create /tmp/hyperledger
to keep all the material generated during the whole tutorial. We are using Fabric-CA-Client in localhost to perform all the certificate generation. The result is all kept inside the subdirectories of /tmp/hyperledger
. We will see four subdirectories tls-ca, org0, org1, org2 over the course, and take a look at what is inside the directories during the tutorial.
Meanwhile the directories are being used for two purposes.
Mapped to network components
If we take a look on network components (orderers or peers), we will see the volume mapping. Take peer1-org1 as an example.
From volumes we see the whole directory /tmp/hyperledger/org1/peer1
of localhost will be seen in /tmp/hyperledger/org1/peer1
of peer1-org1 container, and those materials inside this directory will be used as identity (MSP) and TLS related material. Similar can be seen in other network components.
Configuration forming the consortium network
In our setup, these three organizations are forming a consortium network. They are represented by their membership service provider (MSP). We take a look at the configuration file (extracted).
As a result, after we complete the enrollment, we will put up correct certificates to form these directories /tmp/hyperledger/orgx/msp
. There are specific requirements in structure and we will see them in the tutorial.
Understand Fabric-CA-Server
As the tutorial involves a lot of Fabric CA Server, let’s first take a look how things are working inside.
Here we pick RCA-ORG1 as an example. The docker compose file for RCA-ORG1 is like this.
According to this setup, we learn
- The home for this Fabric-CA-Server is mapped to
/tmp/hyperledger/org1/ca/crypto
of the localhost. During the tutorial we seldom go into the containers. Instead we can inspect and refer material from the localhost. - The CA is defined with bootstrap credential. In this CA it is
rca-org1-admin:rca-org1-adminpw
. This is being used when we use a Fabric-CA-Client to enrol an admin (registrar). - TLS is enabled. With this, after the CA is up and running, it will issue a TLS server certificate. It is only used for accessing this RCA-ORG1, and not part of TLS of network components. And do not mix this with the TLS-CA as TLS-CA is for TLS server certificates of network components of organizations.
Now we just bring up this container and make an observation.
Bring up the RCA-ORG1 container.
Here is an illustration of RCA-ORG1, with those components of our interests.
Observe directory structure (localhost). We see a directory /tmp/hyperledger/org1/ca/crypto
in my localhost, which is the server home for Fabric-CA-Server of RCA-ORG1.
For our interest, we first locate the two certificates in this directory (ca-cert.pem
and tls-cert.pem
). We take a look at the subject and issuer of each certificate.
The certificate ca-cert.pem
is the identity Root CA certificate for org1 (the top one in our diagram). It is the self-signed certificate (issuer =subject). All certificates issued and signed by Root CA (by RCA’s private key) can be verified by this certificate.
Another certificate tls-cert.pem
is issued by the RCA (see the issuer). This is the bottom one in our diagram. This is a TLS server certificate only for TLS communication to this RCA. Concretely, when a client accesses the RCA-ORG1, RCA-ORG1 will present this server certificate to the client. The client will use the issuer (that is, the Root CA certificate) to verify this server certificate, and confirm the client is talking to the right server (RCA-ORG1), and the communication between the client and RCA-ORG1 is encrypted.
We can also locate the private keys (secret keys) corresponding to these two certificates. They are stored in msp/keystore
.
We see two here. By a quick check we know which corresponds to which (the method is to deduce the public key from the private key, and compare it with the public key in certificates).
This private key (647e…) is for ca-cert.pem
And this private key (526e…) is for tls-cert.pem
Finally, we also see a database (sqlite3). This database keeps tracking all upcoming entity registration and enrollment. Note that the bootstrap ID and secret is also placed in the database, as a registered entity. We will take a look at the flow in the tutorial.
Tutorial Detail
As you have seen in the readthedoc, the whole process involves a lot of commands. In this guide we will break them and then group them into a sequence of shell scripts. Some rearrangement is made in order to make the flow logical. We will make some observations and highlights.
It is just my practice to put it under fabric-samples/
. It can be anywhere. Just make sure you have PATH including the fabric-samples/bin/
directory
cd fabric-samples
mkdir guide
Copy the two configuration files: docker-compose.yaml
and configtx.yaml
. Over the tutorial, just place the script file in guide/
and execute it.
In case any time we wish to reset everything and begin from Step 1, we can reset the network through
cd guide
docker-compose downrm -rf /tmp/hyperledger
Then you can begin with Step 1 again.
Step 1: Bring Up TLS-CA
Script: 1_ca-tls.sh
We will walk through the whole script.
- First we bring up the TLS-CA container. After the TLS-CA container is up and running, several things happen
- The TLS-CA home directory is mapped to
/tmp/hyperledger/tls-ca/crypto/
of localhost. We can refer to this directory if we are referring any material in the TLS-CA home directory. - We are using Fabric-CA-Client (client) in localhost. Two parameters are set for the client.
- We extract the TLS-CA Root Certificate (
tls-cert.pem
) and keep it inFABRIC_CA_CLIENT_TLS_CERTFILES
. This name is a bit unclear. It is the CA certificate to verify the TLS server certificate from TLS-CA (see above Understand Fabric-CA-Server session about TLS). - The home directory is set to
/tmp-hyperledger/tls-ca/admin
. The crypto material will be kept in this directory. - There is a bootstrap ID name (
tls-ca-admin
) and secret (tls-ca-adminpw
) configured in the docker-compose file on TLS-CA (line 10 indocker-compose.yaml
). This is an entity registered in the TLS-CA database. - We now use Fabric-CA-Client to enroll a registrar on TLS-CA (https://0.0.0.0:7052), with this bootstrap ID name and secret. The result is kept in the home directory,
/tmp-hyperledger/tls-ca/admin
. This is the identity for a registrar. - With this identity, we use Fabric-CA-Client to register the five network components in the network. Each register is done with an ID name, secret (provided in this tutorial, but can be generated by CA) and type.
- The result is that the TLS-CA database now keeps these five entities information. They are used in later steps when these entities enrol to TLS-CA.
The last line in the script is just for showing the entities registered in TLS-CA database, including the bootstrap tls-ca-admin
, and those five components registered in this script.
Here is the result after the script is executed.
We can also take a look at the directory in the localhost. A quick recap
tls-ca/crypto/
: Directory for Fabric-CA-Server Home of TLS-CA, mapped to localhost.tls-ca/admin/
: It is where Fabric-CA-Client stores registrar for TLS-CA in localhost
Step 2: Bring Up RCA-ORG0
Script: 2_rca-org0.sh
The pattern is the same as the TLS-CA in Step 1. Without repeating everything, here we only register two entities: orderer1-org0 and admin-org0. Here is the result of the last command.
When we examine the directory, we see org0/ca/
. This is similar to what we observe in TLS-CA. Again, the crypto/
is a mapping of Fabric-CA-Server Home directory, and the admin/
is registrar for RCA-ORG0.
Step 3 and 4: Bring Up RCA-ORG1 and RCA-ORG2
Script 3_rca_org1.sh
Script 4_rca_org2.sh
The result directories are org1/ca/
and org2/ca/
, respectively.
There is a point of difference. When we register admin-org2 in RCA-ORG2, we put an attribute abac.init=true
. This will be placed in the certificate when this admin-org2 enrols in the RCA-ORG2. We will examine this when enrollment is made. Meanwhile, admin-org1 does not have this attribute.
The use of this attribute is to link to the demonstration of chaincode. After the network is running, we will deploy chaincode/abac/go
. The deployment requires the deployer with this attribute abac.init=true
. In Step 11, we will deploy chaincode from both admin-org1 and admin-org2, and we can see that only admin-org2 can deploy but admin-org1 cannot, due to this missing attribute.
Here are the entities registered in each CA database after the four scripts. Note that enrollment is not done yet. In the next steps we enrol those entities in organizations, one by one.
Step 5: Enrol Entities for org0
Script 5_enrollOrg0.sh
The purpose of this script is to enrol entities for org0. There are two entities to be enrolled: orderer1-org0 and admin-org0.
We will walk through this script.
- All the material for org0 will be built under
/tmp/hyperledger/org0/
. - The network component orderer1-org0 will be stored in
orderer/
, the user admin-org0 inadmin/
. - First we prepare two directories:
orderer/assets/ca/
andorderer/assets/tls-ca/
, they are holding the CA certificate of RCA-ORG0 and TLS-CA, respectively. We copy the certificates from those mapped volumes of these CA. - These two CA certificates are required when accessing RCA-ORG0 and TLS-CA with TLS. and are specified in
FABRIC_CA_CLIENT_TLS_CERTFILES
during the enrollment.
We start enrolling orderer1-org0, both identity and TLS, and admin-org0 for identity only.
For orderer1-org0,
- We specify the
org0/orderer/
as the Fabric-CA-Client home directory, meaning that the result will be stored in this directory. - Identity for orderer1-org0, we specify
msp/
to hold the result, and enrol it in RCA-ORG0. - TLS for orderer1-org0, we specify
tls-msp/
to hold the result, and enrol it in TLS-CA.
For admin-org0,
- We specify the
org0/admin/
as the Fabric-CA-Client home directory, meaning that the result will be stored in this directory. - Identity for admin-org0, we specify
msp/
to hold the result, and enrol it in RCA-ORG0.
Finally we will create a directory org0/msp/
, which includes the following directories and contents. It is used when the fabric network configuration is being built.
admincerts/
cacerts/
tlscacerts/
users/
We copy those certificates, and rename when necessary.
After the script is fully executed, we will see some directories in /tmp/hyperledger/org0/
.
For our interests, we will inspect first the org0/orderer/
. We see two directories: msp/
and tls-msp/
, inside which are the crypto material for orderer1-org0
.
In msp/
it is the identity. The private key is kept in keystore/
and the certificate is in signcert/
.
We first do a matching and make sure the private key matches the public key in the certificate.
Then we take a look at the certificate, in particular we are interested in the subject and the issuer.
We see the issuer of this identity certificate is RCA-ORG0, and the subject (owner) of certificate is orderer1-org0, with OU=orderer, which is what we specify in “type” during registration (see Step 2).
Similar directory structure is seen in tls-msp/
. Without repeating all steps above, we will take a look at the TLS server certificate, inside tls-msp/signcert/
We see the issuer of this TLS server certificate is TLS-CA.
Enrollment for orderer1-org0
Certificates issued to orderer1.org0.
Finally, we take a look at the admin-org0, which is stored in org0/admin/
. We see a similar directory structure, and the identity is stored in msp/
. From the certificate we can see that it is RCA-ORG0 issuing this certificate.
Enrollment for admin-org0
Certificate issued to admin-org0
Now we have everything for org0.
Finally we have prepared org0/msp/
which is useful when we form the fabric network.
Step 6: Enrol Entities for org1
Script 6_enrollOrg1.sh
The overall flow is largely similar to org0 (Step 5). The only difference is that in org1 we have two peers, peer1-org1 and peer2-org1. The same process is repeated for each peer. We only enrol one admin for org1.
Here is the directory structure of org1 after the script is completely executed.
We now have peer1/
and peer2/
for the peers, and admin/
for the admin of org1.
Again, without repeating what has been introduced in org0 (Step 5), here we just inspect the certificate of each component and user.
Identity certificate for peer1-org1, peer2-org1 and admin-org1. We see all certificates are issued by RCA-ORG1.
TLS server certificate for peer1-org1 and peer2-org1. We see all certificates are issued by TLS-CA.
Besides, per msp requirement, for peer1/msp/
, peer2/msp/
and admin/msp/
we need a admincerts/
directory holding the admin certificate for this organization (see line 62–69 in this script).
Step 7: Enrol Entities for org2
Script 7_enrollOrg2.sh
We can see this script is largely the same as the script for org1, except that everything is now applied on org2.
We just repeat the last inspection on the certificates of the two peers peer1-org2 and peer2-org2, and the user admin-org2.
Identity certificate for peer1-org2, peer2-org2 and admin-org2. We see all certificates are issued by RCA-ORG2.
TLS server certificate for peer1-org2 and peer2-org2. We see all certificates are issued by TLS-CA.
In particular, we have admin-org2 with attribute abac.init:true
(see Step 4). Here we can see the attributes in the certificate.
Now we have all identity certificates and TLS server certificates generated for our network. We can now move to the fabric network part, and we will not interact with these CAs unless we need to add more network components (orderers or peers) and/or users.
Here is how the network looks like after all the required crypto material is generated.
Step 8: Bring Up all the Components
Script 8_bringUpContainers.sh
Our objective is to bring up all the components, including orderer1-org0, peer1-org1, peer2-org1, peer1-org2 and peer2-org2. Also we have two CLIs, one for a peer organization, for our actions later.
Meanwhile, orderer1-org0 requires the genesis block file (genesis.block
) according to the docker-compose.yaml
. Therefore we use configtxgen
to generate this locally (line 4), and the result is placed in org0/
directory, which is mapped to orderer1-org0. We also generate the channel configuration transaction channel.tx
, and also kept in org0/
directory (line 6).
When things are working fine, we will see all these containers up and running.
From now on we have finished the component level. The remaining part is purely the operation of Hyperledger Fabric. And we do not work with the CAs any more.
Step 9: Create Channel and Join Peers to Channel
We follow the standard way to create and join channels.
First we bring up two CLI: cli-org1 and cli-org2. In these two CLIs, the environment variables are set for org1 and org2. The default target peer is peer1-org1 and peer1-org2, respectively. In case peer2 is needed in the two CLIs, we only set the variable.
For org1 terminal,
docker exec -it cli-org1 bash
#
For org2 terminal,
docker exec -it cli-org2 bash
#
First, we need to copy the channel configuration transaction (channel.tx
). It is currently in org0/orderer/
directory (see Step 8). Copy it to org1/peer1/assets/
. Note that in real life it may be handled out-of-band, but for our tutorial we just copy between mapped volumes between org0/
and org1/
.
In localhost,
cd /tmp/hyperledger
cp org0/orderer/channel.tx org1/peer1/assets/
Use org1 terminal to create channel genesis block
In org1 terminal
peer channel create -c mychannel -f /tmp/hyperledger/org1/peer1/assets/channel.tx -o orderer1-org0:7050 --outputBlock /tmp/hyperledger/org1/peer1/assets/mychannel.block --tls --cafile /tmp/hyperledger/org1/peer1/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem
The result is the block file mychannel.block
kept in org1/peer1/assets/
.
Use org1 terminal to join peer1-org1 and peer2-org1. Note that we temporarily set the variable in order to target the peer command to peer2-org1.
peer channel join -b /tmp/hyperledger/org1/peer1/assets/mychannel.blockCORE_PEER_ADDRESS=peer2-org1:7051 peer channel join -b /tmp/hyperledger/org1/peer1/assets/mychannel.block
We need to copy this mychannel.block
to cli-org2. Again we are using the mapped volumes.
In localhost,
cd /tmp/hyperledger
cp org1/peer1/assets/mychannel.block org2/peer1/assets/
Similarly, use org2 terminal to join peer1-org2 and peer2-org2.
In org2 terminal,
peer channel join -b /tmp/hyperledger/org2/peer1/assets/mychannel.blockCORE_PEER_ADDRESS=peer2-org2:7051 peer channel join -b /tmp/hyperledger/org2/peer1/assets/mychannel.block
To check if all the peers have successfully joined the channel, we can check
In org1 terminal,
peer channel getinfo -c mychannelCORE_PEER_ADDRESS=peer2-org1:7051 peer channel getinfo -c mychannel
In org2 terminal,
peer channel getinfo -c mychannelCORE_PEER_ADDRESS=peer2-org2:7051 peer channel getinfo -c mychannel
We should get back the same result of the four commands above, meaning that all the peers have the same ledger (blockchain).
With that, all the peers have joined the channel, and we can start working on the chaincode.
Step 10: Install Chaincode ABAC in all the Peers
We install the chaincode/abac/go
to the peers. The chaincode directory is mapped to cli-org1 and cli-org2 in docker-compose file.
In org1 terminal,
peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric-samples/chaincode/abac/goCORE_PEER_ADDRESS=peer2-org1:7051 peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric-samples/chaincode/abac/go
In org2 terminal,
peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric-samples/chaincode/abac/goCORE_PEER_ADDRESS=peer2-org2:7051 peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric-samples/chaincode/abac/go
Step 11: Instantiate Chaincode with Org1 and Org2
With chaincode installed in all the peers, we now instantiate chaincode.
Before we instantiate chaincode, we first take a look at the Attribute-Based Access Control (ABAC) in the chaincode/abac/go/abac.go
. In the Init() part,
In line 42, the chaincode will extract the client (proposal sender) certificate, and see if attribute abac.init:true
is in the certificate. If not, error is returned.
We first instantiate from org1. Remember that admin-org1 does not have the attribute abac.init:true
.
In org1 terminal,
peer chaincode instantiate -C mychannel -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -o orderer1-org0:7050 --tls --cafile /tmp/hyperledger/org1/peer1/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem
This error message shows that the instantiation fails due to the missing attribute.
Now we instantiate from org2. Remember that admin-org2 has this attribute (see Step 7)
In org2 terminal,
peer chaincode instantiate -C mychannel -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -o orderer1-org0:7050 --tls --cafile /tmp/hyperledger/org2/peer1/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem
We see no error, and the instantiation is complete. We will interact with the chaincode functions in the final step of this tutorial.
Step 12: Invoke and Query Chaincode
We first query the current value of a, which should be 100 according to chaincode design and arguments set when chaincode is instantiated.
In org1 terminal,
peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'CORE_PEER_ADDRESS=peer2-org1:7051 peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'
In org2 terminal,
peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'CORE_PEER_ADDRESS=peer2-org2:7051 peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'
Now invoke chaincode function in org1 terminal
peer chaincode invoke -C mychannel -n mycc -c '{"Args":["invoke","a","b","10"]}' --tls --cafile /tmp/hyperledger/org1/peer1/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem
Note: invoking chaincode can also be done on org2 terminal. Just change the TLS certificate with the right path (i.e. org2 instead of org1).
After chaincode function invoked, we query the value of a again in all the peers. All should be updated to 90.
In org1 terminal,
peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'CORE_PEER_ADDRESS=peer2-org1:7051 peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'
In org2 terminal,
peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'CORE_PEER_ADDRESS=peer2-org2:7051 peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'
We get back the correct result. The network is running properly.
This is the end of the tutorial.
Summary
We have built a typical fabric network, with all crypto material generated by Fabric CA Server. By carefully design and proper process, we have all entities acquiring identity certificates from CA of each organization, while all network components acquiring TLS server certificates from a single TLS CA for all organizations in this network. We also use a chaincode with intelligence in checking identity to show how to control access based on the attributes inside a certificate.
This is a heavy article, matching the original lengthy operation guide. By breaking them into steps, I hope you now have a clearer picture about how to use Fabric CA to build your own network design.