Victor Van Doom
Victor Van Doom

Reputation: 103

Hyperledger Fabric - external chaincode with TLS from fabric-ca

I'm trying to setup Hyperledger Fabric using the new external chaincode service feature. Running the chaincode with the default configuration (no tls or peer authentication) works as expected.

I've read quite a few tutorials about this topic, but they all only use self-signed certificates for this purpose - which is not very helpful since I am working on configuring a production system. I Would like to use the certificate authorities (fabric-ca-server) that are already running in my network and provide the certificates for my orderers, peers etc.

My question would be: How do I generate the root_cert as well as client_cert and client_key using my existing CA? There must be a way to do this using the fabric-ca-client. I've already tried to use the ca-certificate of my peer-organization, but that did not work (It does not seem to contain the hostname of the chaincode-service).

Thank you for your help.

UPDATE:

I've now tried to use the fabric-ca-client's register and enroll commands to register an identity and get myself an tls Enrollment-profile.

fabric-ca-client register --caname $CANAME --id.name chaincode --id.secret chainpw --tls.certfiles $certfile --loglevel error
fabric-ca-client enroll -u https://chaincode: chainpw@$CA_HOST_ADDRESS:$nodePort --caname $CANAME -M "$chainDir/msp" --csr.cn diplom-$validK8SHostName  --csr.hosts diplom-$validK8SHostName --tls.certfiles $certfile --loglevel error
fabric-ca-client enroll -u https://chaincode: chainpw@$CA_HOST_ADDRESS:$nodePort --caname $CANAME -M "$chainDir/tls" --enrollment.profile tls --csr.hosts diplom-$validK8SHostName --csr.hosts localhost --tls.certfiles $certfile --loglevel error

From the generated tls directory, I took the /signcerts/cert.pem and formatted it into single-line via awk 'NF {sub(/\r/, ""); printf "%s\\n",$0;}' ... and pasted it into the connection.json as root_cert.

Similarly I've copied the cert.pem file into the chaincode container and set the environment variable CORE_CHAINCODE_TLS_CLIENT_CACERT_FILE to point to this file. However, the peer still cannot connect to the container.

ClientHandshake -> ERRO 06c Client TLS handshake failed after 752.754µs with error: tls: first record does not look like a TLS handshake

Update 2:

Seems like I've set the wrong environment-variable on the chaincode service. CORE_CHAINCODE_TLS_CERT_FILE must be set to the generated /signcerts/cert.pem and CORE_CHAINCODE_TLS_KEY_FILE to private-key from /keystore.

The chaincode service seems to accept the certificates now, but the peer complains that they were signed by an unknown authority.

Update 3:

Another bit of progress. Seems like I made a mistake in the fabric-ca-client commands. I accidentally set the csr.cn parameter, thereby overwriting my CA hostname. With he following I was able to register my chaincode service with my CA and get the corresponding TLS certificates to be valid for my service and checkout with the organisations CA :-)

fabric-ca-client register --caname $CANAME --id.name $NAME --id.secret $PW --tls.certfiles $certfile --loglevel error
fabric-ca-client enroll -u https://$NAME:$PW@$CA_HOST_ADDRESS:$nodePort --caname $CANAME -M "$chainDir/msp" --csr.hosts chain-$validK8SHostName --tls.certfiles $certfile --loglevel error
fabric-ca-client enroll -u https://$NAME:$PW@$CA_HOST_ADDRESS:$nodePort --caname $CANAME -M "$chainDir/tls" --enrollment.profile tls --csr.hosts chain-$validK8SHostName --csr.hosts localhost --tls.certfiles $certfile --loglevel error

Upvotes: 2

Views: 658

Answers (4)

ravinayag
ravinayag

Reputation: 33

I renamed the files to sync with readme and followed to make it working by updating the connection.json and docker-compose-cc.yaml file

  cp ${PWD}/organizations/peerOrganizations/myorg1/chaincode/msp/signcerts/* ${PWD}/organizations/peerOrganizations/myorg1/chaincode/msp/client.crt
  cp ${PWD}/organizations/peerOrganizations/myorg1/chaincode/msp/keystore/* ${PWD}/organizations/peerOrganizations/myorg1/chaincode/msp/client.key

  cp ${PWD}/organizations/peerOrganizations/myorg1/chaincode/tls/keystore/* ${PWD}/organizations/peerOrganizations/myorg1/chaincode/tls/server.key
  cp ${PWD}/organizations/peerOrganizations/myorg1/chaincode/tls/signcerts/* ${PWD}/organizations/peerOrganizations/myorg1/chaincode/tls/server.crt
  cp ${PWD}/organizations/peerOrganizations/myorg1/chaincode/tls/tlscacerts/* ${PWD}/organizations/peerOrganizations/myorg1/chaincode/tls/root_ca.crt

Upvotes: 0

Calanais
Calanais

Reputation: 1580

For additional information, https://github.com/hyperledgendary/contract-as-a-service is an example repo that shows the chaincode as an external service.

The approach taken there is indeed what Victor has describe above, and is, AFAIK a good way to do this.

Upvotes: 1

Victor Van Doom
Victor Van Doom

Reputation: 103

Finally I was able to find an answer to my problem. As stated in my third update, I've used the fabric-ca-client to enrol an identity for my chaincode-service.

fabric-ca-client register --caname $CANAME --id.name $NAME --id.secret $PW --tls.certfiles $certfile --loglevel error
fabric-ca-client enroll -u https://$NAME:$PW@$CA_HOST_ADDRESS:$nodePort --caname $CANAME -M "$chainDir/msp" --csr.hosts chain-$validK8SHostName --tls.certfiles $certfile --loglevel error
fabric-ca-client enroll -u https://$NAME:$PW@$CA_HOST_ADDRESS:$nodePort --caname $CANAME -M "$chainDir/tls" --enrollment.profile tls --csr.hosts chain-$validK8SHostName --csr.hosts localhost --tls.certfiles $certfile --loglevel error

Pleas note that the validK8SHostName is simply the hostname of my container with the dots replaced by dashes (k8s does not allow dots in service or container names).

These commands generate an msp and tls folder in my chaindDir. The certificates/keys referenced as JSON-propeties are converted into single-line using awk 'NF {sub(/\r/, ""); printf "%s\\n",$0;}'. The environment variables of the chaincode container are the actual files (I've mounted them as secrets in my k8s cluster).

  • tls/signcerts -> Certificated needed for the "root_cert" property and the CORE_CHAINCODE_TLS_CERT_FILE env.
  • tls/keystore -> Private key that is set for the CORE_CHAINCODE_TLS_KEY_FILE env.
  • tls/tlscacerts -> Certificate needed for the CORE_CHAINCODE_TLS_CLIENT_CA_CERT_FILE env.
  • msp/signcert -> Certificate needed for the "client_cert" property.
  • msp/keystore -> Private key that is set for the "client_key" property

With the setup I can start chaincode containers that are TLS-terminated and only communicate with those peers, that have the corresponding Certificate and private-key combination. Thereby all certificates and keys are generated by my organisations CA.

Upvotes: 1

Clyde D'Cruz
Clyde D'Cruz

Reputation: 2065

The Fabric CA docs on initializing a CA server mentions:

The fabric-ca-server init command generates a self-signed CA certificate unless the -u <parent-fabric-ca-server-URL> option is specified. If the -u is specified, the server’s CA certificate is signed by the parent Fabric CA server. In order to authenticate to the parent Fabric CA server, the URL must be of the form <scheme>://<enrollmentID>:<secret>@<host>:<port>, where <enrollmentID> and <secret> correspond to an identity with an hf.IntermediateCA attribute whose value equals true.

It also says you can set a key and certificate file which has already been generated

If you want the Fabric CA server to use a CA signing certificate and key file which you provide, you must place your files in the location referenced by ca.certfile and ca.keyfile respectively. Both files must be PEM-encoded and must not be encrypted. More specifically, the contents of the CA certificate file must begin with -----BEGIN CERTIFICATE----- and the contents of the key file must begin with -----BEGIN PRIVATE KEY----- and not -----BEGIN ENCRYPTED PRIVATE KEY-----.

So if you already a CA server running, it should be possible to get a certificate signed by it or to create one and include it in your child CA

Upvotes: 0

Related Questions