Monday, November 25, 2019

Change OpenShift SecurityContextConstraints

Use this command to change the securityContextConstraints to run the cello on OpenShift

oc edit scc restricted
 
Once in the editor, change things like this
 
allowHostDirVolumePlugin: false
allowHostIPC: false
allowHostNetwork: false
allowHostPID: false
allowHostPorts: true
allowPrivilegeEscalation: true
allowPrivilegedContainer: true
allowedCapabilities: null
apiVersion: security.openshift.io/v1
defaultAddCapabilities: null
fsGroup:
  type: RunAsAny
groups:
- system:authenticated
kind: SecurityContextConstraints
metadata:
  annotations:
    kubernetes.io/description: restricted denies access to all host features and requires
      pods to be run with a UID, and SELinux context that are allocated to the namespace.  This
      is the most restrictive SCC and it is used by default for authenticated users.
  creationTimestamp: 2019-11-25T16:01:36Z
  name: restricted
  resourceVersion: "103032"
  selfLink: /apis/security.openshift.io/v1/securitycontextconstraints/restricted
  uid: dbbb5df1-0f9c-11ea-842f-9a1f5595b3c8
priority: null
readOnlyRootFilesystem: false
requiredDropCapabilities:
- KILL
- MKNOD
- SETUID
- SETGID
runAsUser:
  type: RunAsAny
seLinuxContext:
  type: RunAsAny
supplementalGroups:
  type: RunAsAny
users: []
volumes:
- configMap
- downwardAPI
- emptyDir
- persistentVolumeClaim
- projected
- secret 


Thursday, November 7, 2019

Add new org to a channel

The process of adding a new org to a channel is long, I will break this process up to three parts,

1. Just to add an org to an existing channel
2. Join the peer in the new org to the channel.
3. Chaincode upgrade and endorsement policies

Add an org to an existing channel

Prepare the new org

Start from just configtx.yaml and org3-crypto.yaml, run cryptogen and configtxgen to produce crypto materials and org3.json file:

cryptogen generate --config ./org3-crypto.yaml
configtxgen -printOrg Org3MSP > ../channel-artifacts/org3.json

Prepare the existing channel, (notice I am omitting all the conversion steps either from common block to json or json to common block, these steps are absolutely necessary)

Retrieve the channel configuration:

     peer channel fetch config config_block.pb

Get the channel config element using jq:

     jq .data.data[0].payload.data.config allConfig.json > config.json

Add the new org into the channel configuration which is the config.json file
   
  jq -s '.[0] * {"channel_group":{"groups":{"Application":{"groups": {"Org3MSP":.[1]}}}}}' \
     config.json org3.json > modified_config.json

Now we have the original configuration and modified configuration json file, we need to calculate the differences, but to be able to do that, we have to encode both into binary format.

  configtxlator proto_encode --input config.json --type common.Config --output config.pb
  configtxlator proto_encode --input modified_config.json --type common.Config --output modified_config.pb


Then we can calculate the update protobuf binary:

  configtxlator compute_update --channel_id $CHANNEL_NAME --original config.pb \
    --updated modified_config.pb --output org3_update.pb
 
Again, we need to convert this into json format so that we can create update envolop
 
  configtxlator proto_decode --input org3_update.pb \
    --type common.ConfigUpdate | jq . > org3_update.json

Now we need to the update envolop json file:
 
  echo '{"payload":{"header":{"channel_header":{"channel_id":"mychannel", "type":2}},"data":{"config_update":'$(cat org3_update.json)'}}}' | jq . > org3_update_in_envelope.json
 
Now we need to create the protobuf binary.
 
  configtxlator proto_encode --input org3_update_in_envelope.json \
  --type common.Envelope --output org3_update_in_envelope.pb  

We finally have the channel update request content (the protobuf binary file),
we need to sign that and eventually submit
 
  peer channel signconfigtx -f org3_update_in_envelope.pb 
 
This basically gathered one signature. We need to collect more and submit. The good news
is that peer channel update actually also attach a signature, if we use another org's peer
credential to submit channel update, then that org's peer signature will be also included.
 
  peer channel update -f org3_update_in_envelope.pb -c $CHANNEL_NAME \
    -o orderer.example.com:7050 --tls --cafile $ORDERER_CA 

At this point, the channel officially includes the new organization. But peers in that
organization are not part of this channel yet because peers in that organization will
need to utilize peer join command to do that.

Join the peer in the new org to the channel

Use the peer channel fetch command to retrieve the first block:

  peer channel fetch 0 mychannel.block -o orderer.example.com:7050 \
   -c $CHANNEL_NAME --tls --cafile $ORDERER_CA
 
Now use the peer join command to join the peer, but make sure all the environment varilables
are setup to use new org peer's certs, new org's ca certs etc
 
  peer channel join -b mychannel.block

Chaincode upgrade and endorsement policies

Use normal chaincode install and chaincode upgrade to change the endorsement policies to include the new organization.

Monday, November 4, 2019

What is needed to stand up a peer or orderer node in fabric

To stand up a fabric peer or orderer node, the following must be provided:

  • msp directory which contains at least the following:
    1. admincerts: admin certs, the actual admin user, can be shared cross all the peers in an org.
    2. cacerts: ca certificate
    3. keystore: the node signing key, that is the private key
    4. signcert: the node x509 certificate, the public key
  • tls directory which contains the following if tls is enabled:
    1. ca.crt
    2. server.crt
    3. server.key

So basically, you will need to enroll 3 times,

1. Enroll an admin user, so that you get admincert
2. Enroll a node, so that you get node keystore (private key) and signing key (public key)
3. Enroll a node tls certs, this is only required if you have tls enabled for the node.

Once these things are available, then you can start a node, either peer or orderer can use the same cert materials. remember to mount msp directory to /etc/hyperledger/fabric/msp, and tls directory to /etc/hyperledger/fabric/tls, with the default settings, peer and orderer will be able to find the right certs to start the node.

The above step is when you have a CA server available.

If you simply try to bootstrap a network using cryptogen, then you basically create crypto-config.yaml file, then run cryptogen command to generate necessary certs.

make sure that your file is named crypto-config.yaml, then run the following command:

cryptogen generate --output="a directory name" --config=configfile.yaml

Strange behavior of ca enroll command

There is really a very strange behavior, enroll always uses the current request user name as common name,  this creates a certificate always uses the current request user name as the common name, the only way that I can overcome this problem is to do the following:

1. enroll a new userid
2. register that user, then simply delete the entire directory which hold the new users certs
3. then enroll again using the new user's id and password

The right method to over come the strange behavior

1. make sure that your CA_CFG_PATH=$(pwd)
2. enroll the ca admin user first, and make sure
3. register the new user first
4. then enroll the new user using the new user id and password.

Sunday, November 3, 2019

configtx.yaml

Profiles defined in configtx.yaml file are the starting point which use other sections of configtx.yaml.
There are two different types of profiles, one is to be used for genesis block which is for bootstrapping orderer nodes, the other is to be used for channel block. What to be generated by configtxgen depends on which profile to be used and what flag is specified in the command line.

For example -profile -outputBlock flags are used to specify a profile to generate a genesis block.
Where -profile -outputCreateChannelTx is used to specify a profile to generate a channel create tx.


Profiles for genesis block should always contains Orderers and Consortiums elements. Profiles for just a channel should just contains Consortium and Application section. Notice for the genesis profile, the element is Consortiums, for a channel is Consortimum, so there are some small diference though.

Hyperledger Fabric ACLs

# in the system. These "resources" could be functions on system chaincodes
# (e.g., "GetBlockByNumber" on the "qscc" system chaincode) or other resources
# (e.g.,who can receive Block events). This section does NOT specify the resource's
# definition or API, but just the ACL policy for it.
#
# User's can override these defaults with their own policy mapping by defining the
# mapping under ACLs in their channel definition
#---Lifecycle System Chaincode (lscc) function to policy mapping for access control---#
# ACL policy for lscc's "getid" function
lscc/ChaincodeExists: /Channel/Application/Readers
# ACL policy for lscc's "getdepspec" function
lscc/GetDeploymentSpec: /Channel/Application/Readers
# ACL policy for lscc's "getccdata" function
lscc/GetChaincodeData: /Channel/Application/Readers
# ACL Policy for lscc's "getchaincodes" function
lscc/GetInstantiatedChaincodes: /Channel/Application/Readers
#---Query System Chaincode (qscc) function to policy mapping for access control---#
# ACL policy for qscc's "GetChainInfo" function
qscc/GetChainInfo: /Channel/Application/Readers
# ACL policy for qscc's "GetBlockByNumber" function
qscc/GetBlockByNumber: /Channel/Application/Readers
# ACL policy for qscc's "GetBlockByHash" function
qscc/GetBlockByHash: /Channel/Application/Readers
# ACL policy for qscc's "GetTransactionByID" function
qscc/GetTransactionByID: /Channel/Application/Readers
# ACL policy for qscc's "GetBlockByTxID" function
qscc/GetBlockByTxID: /Channel/Application/Readers
#---Configuration System Chaincode (cscc) function to policy mapping for access control---#
# ACL policy for cscc's "GetConfigBlock" function
cscc/GetConfigBlock: /Channel/Application/Readers
# ACL policy for cscc's "GetConfigTree" function
cscc/GetConfigTree: /Channel/Application/Readers
# ACL policy for cscc's "SimulateConfigTreeUpdate" function
cscc/SimulateConfigTreeUpdate: /Channel/Application/Readers
#---Miscellanesous peer function to policy mapping for access control---#
# ACL policy for invoking chaincodes on peer
peer/Propose: /Channel/Application/Writers
# ACL policy for chaincode to chaincode invocation
peer/ChaincodeToChaincode: /Channel/Application/Readers
#---Events resource to policy mapping for access control###---#
# ACL policy for sending block events
event/Block: /Channel/Application/Readers
# ACL policy for sending filtered block events
event/FilteredBlock: /Channel/Application/Readers
# This section provides defaults for policies for various resources

Fabric channel configuration structure again

Each channel configuration is a nasty nested json file.


The top level has three elements, they are data, header and metadata.

Element header contains the data_hash, number and previous_hash, this is basically the block info, where the block sits (number),  the block hash and previous hash, these.

Element metadata for the system channel is empty. It also has metadata as its member which in turn is a list.

Element data contains yet another element named data which contains payload and signature.

What is important is really the payload which contains again data and header just like the very top structure.

In the payload.header element, we can see the channel_header and signature_header.

The data.config element is where everything is defined, channel_group is the starting point of the channel configuration. For the detailed structure from this point on please refer to the this blog

config.channel_group is the start of the system channel which is the very first channel created on a given orderering cluster. 

Hyperledger Fabric Policy

Hyperledger Fabric Policy in the configtx.yaml file uses shorthanded notation, which normally looks like a file path like this:

Channel/Application/Writers

That notation basically indicates the policy defined in

Channel/Groups/Application/Policies/Writers

Noticed that the Groups and Policies in the path are omitted.


Notice the 1st mod_policy in the chart is "/Channel/Orderer/Admins" which actually refers channel_group/groups/Orderer/policies/Admins element. The reason why it refers to that is because it starts with an absolute path. Actually the 2nd mod_policy also points to the same role but it uses relative path.

Though 2nd and 3rd mod_policy both only use the relative path "Admins", they actually point to the different role in the policies. The 2nd as indicated above, it points to the 1st Admins role, but the 3rd policy points to the 2nd Admins role. So if the absolute path used for the 2nd mod_policy, it would have been "/Channel/Orderer/Admins", same way if the absolute path used for the 3rd mod_policy, it would have been "/Channel/Admins", notice it has no word Orderer in it.

Do not mix up policy and policies. The element policy is always under defined role such as Admins, Readers and Writers etc, these roles are always directly under element policies. Where element policies is always under groups.<Something>, in our above example, you can see policies elements are under groups.Consortiums, groups.Orderer, config.channel_group. The element policies really just defines the role, element policy defines a specific rule. Policy has types, policies just have a list of roles. Policy type 1 is SignaturePolicy and type 3 is ImplictMetaPolicy. type 2 is the msp.

mod_policy indicates what role can make modifications to the Policies itself, policies control very much the fabric configuration, so in nearly all the cases, this means who can make changes channel configurations, who can read the channel configurations. The channel in this case can be either system channel or application channel. Now regarding who can create proposal, commit tx, prove tx all are controlled by ACL.

Policy defaults:

The configtxgen tool creates default policies as follows:


/Channel/Readers : ImplicitMetaPolicy for ANY of /Channel/*/Readers
/Channel/Writers : ImplicitMetaPolicy for ANY of /Channel/*/Writers
/Channel/Admins  : ImplicitMetaPolicy for MAJORITY of /Channel/*/Admins

/Channel/Application/Readers : ImplicitMetaPolicy for ANY of /Channel/Application/*/Readers
/Channel/Application/Writers : ImplicitMetaPolicy for ANY of /Channel/Application/*/Writers
/Channel/Application/Admins  : ImplicitMetaPolicy for MAJORITY of /Channel/Application/*/Admins

/Channel/Orderer/Readers : ImplicitMetaPolicy for ANY of /Channel/Orderer/*/Readers
/Channel/Orderer/Writers : ImplicitMetaPolicy for ANY of /Channel/Orderer/*/Writers
/Channel/Orderer/Admins  : ImplicitMetaPolicy for MAJORITY of /Channel/Orderer/*/Admins

# Here * represents either Orderer, or Application, and this is repeated for each org
/Channel/*/Org/Readers : SignaturePolicy for 1 of MSP Principal Org Member
/Channel/*/Org/Writers : SignaturePolicy for 1 of MSP Principal Org Member
/Channel/*/Org/Admins  : SignaturePolicy for 1 of MSP Principal Org Admin



see the following chart for examples of ImplictMetaPolicy and SignaturePolicy

The principal_classification can either be ROLE or IDENTITY. However, more commonly the ROLE type is used, as it allows the principal to match many different certs issued by the MSP's CA. The role matches MSPRole defined as MEMBER, ADMIN, CLIENT, PEER.

Member matches any certificate issued by the MSP. Admin matches certificate enumerated as admin in the MSP definition. Client (Peer) matches certificates that carry the client(peer) Organizational Unit.

In the case of IDENTITY the principal field is set to the bytes of a certificate literal.That is, the principal field should just contain the base64 encoded (The very long string) certificate for that identity.

The sub_policy in the ImplicitMetaPolicy indicate any named policy in its value, in the example above, which is Admins, so any the policy named Admins at that level or under will be used. If the rule is ALL, then all the policies named Admins at that level or under will be evaluated.