Skip to content

Commit e90b92b

Browse files
committed
[FAB-6716] Enabled mutual TLS support for orderer
The orderer currently supports the ability to require mutual TLS, however it only uses a static list of root CAs to validate client certificates. In order to support the dynamic membership capabilities of channels, the trusted client roots for the gRPC server need to be updated whenever channel membership is changed. Also need to modify a core/peer test as a TLS intermediate root was added to the sampleconfig for completeness Change-Id: I4eccfd88ff7b86621b356e9f880062f98c425c60 Signed-off-by: Gari Singh <gari.r.singh@gmail.com>
1 parent 2c1a126 commit e90b92b

File tree

10 files changed

+288
-60
lines changed

10 files changed

+288
-60
lines changed

core/peer/pkg_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ func TestUpdateRootsFromConfigBlock(t *testing.T) {
243243
createChannel: func() { createChannel("channel1", channel1Block) },
244244
goodOptions: []grpc.DialOption{grpc.WithTransportCredentials(org1Creds)},
245245
badOptions: []grpc.DialOption{grpc.WithTransportCredentials(ordererOrgCreds)},
246-
numAppCAs: 2, // each channel also has a DEFAULT MSP
246+
numAppCAs: 3, // each channel also has a DEFAULT MSP
247247
numOrdererCAs: 1,
248248
},
249249
{
@@ -261,7 +261,7 @@ func TestUpdateRootsFromConfigBlock(t *testing.T) {
261261
grpc.WithTransportCredentials(org2Creds)},
262262
badOptions: []grpc.DialOption{
263263
grpc.WithTransportCredentials(ordererOrgCreds)},
264-
numAppCAs: 4,
264+
numAppCAs: 6,
265265
numOrdererCAs: 2,
266266
},
267267
{
@@ -279,7 +279,7 @@ func TestUpdateRootsFromConfigBlock(t *testing.T) {
279279
grpc.WithTransportCredentials(org2IntermediateCreds)},
280280
badOptions: []grpc.DialOption{
281281
grpc.WithTransportCredentials(ordererOrgCreds)},
282-
numAppCAs: 7,
282+
numAppCAs: 10,
283283
numOrdererCAs: 3,
284284
},
285285
}

orderer/common/multichannel/registrar.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ type Registrar struct {
103103
systemChannelID string
104104
systemChannel *ChainSupport
105105
templator msgprocessor.ChannelConfigTemplator
106+
callbacks []func(bundle *channelconfig.Bundle)
106107
}
107108

108109
func getConfigTx(reader ledger.Reader) *cb.Envelope {
@@ -120,12 +121,14 @@ func getConfigTx(reader ledger.Reader) *cb.Envelope {
120121
}
121122

122123
// NewRegistrar produces an instance of a *Registrar.
123-
func NewRegistrar(ledgerFactory ledger.Factory, consenters map[string]consensus.Consenter, signer crypto.LocalSigner) *Registrar {
124+
func NewRegistrar(ledgerFactory ledger.Factory, consenters map[string]consensus.Consenter,
125+
signer crypto.LocalSigner, callbacks ...func(bundle *channelconfig.Bundle)) *Registrar {
124126
r := &Registrar{
125127
chains: make(map[string]*ChainSupport),
126128
ledgerFactory: ledgerFactory,
127129
consenters: consenters,
128130
signer: signer,
131+
callbacks: callbacks,
129132
}
130133

131134
existingChains := ledgerFactory.ChainIDs()
@@ -258,8 +261,10 @@ func (r *Registrar) newLedgerResources(configTx *cb.Envelope) *ledgerResources {
258261
}
259262

260263
return &ledgerResources{
261-
configResources: &configResources{mutableResources: channelconfig.NewBundleSource(bundle)},
262-
ReadWriter: ledger,
264+
configResources: &configResources{
265+
mutableResources: channelconfig.NewBundleSource(bundle, r.callbacks...),
266+
},
267+
ReadWriter: ledger,
263268
}
264269
}
265270

orderer/common/server/main.go

Lines changed: 111 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ import (
1414
_ "net/http/pprof" // This is essentially the main package for the orderer
1515
"os"
1616

17+
"github.com/hyperledger/fabric/common/channelconfig"
1718
"github.com/hyperledger/fabric/common/crypto"
1819
"github.com/hyperledger/fabric/common/flogging"
1920
"github.com/hyperledger/fabric/common/tools/configtxgen/encoder"
2021
genesisconfig "github.com/hyperledger/fabric/common/tools/configtxgen/localconfig"
2122
"github.com/hyperledger/fabric/core/comm"
23+
"github.com/hyperledger/fabric/msp"
2224
"github.com/hyperledger/fabric/orderer/common/bootstrap/file"
2325
"github.com/hyperledger/fabric/orderer/common/ledger"
2426
"github.com/hyperledger/fabric/orderer/common/localconfig"
@@ -75,14 +77,27 @@ func Main() {
7577
// Start provides a layer of abstraction for benchmark test
7678
func Start(cmd string, conf *config.TopLevel) {
7779
signer := localmsp.NewSigner()
78-
manager := initializeMultichannelRegistrar(conf, signer)
80+
secureConfig := initializeSecureServerConfig(conf)
81+
grpcServer := initializeGrpcServer(conf, secureConfig)
82+
caSupport := &comm.CASupport{
83+
AppRootCAsByChain: make(map[string][][]byte),
84+
OrdererRootCAsByChain: make(map[string][][]byte),
85+
ClientRootCAs: secureConfig.ClientRootCAs,
86+
}
87+
tlsCallback := func(bundle *channelconfig.Bundle) {
88+
// only need to do this if mutual TLS is required
89+
if grpcServer.MutualTLSRequired() {
90+
logger.Debug("Executing callback to update root CAs")
91+
updateTrustedRoots(grpcServer, caSupport, bundle)
92+
}
93+
}
94+
manager := initializeMultichannelRegistrar(conf, signer, tlsCallback)
7995
server := NewServer(manager, signer, &conf.Debug)
8096

8197
switch cmd {
8298
case start.FullCommand(): // "start" command
8399
logger.Infof("Starting %s", metadata.GetVersionInfo())
84100
initializeProfilingService(conf)
85-
grpcServer := initializeGrpcServer(conf)
86101
ab.RegisterAtomicBroadcastServer(grpcServer.Server(), server)
87102
logger.Info("Beginning to serve requests")
88103
grpcServer.Start()
@@ -119,7 +134,7 @@ func initializeSecureServerConfig(conf *config.TopLevel) comm.SecureServerConfig
119134
}
120135
// check to see if TLS is enabled
121136
if secureConfig.UseTLS {
122-
logger.Info("Starting orderer with TLS enabled")
137+
msg := "TLS"
123138
// load crypto material from files
124139
serverCertificate, err := ioutil.ReadFile(conf.General.TLS.Certificate)
125140
if err != nil {
@@ -149,11 +164,13 @@ func initializeSecureServerConfig(conf *config.TopLevel) comm.SecureServerConfig
149164
}
150165
clientRootCAs = append(clientRootCAs, root)
151166
}
167+
msg = "mutual TLS"
152168
}
153169
secureConfig.ServerKey = serverKey
154170
secureConfig.ServerCertificate = serverCertificate
155171
secureConfig.ServerRootCAs = serverRootCAs
156172
secureConfig.ClientRootCAs = clientRootCAs
173+
logger.Infof("Starting orderer with %s enabled", msg)
157174
}
158175
return secureConfig
159176
}
@@ -186,9 +203,7 @@ func initializeBootstrapChannel(conf *config.TopLevel, lf ledger.Factory) {
186203
}
187204
}
188205

189-
func initializeGrpcServer(conf *config.TopLevel) comm.GRPCServer {
190-
secureConfig := initializeSecureServerConfig(conf)
191-
206+
func initializeGrpcServer(conf *config.TopLevel, secureConfig comm.SecureServerConfig) comm.GRPCServer {
192207
lis, err := net.Listen("tcp", fmt.Sprintf("%s:%d", conf.General.ListenAddress, conf.General.ListenPort))
193208
if err != nil {
194209
logger.Fatal("Failed to listen:", err)
@@ -211,7 +226,8 @@ func initializeLocalMsp(conf *config.TopLevel) {
211226
}
212227
}
213228

214-
func initializeMultichannelRegistrar(conf *config.TopLevel, signer crypto.LocalSigner) *multichannel.Registrar {
229+
func initializeMultichannelRegistrar(conf *config.TopLevel, signer crypto.LocalSigner,
230+
callbacks ...func(bundle *channelconfig.Bundle)) *multichannel.Registrar {
215231
lf, _ := createLedgerFactory(conf)
216232
// Are we bootstrapping?
217233
if len(lf.ChainIDs()) == 0 {
@@ -224,5 +240,92 @@ func initializeMultichannelRegistrar(conf *config.TopLevel, signer crypto.LocalS
224240
consenters["solo"] = solo.New()
225241
consenters["kafka"] = kafka.New(conf.Kafka)
226242

227-
return multichannel.NewRegistrar(lf, consenters, signer)
243+
return multichannel.NewRegistrar(lf, consenters, signer, callbacks...)
244+
}
245+
246+
func updateTrustedRoots(srv comm.GRPCServer, rootCASupport *comm.CASupport,
247+
cm channelconfig.Resources) {
248+
rootCASupport.Lock()
249+
defer rootCASupport.Unlock()
250+
251+
appRootCAs := [][]byte{}
252+
ordererRootCAs := [][]byte{}
253+
appOrgMSPs := make(map[string]struct{})
254+
ordOrgMSPs := make(map[string]struct{})
255+
256+
if ac, ok := cm.ApplicationConfig(); ok {
257+
//loop through app orgs and build map of MSPIDs
258+
for _, appOrg := range ac.Organizations() {
259+
appOrgMSPs[appOrg.MSPID()] = struct{}{}
260+
}
261+
}
262+
263+
if ac, ok := cm.OrdererConfig(); ok {
264+
//loop through orderer orgs and build map of MSPIDs
265+
for _, ordOrg := range ac.Organizations() {
266+
ordOrgMSPs[ordOrg.MSPID()] = struct{}{}
267+
}
268+
}
269+
270+
cid := cm.ConfigtxManager().ChainID()
271+
logger.Debugf("updating root CAs for channel [%s]", cid)
272+
msps, err := cm.MSPManager().GetMSPs()
273+
if err != nil {
274+
logger.Errorf("Error getting root CAs for channel %s (%s)", cid, err)
275+
}
276+
if err == nil {
277+
for k, v := range msps {
278+
// check to see if this is a FABRIC MSP
279+
if v.GetType() == msp.FABRIC {
280+
for _, root := range v.GetTLSRootCerts() {
281+
// check to see of this is an app org MSP
282+
if _, ok := appOrgMSPs[k]; ok {
283+
logger.Debugf("adding app root CAs for MSP [%s]", k)
284+
appRootCAs = append(appRootCAs, root)
285+
}
286+
// check to see of this is an orderer org MSP
287+
if _, ok := ordOrgMSPs[k]; ok {
288+
logger.Debugf("adding orderer root CAs for MSP [%s]", k)
289+
ordererRootCAs = append(ordererRootCAs, root)
290+
}
291+
}
292+
for _, intermediate := range v.GetTLSIntermediateCerts() {
293+
// check to see of this is an app org MSP
294+
if _, ok := appOrgMSPs[k]; ok {
295+
logger.Debugf("adding app root CAs for MSP [%s]", k)
296+
appRootCAs = append(appRootCAs, intermediate)
297+
}
298+
// check to see of this is an orderer org MSP
299+
if _, ok := ordOrgMSPs[k]; ok {
300+
logger.Debugf("adding orderer root CAs for MSP [%s]", k)
301+
ordererRootCAs = append(ordererRootCAs, intermediate)
302+
}
303+
}
304+
}
305+
}
306+
rootCASupport.AppRootCAsByChain[cid] = appRootCAs
307+
rootCASupport.OrdererRootCAsByChain[cid] = ordererRootCAs
308+
309+
// now iterate over all roots for all app and orderer chains
310+
trustedRoots := [][]byte{}
311+
for _, roots := range rootCASupport.AppRootCAsByChain {
312+
trustedRoots = append(trustedRoots, roots...)
313+
}
314+
for _, roots := range rootCASupport.OrdererRootCAsByChain {
315+
trustedRoots = append(trustedRoots, roots...)
316+
}
317+
// also need to append statically configured root certs
318+
if len(rootCASupport.ClientRootCAs) > 0 {
319+
trustedRoots = append(trustedRoots, rootCASupport.ClientRootCAs...)
320+
}
321+
322+
// now update the client roots for the gRPC server
323+
err := srv.SetClientRootCAs(trustedRoots)
324+
if err != nil {
325+
msg := "Failed to update trusted roots for orderer from latest config " +
326+
"block. This orderer may not be able to communicate " +
327+
"with members of channel %s (%s)"
328+
logger.Warningf(msg, cm.ConfigtxManager().ChainID(), err)
329+
}
330+
}
228331
}

0 commit comments

Comments
 (0)