0

Facing an issue while querying ledger. Here is the how our network is laid out. There are 2 orgs on a kubernetes cluster inside the corp network and one on a docker swarm on an azure vm inside the network too. The azure vm node and the k8s cluster nodes communicate with each other over an nginx server. Now the reason behind this elaborate setup is because our supplychain usecase requires partners from different companies to join our network. So to simulate an external partner outside the corp network we use the azure vm. Since we plan to productionize the implementation we couldn't use Fabric crypto config generated certificates and got new certificates issued using our company's intermediate and root certs. Now there are chaincodes installed on this network setup with endorsement policy enabled that works perfectly on all 3 nodes. We are using Fabric 2.3.0

Now the first issue that I had faced, was the TLS certificate to use in the connection.json file. That was solved by chaining the certificates as described in the SO post here. The current issue is that the nodejs code is able to connect to the orgs but is unable to execute any read or write operations. In the JS code below if I uncomment the console logs of the channel.getPeer() responses it prints the entire peer object properly.

Here is my connection.json. All the 10.100.xx.xx ips are of the pods in the k8s cluster and the public.ip.address is that of the nginx server

{
    "name": "byfn",
    "version": "1.0.0",
    "client": {
        "organization": "ORG2MSP",
        "connection": {
            "timeout": {
                "peer": {
                    "endorser": "10000"
                },
                "orderer": "10000"
            }
        }
    },
    "channels": {
        "supplychain": {
            "orderers": [
                "ord1.orderers.org1.com",
                "ord2.orderers.org1.com",
                "ord3.orderers.org1.com"
            ],
            "peers": {
                "peer1.peers.org1.com": {
                    "endorsingPeer": true,
                    "chaincodeQuery": true,
                    "ledgerQuery": true,
                    "eventSource": true
                },
                "peer1.peers.org3.com": {
                    "endorsingPeer": true,
                    "chaincodeQuery": true,
                    "ledgerQuery": true,
                    "eventSource": true
                },
                "peer1.peers.org2.com": {
                    "endorsingPeer": true,
                    "chaincodeQuery": true,
                    "ledgerQuery": true,
                    "eventSource": true
                }
            }
        }
    },
    "organizations": {
        "ORG2MSP": {
            "mspid": "ORG2MSP",
            "peers": [
                "peer1.peers.org2.com",
                "peer2.peers.org2.com"
            ]
        }
    },
    "orderers": {
        "ord1.orderers.org1.com": {
            "url": "grpcs://10.100.xxx.xxx:7050",
            "grpcOptions": {
                "ssl-target-name-override": "ord1.orderers.org1.com",
                "request-timeout": 12000
            },
            "tlsCACerts": {
                "path": "temp.pem"
            }
        },
        "ord2.orderers.org1.com": {
            "url": "grpcs://10.100.xxx.xxx:7050",
            "grpcOptions": {
                "ssl-target-name-override": "ord2.orderers.org1.com",
                "request-timeout": 12000
            },
            "tlsCACerts": {
                "path": "temp.pem"
            }
        },
        "ord3.orderers.org1.com": {
            "url": "grpcs://10.100.xxx.xxx:7050",
            "grpcOptions": {
                "ssl-target-name-override": "ord3.orderers.org1.com",
                "request-timeout": 12000
            },
            "tlsCACerts": {
                "path": "temp.pem"
            }
        }
    },
    "peers": {
        "peer1.peers.org1.com": {
            "url": "grpcs://10.100.xxx.xxx:7051",
            "grpcOptions": {
                "ssl-target-name-override": "peer1.peers.org1.com",
                "request-timeout": 12000,
                "grpc.keepalive_time_ms": 600000
            },
            "tlsCACerts": {
                "path": "temp.pem"
            }
        },
        "peer1.peers.org3.com": {
            "url": "grpcs://public.ip.address:7051",
            "grpcOptions": {
                "ssl-target-name-override": "peer1.peers.org3.com",
                "request-timeout": 12000,
                "grpc.keepalive_time_ms": 600000
            },
            "tlsCACerts": {
                "path": "temp.pem"
            }
        },
        "peer1.peers.org2.com": {
            "url": "grpcs://10.100.xxx.xxx:7051",
            "grpcOptions": {
                "ssl-target-name-override": "peer1.peers.org2.com",
                "request-timeout": 12000,
                "grpc.keepalive_time_ms": 600000
            },
            "tlsCACerts": {
                "path": "temp.pem"
            }
        }
    }
}

Here is my code

'use strict';

const { Wallets, Gateway } = require('fabric-network');
const fs = require('fs');
const path = require('path');

const ccpPath = path.resolve(__dirname,'connection.json');
const ccpJSON = fs.readFileSync(ccpPath, 'utf8');
const ccp = JSON.parse(ccpJSON);


async function main(){
    try {
        // const walletPath = path.join(process.cwd(), 'wallet');
        const wallet = await Wallets.newFileSystemWallet('wallet');
        // console.log(`Wallet path: ${walletPath}`);

        // Check to see if we've already enrolled the user.
        const userExists = await wallet.get('usernew');
        const tlsExists = await wallet.get('tlsid');
        if (!userExists) {
            console.log('An identity for the user "usernew" does not exist in the wallet');
            return;
        }
        if (!tlsExists) {
            console.log('An identity for the user "tls" does not exist in the wallet');
            return;
        }
        console.log("Here");
        // Create a new gateway for connecting to our peer node.
        const gateway = new Gateway();
        await gateway.connect(ccp, { wallet, identity: 'usernew', discovery: { enabled: false, asLocalhost: false }, clientTlsIdentity: 'tlsid' });

        console.log("Here1");
        // Get the network (channel) our contract is deployed to.
        const network = await gateway.getNetwork('supplychain');

        console.log("Here2");
        //Get the channel object to fetch out peers
        const channel = network.getChannel();

        console.log("Here3");
        //Get peers for endorsement
        //channel.getEndorsers();
        const org1Peer = channel.getPeer('peer1.peers.org1.com');
        //console.log(org1Peer);
        const org2Peer = channel.getPeer('peer1.peers.org2.com');
        //console.log(org2Peer);
        const org3Peer = channel.getPeer('peer1.peers.org3.com');
        //console.log(org3Peer);
        // All the above logs print correct information


        // Get the contract from the network.
        const contract = network.getContract('mycontract');

        const result = await contract.evaluateTransaction('queryAllObjects');
        
        console.log(`Transaction has been evaluated, result is: ${result.toString()}`);

    } catch (error) {
        console.error(`Failed to evaluate transaction: ${error}`);
    }
}

main()

Here is the crypto folder tree

C:.
├───peers.org1.com
│   └───users
│       ├───Admin@peers.org1.com
│       │   ├───msp
│       │   │   ├───admincerts
│       │   │   ├───cacerts
│       │   │   ├───intermediatecerts
│       │   │   ├───keystore
│       │   │   ├───signcerts
│       │   │   ├───tlscacerts
│       │   │   └───tlsintermediatecerts
│       │   └───tls
│       └───User1@peers.org1.com
│           ├───msp
│           │   ├───admincerts
│           │   ├───cacerts
│           │   ├───intermediatecerts
│           │   ├───keystore
│           │   ├───signcerts
│           │   ├───tlscacerts
│           │   └───tlsintermediatecerts
│           └───tls
├───peers.org2.com
│   └───users
│       ├───Admin@peers.org2.com
│       │   ├───msp
│       │   │   ├───admincerts
│       │   │   ├───cacerts
│       │   │   ├───intermediatecerts
│       │   │   ├───keystore
│       │   │   ├───signcerts
│       │   │   ├───tlscacerts
│       │   │   └───tlsintermediatecerts
│       │   └───tls
│       └───User1@peers.org2.com
│           ├───msp
│           │   ├───admincerts
│           │   ├───cacerts
│           │   ├───intermediatecerts
│           │   ├───keystore
│           │   ├───signcerts
│           │   ├───tlscacerts
│           │   └───tlsintermediatecerts
│           └───tls
└───peers.org3.com
    └───users
        ├───Admin@peers.org3.com
        │   ├───msp
        │   │   ├───admincerts
        │   │   ├───cacerts
        │   │   ├───intermediatecerts
        │   │   ├───keystore
        │   │   ├───signcerts
        │   │   ├───tlscacerts
        │   │   └───tlsintermediatecerts
        │   └───tls
        └───User1@peers.org3.com
            ├───msp
            │   ├───admincerts
            │   ├───cacerts
            │   ├───intermediatecerts
            │   ├───keystore
            │   ├───signcerts
            │   ├───tlscacerts
            │   └───tlsintermediatecerts
            └───tls

The temp.pem used in the connection file above is prepared by appending the ica.pem and ca.pem shown below. Here is how the cerificates look for Org2. Looks similar for other 2 orgs. msp/tlscacerts/ca.pem

Issuer: C=XX, ST=XXXX, L=XXXX, O=MyCompany, OU=Cybersecurity, CN=MyCompany Root Certificate Authority 2018
Validity
    Not Before: Jul 23 17:07:45 2018 GMT
    Not After : Jul 23 17:17:44 2043 GMT
Subject: C=XX, ST=XXXX, L=XXXX, O=MyCompany, OU=Cybersecurity, CN=MyCompany Root Certificate Authority

msp/tlsintermediatecerts/ica.pem

Issuer: C=XX, ST=XXXX, L=XXXX, O=MyCompany, OU=Cybersecurity, CN=MyCompany Root Certificate Authority 2018
Validity
    Not Before: Nov 14 21:26:35 2018 GMT
    Not After : Nov 14 21:36:35 2025 GMT
Subject: C=XX, ST=XXXX, L=XXXX, O=MyCompany, CN=MyCompany Issuing CA 101

tls/server.crt

Issuer: C=XX, ST=XXXX, L=XXXX, O=MyCompany, CN=MyCompany Issuing CA 101
Validity
    Not Before: Jan 18 20:30:30 2021 GMT
    Not After : Jan 18 20:30:30 2023 GMT
Subject: C=XX, ST=XXXX, L=XXXX, O=MyCompany Inc., OU=org2client, CN=*.peers.org2.com
.
.
.
X509v3 Subject Alternative Name:
    DNS:*.peers.org2.com

Org2 NodeJs log

2021-02-25T10:21:33.736Z - error: [Endorser]: sendProposal[peer1.peers.org2.com] - Received error response from: grpcs://10.100.xxx.xxx:7051 error: Error: 2 UNKNOWN: error validating proposal: access denied: channel [supplychain] creator org [ORG2MSP]
2021-02-25T10:21:33.738Z - error: [Endorser]: sendProposal[peer1.peers.org2.com] - rejecting with: Error: 2 UNKNOWN: error validating proposal: access denied: channel [supplychain] creator org [ORG2MSP]
2021-02-25T10:21:33.738Z - error: [SingleQueryHandler]: evaluate: message=Query failed. Errors: ["Error: 2 UNKNOWN: error validating proposal: access denied: channel [supplychain] creator org [ORG2MSP]"], stack=FabricError: Query failed. Errors: ["Error: 2 UNKNOWN: error validating proposal: access denied: channel [supplychain] creator org [ORG2MSP]"]
    at SingleQueryHandler.evaluate (/fabric23/node_modules/fabric-network/lib/impl/query/singlequeryhandler.js:47:23)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
    at async Transaction.evaluate (/fabric23/node_modules/fabric-network/lib/transaction.js:276:25)
    at async main (/fabric23/test.js:67:25), name=FabricError
Failed to evaluate transaction: FabricError: Query failed. Errors: ["Error: 2 UNKNOWN: error validating proposal: access denied: channel [supplychain] creator org [ORG2MSP]"]

Org2 peer logs

2021-02-25 10:21:33.732 UTC [endorser] Validate -> WARN 08f access denied: creator's signature over the proposal is not valid: The signature is invalid channel=supplychain txID=01bde838 mspID=ORG2MSP
2021-02-25 10:21:33.732 UTC [comm.grpc.server] 1 -> INFO 090 unary call completed grpc.service=protos.Endorser grpc.method=ProcessProposal grpc.peer_address=172.23.238.200:40928 grpc.peer_subject="CN=*.peers.org3.com,OU=org3client,O=MyCompany Inc.,L=XXXX,ST=XXXX,C=XX" error="error validating proposal: access denied: channel [supplychain] creator org [ORG2MSP]" grpc.code=Unknown grpc.call_duration=12.335491ms

Org3 peer logs

2021-02-26 13:42:26.081 UTC [gossip.channel] publishStateInfo -> DEBU 6155d8 Empty membership, no one to publish state info to
2021-02-26 13:42:26.493 UTC [core.comm] ServerHandshake -> DEBU 6155d9 Server TLS handshake completed in 49.605106ms server=PeerServer remoteaddress=public.ip.address:291542021-02-26 13:42:26.597 UTC [grpc] InfoDepth -> DEBU 6155da [transport]transport: loopyWriter.run returning. connection error: desc = "transport is closing"
2021-02-26 13:42:26.927 UTC [gossip.channel] publishStateInfo -> DEBU 6155db Empty membership, no one to publish state info to

I have also tried deploying the same code on the docker swarm on the azure vm. But there it gives the same error what I was getting when I was using the wrong certificate as given in the SO post here

SOUPTIK BANERJEE
  • 143
  • 3
  • 10

1 Answers1

0

Some points you may check:

  • the peer server TLS cert of your org3 should have an alternative name like "*.ip.adress"?
  • the channel has all 3 orgs right? From logs of org2 I see "creator's signature over the proposal is not valid"
  • Check the user identity "usernew" PKI (not the TLS) to make sure the CA that issued the cert is one of the CA MSP on the channel. If you use intermediate CA those CAs certs should be also on the channel.

Best Regards, Tsvetan

  • Hi Tsvetan. I checked the points you mentioned above – SOUPTIK BANERJEE Mar 05 '21 at 07:45
  • 1. In the post body above you can see I have given the TLS cert for org2. The certificate looks similar to that of org3. In the SAN section of the certificate we have given the DNS of that peer org. When you say "*.ip.adress" do you mean the ip address of the azure vm, or the peer container in the vm or the nginx proxy server ip? 2. The channel has all 3 orgs and they work properly for transactions executed from the CLI 3. The intermediate CA cert is part of the channel. – SOUPTIK BANERJEE Mar 05 '21 at 07:54
  • I execute commands from the org2 cli using these certificates `--tls $CORE_PEER_TLS_ENABLED --cafile /var/hyperledger/msp/tlsintermediatecerts/ica.pem --certfile /var/hyperledger/tls/server.crt --clientauth --keyfile /var/hyperledger/tls/server.key -C supplychain -n mycontract --peerAddresses $CORE_PEER_ADDRESS --peerAddresses peer1.peers.org1.com:7051 --peerAddresses peer1.peers.org3.com:7051 --tlsRootCertFiles /var/hyperledger/tls/ca.crt --tlsRootCertFiles /var/hyperledger/tls/ca.crt --tlsRootCertFiles /var/hyperledger/tls/ca.crt` same for the org3 cli, only the --peerAddresses list changes – SOUPTIK BANERJEE Mar 05 '21 at 08:57
  • So when you run a CLI command on behalf of each of the 3 orgs it works fine? Few more things 1) you may have a separate connection profile for each org. Just configure the peer of the org of your client. Let the Service Discovery deal with the rest. Of course you have to setup properly your TLS certs to avoid ssl-override 2) I see you have the same tlsCACerts file for the peers of the 3 orgs.. does it mean you use the same CA to issue the TLS certificates (in real life those will be 3 different CAs). Does this file contain all TLS CA servers certs? I see in the CLI you use a different one. – Tsvetan Georgiev Mar 08 '21 at 03:53
  • Yes the CLI commands from all 3 orgs works perfectly with or without endorsement policy on the chaincode. 1. I have separate connection profiles for all orgs but haven't deployed the rest of the APIs yet. I want to get atleast the one from org2 to work so that I can apply the learnings and changes to the rest. I have tried deploying one api in the VM node but it is not able to connect to any of the peers. Not even the peer of that org itself. Regarding the service discovery, i don't believe we have deployed/enabled that assuming that it is a separate component that needs to be deployed. – SOUPTIK BANERJEE Mar 10 '21 at 06:33
  • 2. Yes we use the same CA to issue the TLS certs for all 3 orgs. That CA is our company's intermediate CA that is in turn signed by the company's root CA. In case of CLI commands I use the intermediate CA and it works fine. In case of the APIs the intermediate CA itself wasn't working so in the SO post mentioned in the main post, it was suggested to use a certificate chain of the intermediate and root cert. Having done that the APIs stopped throwing the connection error. The error that I was getting when using the wrong cert in org2 is now coming in org3(vm) node pod with the same cert setup. – SOUPTIK BANERJEE Mar 10 '21 at 07:04
  • 1. The service discovery is running on the peers and the client can consume it through the SDKs or CLI. There is no need to deploy it explicitly it should be enabled by default unless you turn it off on the peer. 2. As all your TLS certs are the same across peers and orgs then you should be able to establish a TLS connection properly as soon the ssl host override is set correctly. IF your CLI works for all 3 orgs then you SDK should work for all 3 orgs. Check what is different in parameters you pass. – Tsvetan Georgiev Mar 16 '21 at 02:01
  • The connections work from Org2 nodejs. But the log says "[endorser] Validate -> WARN 08f access denied: creator's signature over the proposal is not valid: The signature is invalid channel=supplychain txID=01bde838 mspID=ORG2MSP" – SOUPTIK BANERJEE Mar 16 '21 at 05:00
  • Invalid signature usually means the user certificate is not issued by any of the organization on the channel. 1. Make sure the user cert is issued by an org that is on the channel. 2. Cross check that with the CA org certs on the channel. Mostly when I see such issue it is becuase I use wrong user cert (issued by a CA MSP that is not on the channel).. – Tsvetan Georgiev Mar 20 '21 at 18:49
  • I think we are using the correct certificate signed by the correct CA present in the channel and org because the same certificates work when being used in the CLI transactions. The only new part being used in the node sdk code is the wallet. How would you generate the wallet in this case where we are using certificates like ours? Currently I use the signcert and keystore from the Users/msp folder of that particular peer to generate the user identity and the server cert and key from the Users/tls folder to generate the tlsId. – SOUPTIK BANERJEE Mar 23 '21 at 11:12