Search code examples
sslhyperledger-fabrichyperledgerhyperledger-chaincodehyperledger-fabric-ca

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

Solution

  • 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.