diff --git a/docs/configuration.md b/docs/configuration.md index 0160aabf9..7d8301f39 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -389,6 +389,7 @@ fabric: # it is possible to customize per orderer the TLS behaviour, by using the following attributes tlsClientSideAuth: true tlsDisabled: true + # set to true to enable TLS for this orderer even if fabric..tls.enabled is false tlsEnabled: false # List of trusted peers this node can connect to. @@ -405,6 +406,7 @@ fabric: # it is possible to customize per peer the TLS behaviour, by using the following attributes tlsClientSideAuth: true tlsDisabled: true + # set to true to enable TLS for this peer even if fabric..tls.enabled is false tlsEnabled: false # `usage` allows the developer to specify the function for which this peer should be used. # The available functions are: delivery, discovery, finality, and query. diff --git a/platform/fabric/core/generic/config/service.go b/platform/fabric/core/generic/config/service.go index 21471a585..dce6197f4 100644 --- a/platform/fabric/core/generic/config/service.go +++ b/platform/fabric/core/generic/config/service.go @@ -84,8 +84,8 @@ func NewService(configService Configuration, name string, defaultConfig bool) (* return nil, err } for _, v := range orderers { - v.TLSEnabled = tlsEnabled - if tlsEnabled && len(v.TLSRootCertFile) > 0 { + v.TLSEnabled = effectiveTLSEnabled(tlsEnabled, v) + if v.TLSEnabled && len(v.TLSRootCertFile) > 0 { v.TLSRootCertFile = configService.TranslatePath(v.TLSRootCertFile) } } @@ -358,7 +358,7 @@ func createChannelMap(channels []*Channel) (map[string]*Channel, string, error) func createPeerMap(configService Configuration, peers []*ConnectionConfig, tlsEnabled bool) map[driver.PeerFunctionType][]*ConnectionConfig { peerMapping := map[driver.PeerFunctionType][]*ConnectionConfig{} for _, peerCC := range peers { - peerCC.TLSEnabled = tlsEnabled && !peerCC.TLSDisabled + peerCC.TLSEnabled = effectiveTLSEnabled(tlsEnabled, peerCC) if peerCC.TLSEnabled && len(peerCC.TLSRootCertFile) > 0 { peerCC.TLSRootCertFile = configService.TranslatePath(peerCC.TLSRootCertFile) } @@ -372,6 +372,14 @@ func createPeerMap(configService Configuration, peers []*ConnectionConfig, tlsEn return peerMapping } +func effectiveTLSEnabled(defaultEnabled bool, cc *ConnectionConfig) bool { + if cc.TLSDisabled { + return false + } + + return defaultEnabled || cc.TLSEnabled +} + func readItems[T any](configService Configuration, prefix, key string) ([]T, error) { var items []T if err := configService.UnmarshalKey(fmt.Sprintf("fabric.%s%s", prefix, key), &items); err != nil { diff --git a/platform/fabric/core/generic/config/service_test.go b/platform/fabric/core/generic/config/service_test.go index 51a9793f3..36fe94768 100644 --- a/platform/fabric/core/generic/config/service_test.go +++ b/platform/fabric/core/generic/config/service_test.go @@ -187,6 +187,102 @@ func TestCreatePeerMapAndPickPeer(t *testing.T) { require.NotNil(t, p) } +func TestNewService_honorsPerEndpointTLSEnabledOverride(t *testing.T) { + t.Parallel() + + m := &mock.Configuration{} + m.IsSetReturnsOnCall(0, true) + m.GetStringReturnsOnCall(0, "") + m.GetBoolReturns(false) // shared fabric..tls.enabled + m.TranslatePathStub = func(path string) string { + return "TR:" + path + } + m.UnmarshalKeyStub = func(key string, rawVal interface{}) error { + switch key { + case "fabric.test.peers", "fabric.testpeers": + p, ok := rawVal.(*[]*grpc.ConnectionConfig) + if !ok { + return nil + } + *p = []*grpc.ConnectionConfig{ + {Address: "p1", Usage: "query", TLSEnabled: true, TLSRootCertFile: "peer.pem"}, + {Address: "p2", Usage: "delivery"}, + } + return nil + case "fabric.test.orderers", "fabric.testorderers": + p, ok := rawVal.(*[]*grpc.ConnectionConfig) + if !ok { + return nil + } + *p = []*grpc.ConnectionConfig{{Address: "o1", TLSEnabled: true, TLSRootCertFile: "orderer.pem"}} + return nil + case "fabric.test.channels", "fabric.testchannels": + p, ok := rawVal.(*[]*cfg.Channel) + if !ok { + return nil + } + *p = []*cfg.Channel{{Name: "ch1"}} + return nil + } + return nil + } + + svc, err := cfg.NewService(m, "test", false) + require.NoError(t, err) + + orderer := svc.Orderers()[0] + require.True(t, orderer.TLSEnabled) + require.Equal(t, "TR:orderer.pem", orderer.TLSRootCertFile) + + peer := svc.PickPeer(driver.PeerForQuery) + require.NotNil(t, peer) + require.True(t, peer.TLSEnabled) + require.Equal(t, "TR:peer.pem", peer.TLSRootCertFile) +} + +func TestNewService_tlsDisabledOverridesGlobalAndEndpointTLS(t *testing.T) { + t.Parallel() + + m := &mock.Configuration{} + m.IsSetReturnsOnCall(0, true) + m.GetStringReturnsOnCall(0, "") + m.GetBoolReturns(true) // shared fabric..tls.enabled + m.UnmarshalKeyStub = func(key string, rawVal interface{}) error { + switch key { + case "fabric.test.peers", "fabric.testpeers": + p, ok := rawVal.(*[]*grpc.ConnectionConfig) + if !ok { + return nil + } + *p = []*grpc.ConnectionConfig{ + {Address: "p1", Usage: "query", TLSEnabled: true, TLSDisabled: true, TLSRootCertFile: "peer.pem"}, + } + return nil + case "fabric.test.orderers", "fabric.testorderers": + p, ok := rawVal.(*[]*grpc.ConnectionConfig) + if !ok { + return nil + } + *p = []*grpc.ConnectionConfig{{Address: "o1", TLSEnabled: true, TLSDisabled: true, TLSRootCertFile: "orderer.pem"}} + return nil + case "fabric.test.channels", "fabric.testchannels": + p, ok := rawVal.(*[]*cfg.Channel) + if !ok { + return nil + } + *p = []*cfg.Channel{{Name: "ch1"}} + return nil + } + return nil + } + + svc, err := cfg.NewService(m, "test", false) + require.NoError(t, err) + + require.False(t, svc.Orderers()[0].TLSEnabled) + require.False(t, svc.PickPeer(driver.PeerForQuery).TLSEnabled) +} + func TestPickOrderer_nilAndSetConfigOrderers(t *testing.T) { t.Parallel() m := &mock.Configuration{}