Skip to content

Handle TLS between Peer and CouchDB#5506

Open
mffrench wants to merge 1 commit into
hyperledger:mainfrom
mffrench:handleTLSBetweenPeerAndCouchDB
Open

Handle TLS between Peer and CouchDB#5506
mffrench wants to merge 1 commit into
hyperledger:mainfrom
mffrench:handleTLSBetweenPeerAndCouchDB

Conversation

@mffrench

Copy link
Copy Markdown
Contributor

Add TLS Support for Peer-to-CouchDB Connections

Type of change

  • New feature

Description

This pull request adds native TLS support for connections between Hyperledger Fabric Peers and CouchDB state databases, addressing a critical security vulnerability where all peer-to-CouchDB communication was previously unencrypted.

Problem:
Currently, Fabric peers connect to CouchDB using unencrypted HTTP connections, exposing CouchDB authentication credentials (transmitted in plaintext via HTTP Basic Auth) and the complete blockchain world state data. While documentation recommends co-locating peers and CouchDB on the same VM, this is insufficient for modern cloud-native deployments, particularly in Kubernetes environments where network traffic can be monitored by cloud provider administrators or untrusted parties.

Solution:
This PR implements comprehensive TLS support with server certificate verification, configurable TLS settings, and TLS 1.3 minimum version enforcement. The implementation is backward compatible (TLS disabled by default) and includes proper error handling and security logging.

Key Changes:

  • Extended CouchDBConfig structure with TLS fields (TLSEnabled, TLSCACertFile, TLSSkipVerify)
  • Modified createCouchInstance() to support HTTPS scheme when TLS is enabled
  • Added loadTLSConfig() function for TLS configuration and certificate loading
  • Fixed couchInstance.url() method to return https:// when TLS is enabled
  • Added configuration mappings and environment variable support
  • Updated sample configuration with TLS settings
  • Added comprehensive documentation for TLS setup

Configuration Example:

ledger:
  state:
    stateDatabase: CouchDB
    couchDBConfig:
      couchDBAddress: couchdb.example.com:6984
      username: admin
      password: adminpw
      tls:
        enabled: true
        caFile: /path/to/ca-cert.pem
        skipVerify: false

Security Impact:

  • Encrypts all peer-to-CouchDB communication
  • Protects CouchDB credentials from network sniffing
  • Prevents unauthorized access to blockchain world state data
  • Enables compliance with data protection regulations (GDPR, PCI-DSS, HIPAA, SOC 2)

Additional details

Testing:

  • Verified TLS connection establishment with valid certificates
  • Tested CA certificate loading and validation
  • Confirmed proper error handling for invalid certificates
  • Validated configuration parsing and environment variable mappings
  • Tested backward compatibility with TLS disabled
  • Verified logging output for security warnings

Implementation Notes:

  • Uses Go's standard crypto/tls package
  • TLS configuration loaded once during peer startup for efficiency
  • HTTP client and transport reused across all CouchDB operations (thread-safe)
  • Comprehensive logging for troubleshooting
  • Minimum TLS 1.3 enforcement for security best practices

Migration Path:
Existing deployments can migrate to TLS by:

  1. Configuring CouchDB with TLS certificates
  2. Updating peer configuration to enable TLS
  3. Restarting the peer (no data migration required)

Related issues

Addresses security vulnerability: Lack of TLS support for peer-to-CouchDB connections exposes sensitive ledger data in cloud/Kubernetes deployments.

Release Note

Added TLS support for peer-to-CouchDB connections to encrypt communication and protect sensitive ledger data. New configuration options allow peers to connect to CouchDB over HTTPS with server certificate verification. This feature is particularly important for cloud-native and Kubernetes deployments where network traffic may be accessible to untrusted parties. TLS is disabled by default for backward compatibility. See documentation for configuration details and migration guidance.

@mffrench
mffrench requested review from a team as code owners June 24, 2026 15:19
@mffrench
mffrench force-pushed the handleTLSBetweenPeerAndCouchDB branch 2 times, most recently from db27c61 to 5d7ea9c Compare June 24, 2026 15:26
@pfi79

pfi79 commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

@mffrench Please tell me, did you use AI to generate the changes?

@mffrench

mffrench commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

@pfi79 : I used AI and reviewed/tested by myself and team (so more human than AI still) ...

but AI still very usefull for documenting I think...

Comment thread sampleconfig/core.yaml
@mffrench
mffrench force-pushed the handleTLSBetweenPeerAndCouchDB branch 2 times, most recently from bc997eb to 006e60d Compare June 30, 2026 11:32
Signed-off-by: Mathilde Ffrench <mathilde.ffrench@fr.ibm.com>
@mffrench
mffrench force-pushed the handleTLSBetweenPeerAndCouchDB branch from 006e60d to 083806d Compare June 30, 2026 11:33
@pfi79

pfi79 commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

@pfi79 : I used AI and reviewed/tested by myself and team (so more human than AI still) ...

but AI still very usefull for documenting I think...

Yes, I see that you have modified sampleconfig/core.yaml. Thank you.
The fact is that if a human had done this, they would never have allowed the deletion of a part of the sampleconfig/core.yaml file without explanation.
I came to the conclusion that the AI made the change, but the person who created the PR did not check it.

@mffrench

mffrench commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

@pfi79 : I used AI and reviewed/tested by myself and team (so more human than AI still) ...
but AI still very usefull for documenting I think...

Yes, I see that you have modified sampleconfig/core.yaml. Thank you. The fact is that if a human had done this, they would never have allowed the deletion of a part of the sampleconfig/core.yaml file without explanation. I came to the conclusion that the AI made the change, but the person who created the PR did not check it.

@pfi79 : well I'm not sure. It could be myself while I was reporting some changes... I didn't found that change in my initial PR in our own Fabric fork... Any other feedbacks which can help improve that PR to make it merged ?

@jimthematrix

Copy link
Copy Markdown
Contributor

This is a reasonable requirement and the code updates look pretty good to me. Any chance one of the existing committers can help with review/approve and merge it?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From where, from which page, will the user have to go here?
So far, this documentation page is not linked anywhere.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know... Maybe should it be accessible the same way https://github.com/hyperledger/fabric/blob/main/docs/source/couchdb_tutorial.rst is accessed by the user maybe ? Note however I acceded that doc by browsing docs/source directory only. I didn't know each doc in there was linked to some main doc and I'll be interested to know where is that main doc.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See. Documentation is generated from the docs folder. And by searching or clicking on links, you can get to every page. The search is OK, let's leave it. But clicking on the links is necessary.

In other words, there must be a transition from somewhere to the page you are creating. This means that you need to add a link to your page to an existing page.

Look around, there are many examples.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, you can add changes to the documentation to an existing page. Maybe shorten the text.
Sorry, I haven't read the gist of the documentation yet.

Comment thread sampleconfig/core.yaml
Comment on lines +727 to +740
# TLS configuration for CouchDB connection
tls:
# Enable TLS for CouchDB connection (default: false)
# When enabled, the peer will use HTTPS to connect to CouchDB
# Environment variable: CORE_LEDGER_STATE_COUCHDBCONFIG_TLS_ENABLED
enabled: false
# Path to CA certificate file for verifying the CouchDB server certificate
# If not provided, the system's default CA certificate pool will be used.
# Environment variable: CORE_LEDGER_STATE_COUCHDBCONFIG_TLS_CACERTFILE
caCertFile:
# Skip server certificate verification (default: false)
# WARNING: This is insecure and should only be used for testing purposes.
# Environment variable: CORE_LEDGER_STATE_COUCHDBCONFIG_TLS_SKIPVERIFY
skipVerify: false

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tls setting style already exists in the project (see core.yaml and orderer.yaml). Try to do it in the same style. If this is not possible, please explain why.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand the setting style you're speaking about. Here we want to set client TLS only to the couchdb and not both client & server. Is it the caCertFile: you would like to change to something like:

    # X.509 certificate used for TLS when making client connections.
    # If not set, peer.tls.cert.file will be used instead
    clientCert:
      file:

?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or is it the skyVerify you would like to remove ? I would say that can be an interesting option for some setups and I would advocate to keep it.

tls.enabled looks already be reused from the 'tls style' ...

Back to my previous comment about the caCertFile: clientCert example is not equivalent here. This the client certificate of the TLS client, not the certificate of the CA trusting the couchdb TLS identity. Also, we dont need Couchdb Client TLS identity because CouchDB doesn't handle mTLS. So finally I would tend to keep it that way.

Can you be please a bit more explicit if you think there is a blocker on the current proposal ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are some examples. If you look closely, they are all made in the same style, both clients and servers. I would like your change to be similar to these.
Sorry, I don't really like variety.

example of a tls section in core.yaml

  # TLS configuration for the operations endpoint
  tls:
    # TLS enabled
    enabled: false

    # path to PEM encoded server certificate for the operations server
    # The paths in this section may be relative to FABRIC_CFG_PATH or an absolute path.
    cert:
      file:

    # path to PEM encoded server key for the operations server
    key:
      file:

    # most operations service endpoints require client authentication when TLS
    # is enabled. clientAuthRequired requires client certificate authentication
    # at the TLS layer to access all resources.
    clientAuthRequired: false

    # paths to PEM encoded ca certificates to trust for client authentication
    clientRootCAs:
      files: []

example of tls section in orderer.yaml

  # TLS configuration for the admin endpoint
  TLS:
    # TLS enabled
    Enabled: false

    # Certificate is the location of the PEM encoded TLS certificate
    Certificate:

    # PrivateKey points to the location of the PEM-encoded key
    PrivateKey:

    # Most admin service endpoints require client authentication when TLS
    # is enabled. ClientAuthRequired requires client certificate authentication
    # at the TLS layer to access all resources.
    #
    # NOTE: When TLS is enabled, the admin endpoint requires mutual TLS. The
    # orderer will panic on startup if this value is set to false.
    ClientAuthRequired: true

    # Paths to PEM encoded ca certificates to trust for client authentication
    ClientRootCAs: []

tls example from osnadmin

	if *caFile != "" {
		osnURL = fmt.Sprintf("https://%s", *orderer)
		var err error
		caCertPool = x509.NewCertPool()
		caFilePEM, err := os.ReadFile(*caFile)
		if err != nil {
			return "", 1, fmt.Errorf("reading orderer CA certificate: %s", err)
		}
		if !caCertPool.AppendCertsFromPEM(caFilePEM) {
			return "", 1, errors.New("failed to add ca-file PEM to cert pool")
		}

		tlsClientCert, err = tls.LoadX509KeyPair(*clientCert, *clientKey)
		if err != nil {
			return "", 1, fmt.Errorf("loading client cert/key pair: %s", err)
		}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did read these examples already but I'm personally not agree to add configuration complexity on a use case which is much more simpler than Peer and Order TLS setup which handle both server TLS setup and client mTLS setup. HLF Peer to CouchDB connection is about configuring a client on the Peer for a simple TLS connection to a CouchDB server (and with no mTLS as CouchDB doesn't handle it).

Again, here we are configuring an HTTPs client only and we are requiring only 2 mandatory param:

		TLSEnabled:  wether or not we activate TLS between CouchDB & Peer
		TLSCACertFile:  the CA cert file of the _CouchDB_ server to make work TLS handshake

The last one is to reduce complexity on dev environment in some scenario :

		TLSSkipVerify:         viper.GetBool("ledger.state.couchDBConfig.tls.skipVerify"),

I dont see reasonable rational to add extra params & complexity to follow some examples which do not match the use case.

While I understand you don't like variety, please understand I don't like adding useless complexity : please explain the rational to increase code change complexity in that use case.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fabric is a very complex system.
In my opinion, adding a new tls assignment method, unlike the previous methods, complicates the entire system.
And I think it's ugly, but monotonous.

scheme := "http"
if config.TLSEnabled {
scheme = "https"
couchdbLogger.Info("TLS is enabled for CouchDB connection")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have 6 places in the code where INFO level logging is used. Consider making them DEBUG

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will do

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants