Files
tasks/common/rpc/test/rpc_localstore_tls_test.go
stuart-wellsandGitHub 28fb98c825 Adding JWT auth capability for s2s replication (#10165)
## What changed?
Adds JWT to server-to-server connections. Frontend already had support
for reading auth so this focuses on getting a token and injecting it.

## Why?
s2s is currently a gap in the auth abilities. This provides more
flexibility for users based on their auth requirements.

## How did you test it?
- [x] built
- [x] run locally and tested manually
- [x] covered by existing tests
- [x] added new unit test(s)
- [x] added new functional test(s)

## Potential risks
Need to get auth right. Main risk is a user believing they are secure
when they are not.
2026-05-27 11:00:51 -07:00

657 lines
24 KiB
Go

package rpc
import (
"crypto/tls"
"crypto/x509"
"os"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"go.temporal.io/server/common/config"
"go.temporal.io/server/common/log"
"go.temporal.io/server/common/metrics"
"go.temporal.io/server/common/rpc"
"go.temporal.io/server/common/rpc/encryption"
"go.temporal.io/server/tests/testutils"
"go.uber.org/mock/gomock"
"google.golang.org/grpc/credentials"
)
const (
internodeServerCertSerialNumber = 100
frontendServerCertSerialNumber = 150
)
var (
frontendURL = "dummy://" // not needed for test
frontendHTTPURL = "dummy://" // not needed for test
)
type localStoreRPCSuite struct {
*require.Assertions
*suite.Suite
controller *gomock.Controller
logger log.Logger
insecureRPCFactory *TestFactory
internodeMutualTLSRPCFactory *TestFactory
internodeServerTLSRPCFactory *TestFactory
internodeAltMutualTLSRPCFactory *TestFactory
frontendMutualTLSRPCFactory *TestFactory
frontendServerTLSRPCFactory *TestFactory
frontendSystemWorkerMutualTLSRPCFactory *TestFactory
frontendDynamicTLSFactory *TestFactory
internodeDynamicTLSFactory *TestFactory
internodeMutualTLSRPCRefreshFactory *TestFactory
frontendMutualTLSRPCRefreshFactory *TestFactory
remoteClusterMutualTLSRPCFactory *TestFactory
frontendConfigRootCAForceTLSFactory *TestFactory
internodeCertDir string
frontendCertDir string
frontendAltCertDir string
frontendRollingCertDir string
internodeRefreshCertDir string
frontendRefreshCertDir string
internodeChain testutils.CertChain
frontendChain testutils.CertChain
frontendAltChain testutils.CertChain
frontendRollingCerts []*tls.Certificate
internodeRefreshChain testutils.CertChain
internodeRefreshCA *tls.Certificate
frontendRefreshChain testutils.CertChain
frontendRefreshCA *tls.Certificate
frontendClientCertDir string
frontendClientChain testutils.CertChain
membershipConfig config.Membership
frontendConfigServerTLS config.GroupTLS
frontendConfigMutualTLS config.GroupTLS
frontendConfigPerHostOverrides config.GroupTLS
frontendConfigRootCAOnly config.GroupTLS
frontendConfigRootCAForceTLS config.GroupTLS
frontendConfigAltRootCAOnly config.GroupTLS
systemWorkerOnly config.WorkerTLS
frontendConfigSystemWorker config.WorkerTLS
frontendConfigMutualTLSRefresh config.GroupTLS
internodeConfigMutualTLS config.GroupTLS
internodeConfigServerTLS config.GroupTLS
internodeConfigAltMutualTLS config.GroupTLS
internodeConfigMutualTLSRefresh config.GroupTLS
dynamicCACertPool *x509.CertPool
wrongCACertPool *x509.CertPool
dynamicConfigProvider *encryption.TestDynamicTLSConfigProvider
}
func TestLocalStoreTLSSuite(t *testing.T) {
t.Skip("Skipping flaky test")
suite.Run(t, &localStoreRPCSuite{
Suite: &suite.Suite{},
})
}
func (s *localStoreRPCSuite) TearDownSuite() {
_ = os.RemoveAll(s.internodeCertDir)
_ = os.RemoveAll(s.frontendCertDir)
}
func (s *localStoreRPCSuite) SetupSuite() {
s.Assertions = require.New(s.T())
s.logger = log.NewTestLogger()
provider, err := encryption.NewTLSConfigProviderFromConfig(serverCfgInsecure.TLS, metrics.NoopMetricsHandler, s.logger, nil)
s.NoError(err)
insecureFactory := rpc.NewFactory(cfg, "tester", s.logger, nil, provider, frontendURL, frontendHTTPURL, 0, nil, nil, nil, nil, nil)
s.NotNil(insecureFactory)
s.insecureRPCFactory = i(insecureFactory)
s.frontendCertDir, err = os.MkdirTemp("", "localStoreRPCSuiteFrontend")
s.NoError(err)
s.frontendChain, err = testutils.GenerateTestChain(s.frontendCertDir, localhostIPv4)
s.NoError(err)
s.internodeCertDir, err = os.MkdirTemp("", "localStoreRPCSuiteInternode")
s.NoError(err)
s.internodeChain, err = testutils.GenerateTestChain(s.internodeCertDir, localhostIPv4)
s.NoError(err)
s.frontendAltCertDir, err = os.MkdirTemp("", "localStoreRPCSuiteFrontendAlt")
s.NoError(err)
s.frontendAltChain, err = testutils.GenerateTestChain(s.frontendAltCertDir, localhost)
s.NoError(err)
s.frontendClientCertDir, err = os.MkdirTemp("", "localStoreRPCSuiteFrontendClient")
s.NoError(err)
s.frontendClientChain, err = testutils.GenerateTestChain(s.frontendClientCertDir, localhostIPv4)
s.NoError(err)
s.frontendRollingCertDir, err = os.MkdirTemp("", "localStoreRPCSuiteFrontendRolling")
s.NoError(err)
s.frontendRollingCerts, s.dynamicCACertPool, s.wrongCACertPool, err = testutils.GenerateTestCerts(s.frontendRollingCertDir, localhostIPv4, 2)
s.NoError(err)
s.internodeRefreshCertDir, err = os.MkdirTemp("", "localStoreRPCSuiteInternodeRefresh")
s.NoError(err)
s.internodeRefreshChain, s.internodeRefreshCA, err = testutils.GenerateTestChainWithSN(s.internodeRefreshCertDir, localhostIPv4, internodeServerCertSerialNumber)
s.NoError(err)
s.frontendRefreshCertDir, err = os.MkdirTemp("", "localStoreRPCSuiteFrontendRefresh")
s.NoError(err)
s.frontendRefreshChain, s.frontendRefreshCA, err = testutils.GenerateTestChainWithSN(s.frontendRefreshCertDir, localhostIPv4, frontendServerCertSerialNumber)
s.NoError(err)
s.membershipConfig = config.Membership{
MaxJoinDuration: 5,
BroadcastAddress: localhostIPv4,
}
frontendConfigBase := config.GroupTLS{
Server: config.ServerTLS{
CertFile: s.frontendChain.CertPubFile,
KeyFile: s.frontendChain.CertKeyFile,
},
}
s.frontendConfigServerTLS = frontendConfigBase
s.frontendConfigServerTLS.Client = config.ClientTLS{RootCAFiles: []string{s.frontendChain.CaPubFile}}
s.frontendConfigMutualTLS = frontendConfigBase
s.frontendConfigMutualTLS.Server.ClientCAFiles = []string{s.frontendClientChain.CaPubFile}
s.frontendConfigMutualTLS.Server.RequireClientAuth = true
s.frontendConfigPerHostOverrides = s.frontendConfigServerTLS
s.frontendConfigPerHostOverrides.PerHostOverrides = map[string]config.ServerTLS{
localhost: {
CertFile: s.frontendAltChain.CertPubFile,
KeyFile: s.frontendAltChain.CertKeyFile,
ClientCAFiles: []string{s.frontendAltChain.CaPubFile},
RequireClientAuth: true,
},
}
s.frontendConfigRootCAOnly = config.GroupTLS{
Client: config.ClientTLS{
RootCAData: []string{testutils.ConvertFileToBase64(s.frontendChain.CaPubFile)},
},
}
s.frontendConfigRootCAForceTLS = s.frontendConfigRootCAOnly
s.frontendConfigRootCAForceTLS.Client.ForceTLS = true
s.frontendConfigAltRootCAOnly = config.GroupTLS{
Server: config.ServerTLS{
RequireClientAuth: true,
},
Client: config.ClientTLS{
RootCAData: []string{testutils.ConvertFileToBase64(s.frontendAltChain.CaPubFile)},
},
}
s.systemWorkerOnly = config.WorkerTLS{
CertFile: s.frontendClientChain.CertPubFile,
KeyFile: s.frontendClientChain.CertKeyFile,
}
s.frontendConfigSystemWorker = s.systemWorkerOnly
s.frontendConfigSystemWorker.Client = config.ClientTLS{
RootCAFiles: []string{s.frontendChain.CaPubFile},
}
s.internodeConfigMutualTLS = config.GroupTLS{
Server: config.ServerTLS{
CertFile: s.internodeChain.CertPubFile,
KeyFile: s.internodeChain.CertKeyFile,
ClientCAFiles: []string{s.internodeChain.CaPubFile},
RequireClientAuth: true,
},
Client: config.ClientTLS{
RootCAFiles: []string{s.internodeChain.CaPubFile},
},
}
s.internodeConfigServerTLS = config.GroupTLS{
Server: config.ServerTLS{
CertData: testutils.ConvertFileToBase64(s.internodeChain.CertPubFile),
KeyData: testutils.ConvertFileToBase64(s.internodeChain.CertKeyFile),
},
Client: config.ClientTLS{
RootCAData: []string{testutils.ConvertFileToBase64(s.internodeChain.CaPubFile)},
},
}
s.internodeConfigAltMutualTLS = config.GroupTLS{
Server: config.ServerTLS{
CertFile: s.frontendAltChain.CertPubFile,
KeyFile: s.frontendAltChain.CertKeyFile,
ClientCAFiles: []string{s.frontendAltChain.CaPubFile},
RequireClientAuth: true,
},
Client: config.ClientTLS{
RootCAFiles: []string{s.frontendAltChain.CaPubFile},
},
}
s.internodeConfigMutualTLSRefresh = mutualGroupTLSFromChain(s.internodeRefreshChain)
s.frontendConfigMutualTLSRefresh = mutualGroupTLSFromChain(s.frontendRefreshChain)
}
func mutualGroupTLSFromChain(chain testutils.CertChain) config.GroupTLS {
return config.GroupTLS{
Server: config.ServerTLS{
CertFile: chain.CertPubFile,
KeyFile: chain.CertKeyFile,
ClientCAFiles: []string{chain.CaPubFile},
RequireClientAuth: true,
},
Client: config.ClientTLS{
RootCAFiles: []string{chain.CaPubFile},
},
}
}
func (s *localStoreRPCSuite) SetupTest() {
s.controller = gomock.NewController(s.T())
s.setupInternode()
s.setupFrontend()
}
func (s *localStoreRPCSuite) TearDownTest() {
s.controller.Finish()
}
func (s *localStoreRPCSuite) setupFrontend() {
localStoreServerTLS := &config.Global{
Membership: s.membershipConfig,
TLS: config.RootTLS{
Frontend: s.frontendConfigServerTLS,
},
}
localStoreMutualTLS := &config.Global{
Membership: s.membershipConfig,
TLS: config.RootTLS{
Frontend: s.frontendConfigPerHostOverrides,
},
}
localStoreMutualTLSSystemWorker := &config.Global{
Membership: s.membershipConfig,
TLS: config.RootTLS{
Internode: s.internodeConfigMutualTLS,
Frontend: s.frontendConfigMutualTLS,
SystemWorker: s.frontendConfigSystemWorker,
},
}
localStoreMutualTLSWithRefresh := &config.Global{
Membership: s.membershipConfig,
TLS: config.RootTLS{
Frontend: s.frontendConfigMutualTLSRefresh,
Internode: s.frontendConfigMutualTLSRefresh,
RefreshInterval: time.Second,
ExpirationChecks: config.CertExpirationValidation{
WarningWindow: time.Hour * 24 * 14,
ErrorWindow: time.Hour * 24 * 7,
CheckInterval: time.Second,
},
},
}
localStoreRootCAForceTLS := &config.Global{
Membership: s.membershipConfig,
TLS: config.RootTLS{
Frontend: s.frontendConfigRootCAForceTLS,
},
}
localStoreMutualTLSRemoteCluster := &config.Global{
Membership: s.membershipConfig,
TLS: config.RootTLS{
Frontend: s.frontendConfigPerHostOverrides,
RemoteClusters: map[string]config.GroupTLS{localhostIPv4: s.frontendConfigPerHostOverrides},
},
}
provider, err := encryption.NewTLSConfigProviderFromConfig(localStoreMutualTLS.TLS, metrics.NoopMetricsHandler, s.logger, nil)
s.NoError(err)
tlsConfig, err := provider.GetFrontendClientConfig()
s.NoError(err)
frontendMutualTLSFactory := rpc.NewFactory(cfg, "tester", s.logger, nil, provider, frontendURL, frontendHTTPURL, 0, tlsConfig, nil, nil, nil, nil)
s.NotNil(frontendMutualTLSFactory)
provider, err = encryption.NewTLSConfigProviderFromConfig(localStoreServerTLS.TLS, metrics.NoopMetricsHandler, s.logger, nil)
s.NoError(err)
frontendServerTLSFactory := rpc.NewFactory(cfg, "tester", s.logger, nil, provider, frontendURL, frontendHTTPURL, 0, nil, nil, nil, nil, nil)
s.NotNil(frontendServerTLSFactory)
provider, err = encryption.NewTLSConfigProviderFromConfig(localStoreMutualTLSSystemWorker.TLS, metrics.NoopMetricsHandler, s.logger, nil)
s.NoError(err)
tlsConfig, err = provider.GetFrontendClientConfig()
s.NoError(err)
frontendSystemWorkerMutualTLSFactory := rpc.NewFactory(cfg, "tester", s.logger, nil, provider, frontendURL, frontendHTTPURL, 0, tlsConfig, nil, nil, nil, nil)
s.NotNil(frontendSystemWorkerMutualTLSFactory)
provider, err = encryption.NewTLSConfigProviderFromConfig(localStoreMutualTLSWithRefresh.TLS, metrics.NoopMetricsHandler, s.logger, nil)
s.NoError(err)
tlsConfig, err = provider.GetFrontendClientConfig()
s.NoError(err)
frontendMutualTLSRefreshFactory := rpc.NewFactory(cfg, "tester", s.logger, nil, provider, frontendURL, frontendHTTPURL, 0, tlsConfig, nil, nil, nil, nil)
s.NotNil(frontendMutualTLSRefreshFactory)
s.frontendMutualTLSRPCFactory = f(frontendMutualTLSFactory)
s.frontendServerTLSRPCFactory = f(frontendServerTLSFactory)
s.frontendSystemWorkerMutualTLSRPCFactory = f(frontendSystemWorkerMutualTLSFactory)
s.dynamicConfigProvider, err = encryption.NewTestDynamicTLSConfigProvider(
&localStoreMutualTLS.TLS,
s.frontendRollingCerts,
s.dynamicCACertPool,
s.frontendRollingCerts,
s.dynamicCACertPool,
s.wrongCACertPool)
s.NoError(err)
tlsConfig, err = s.dynamicConfigProvider.GetFrontendClientConfig()
s.NoError(err)
dynamicServerTLSFactory := rpc.NewFactory(cfg, "tester", s.logger, nil, s.dynamicConfigProvider, frontendURL, frontendHTTPURL, 0, tlsConfig, nil, nil, nil, nil)
s.frontendDynamicTLSFactory = f(dynamicServerTLSFactory)
s.internodeDynamicTLSFactory = i(dynamicServerTLSFactory)
s.frontendMutualTLSRPCRefreshFactory = f(frontendMutualTLSRefreshFactory)
provider, err = encryption.NewTLSConfigProviderFromConfig(localStoreRootCAForceTLS.TLS, metrics.NoopMetricsHandler, s.logger, nil)
s.NoError(err)
tlsConfig, err = provider.GetFrontendClientConfig()
s.NoError(err)
frontendRootCAForceTLSFactory := rpc.NewFactory(cfg, "tester", s.logger, nil, provider, frontendURL, frontendHTTPURL, 0, tlsConfig, nil, nil, nil, nil)
s.NotNil(frontendServerTLSFactory)
s.frontendConfigRootCAForceTLSFactory = f(frontendRootCAForceTLSFactory)
provider, err = encryption.NewTLSConfigProviderFromConfig(localStoreMutualTLSRemoteCluster.TLS, metrics.NoopMetricsHandler, s.logger, nil)
s.NoError(err)
tlsConfig, err = provider.GetFrontendClientConfig()
s.NoError(err)
remoteClusterMutualTLSRPCFactory := rpc.NewFactory(cfg, "tester", s.logger, nil, provider, frontendURL, frontendHTTPURL, 0, tlsConfig, nil, nil, nil, nil)
s.NotNil(remoteClusterMutualTLSRPCFactory)
s.remoteClusterMutualTLSRPCFactory = r(remoteClusterMutualTLSRPCFactory)
}
func (s *localStoreRPCSuite) setupInternode() {
localStoreServerTLS := &config.Global{
Membership: s.membershipConfig,
TLS: config.RootTLS{
Internode: s.internodeConfigServerTLS,
Frontend: s.frontendConfigRootCAOnly,
},
}
localStoreMutualTLS := &config.Global{
Membership: s.membershipConfig,
TLS: config.RootTLS{
Internode: s.internodeConfigMutualTLS,
Frontend: s.frontendConfigRootCAOnly,
},
}
localStoreAltMutualTLS := &config.Global{
Membership: s.membershipConfig,
TLS: config.RootTLS{
Internode: s.internodeConfigAltMutualTLS,
Frontend: s.frontendConfigAltRootCAOnly,
},
}
localStoreMutualTLSWithRefresh := *localStoreMutualTLS
localStoreMutualTLSWithRefresh.TLS.Internode = s.internodeConfigMutualTLSRefresh
localStoreMutualTLSWithRefresh.TLS.RefreshInterval = time.Second
provider, err := encryption.NewTLSConfigProviderFromConfig(localStoreMutualTLS.TLS, metrics.NoopMetricsHandler, s.logger, nil)
s.NoError(err)
tlsConfig, err := provider.GetFrontendClientConfig()
s.NoError(err)
internodeMutualTLSFactory := rpc.NewFactory(cfg, "tester", s.logger, nil, provider, frontendURL, frontendHTTPURL, 0, tlsConfig, nil, nil, nil, nil)
s.NotNil(internodeMutualTLSFactory)
provider, err = encryption.NewTLSConfigProviderFromConfig(localStoreServerTLS.TLS, metrics.NoopMetricsHandler, s.logger, nil)
s.NoError(err)
tlsConfig, err = provider.GetFrontendClientConfig()
s.NoError(err)
internodeServerTLSFactory := rpc.NewFactory(cfg, "tester", s.logger, nil, provider, frontendURL, frontendHTTPURL, 0, tlsConfig, nil, nil, nil, nil)
s.NotNil(internodeServerTLSFactory)
provider, err = encryption.NewTLSConfigProviderFromConfig(localStoreAltMutualTLS.TLS, metrics.NoopMetricsHandler, s.logger, nil)
s.NoError(err)
tlsConfig, err = provider.GetFrontendClientConfig()
s.NoError(err)
internodeMutualAltTLSFactory := rpc.NewFactory(cfg, "tester", s.logger, nil, provider, frontendURL, frontendHTTPURL, 0, tlsConfig, nil, nil, nil, nil)
s.NotNil(internodeMutualAltTLSFactory)
provider, err = encryption.NewTLSConfigProviderFromConfig(localStoreMutualTLSWithRefresh.TLS, metrics.NoopMetricsHandler, s.logger, nil)
s.NoError(err)
tlsConfig, err = provider.GetFrontendClientConfig()
s.NoError(err)
internodeMutualTLSRefreshFactory := rpc.NewFactory(cfg, "tester", s.logger, nil, provider, frontendURL, frontendHTTPURL, 0, tlsConfig, nil, nil, nil, nil)
s.NotNil(internodeMutualTLSRefreshFactory)
s.internodeMutualTLSRPCFactory = i(internodeMutualTLSFactory)
s.internodeServerTLSRPCFactory = i(internodeServerTLSFactory)
s.internodeAltMutualTLSRPCFactory = i(internodeMutualAltTLSFactory)
s.internodeMutualTLSRPCRefreshFactory = i(internodeMutualTLSRefreshFactory)
}
func f(r *rpc.RPCFactory) *TestFactory {
return &TestFactory{serverUsage: Frontend, RPCFactory: r}
}
func i(r *rpc.RPCFactory) *TestFactory {
return &TestFactory{serverUsage: Internode, RPCFactory: r}
}
func r(r *rpc.RPCFactory) *TestFactory {
return &TestFactory{serverUsage: RemoteCluster, RPCFactory: r}
}
func (s *localStoreRPCSuite) TestServerTLS() {
runTestServerTest(s.Suite, localhostIPv4, s.internodeServerTLSRPCFactory, s.internodeServerTLSRPCFactory, true)
}
func (s *localStoreRPCSuite) TestServerTLSFrontendToFrontend() {
runTestServerTest(s.Suite, localhostIPv4, s.frontendServerTLSRPCFactory, s.frontendServerTLSRPCFactory, true)
}
func (s *localStoreRPCSuite) TestMutualTLS() {
runTestServerTest(s.Suite, localhostIPv4, s.internodeMutualTLSRPCFactory, s.internodeMutualTLSRPCFactory, true)
}
func (s *localStoreRPCSuite) TestMutualTLSFrontendToFrontend() {
runTestServerTest(s.Suite, localhostIPv4, s.frontendMutualTLSRPCFactory, s.frontendMutualTLSRPCFactory, true)
}
func (s *localStoreRPCSuite) TestMutualTLSFrontendToRemoteCluster() {
runTestServerTest(s.Suite, localhostIPv4, s.remoteClusterMutualTLSRPCFactory, s.remoteClusterMutualTLSRPCFactory, true)
}
func (s *localStoreRPCSuite) TestMutualTLSButClientInsecure() {
runTestServerTest(s.Suite, localhostIPv4, s.internodeMutualTLSRPCFactory, s.insecureRPCFactory, false)
}
func (s *localStoreRPCSuite) TestServerTLSButClientInsecure() {
runTestServerTest(s.Suite, localhostIPv4, s.internodeServerTLSRPCFactory, s.insecureRPCFactory, false)
}
func (s *localStoreRPCSuite) TestMutualTLSButClientNoCert() {
runTestServerTest(s.Suite, localhostIPv4, s.internodeMutualTLSRPCFactory, s.internodeServerTLSRPCFactory, false)
}
func (s *localStoreRPCSuite) TestServerTLSButClientAddsCert() {
runTestServerTest(s.Suite, localhostIPv4, s.internodeServerTLSRPCFactory, s.internodeMutualTLSRPCFactory, true)
}
func (s *localStoreRPCSuite) TestMutualTLSSystemWorker() {
runTestServerTest(s.Suite, localhostIPv4, s.frontendSystemWorkerMutualTLSRPCFactory, s.frontendSystemWorkerMutualTLSRPCFactory, true)
}
func (s *localStoreRPCSuite) TestDynamicServerTLSFrontend() {
s.testDynamicServerTLS(localhostIPv4, true)
}
func (s *localStoreRPCSuite) TestDynamicServerTLSInternode() {
s.testDynamicServerTLS(localhostIPv4, false)
}
func (s *localStoreRPCSuite) TestDynamicServerTLSOverrideFrontend() {
s.testDynamicServerTLS(localhost, true)
}
func (s *localStoreRPCSuite) TestDynamicServerTLSOverrideInternode() {
s.testDynamicServerTLS(localhost, false)
}
func (s *localStoreRPCSuite) testDynamicServerTLS(host string, frontend bool) {
server, client := s.getTestFactory(frontend)
var index int
s.dynamicConfigProvider.InternodeClientCertProvider.SetServerName(host)
s.dynamicConfigProvider.FrontendClientCertProvider.SetServerName(host)
runTestServerMultipleDials(s.Suite, host, server, client, 5,
func(tlsInfo *credentials.TLSInfo, err error) {
s.validateTLSInfo(tlsInfo, err, int64((index+1)%2+100))
index++
})
}
func (s *localStoreRPCSuite) TestDynamicRootCAFrontend() {
s.testDynamicRootCA(localhostIPv4, true)
}
func (s *localStoreRPCSuite) TestDynamicRootCAInternode() {
s.testDynamicRootCA(localhostIPv4, true)
}
func (s *localStoreRPCSuite) TestDynamicRootCAOverrideFrontend() {
s.testDynamicRootCA(localhost, true)
}
func (s *localStoreRPCSuite) TestDynamicRootCAOverrideInternode() {
s.testDynamicRootCA(localhost, true)
}
func (s *localStoreRPCSuite) TestCertExpiration() {
sixHours := time.Hour * 6
s.testCertExpiration(s.insecureRPCFactory, sixHours, 0)
s.testCertExpiration(s.internodeMutualTLSRPCFactory, sixHours, 0)
s.testCertExpiration(s.internodeServerTLSRPCFactory, sixHours, 0)
s.testCertExpiration(s.internodeAltMutualTLSRPCFactory, sixHours, 0)
s.testCertExpiration(s.frontendMutualTLSRPCFactory, sixHours, 0)
s.testCertExpiration(s.frontendServerTLSRPCFactory, sixHours, 0)
s.testCertExpiration(s.frontendSystemWorkerMutualTLSRPCFactory, sixHours, 0)
twoDays := time.Hour * 48
s.testCertExpiration(s.insecureRPCFactory, twoDays, 0)
s.testCertExpiration(s.internodeMutualTLSRPCFactory, twoDays, 3)
s.testCertExpiration(s.internodeServerTLSRPCFactory, twoDays, 3)
s.testCertExpiration(s.internodeAltMutualTLSRPCFactory, twoDays, 2)
s.testCertExpiration(s.frontendMutualTLSRPCFactory, twoDays, 4)
s.testCertExpiration(s.frontendServerTLSRPCFactory, twoDays, 2)
s.testCertExpiration(s.frontendSystemWorkerMutualTLSRPCFactory, twoDays, 6)
}
func (s *localStoreRPCSuite) testCertExpiration(factory *TestFactory, timeWindow time.Duration, nExpiring int) {
expiring, expired, err := factory.GetTLSConfigProvider().GetExpiringCerts(timeWindow)
s.NotNil(expiring)
s.Empty(expired)
s.NoError(err)
s.Equal(nExpiring, len(expiring))
}
func (s *localStoreRPCSuite) testDynamicRootCA(host string, frontend bool) {
server, client := s.getTestFactory(frontend)
var index int
valid := true
runTestServerMultipleDials(s.Suite, host, server, client, 5,
func(tlsInfo *credentials.TLSInfo, err error) {
if valid {
s.NoError(err)
} else {
s.Error(err)
}
index++
if index == 2 {
s.dynamicConfigProvider.InternodeClientCertProvider.SwitchToWrongServerRootCACerts()
s.dynamicConfigProvider.FrontendClientCertProvider.SwitchToWrongServerRootCACerts()
valid = false
}
})
}
func (s *localStoreRPCSuite) getTestFactory(frontend bool) (server *TestFactory, client *TestFactory) {
if frontend {
server = s.frontendDynamicTLSFactory
client = s.frontendDynamicTLSFactory
} else {
server = s.internodeDynamicTLSFactory
client = s.internodeDynamicTLSFactory
}
return server, client
}
func (s *localStoreRPCSuite) TestServerTLSRefreshInternode() {
s.testServerTLSRefresh(s.internodeMutualTLSRPCRefreshFactory, s.internodeRefreshCA, s.internodeRefreshCertDir, internodeServerCertSerialNumber)
}
func (s *localStoreRPCSuite) TestServerTLSRefreshFrontend() {
s.testServerTLSRefresh(s.frontendMutualTLSRPCRefreshFactory, s.frontendRefreshCA, s.frontendRefreshCertDir, frontendServerCertSerialNumber)
}
func (s *localStoreRPCSuite) testServerTLSRefresh(factory *TestFactory, ca *tls.Certificate, certDir string, serialNumber int64) {
server, port := startTestServiceServer(s.Suite, factory)
defer server.Stop()
host := localhostIPv4 + ":" + port
tlsInfo, err := dialTestServiceAndGetTLSInfo(s.Suite, host, factory, factory.serverUsage)
s.validateTLSInfo(tlsInfo, err, serialNumber) // serial number of server cert before refresh
srvrCert, err := testutils.GenerateServerCert(ca, localhostIPv4, serialNumber+100, testutils.CertFilePath(certDir), testutils.KeyFilePath(certDir))
s.NoError(err)
s.NotNil(srvrCert)
time.Sleep(time.Second * 2) // let server refresh certs
tlsInfo, err = dialTestServiceAndGetTLSInfo(s.Suite, host, factory, factory.serverUsage)
s.validateTLSInfo(tlsInfo, err, serialNumber+100) // serial number of server cert after refresh
}
func (s *localStoreRPCSuite) validateTLSInfo(tlsInfo *credentials.TLSInfo, err error, serialNumber int64) {
s.NoError(err)
s.NotNil(tlsInfo)
s.NotNil(tlsInfo.State.PeerCertificates)
sn := (*tlsInfo.State.PeerCertificates[0].SerialNumber).Int64()
s.Equal(serialNumber, sn)
}
func (s *localStoreRPCSuite) TestClientForceTLS() {
options, err := s.frontendConfigRootCAForceTLSFactory.RPCFactory.GetFrontendGRPCServerOptions()
s.NoError(err)
s.Nil(options)
}
func (s *localStoreRPCSuite) TestSystemWorkerOnlyConfig() {
localStoreSystemWorkerOnly := &config.Global{
Membership: s.membershipConfig,
TLS: config.RootTLS{
SystemWorker: s.systemWorkerOnly,
},
}
provider, err := encryption.NewTLSConfigProviderFromConfig(localStoreSystemWorkerOnly.TLS, metrics.NoopMetricsHandler, s.logger, nil)
s.NoError(err)
tlsConfig, err := provider.GetFrontendClientConfig()
s.NoError(err)
s.NotNil(tlsConfig)
s.NotNil(tlsConfig.GetClientCertificate)
cert, err := tlsConfig.GetClientCertificate(nil)
s.NoError(err)
s.NotNil(cert)
}