diff --git a/fabric/v1.3/fabric-ca/.env b/fabric/v1.3/fabric-ca/.env new file mode 100644 index 0000000..4fd2ee0 --- /dev/null +++ b/fabric/v1.3/fabric-ca/.env @@ -0,0 +1 @@ +COMPOSE_PROJECT_NAME=net diff --git a/fabric/v1.3/fabric-ca/.gitignore b/fabric/v1.3/fabric-ca/.gitignore new file mode 100644 index 0000000..d21ef6d --- /dev/null +++ b/fabric/v1.3/fabric-ca/.gitignore @@ -0,0 +1,5 @@ +docker-compose.yml +fabric-ca-orderer.dockerfile +fabric-ca-peer.dockerfile +fabric-ca-tools.dockerfile +data diff --git a/fabric/v1.3/fabric-ca/README.md b/fabric/v1.3/fabric-ca/README.md new file mode 100755 index 0000000..568a198 --- /dev/null +++ b/fabric/v1.3/fabric-ca/README.md @@ -0,0 +1,102 @@ +# Hyperledger Fabric CA sample + +The Hyperledger Fabric CA sample demonstrates the following: + +* How to use the Hyperledger Fabric CA client and server to generate all crypto + material rather than using cryptogen. The cryptogen tool is not intended for + a production environment because it generates all private keys in one location + which must then be copied to the appropriate host or container. This sample + demonstrates how to generate crypto material for orderers, peers, + administrators, and end users so that private keys never leave the host or + container in which they are generated. + +* How to use Attribute-Based Access Control (ABAC). See + fabric-samples/chaincode/abac/abac.go and note the use of the *github.com/hyperledger/fabric/core/chaincode/lib/cid* package to extract + attributes from the invoker's identity. Only identities with the *abac.init* + attribute value of *true* can successfully call the *Init* function to + instantiate the chaincode. + +## Running this sample + +1. To run this sample, simply run the *start.sh* script. You may do this +multiple times in a row as needed since the *start.sh* script cleans up before +starting each time. This sample can be run with the latest released version, +an older released version, or from locally built docker images as follows: + + a. By default, the sample is run with the latest released version of Fabric + and Fabric CA. + + b. Older versions of Fabric and Fabric CA can be used by setting the + `FABRIC_TAG` environment variable. For example, `export FABRIC_TAG=1.3.0` + will run the sample with 1.3.0 version of Fabric and Fabric CA. + + c. The sample can also be run with locally built Fabric and Fabric CA + docker images. Fabric and Fabric CA repositories must be cloned with following + commands: + + `git clone https://github.com/hyperledger/fabric.git` + `git clone https://github.com/hyperledger/fabric-ca.git` + + Then execute the `make docker-all` command from the fabric-ca repository. This will + build the necessary images based on the local source code. Before executing the + *start.sh* script, set the `FABRIC_TAG` environment variable to 'local' as follows: + `export FABRIC_TAG=local`. + +2. To stop the containers which are started by the *start.sh* script, you may run the *stop.sh* script. + +## Understanding this sample + +There are some variables at the top of *fabric-samples/fabric-ca/scripts/env.sh* +script which define the names and topology of this sample. You may modify these +as described in the comments of the script in order to customize this sample. +By default, there are three organizations. The orderer organization is *org0*, +and two peer organizations are *org1* and *org2*. + +The *start.sh* script first builds the *docker-compose.yml* file (by invoking the +*makeDocker.sh* script) and then starts the docker containers. +The *data* directory is a volume mount for all containers. +This volume mount is not be needed in a real scenario, but it is used by this +sample for the following reasons: + a) so that all containers can write their logs to a common directory + (i.e. *the *data/logs* directory) to make debugging easier; + b) to synchronize the sequence in which containers start as described below + (for example, an intermediate CA in an *ica* container must wait for the + corresponding root CA in a *rca* container to write its certificate to + the *data* directory); + c) to access bootstrap certificates required by clients to connect over TLS. + +The containers defined in the *docker-compose.yml* file are started in the +following sequence. + +1. The *rca* (root CA) containers start first, one for each organization. +An *rca* container runs the fabric-ca-server for the root CA of an +organization. The root CA certificate is written to the *data* directory +and is used when an intermediate CA must connect to it over TLS. + +2. The *ica* (Intermediate CA) containers start next. An *ica* container +runs the fabric-ca-server for the intermediate CA of an organization. +Each of these containers enrolls with a corresponding root CA. +The intermediate CA certificate is also written to the *data* directory. + +3. The *setup* container registers identities with the intermediate CAs, +generates the genesis block, and other artifacts needed to setup the +blockchain network. This is performed by the +*fabric-samples/fabric-ca/scripts/setup-fabric.sh* script. Note that the +admin identity is registered with **abac.init=true:ecert** +(see the *registerPeerIdentities* function of this script). This causes +the admin's enrollment certificate (ECert) to have an attribute named "abac.init" +with a value of "true". Note further that the chaincode used by this sample +requires this attribute be included in the certificate of the identity that +invokes its Init function. See the chaincode at *fabric-samples/chaincode/abac/abac.go*). +For more information on Attribute-Based Access Control (ABAC), see +https://github.com/hyperledger/fabric/blob/master/core/chaincode/lib/cid/README.md. + +4. The orderer and peer containers are started. The naming of these containers +is straight-forward as is their log files in the *data/logs* directory. + +5. The *run* container is started which runs the actual test case. It creates +a channel, peers join the channel, chaincode is installed and instantiated, +and the chaincode is queried and invoked. See the *main* function of the +*fabric-samples/fabric-ca/scripts/run-fabric.sh* script for more details. + +Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License diff --git a/fabric/v1.3/fabric-ca/build-images.sh b/fabric/v1.3/fabric-ca/build-images.sh new file mode 100755 index 0000000..e49bf4e --- /dev/null +++ b/fabric/v1.3/fabric-ca/build-images.sh @@ -0,0 +1,54 @@ +#!/bin/bash +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# +# This script builds the images required to run this sample. +# + +function assertOnMasterBranch { + if [ "`git rev-parse --abbrev-ref HEAD`" != "master" ]; then + fatal "You must switch to the master branch in `pwd`" + fi +} + +set -e + +SDIR=$(dirname "$0") +source $SDIR/scripts/env.sh + +# Delete docker containers +dockerContainers=$(docker ps -a | awk '$2~/hyperledger/ {print $1}') +if [ "$dockerContainers" != "" ]; then + log "Deleting existing docker containers ..." + docker rm -f $dockerContainers > /dev/null +fi + +# Remove chaincode docker images +chaincodeImages=`docker images | grep "^dev-peer" | awk '{print $3}'` +if [ "$chaincodeImages" != "" ]; then + log "Removing chaincode docker images ..." + docker rmi $chaincodeImages > /dev/null +fi + +# Perform docker clean for fabric-ca +log "Cleaning fabric-ca docker images ..." +cd $GOPATH/src/github.com/hyperledger/fabric-ca +assertOnMasterBranch +make docker-clean + +# Perform docker clean for fabric and rebuild +log "Cleaning and rebuilding fabric docker images ..." +cd $GOPATH/src/github.com/hyperledger/fabric +assertOnMasterBranch +make docker-clean docker + +# Perform docker clean for fabric and rebuild against latest fabric images just built +log "Rebuilding fabric-ca docker images ..." +cd $GOPATH/src/github.com/hyperledger/fabric-ca +FABRIC_TAG=latest make docker + +log "Setup completed successfully. You may run the tests multiple times by running start.sh." diff --git a/fabric/v1.3/fabric-ca/desktopConfig.yaml b/fabric/v1.3/fabric-ca/desktopConfig.yaml new file mode 100644 index 0000000..4eed0cd --- /dev/null +++ b/fabric/v1.3/fabric-ca/desktopConfig.yaml @@ -0,0 +1,10 @@ +peerGrpcUrl: grpcs://localhost:7051 +peerEventUrl: grpcs://localhost:7053 +ordererUrl: grpcs://localhost:7050 +mspId: org1MSP +certificate: data/orgs/org1/admin/msp/signcerts/cert.pem +privateKey: data/orgs/org1/admin/msp/keystore/6a65f3b294f455b1dc41bfec77da60ed86570cb5a342a21f052d3930d0d4f7c0_sk +peerTlsCaCert: data/org1-ca-chain.pem +ordererTlsCaCert: data/org0-ca-chain.pem +peerSslTarget: peer1-org1 +ordererSslTarget: orderer1-org0 diff --git a/fabric/v1.3/fabric-ca/makeDocker.sh b/fabric/v1.3/fabric-ca/makeDocker.sh new file mode 100755 index 0000000..168503f --- /dev/null +++ b/fabric/v1.3/fabric-ca/makeDocker.sh @@ -0,0 +1,316 @@ +#!/bin/bash +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# +# This script builds the docker compose file needed to run this sample. +# + +# IMPORTANT: The following default FABRIC_TAG value should be updated for each +# release after the fabric-orderer and fabric-peer images have been published +# for the release. +export FABRIC_TAG=${FABRIC_TAG:-1.3.0} + +export FABRIC_CA_TAG=${FABRIC_CA_TAG:-${FABRIC_TAG}} +export NS=${NS:-hyperledger} +export MARCH=$(echo "$(uname -s|tr '[:upper:]' '[:lower:]'|sed 's/mingw64_nt.*/windows/')-$(uname -m | sed 's/x86_64/amd64/g')" | awk '{print tolower($0)}') +CA_BINARY_FILE=hyperledger-fabric-ca-${MARCH}-${FABRIC_CA_TAG}.tar.gz +URL=https://nexus.hyperledger.org/content/repositories/releases/org/hyperledger/fabric-ca/hyperledger-fabric-ca/${MARCH}-${FABRIC_CA_TAG}/${CA_BINARY_FILE} + +SDIR=$(dirname "$0") +source $SDIR/scripts/env.sh + +function main { + { + createDockerFiles + writeHeader + writeRootFabricCA + if $USE_INTERMEDIATE_CA; then + writeIntermediateFabricCA + fi + writeSetupFabric + writeStartFabric + writeRunFabric + } > $SDIR/docker-compose.yml + log "Created docker-compose.yml" +} + +# Create various dockerfiles used by this sample +function createDockerFiles { + if [ "$FABRIC_TAG" = "local" ]; then + ORDERER_BUILD="image: hyperledger/fabric-ca-orderer" + PEER_BUILD="image: hyperledger/fabric-ca-peer" + TOOLS_BUILD="image: hyperledger/fabric-ca-tools" + else + createDockerFile orderer + ORDERER_BUILD="build: + context: . + dockerfile: fabric-ca-orderer.dockerfile" + createDockerFile peer + PEER_BUILD="build: + context: . + dockerfile: fabric-ca-peer.dockerfile" + createDockerFile tools + TOOLS_BUILD="build: + context: . + dockerfile: fabric-ca-tools.dockerfile" + fi +} + +# createDockerFile +function createDockerFile { + { + echo "FROM ${NS}/fabric-${1}:${FABRIC_TAG}" + echo 'RUN apt-get update && apt-get install -y netcat jq && apt-get install -y curl && rm -rf /var/cache/apt' + echo "RUN curl -o /tmp/fabric-ca-client.tar.gz $URL && tar -xzvf /tmp/fabric-ca-client.tar.gz -C /tmp && cp /tmp/bin/fabric-ca-client /usr/local/bin" + echo 'RUN chmod +x /usr/local/bin/fabric-ca-client' + echo 'ARG FABRIC_CA_DYNAMIC_LINK=false' + # libraries needed when image is built dynamically + echo 'RUN if [ "\$FABRIC_CA_DYNAMIC_LINK" = "true" ]; then apt-get install -y libltdl-dev; fi' + } > $SDIR/fabric-ca-${1}.dockerfile +} + +# Write services for the root fabric CA servers +function writeRootFabricCA { + for ORG in $ORGS; do + initOrgVars $ORG + writeRootCA + done +} + +# Write services for the intermediate fabric CA servers +function writeIntermediateFabricCA { + for ORG in $ORGS; do + initOrgVars $ORG + writeIntermediateCA + done +} + +# Write a service to setup the fabric artifacts (e.g. genesis block, etc) +function writeSetupFabric { + echo " setup: + container_name: setup + $TOOLS_BUILD + command: /bin/bash -c '/scripts/setup-fabric.sh 2>&1 | tee /$SETUP_LOGFILE; sleep 99999' + volumes: + - ./scripts:/scripts + - ./$DATA:/$DATA + networks: + - $NETWORK + depends_on:" + for ORG in $ORGS; do + initOrgVars $ORG + echo " - $CA_NAME" + done + echo "" +} + +# Write services for fabric orderer and peer containers +function writeStartFabric { + for ORG in $ORDERER_ORGS; do + COUNT=1 + while [[ "$COUNT" -le $NUM_ORDERERS ]]; do + initOrdererVars $ORG $COUNT + writeOrderer + COUNT=$((COUNT+1)) + done + done + for ORG in $PEER_ORGS; do + COUNT=1 + while [[ "$COUNT" -le $NUM_PEERS ]]; do + initPeerVars $ORG $COUNT + writePeer + COUNT=$((COUNT+1)) + done + done +} + +# Write a service to run a fabric test including creating a channel, +# installing chaincode, invoking and querying +function writeRunFabric { + # Set samples directory relative to this script + SAMPLES_DIR=$(dirname $(cd ${SDIR} && pwd)) + # Set fabric directory relative to GOPATH + FABRIC_DIR=${GOPATH}/src/github.com/hyperledger/fabric + echo " run: + container_name: run + image: hyperledger/fabric-ca-tools + environment: + - GOPATH=/opt/gopath + command: /bin/bash -c 'sleep 3;/scripts/run-fabric.sh 2>&1 | tee /$RUN_LOGFILE; sleep 99999' + volumes: + - ./scripts:/scripts + - ./$DATA:/$DATA + - ${SAMPLES_DIR}:/opt/gopath/src/github.com/hyperledger/fabric-samples + - ${FABRIC_DIR}:/opt/gopath/src/github.com/hyperledger/fabric + networks: + - $NETWORK + depends_on:" + for ORG in $ORDERER_ORGS; do + COUNT=1 + while [[ "$COUNT" -le $NUM_ORDERERS ]]; do + initOrdererVars $ORG $COUNT + echo " - $ORDERER_NAME" + COUNT=$((COUNT+1)) + done + done + for ORG in $PEER_ORGS; do + COUNT=1 + while [[ "$COUNT" -le $NUM_PEERS ]]; do + initPeerVars $ORG $COUNT + echo " - $PEER_NAME" + COUNT=$((COUNT+1)) + done + done +} + +function writeRootCA { + echo " $ROOT_CA_NAME: + container_name: $ROOT_CA_NAME + image: hyperledger/fabric-ca + command: /bin/bash -c '/scripts/start-root-ca.sh 2>&1 | tee /$ROOT_CA_LOGFILE' + environment: + - FABRIC_CA_SERVER_HOME=/etc/hyperledger/fabric-ca + - FABRIC_CA_SERVER_TLS_ENABLED=true + - FABRIC_CA_SERVER_CSR_CN=$ROOT_CA_NAME + - FABRIC_CA_SERVER_CSR_HOSTS=$ROOT_CA_HOST + - FABRIC_CA_SERVER_DEBUG=true + - BOOTSTRAP_USER_PASS=$ROOT_CA_ADMIN_USER_PASS + - TARGET_CERTFILE=$ROOT_CA_CERTFILE + - FABRIC_ORGS="$ORGS" + volumes: + - ./scripts:/scripts + - ./$DATA:/$DATA + networks: + - $NETWORK +" +} + +function writeIntermediateCA { + echo " $INT_CA_NAME: + container_name: $INT_CA_NAME + image: hyperledger/fabric-ca + command: /bin/bash -c '/scripts/start-intermediate-ca.sh $ORG 2>&1 | tee /$INT_CA_LOGFILE' + environment: + - FABRIC_CA_SERVER_HOME=/etc/hyperledger/fabric-ca + - FABRIC_CA_SERVER_CA_NAME=$INT_CA_NAME + - FABRIC_CA_SERVER_INTERMEDIATE_TLS_CERTFILES=$ROOT_CA_CERTFILE + - FABRIC_CA_SERVER_CSR_HOSTS=$INT_CA_HOST + - FABRIC_CA_SERVER_TLS_ENABLED=true + - FABRIC_CA_SERVER_DEBUG=true + - BOOTSTRAP_USER_PASS=$INT_CA_ADMIN_USER_PASS + - PARENT_URL=https://$ROOT_CA_ADMIN_USER_PASS@$ROOT_CA_HOST:7054 + - TARGET_CHAINFILE=$INT_CA_CHAINFILE + - ORG=$ORG + - FABRIC_ORGS="$ORGS" + volumes: + - ./scripts:/scripts + - ./$DATA:/$DATA + networks: + - $NETWORK + depends_on: + - $ROOT_CA_NAME +" +} + +function writeOrderer { + MYHOME=/etc/hyperledger/orderer + echo " $ORDERER_NAME: + container_name: $ORDERER_NAME + $ORDERER_BUILD + environment: + - FABRIC_CA_CLIENT_HOME=$MYHOME + - FABRIC_CA_CLIENT_TLS_CERTFILES=$CA_CHAINFILE + - ENROLLMENT_URL=https://$ORDERER_NAME_PASS@$CA_HOST:7054 + - ORDERER_HOME=$MYHOME + - ORDERER_HOST=$ORDERER_HOST + - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 + - ORDERER_GENERAL_GENESISMETHOD=file + - ORDERER_GENERAL_GENESISFILE=$GENESIS_BLOCK_FILE + - ORDERER_GENERAL_LOCALMSPID=$ORG_MSP_ID + - ORDERER_GENERAL_LOCALMSPDIR=$MYHOME/msp + - ORDERER_GENERAL_TLS_ENABLED=true + - ORDERER_GENERAL_TLS_PRIVATEKEY=$MYHOME/tls/server.key + - ORDERER_GENERAL_TLS_CERTIFICATE=$MYHOME/tls/server.crt + - ORDERER_GENERAL_TLS_ROOTCAS=[$CA_CHAINFILE] + - ORDERER_GENERAL_TLS_CLIENTAUTHREQUIRED=true + - ORDERER_GENERAL_TLS_CLIENTROOTCAS=[$CA_CHAINFILE] + - ORDERER_GENERAL_LOGLEVEL=debug + - ORDERER_DEBUG_BROADCASTTRACEDIR=$LOGDIR + - ORG=$ORG + - ORG_ADMIN_CERT=$ORG_ADMIN_CERT + command: /bin/bash -c '/scripts/start-orderer.sh 2>&1 | tee /$ORDERER_LOGFILE' + volumes: + - ./scripts:/scripts + - ./$DATA:/$DATA + networks: + - $NETWORK + depends_on: + - setup +" +} + +function writePeer { + MYHOME=/opt/gopath/src/github.com/hyperledger/fabric/peer + echo " $PEER_NAME: + container_name: $PEER_NAME + $PEER_BUILD + environment: + - FABRIC_CA_CLIENT_HOME=$MYHOME + - FABRIC_CA_CLIENT_TLS_CERTFILES=$CA_CHAINFILE + - ENROLLMENT_URL=https://$PEER_NAME_PASS@$CA_HOST:7054 + - PEER_NAME=$PEER_NAME + - PEER_HOME=$MYHOME + - PEER_HOST=$PEER_HOST + - PEER_NAME_PASS=$PEER_NAME_PASS + - CORE_PEER_ID=$PEER_HOST + - CORE_PEER_ADDRESS=$PEER_HOST:7051 + - CORE_PEER_LOCALMSPID=$ORG_MSP_ID + - CORE_PEER_MSPCONFIGPATH=$MYHOME/msp + - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock + - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=net_${NETWORK} + - CORE_LOGGING_LEVEL=DEBUG + - CORE_PEER_TLS_ENABLED=true + - CORE_PEER_TLS_CERT_FILE=$MYHOME/tls/server.crt + - CORE_PEER_TLS_KEY_FILE=$MYHOME/tls/server.key + - CORE_PEER_TLS_ROOTCERT_FILE=$CA_CHAINFILE + - CORE_PEER_TLS_CLIENTAUTHREQUIRED=true + - CORE_PEER_TLS_CLIENTROOTCAS_FILES=$CA_CHAINFILE + - CORE_PEER_TLS_CLIENTCERT_FILE=/$DATA/tls/$PEER_NAME-client.crt + - CORE_PEER_TLS_CLIENTKEY_FILE=/$DATA/tls/$PEER_NAME-client.key + - CORE_PEER_GOSSIP_USELEADERELECTION=true + - CORE_PEER_GOSSIP_ORGLEADER=false + - CORE_PEER_GOSSIP_EXTERNALENDPOINT=$PEER_HOST:7051 + - CORE_PEER_GOSSIP_SKIPHANDSHAKE=true + - ORG=$ORG + - ORG_ADMIN_CERT=$ORG_ADMIN_CERT" + if [ $NUM -gt 1 ]; then + echo " - CORE_PEER_GOSSIP_BOOTSTRAP=peer1-${ORG}:7051" + fi + echo " working_dir: $MYHOME + command: /bin/bash -c '/scripts/start-peer.sh 2>&1 | tee /$PEER_LOGFILE' + volumes: + - ./scripts:/scripts + - ./$DATA:/$DATA + - /var/run:/host/var/run + networks: + - $NETWORK + depends_on: + - setup +" +} + +function writeHeader { + echo "version: '2' + +networks: + $NETWORK: + +services: +" +} + +main diff --git a/fabric/v1.3/fabric-ca/scripts/env.sh b/fabric/v1.3/fabric-ca/scripts/env.sh new file mode 100755 index 0000000..ca0ecfa --- /dev/null +++ b/fabric/v1.3/fabric-ca/scripts/env.sh @@ -0,0 +1,402 @@ +#!/bin/bash +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# +# The following variables describe the topology and may be modified to provide +# different organization names or the number of peers in each peer organization. +# + +# Name of the docker-compose network +NETWORK=fabric-ca + +# Names of the orderer organizations +ORDERER_ORGS="org0" + +# Names of the peer organizations +PEER_ORGS="org1 org2" + +# Number of peers in each peer organization +NUM_PEERS=2 + +# +# The remainder of this file contains variables which typically would not be changed. +# + +# All org names +ORGS="$ORDERER_ORGS $PEER_ORGS" + +# Set to true to populate the "admincerts" folder of MSPs +ADMINCERTS=true + +# Number of orderer nodes +NUM_ORDERERS=1 + +# The volume mount to share data between containers +DATA=data + +# The path to the genesis block +GENESIS_BLOCK_FILE=/$DATA/genesis.block + +# The path to a channel transaction +CHANNEL_TX_FILE=/$DATA/channel.tx + +# Name of test channel +CHANNEL_NAME=mychannel + +# Query timeout in seconds +QUERY_TIMEOUT=15 + +# Setup timeout in seconds (for setup container to complete) +SETUP_TIMEOUT=120 + +# Log directory +LOGDIR=$DATA/logs +LOGPATH=/$LOGDIR + +# Name of a the file to create when setup is successful +SETUP_SUCCESS_FILE=${LOGDIR}/setup.successful +# The setup container's log file +SETUP_LOGFILE=${LOGDIR}/setup.log + +# The run container's log file +RUN_LOGFILE=${LOGDIR}/run.log +# The run container's summary log file +RUN_SUMFILE=${LOGDIR}/run.sum +RUN_SUMPATH=/${RUN_SUMFILE} +# Run success and failure files +RUN_SUCCESS_FILE=${LOGDIR}/run.success +RUN_FAIL_FILE=${LOGDIR}/run.fail + +# Affiliation is not used to limit users in this sample, so just put +# all identities in the same affiliation. +export FABRIC_CA_CLIENT_ID_AFFILIATION=org1 + +# Set to true to enable use of intermediate CAs +USE_INTERMEDIATE_CA=true + + +# Config block file path +CONFIG_BLOCK_FILE=/tmp/config_block.pb + +# Update config block payload file path +CONFIG_UPDATE_ENVELOPE_FILE=/tmp/config_update_as_envelope.pb + +# initOrgVars +function initOrgVars { + if [ $# -ne 1 ]; then + echo "Usage: initOrgVars " + exit 1 + fi + ORG=$1 + ORG_CONTAINER_NAME=${ORG//./-} + ROOT_CA_HOST=rca-${ORG} + ROOT_CA_NAME=rca-${ORG} + ROOT_CA_LOGFILE=$LOGDIR/${ROOT_CA_NAME}.log + INT_CA_HOST=ica-${ORG} + INT_CA_NAME=ica-${ORG} + INT_CA_LOGFILE=$LOGDIR/${INT_CA_NAME}.log + + # Root CA admin identity + ROOT_CA_ADMIN_USER=rca-${ORG}-admin + ROOT_CA_ADMIN_PASS=${ROOT_CA_ADMIN_USER}pw + ROOT_CA_ADMIN_USER_PASS=${ROOT_CA_ADMIN_USER}:${ROOT_CA_ADMIN_PASS} + # Root CA intermediate identity to bootstrap the intermediate CA + ROOT_CA_INT_USER=ica-${ORG} + ROOT_CA_INT_PASS=${ROOT_CA_INT_USER}pw + ROOT_CA_INT_USER_PASS=${ROOT_CA_INT_USER}:${ROOT_CA_INT_PASS} + # Intermediate CA admin identity + INT_CA_ADMIN_USER=ica-${ORG}-admin + INT_CA_ADMIN_PASS=${INT_CA_ADMIN_USER}pw + INT_CA_ADMIN_USER_PASS=${INT_CA_ADMIN_USER}:${INT_CA_ADMIN_PASS} + # Admin identity for the org + ADMIN_NAME=admin-${ORG} + ADMIN_PASS=${ADMIN_NAME}pw + # Typical user identity for the org + USER_NAME=user-${ORG} + USER_PASS=${USER_NAME}pw + + ROOT_CA_CERTFILE=/${DATA}/${ORG}-ca-cert.pem + INT_CA_CHAINFILE=/${DATA}/${ORG}-ca-chain.pem + ANCHOR_TX_FILE=/${DATA}/orgs/${ORG}/anchors.tx + ORG_MSP_ID=${ORG}MSP + ORG_MSP_DIR=/${DATA}/orgs/${ORG}/msp + ORG_ADMIN_CERT=${ORG_MSP_DIR}/admincerts/cert.pem + ORG_ADMIN_HOME=/${DATA}/orgs/$ORG/admin + + if test "$USE_INTERMEDIATE_CA" = "true"; then + CA_NAME=$INT_CA_NAME + CA_HOST=$INT_CA_HOST + CA_CHAINFILE=$INT_CA_CHAINFILE + CA_ADMIN_USER_PASS=$INT_CA_ADMIN_USER_PASS + CA_LOGFILE=$INT_CA_LOGFILE + else + CA_NAME=$ROOT_CA_NAME + CA_HOST=$ROOT_CA_HOST + CA_CHAINFILE=$ROOT_CA_CERTFILE + CA_ADMIN_USER_PASS=$ROOT_CA_ADMIN_USER_PASS + CA_LOGFILE=$ROOT_CA_LOGFILE + fi +} + +# initOrdererVars +function initOrdererVars { + if [ $# -ne 2 ]; then + echo "Usage: initOrdererVars " + exit 1 + fi + initOrgVars $1 + NUM=$2 + ORDERER_HOST=orderer${NUM}-${ORG} + ORDERER_NAME=orderer${NUM}-${ORG} + ORDERER_PASS=${ORDERER_NAME}pw + ORDERER_NAME_PASS=${ORDERER_NAME}:${ORDERER_PASS} + ORDERER_LOGFILE=$LOGDIR/${ORDERER_NAME}.log + MYHOME=/etc/hyperledger/orderer + + export FABRIC_CA_CLIENT=$MYHOME + export ORDERER_GENERAL_LOGLEVEL=debug + export ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 + export ORDERER_GENERAL_GENESISMETHOD=file + export ORDERER_GENERAL_GENESISFILE=$GENESIS_BLOCK_FILE + export ORDERER_GENERAL_LOCALMSPID=$ORG_MSP_ID + export ORDERER_GENERAL_LOCALMSPDIR=$MYHOME/msp + # enabled TLS + export ORDERER_GENERAL_TLS_ENABLED=true + TLSDIR=$MYHOME/tls + export ORDERER_GENERAL_TLS_PRIVATEKEY=$TLSDIR/server.key + export ORDERER_GENERAL_TLS_CERTIFICATE=$TLSDIR/server.crt + export ORDERER_GENERAL_TLS_ROOTCAS=[$CA_CHAINFILE] +} + +function genClientTLSCert { + if [ $# -ne 3 ]; then + echo "Usage: genClientTLSCert : $*" + exit 1 + fi + + HOST_NAME=$1 + CERT_FILE=$2 + KEY_FILE=$3 + + # Get a client cert + fabric-ca-client enroll -d --enrollment.profile tls -u $ENROLLMENT_URL -M /tmp/tls --csr.hosts $HOST_NAME + + mkdir /$DATA/tls || true + cp /tmp/tls/signcerts/* $CERT_FILE + cp /tmp/tls/keystore/* $KEY_FILE + rm -rf /tmp/tls +} + +# initPeerVars +function initPeerVars { + if [ $# -ne 2 ]; then + echo "Usage: initPeerVars : $*" + exit 1 + fi + initOrgVars $1 + NUM=$2 + PEER_HOST=peer${NUM}-${ORG} + PEER_NAME=peer${NUM}-${ORG} + PEER_PASS=${PEER_NAME}pw + PEER_NAME_PASS=${PEER_NAME}:${PEER_PASS} + PEER_LOGFILE=$LOGDIR/${PEER_NAME}.log + MYHOME=/opt/gopath/src/github.com/hyperledger/fabric/peer + TLSDIR=$MYHOME/tls + + export FABRIC_CA_CLIENT=$MYHOME + export CORE_PEER_ID=$PEER_HOST + export CORE_PEER_ADDRESS=$PEER_HOST:7051 + export CORE_PEER_LOCALMSPID=$ORG_MSP_ID + export CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock + # the following setting starts chaincode containers on the same + # bridge network as the peers + # https://docs.docker.com/compose/networking/ + #export CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_${NETWORK} + export CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=net_${NETWORK} + # export CORE_LOGGING_LEVEL=ERROR + export CORE_LOGGING_LEVEL=DEBUG + export CORE_PEER_TLS_ENABLED=true + export CORE_PEER_TLS_CLIENTAUTHREQUIRED=true + export CORE_PEER_TLS_ROOTCERT_FILE=$CA_CHAINFILE + export CORE_PEER_TLS_CLIENTCERT_FILE=/$DATA/tls/$PEER_NAME-cli-client.crt + export CORE_PEER_TLS_CLIENTKEY_FILE=/$DATA/tls/$PEER_NAME-cli-client.key + export CORE_PEER_PROFILE_ENABLED=true + # gossip variables + export CORE_PEER_GOSSIP_USELEADERELECTION=true + export CORE_PEER_GOSSIP_ORGLEADER=false + export CORE_PEER_GOSSIP_EXTERNALENDPOINT=$PEER_HOST:7051 + if [ $NUM -gt 1 ]; then + # Point the non-anchor peers to the anchor peer, which is always the 1st peer + export CORE_PEER_GOSSIP_BOOTSTRAP=peer1-${ORG}:7051 + fi + export ORDERER_CONN_ARGS="$ORDERER_PORT_ARGS --keyfile $CORE_PEER_TLS_CLIENTKEY_FILE --certfile $CORE_PEER_TLS_CLIENTCERT_FILE" +} + +# Switch to the current org's admin identity. Enroll if not previously enrolled. +function switchToAdminIdentity { + if [ ! -d $ORG_ADMIN_HOME ]; then + dowait "$CA_NAME to start" 60 $CA_LOGFILE $CA_CHAINFILE + log "Enrolling admin '$ADMIN_NAME' with $CA_HOST ..." + export FABRIC_CA_CLIENT_HOME=$ORG_ADMIN_HOME + export FABRIC_CA_CLIENT_TLS_CERTFILES=$CA_CHAINFILE + fabric-ca-client enroll -d -u https://$ADMIN_NAME:$ADMIN_PASS@$CA_HOST:7054 + # If admincerts are required in the MSP, copy the cert there now and to my local MSP also + if [ $ADMINCERTS ]; then + mkdir -p $(dirname "${ORG_ADMIN_CERT}") + cp $ORG_ADMIN_HOME/msp/signcerts/* $ORG_ADMIN_CERT + mkdir $ORG_ADMIN_HOME/msp/admincerts + cp $ORG_ADMIN_HOME/msp/signcerts/* $ORG_ADMIN_HOME/msp/admincerts + fi + fi + export CORE_PEER_MSPCONFIGPATH=$ORG_ADMIN_HOME/msp +} + +# Switch to the current org's user identity. Enroll if not previously enrolled. +function switchToUserIdentity { + export FABRIC_CA_CLIENT_HOME=/etc/hyperledger/fabric/orgs/$ORG/user + export CORE_PEER_MSPCONFIGPATH=$FABRIC_CA_CLIENT_HOME/msp + if [ ! -d $FABRIC_CA_CLIENT_HOME ]; then + dowait "$CA_NAME to start" 60 $CA_LOGFILE $CA_CHAINFILE + log "Enrolling user for organization $ORG with home directory $FABRIC_CA_CLIENT_HOME ..." + export FABRIC_CA_CLIENT_TLS_CERTFILES=$CA_CHAINFILE + fabric-ca-client enroll -d -u https://$USER_NAME:$USER_PASS@$CA_HOST:7054 + # Set up admincerts directory if required + if [ $ADMINCERTS ]; then + ACDIR=$CORE_PEER_MSPCONFIGPATH/admincerts + mkdir -p $ACDIR + cp $ORG_ADMIN_HOME/msp/signcerts/* $ACDIR + fi + fi +} + +# Revokes the fabric user +function revokeFabricUserAndGenerateCRL { + switchToAdminIdentity + export FABRIC_CA_CLIENT_HOME=$ORG_ADMIN_HOME + logr "Revoking the user '$USER_NAME' of the organization '$ORG' with Fabric CA Client home directory set to $FABRIC_CA_CLIENT_HOME and generating CRL ..." + export FABRIC_CA_CLIENT_TLS_CERTFILES=$CA_CHAINFILE + fabric-ca-client revoke -d --revoke.name $USER_NAME --gencrl +} + +# Generates a CRL that contains serial numbers of all revoked enrollment certificates. +# The generated CRL is placed in the crls folder of the admin's MSP +function generateCRL { + switchToAdminIdentity + export FABRIC_CA_CLIENT_HOME=$ORG_ADMIN_HOME + logr "Generating CRL for the organization '$ORG' with Fabric CA Client home directory set to $FABRIC_CA_CLIENT_HOME ..." + export FABRIC_CA_CLIENT_TLS_CERTFILES=$CA_CHAINFILE + fabric-ca-client gencrl -d +} + +# Copy the org's admin cert into some target MSP directory +# This is only required if ADMINCERTS is enabled. +function copyAdminCert { + if [ $# -ne 1 ]; then + fatal "Usage: copyAdminCert " + fi + if $ADMINCERTS; then + dstDir=$1/admincerts + mkdir -p $dstDir + dowait "$ORG administator to enroll" 60 $SETUP_LOGFILE $ORG_ADMIN_CERT + cp $ORG_ADMIN_CERT $dstDir + fi +} + +# Create the TLS directories of the MSP folder if they don't exist. +# The fabric-ca-client should do this. +function finishMSPSetup { + if [ $# -ne 1 ]; then + fatal "Usage: finishMSPSetup " + fi + if [ ! -d $1/tlscacerts ]; then + mkdir $1/tlscacerts + cp $1/cacerts/* $1/tlscacerts + if [ -d $1/intermediatecerts ]; then + mkdir $1/tlsintermediatecerts + cp $1/intermediatecerts/* $1/tlsintermediatecerts + fi + fi +} + +function awaitSetup { + dowait "the 'setup' container to finish registering identities, creating the genesis block and other artifacts" $SETUP_TIMEOUT $SETUP_LOGFILE /$SETUP_SUCCESS_FILE +} + +# Wait for one or more files to exist +# Usage: dowait [ ...] +function dowait { + if [ $# -lt 4 ]; then + fatal "Usage: dowait: $*" + fi + local what=$1 + local secs=$2 + local logFile=$3 + shift 3 + local logit=true + local starttime=$(date +%s) + for file in $*; do + until [ -f $file ]; do + if [ "$logit" = true ]; then + log -n "Waiting for $what ..." + logit=false + fi + sleep 1 + if [ "$(($(date +%s)-starttime))" -gt "$secs" ]; then + echo "" + fatal "Failed waiting for $what ($file not found); see $logFile" + fi + echo -n "." + done + done + echo "" +} + +# Wait for a process to begin to listen on a particular host and port +# Usage: waitPort +function waitPort { + set +e + local what=$1 + local secs=$2 + local logFile=$3 + local host=$4 + local port=$5 + nc -z $host $port > /dev/null 2>&1 + if [ $? -ne 0 ]; then + log -n "Waiting for $what ..." + local starttime=$(date +%s) + while true; do + sleep 1 + nc -z $host $port > /dev/null 2>&1 + if [ $? -eq 0 ]; then + break + fi + if [ "$(($(date +%s)-starttime))" -gt "$secs" ]; then + fatal "Failed waiting for $what; see $logFile" + fi + echo -n "." + done + echo "" + fi + set -e +} + + +# log a message +function log { + if [ "$1" = "-n" ]; then + shift + echo -n "##### `date '+%Y-%m-%d %H:%M:%S'` $*" + else + echo "##### `date '+%Y-%m-%d %H:%M:%S'` $*" + fi +} + +# fatal a message +function fatal { + log "FATAL: $*" + exit 1 +} diff --git a/fabric/v1.3/fabric-ca/scripts/run-fabric.sh b/fabric/v1.3/fabric-ca/scripts/run-fabric.sh new file mode 100755 index 0000000..c812f96 --- /dev/null +++ b/fabric/v1.3/fabric-ca/scripts/run-fabric.sh @@ -0,0 +1,291 @@ +#!/bin/bash +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +set -e + +source $(dirname "$0")/env.sh + +function main { + + done=false + + # Wait for setup to complete and then wait another 10 seconds for the orderer and peers to start + awaitSetup + sleep 10 + + trap finish EXIT + + mkdir -p $LOGPATH + logr "The docker 'run' container has started" + + # Set ORDERER_PORT_ARGS to the args needed to communicate with the 1st orderer + IFS=', ' read -r -a OORGS <<< "$ORDERER_ORGS" + initOrdererVars ${OORGS[0]} 1 + export ORDERER_PORT_ARGS="-o $ORDERER_HOST:7050 --tls --cafile $CA_CHAINFILE --clientauth" + + # Convert PEER_ORGS to an array named PORGS + IFS=', ' read -r -a PORGS <<< "$PEER_ORGS" + + # Create the channel + createChannel + + # All peers join the channel + for ORG in $PEER_ORGS; do + local COUNT=1 + while [[ "$COUNT" -le $NUM_PEERS ]]; do + initPeerVars $ORG $COUNT + joinChannel + COUNT=$((COUNT+1)) + done + done + + # Update the anchor peers + for ORG in $PEER_ORGS; do + initPeerVars $ORG 1 + switchToAdminIdentity + logr "Updating anchor peers for $PEER_HOST ..." + peer channel update -c $CHANNEL_NAME -f $ANCHOR_TX_FILE $ORDERER_CONN_ARGS + done + + # Install chaincode on the 1st peer in each org + for ORG in $PEER_ORGS; do + initPeerVars $ORG 1 + installChaincode + done + + # Instantiate chaincode on the 1st peer of the 2nd org + makePolicy + initPeerVars ${PORGS[1]} 1 + switchToAdminIdentity + logr "Instantiating chaincode on $PEER_HOST ..." + peer chaincode instantiate -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "$POLICY" $ORDERER_CONN_ARGS + + # Query chaincode from the 1st peer of the 1st org + initPeerVars ${PORGS[0]} 1 + switchToUserIdentity + chaincodeQuery 100 + + # Invoke chaincode on the 1st peer of the 1st org + initPeerVars ${PORGS[0]} 1 + switchToUserIdentity + logr "Sending invoke transaction to $PEER_HOST ..." + peer chaincode invoke -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}' $ORDERER_CONN_ARGS + + ## Install chaincode on 2nd peer of 2nd org + initPeerVars ${PORGS[1]} 2 + installChaincode + + # Query chaincode on 2nd peer of 2nd org + sleep 10 + initPeerVars ${PORGS[1]} 2 + switchToUserIdentity + chaincodeQuery 90 + + initPeerVars ${PORGS[0]} 1 + switchToUserIdentity + + # Revoke the user and generate CRL using admin's credentials + revokeFabricUserAndGenerateCRL + + # Fetch config block + fetchConfigBlock + + # Create config update envelope with CRL and update the config block of the channel + createConfigUpdatePayloadWithCRL + updateConfigBlock + + # querying the chaincode should fail as the user is revoked + switchToUserIdentity + queryAsRevokedUser + if [ "$?" -ne 0 ]; then + logr "The revoked user $USER_NAME should have failed to query the chaincode in the channel '$CHANNEL_NAME'" + exit 1 + fi + logr "Congratulations! The tests ran successfully." + + done=true +} + +# Enroll as a peer admin and create the channel +function createChannel { + initPeerVars ${PORGS[0]} 1 + switchToAdminIdentity + logr "Creating channel '$CHANNEL_NAME' on $ORDERER_HOST ..." + peer channel create --logging-level=DEBUG -c $CHANNEL_NAME -f $CHANNEL_TX_FILE $ORDERER_CONN_ARGS +} + +# Enroll as a fabric admin and join the channel +function joinChannel { + switchToAdminIdentity + set +e + local COUNT=1 + MAX_RETRY=10 + while true; do + logr "Peer $PEER_HOST is attempting to join channel '$CHANNEL_NAME' (attempt #${COUNT}) ..." + peer channel join -b $CHANNEL_NAME.block + if [ $? -eq 0 ]; then + set -e + logr "Peer $PEER_HOST successfully joined channel '$CHANNEL_NAME'" + return + fi + if [ $COUNT -gt $MAX_RETRY ]; then + fatalr "Peer $PEER_HOST failed to join channel '$CHANNEL_NAME' in $MAX_RETRY retries" + fi + COUNT=$((COUNT+1)) + sleep 1 + done +} + +function chaincodeQuery { + if [ $# -ne 1 ]; then + fatalr "Usage: chaincodeQuery " + fi + set +e + logr "Querying chaincode in the channel '$CHANNEL_NAME' on the peer '$PEER_HOST' ..." + local rc=1 + local starttime=$(date +%s) + # Continue to poll until we get a successful response or reach QUERY_TIMEOUT + while test "$(($(date +%s)-starttime))" -lt "$QUERY_TIMEOUT"; do + sleep 1 + peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}' >& log.txt + VALUE=$(cat log.txt | awk '/Query Result/ {print $NF}') + if [ $? -eq 0 -a "$VALUE" = "$1" ]; then + logr "Query of channel '$CHANNEL_NAME' on peer '$PEER_HOST' was successful" + set -e + return 0 + else + # removed the string "Query Result" from peer chaincode query command result, as a result, have to support both options until the change is merged. + VALUE=$(cat log.txt | egrep '^[0-9]+$') + if [ $? -eq 0 -a "$VALUE" = "$1" ]; then + logr "Query of channel '$CHANNEL_NAME' on peer '$PEER_HOST' was successful" + set -e + return 0 + fi + fi + echo -n "." + done + cat log.txt + cat log.txt >> $RUN_SUMFILE + fatalr "Failed to query channel '$CHANNEL_NAME' on peer '$PEER_HOST'; expected value was $1 and found $VALUE" +} + +function queryAsRevokedUser { + set +e + logr "Querying the chaincode in the channel '$CHANNEL_NAME' on the peer '$PEER_HOST' as revoked user '$USER_NAME' ..." + local starttime=$(date +%s) + # Continue to poll until we get an expected response or reach QUERY_TIMEOUT + while test "$(($(date +%s)-starttime))" -lt "$QUERY_TIMEOUT"; do + sleep 1 + peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}' >& log.txt + if [ $? -ne 0 ]; then + err=$(cat log.txt | grep "access denied") + if [ "$err" != "" ]; then + logr "Expected error occurred when the revoked user '$USER_NAME' queried the chaincode in the channel '$CHANNEL_NAME'" + set -e + return 0 + fi + fi + echo -n "." + done + set -e + cat log.txt + cat log.txt >> $RUN_SUMFILE + return 1 +} + +function makePolicy { + POLICY="OR(" + local COUNT=0 + for ORG in $PEER_ORGS; do + if [ $COUNT -ne 0 ]; then + POLICY="${POLICY}," + fi + initOrgVars $ORG + POLICY="${POLICY}'${ORG_MSP_ID}.member'" + COUNT=$((COUNT+1)) + done + POLICY="${POLICY})" + log "policy: $POLICY" +} + +function installChaincode { + switchToAdminIdentity + logr "Installing chaincode on $PEER_HOST ..." + peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric-samples/chaincode/abac/go +} + +function fetchConfigBlock { + logr "Fetching the configuration block of the channel '$CHANNEL_NAME'" + peer channel fetch config $CONFIG_BLOCK_FILE -c $CHANNEL_NAME $ORDERER_CONN_ARGS +} + +function updateConfigBlock { + logr "Updating the configuration block of the channel '$CHANNEL_NAME'" + peer channel update -f $CONFIG_UPDATE_ENVELOPE_FILE -c $CHANNEL_NAME $ORDERER_CONN_ARGS +} + +function createConfigUpdatePayloadWithCRL { + logr "Creating config update payload with the generated CRL for the organization '$ORG'" + # Start the configtxlator + configtxlator start & + configtxlator_pid=$! + log "configtxlator_pid:$configtxlator_pid" + logr "Sleeping 5 seconds for configtxlator to start..." + sleep 5 + + pushd /tmp + + CTLURL=http://127.0.0.1:7059 + # Convert the config block protobuf to JSON + curl -X POST --data-binary @$CONFIG_BLOCK_FILE $CTLURL/protolator/decode/common.Block > config_block.json + # Extract the config from the config block + jq .data.data[0].payload.data.config config_block.json > config.json + + # Update crl in the config json + CRL=$(cat $CORE_PEER_MSPCONFIGPATH/crls/crl*.pem | base64 | tr -d '\n') + cat config.json | jq --arg org "$ORG" --arg crl "$CRL" '.channel_group.groups.Application.groups[$org].values.MSP.value.config.revocation_list = [$crl]' > updated_config.json + + # Create the config diff protobuf + curl -X POST --data-binary @config.json $CTLURL/protolator/encode/common.Config > config.pb + curl -X POST --data-binary @updated_config.json $CTLURL/protolator/encode/common.Config > updated_config.pb + curl -X POST -F original=@config.pb -F updated=@updated_config.pb $CTLURL/configtxlator/compute/update-from-configs -F channel=$CHANNEL_NAME > config_update.pb + + # Convert the config diff protobuf to JSON + curl -X POST --data-binary @config_update.pb $CTLURL/protolator/decode/common.ConfigUpdate > config_update.json + + # Create envelope protobuf container config diff to be used in the "peer channel update" command to update the channel configuration block + echo '{"payload":{"header":{"channel_header":{"channel_id":"'"${CHANNEL_NAME}"'", "type":2}},"data":{"config_update":'$(cat config_update.json)'}}}' > config_update_as_envelope.json + curl -X POST --data-binary @config_update_as_envelope.json $CTLURL/protolator/encode/common.Envelope > $CONFIG_UPDATE_ENVELOPE_FILE + + # Stop configtxlator + kill $configtxlator_pid + + popd +} + +function finish { + if [ "$done" = true ]; then + logr "See $RUN_LOGFILE for more details" + touch /$RUN_SUCCESS_FILE + else + logr "Tests did not complete successfully; see $RUN_LOGFILE for more details" + touch /$RUN_FAIL_FILE + exit 1 + fi +} + +function logr { + log $* + log $* >> $RUN_SUMPATH +} + +function fatalr { + logr "FATAL: $*" + exit 1 +} + +main diff --git a/fabric/v1.3/fabric-ca/scripts/setup-fabric.sh b/fabric/v1.3/fabric-ca/scripts/setup-fabric.sh new file mode 100755 index 0000000..48c3c57 --- /dev/null +++ b/fabric/v1.3/fabric-ca/scripts/setup-fabric.sh @@ -0,0 +1,287 @@ +#!/bin/bash +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# +# This script does the following: +# 1) registers orderer and peer identities with intermediate fabric-ca-servers +# 2) Builds the channel artifacts (e.g. genesis block, etc) +# + +function main { + log "Beginning building channel artifacts ..." + registerIdentities + getCACerts + makeConfigTxYaml + generateChannelArtifacts + log "Finished building channel artifacts" + touch /$SETUP_SUCCESS_FILE +} + +# Enroll the CA administrator +function enrollCAAdmin { + waitPort "$CA_NAME to start" 90 $CA_LOGFILE $CA_HOST 7054 + log "Enrolling with $CA_NAME as bootstrap identity ..." + export FABRIC_CA_CLIENT_HOME=$HOME/cas/$CA_NAME + export FABRIC_CA_CLIENT_TLS_CERTFILES=$CA_CHAINFILE + fabric-ca-client enroll -d -u https://$CA_ADMIN_USER_PASS@$CA_HOST:7054 +} + +function registerIdentities { + log "Registering identities ..." + registerOrdererIdentities + registerPeerIdentities +} + +# Register any identities associated with the orderer +function registerOrdererIdentities { + for ORG in $ORDERER_ORGS; do + initOrgVars $ORG + enrollCAAdmin + local COUNT=1 + while [[ "$COUNT" -le $NUM_ORDERERS ]]; do + initOrdererVars $ORG $COUNT + log "Registering $ORDERER_NAME with $CA_NAME" + fabric-ca-client register -d --id.name $ORDERER_NAME --id.secret $ORDERER_PASS --id.type orderer + COUNT=$((COUNT+1)) + done + log "Registering admin identity with $CA_NAME" + # The admin identity has the "admin" attribute which is added to ECert by default + fabric-ca-client register -d --id.name $ADMIN_NAME --id.secret $ADMIN_PASS --id.attrs "admin=true:ecert" + done +} + +# Register any identities associated with a peer +function registerPeerIdentities { + for ORG in $PEER_ORGS; do + initOrgVars $ORG + enrollCAAdmin + local COUNT=1 + while [[ "$COUNT" -le $NUM_PEERS ]]; do + initPeerVars $ORG $COUNT + log "Registering $PEER_NAME with $CA_NAME" + fabric-ca-client register -d --id.name $PEER_NAME --id.secret $PEER_PASS --id.type peer + COUNT=$((COUNT+1)) + done + log "Registering admin identity with $CA_NAME" + # The admin identity has the "admin" attribute which is added to ECert by default + fabric-ca-client register -d --id.name $ADMIN_NAME --id.secret $ADMIN_PASS --id.attrs "hf.Registrar.Roles=client,hf.Registrar.Attributes=*,hf.Revoker=true,hf.GenCRL=true,admin=true:ecert,abac.init=true:ecert" + log "Registering user identity with $CA_NAME" + fabric-ca-client register -d --id.name $USER_NAME --id.secret $USER_PASS + done +} + +function getCACerts { + log "Getting CA certificates ..." + for ORG in $ORGS; do + initOrgVars $ORG + log "Getting CA certs for organization $ORG and storing in $ORG_MSP_DIR" + export FABRIC_CA_CLIENT_TLS_CERTFILES=$CA_CHAINFILE + fabric-ca-client getcacert -d -u https://$CA_HOST:7054 -M $ORG_MSP_DIR + finishMSPSetup $ORG_MSP_DIR + # If ADMINCERTS is true, we need to enroll the admin now to populate the admincerts directory + if [ $ADMINCERTS ]; then + switchToAdminIdentity + fi + done +} + +# printOrg +function printOrg { + echo " + - &$ORG_CONTAINER_NAME + + Name: $ORG + + # ID to load the MSP definition as + ID: $ORG_MSP_ID + + # MSPDir is the filesystem path which contains the MSP configuration + MSPDir: $ORG_MSP_DIR" +} + +# printOrdererOrg +function printOrdererOrg { + initOrgVars $1 + printOrg +} + +# printPeerOrg +function printPeerOrg { + initPeerVars $1 $2 + printOrg + echo " + AnchorPeers: + # AnchorPeers defines the location of peers which can be used + # for cross org gossip communication. Note, this value is only + # encoded in the genesis block in the Application section context + - Host: $PEER_HOST + Port: 7051" +} + +function makeConfigTxYaml { + { + echo " +################################################################################ +# +# Section: Organizations +# +# - This section defines the different organizational identities which will +# be referenced later in the configuration. +# +################################################################################ +Organizations:" + + for ORG in $ORDERER_ORGS; do + printOrdererOrg $ORG + done + + for ORG in $PEER_ORGS; do + printPeerOrg $ORG 1 + done + + echo " +################################################################################ +# +# SECTION: Application +# +# This section defines the values to encode into a config transaction or +# genesis block for application related parameters +# +################################################################################ +Application: &ApplicationDefaults + + # Organizations is the list of orgs which are defined as participants on + # the application side of the network + Organizations: +" + echo " +################################################################################ +# +# Profile +# +# - Different configuration profiles may be encoded here to be specified +# as parameters to the configtxgen tool +# +################################################################################ +Profiles: + + OrgsOrdererGenesis: + Orderer: + # Orderer Type: The orderer implementation to start + # Available types are \"solo\" and \"kafka\" + OrdererType: solo + Addresses:" + + for ORG in $ORDERER_ORGS; do + local COUNT=1 + while [[ "$COUNT" -le $NUM_ORDERERS ]]; do + initOrdererVars $ORG $COUNT + echo " - $ORDERER_HOST:7050" + COUNT=$((COUNT+1)) + done + done + + echo " + # Batch Timeout: The amount of time to wait before creating a batch + BatchTimeout: 2s + + # Batch Size: Controls the number of messages batched into a block + BatchSize: + + # Max Message Count: The maximum number of messages to permit in a batch + MaxMessageCount: 10 + + # Absolute Max Bytes: The absolute maximum number of bytes allowed for + # the serialized messages in a batch. + AbsoluteMaxBytes: 99 MB + + # Preferred Max Bytes: The preferred maximum number of bytes allowed for + # the serialized messages in a batch. A message larger than the preferred + # max bytes will result in a batch larger than preferred max bytes. + PreferredMaxBytes: 512 KB + + Kafka: + # Brokers: A list of Kafka brokers to which the orderer connects + # NOTE: Use IP:port notation + Brokers: + - 127.0.0.1:9092 + + # Organizations is the list of orgs which are defined as participants on + # the orderer side of the network + Organizations:" + + for ORG in $ORDERER_ORGS; do + initOrgVars $ORG + echo " - *${ORG_CONTAINER_NAME}" + done + + echo " + Consortiums: + + SampleConsortium: + + Organizations:" + + for ORG in $PEER_ORGS; do + initOrgVars $ORG + echo " - *${ORG_CONTAINER_NAME}" + done + + echo " + OrgsChannel: + Consortium: SampleConsortium + Application: + <<: *ApplicationDefaults + Organizations:" + + for ORG in $PEER_ORGS; do + initOrgVars $ORG + echo " - *${ORG_CONTAINER_NAME}" + done + + } > /etc/hyperledger/fabric/configtx.yaml + # Copy it to the data directory to make debugging easier + cp /etc/hyperledger/fabric/configtx.yaml /$DATA +} + +function generateChannelArtifacts() { + which configtxgen + if [ "$?" -ne 0 ]; then + fatal "configtxgen tool not found. exiting" + fi + + log "Generating orderer genesis block at $GENESIS_BLOCK_FILE" + # Note: For some unknown reason (at least for now) the block file can't be + # named orderer.genesis.block or the orderer will fail to launch! + configtxgen -profile OrgsOrdererGenesis -outputBlock $GENESIS_BLOCK_FILE + if [ "$?" -ne 0 ]; then + fatal "Failed to generate orderer genesis block" + fi + + log "Generating channel configuration transaction at $CHANNEL_TX_FILE" + configtxgen -profile OrgsChannel -outputCreateChannelTx $CHANNEL_TX_FILE -channelID $CHANNEL_NAME + if [ "$?" -ne 0 ]; then + fatal "Failed to generate channel configuration transaction" + fi + + for ORG in $PEER_ORGS; do + initOrgVars $ORG + log "Generating anchor peer update transaction for $ORG at $ANCHOR_TX_FILE" + configtxgen -profile OrgsChannel -outputAnchorPeersUpdate $ANCHOR_TX_FILE \ + -channelID $CHANNEL_NAME -asOrg $ORG + if [ "$?" -ne 0 ]; then + fatal "Failed to generate anchor peer update for $ORG" + fi + done +} + +set -e + +SDIR=$(dirname "$0") +source $SDIR/env.sh + +main diff --git a/fabric/v1.3/fabric-ca/scripts/start-intermediate-ca.sh b/fabric/v1.3/fabric-ca/scripts/start-intermediate-ca.sh new file mode 100755 index 0000000..01bf14b --- /dev/null +++ b/fabric/v1.3/fabric-ca/scripts/start-intermediate-ca.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +source $(dirname "$0")/env.sh +initOrgVars $ORG + +set -e + +# Wait for the root CA to start +waitPort "root CA to start" 60 $ROOT_CA_LOGFILE $ROOT_CA_HOST 7054 + +# Initialize the intermediate CA +fabric-ca-server init -b $BOOTSTRAP_USER_PASS -u $PARENT_URL + +# Copy the intermediate CA's certificate chain to the data directory to be used by others +cp $FABRIC_CA_SERVER_HOME/ca-chain.pem $TARGET_CHAINFILE + +# Add the custom orgs +for o in $FABRIC_ORGS; do + aff=$aff"\n $o: []" +done +aff="${aff#\\n }" +sed -i "/affiliations:/a \\ $aff" \ + $FABRIC_CA_SERVER_HOME/fabric-ca-server-config.yaml + +# Start the intermediate CA +fabric-ca-server start diff --git a/fabric/v1.3/fabric-ca/scripts/start-orderer.sh b/fabric/v1.3/fabric-ca/scripts/start-orderer.sh new file mode 100755 index 0000000..c354dda --- /dev/null +++ b/fabric/v1.3/fabric-ca/scripts/start-orderer.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +set -e + +source $(dirname "$0")/env.sh + +# Wait for setup to complete sucessfully +awaitSetup + +# Enroll to get orderer's TLS cert (using the "tls" profile) +fabric-ca-client enroll -d --enrollment.profile tls -u $ENROLLMENT_URL -M /tmp/tls --csr.hosts $ORDERER_HOST + +# Copy the TLS key and cert to the appropriate place +TLSDIR=$ORDERER_HOME/tls +mkdir -p $TLSDIR +cp /tmp/tls/keystore/* $ORDERER_GENERAL_TLS_PRIVATEKEY +cp /tmp/tls/signcerts/* $ORDERER_GENERAL_TLS_CERTIFICATE +rm -rf /tmp/tls + +# Enroll again to get the orderer's enrollment certificate (default profile) +fabric-ca-client enroll -d -u $ENROLLMENT_URL -M $ORDERER_GENERAL_LOCALMSPDIR + +# Finish setting up the local MSP for the orderer +finishMSPSetup $ORDERER_GENERAL_LOCALMSPDIR +copyAdminCert $ORDERER_GENERAL_LOCALMSPDIR + +# Wait for the genesis block to be created +dowait "genesis block to be created" 60 $SETUP_LOGFILE $ORDERER_GENERAL_GENESISFILE + +# Start the orderer +env | grep ORDERER +orderer diff --git a/fabric/v1.3/fabric-ca/scripts/start-peer.sh b/fabric/v1.3/fabric-ca/scripts/start-peer.sh new file mode 100755 index 0000000..9dd7438 --- /dev/null +++ b/fabric/v1.3/fabric-ca/scripts/start-peer.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +set -e + +source $(dirname "$0")/env.sh + +awaitSetup + +# Although a peer may use the same TLS key and certificate file for both inbound and outbound TLS, +# we generate a different key and certificate for inbound and outbound TLS simply to show that it is permissible + +# Generate server TLS cert and key pair for the peer +fabric-ca-client enroll -d --enrollment.profile tls -u $ENROLLMENT_URL -M /tmp/tls --csr.hosts $PEER_HOST + +# Copy the TLS key and cert to the appropriate place +TLSDIR=$PEER_HOME/tls +mkdir -p $TLSDIR +cp /tmp/tls/signcerts/* $CORE_PEER_TLS_CERT_FILE +cp /tmp/tls/keystore/* $CORE_PEER_TLS_KEY_FILE +rm -rf /tmp/tls + +# Generate client TLS cert and key pair for the peer +genClientTLSCert $PEER_NAME $CORE_PEER_TLS_CLIENTCERT_FILE $CORE_PEER_TLS_CLIENTKEY_FILE + +# Generate client TLS cert and key pair for the peer CLI +genClientTLSCert $PEER_NAME /$DATA/tls/$PEER_NAME-cli-client.crt /$DATA/tls/$PEER_NAME-cli-client.key + +# Enroll the peer to get an enrollment certificate and set up the core's local MSP directory +fabric-ca-client enroll -d -u $ENROLLMENT_URL -M $CORE_PEER_MSPCONFIGPATH +finishMSPSetup $CORE_PEER_MSPCONFIGPATH +copyAdminCert $CORE_PEER_MSPCONFIGPATH + +# Start the peer +log "Starting peer '$CORE_PEER_ID' with MSP at '$CORE_PEER_MSPCONFIGPATH'" +env | grep CORE +peer node start diff --git a/fabric/v1.3/fabric-ca/scripts/start-root-ca.sh b/fabric/v1.3/fabric-ca/scripts/start-root-ca.sh new file mode 100755 index 0000000..f1fa244 --- /dev/null +++ b/fabric/v1.3/fabric-ca/scripts/start-root-ca.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +set -e + +# Initialize the root CA +fabric-ca-server init -b $BOOTSTRAP_USER_PASS + +# Copy the root CA's signing certificate to the data directory to be used by others +cp $FABRIC_CA_SERVER_HOME/ca-cert.pem $TARGET_CERTFILE + +# Add the custom orgs +for o in $FABRIC_ORGS; do + aff=$aff"\n $o: []" +done +aff="${aff#\\n }" +sed -i "/affiliations:/a \\ $aff" \ + $FABRIC_CA_SERVER_HOME/fabric-ca-server-config.yaml + +# Start the root CA +fabric-ca-server start diff --git a/fabric/v1.3/fabric-ca/start.sh b/fabric/v1.3/fabric-ca/start.sh new file mode 100755 index 0000000..13e994c --- /dev/null +++ b/fabric/v1.3/fabric-ca/start.sh @@ -0,0 +1,74 @@ +#!/bin/bash +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# +# This script does everything required to run the fabric CA sample. +# +# By default, this test is run with the latest released docker images. +# +# To run against a specific fabric/fabric-ca version: +# export FABRIC_TAG=1.3.0 +# +# To run with locally built images: +# export FABRIC_TAG=local + +set -e + +SDIR=$(dirname "$0") +source ${SDIR}/scripts/env.sh + +cd ${SDIR} + +# Delete docker containers +dockerContainers=$(docker ps -a | awk '$2~/hyperledger/ {print $1}') +if [ "$dockerContainers" != "" ]; then + log "Deleting existing docker containers ..." + docker rm -f $dockerContainers > /dev/null +fi + +# Remove chaincode docker images +chaincodeImages=`docker images | grep "^dev-peer" | awk '{print $3}'` +if [ "$chaincodeImages" != "" ]; then + log "Removing chaincode docker images ..." + docker rmi -f $chaincodeImages > /dev/null +fi + +# Start with a clean data directory +DDIR=${SDIR}/${DATA} +if [ -d ${DDIR} ]; then + log "Cleaning up the data directory from previous run at $DDIR" + rm -rf ${SDIR}/data +fi +mkdir -p ${DDIR}/logs + +# Create the docker-compose file +${SDIR}/makeDocker.sh + +# Create the docker containers +log "Creating docker containers ..." +docker-compose up -d + +# Wait for the setup container to complete +dowait "the 'setup' container to finish registering identities, creating the genesis block and other artifacts" 90 $SDIR/$SETUP_LOGFILE $SDIR/$SETUP_SUCCESS_FILE + +# Wait for the run container to start and then tails it's summary log +dowait "the docker 'run' container to start" 60 ${SDIR}/${SETUP_LOGFILE} ${SDIR}/${RUN_SUMFILE} +tail -f ${SDIR}/${RUN_SUMFILE}& +TAIL_PID=$! + +# Wait for the run container to complete +while true; do + if [ -f ${SDIR}/${RUN_SUCCESS_FILE} ]; then + kill -9 $TAIL_PID + exit 0 + elif [ -f ${SDIR}/${RUN_FAIL_FILE} ]; then + kill -9 $TAIL_PID + exit 1 + else + sleep 1 + fi +done diff --git a/fabric/v1.3/fabric-ca/stop.sh b/fabric/v1.3/fabric-ca/stop.sh new file mode 100755 index 0000000..8f85406 --- /dev/null +++ b/fabric/v1.3/fabric-ca/stop.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +set -e +SDIR=$(dirname "$0") +source $SDIR/scripts/env.sh + +log "Stopping docker containers ..." +docker-compose down +# Stop chaincode containers and images as well +docker rm -f $(docker ps -aq --filter name=dev-peer) +docker rmi $(docker images | awk '$1 ~ /dev-peer/ { print $3 }') +log "Docker containers have been stopped"