Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FAB-18188] Log orderer and peer cert expiration date upon startup (bp #1804) #1806

Merged
merged 1 commit into from
Aug 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions common/crypto/expiration.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,35 +41,35 @@ func certExpirationTime(pemBytes []byte) time.Time {
return cert.NotAfter
}

// WarnFunc notifies a warning happened with the given format, and can be replaced with Warnf of a logger.
type WarnFunc func(format string, args ...interface{})
// MessageFunc notifies a message happened with the given format, and can be replaced with Warnf or Infof of a logger.
type MessageFunc func(format string, args ...interface{})

// Scheduler invokes f after d time, and can be replaced with time.AfterFunc.
type Scheduler func(d time.Duration, f func()) *time.Timer

// TrackExpiration warns a week before one of the certificates expires
func TrackExpiration(tls bool, serverCert []byte, clientCertChain [][]byte, sIDBytes []byte, warn WarnFunc, now time.Time, s Scheduler) {
func TrackExpiration(tls bool, serverCert []byte, clientCertChain [][]byte, sIDBytes []byte, info MessageFunc, warn MessageFunc, now time.Time, s Scheduler) {
sID := &msp.SerializedIdentity{}
if err := proto.Unmarshal(sIDBytes, sID); err != nil {
return
}

trackCertExpiration(sID.IdBytes, "enrollment", warn, now, s)
trackCertExpiration(sID.IdBytes, "enrollment", info, warn, now, s)

if !tls {
return
}

trackCertExpiration(serverCert, "server TLS", warn, now, s)
trackCertExpiration(serverCert, "server TLS", info, warn, now, s)

if len(clientCertChain) == 0 || len(clientCertChain[0]) == 0 {
return
}

trackCertExpiration(clientCertChain[0], "client TLS", warn, now, s)
trackCertExpiration(clientCertChain[0], "client TLS", info, warn, now, s)
}

func trackCertExpiration(rawCert []byte, certRole string, warn WarnFunc, now time.Time, sched Scheduler) {
func trackCertExpiration(rawCert []byte, certRole string, info MessageFunc, warn MessageFunc, now time.Time, sched Scheduler) {
expirationTime := certExpirationTime(rawCert)
if expirationTime.IsZero() {
// If the certificate expiration time cannot be classified, return.
Expand All @@ -84,6 +84,8 @@ func trackCertExpiration(rawCert []byte, certRole string, warn WarnFunc, now tim
return
}

info("The %s certificate will expire on %s", certRole, expirationTime)

if timeLeftUntilExpiration < oneWeek {
days := timeLeftUntilExpiration / (time.Hour * 24)
hours := (timeLeftUntilExpiration - (days * time.Hour * 24)) / time.Hour
Expand All @@ -96,6 +98,7 @@ func trackCertExpiration(rawCert []byte, certRole string, warn WarnFunc, now tim
sched(timeLeftUntilOneWeekBeforeExpiration, func() {
warn("The %s certificate will expire within one week", certRole)
})

}

var (
Expand Down
96 changes: 61 additions & 35 deletions common/crypto/expiration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"fmt"
"io/ioutil"
"path/filepath"
"strings"
"testing"
"time"

Expand Down Expand Up @@ -91,73 +92,90 @@ func TestTrackExpiration(t *testing.T) {
IdBytes: tlsCert.Cert,
})

shouldNotBeInvoked := func(format string, args ...interface{}) {
warnShouldNotBeInvoked := func(format string, args ...interface{}) {
t.Fatalf(format, args...)
}

var formattedWarning string
shouldBeInvoked := func(format string, args ...interface{}) {
warnShouldBeInvoked := func(format string, args ...interface{}) {
formattedWarning = fmt.Sprintf(format, args...)
}

var formattedInfo string
infoShouldBeInvoked := func(format string, args ...interface{}) {
formattedInfo = fmt.Sprintf(format, args...)
}

for _, testCase := range []struct {
description string
tls bool
serverCert []byte
clientCertChain [][]byte
sIDBytes []byte
warn WarnFunc
now time.Time
expectedWarn string
description string
tls bool
serverCert []byte
clientCertChain [][]byte
sIDBytes []byte
info MessageFunc
warn MessageFunc
now time.Time
expectedInfoPrefix string
expectedWarn string
}{
{
description: "No TLS, enrollment cert isn't valid logs a warning",
warn: shouldNotBeInvoked,
warn: warnShouldNotBeInvoked,
sIDBytes: []byte{1, 2, 3},
},
{
description: "No TLS, enrollment cert expires soon",
sIDBytes: signingIdentity,
warn: shouldBeInvoked,
now: monthBeforeExpiration,
expectedWarn: "The enrollment certificate will expire within one week",
description: "No TLS, enrollment cert expires soon",
sIDBytes: signingIdentity,
info: infoShouldBeInvoked,
warn: warnShouldBeInvoked,
now: monthBeforeExpiration,
expectedInfoPrefix: "The enrollment certificate will expire on",
expectedWarn: "The enrollment certificate will expire within one week",
},
{
description: "TLS, server cert expires soon",
warn: shouldBeInvoked,
now: monthBeforeExpiration,
tls: true,
serverCert: tlsCert.Cert,
expectedWarn: "The server TLS certificate will expire within one week",
description: "TLS, server cert expires soon",
info: infoShouldBeInvoked,
warn: warnShouldBeInvoked,
now: monthBeforeExpiration,
tls: true,
serverCert: tlsCert.Cert,
expectedInfoPrefix: "The server TLS certificate will expire on",
expectedWarn: "The server TLS certificate will expire within one week",
},
{
description: "TLS, server cert expires really soon",
warn: shouldBeInvoked,
now: twoDaysBeforeExpiration,
tls: true,
serverCert: tlsCert.Cert,
expectedWarn: "The server TLS certificate expires within 2 days and 12 hours",
description: "TLS, server cert expires really soon",
info: infoShouldBeInvoked,
warn: warnShouldBeInvoked,
now: twoDaysBeforeExpiration,
tls: true,
serverCert: tlsCert.Cert,
expectedInfoPrefix: "The server TLS certificate will expire on",
expectedWarn: "The server TLS certificate expires within 2 days and 12 hours",
},
{
description: "TLS, server cert has expired",
warn: shouldBeInvoked,
info: infoShouldBeInvoked,
warn: warnShouldBeInvoked,
now: expirationTime.Add(time.Hour),
tls: true,
serverCert: tlsCert.Cert,
expectedWarn: "The server TLS certificate has expired",
},
{
description: "TLS, client cert expires soon",
warn: shouldBeInvoked,
now: monthBeforeExpiration,
tls: true,
clientCertChain: [][]byte{tlsCert.Cert},
expectedWarn: "The client TLS certificate will expire within one week",
description: "TLS, client cert expires soon",
info: infoShouldBeInvoked,
warn: warnShouldBeInvoked,
now: monthBeforeExpiration,
tls: true,
clientCertChain: [][]byte{tlsCert.Cert},
expectedInfoPrefix: "The client TLS certificate will expire on",
expectedWarn: "The client TLS certificate will expire within one week",
},
} {
t.Run(testCase.description, func(t *testing.T) {
defer func() {
formattedWarning = ""
formattedInfo = ""
}()

fakeTimeAfter := func(duration time.Duration, f func()) *time.Timer {
Expand All @@ -172,15 +190,23 @@ func TestTrackExpiration(t *testing.T) {
testCase.serverCert,
testCase.clientCertChain,
testCase.sIDBytes,
testCase.info,
testCase.warn,
testCase.now,
fakeTimeAfter)

if testCase.expectedInfoPrefix != "" {
require.True(t, strings.HasPrefix(formattedInfo, testCase.expectedInfoPrefix))
} else {
require.Empty(t, formattedInfo)
}

if testCase.expectedWarn != "" {
assert.Equal(t, testCase.expectedWarn, formattedWarning)
} else {
assert.Empty(t, formattedWarning)
}

})
}
}
Expand Down
1 change: 1 addition & 0 deletions internal/peer/node/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ func serve(args []string) error {
serverConfig.SecOpts.Certificate,
cs.GetClientCertificate().Certificate,
signingIdentityBytes,
expirationLogger.Infof,
expirationLogger.Warnf, // This can be used to piggyback a metric event in the future
time.Now(),
time.AfterFunc,
Expand Down
1 change: 1 addition & 0 deletions orderer/common/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ func Main() {
serverConfig.SecOpts.Certificate,
[][]byte{clusterClientConfig.SecOpts.Certificate},
identityBytes,
expirationLogger.Infof,
expirationLogger.Warnf, // This can be used to piggyback a metric event in the future
time.Now(),
time.AfterFunc)
Expand Down