Skip to content

Commit c91f23f

Browse files
committed
integrate cert-source lib, add listener CLR file and cert rotation
1 parent adfee6a commit c91f23f

File tree

21 files changed

+1373
-79
lines changed

21 files changed

+1373
-79
lines changed

cmd/kafka-proxy/server.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,12 @@ func initFlags() {
103103
Server.Flags().DurationVar(&c.Proxy.ListenerKeepAlive, "proxy-listener-keep-alive", 60*time.Second, "Keep alive period for an active network connection. If zero, keep-alives are disabled")
104104

105105
Server.Flags().BoolVar(&c.Proxy.TLS.Enable, "proxy-listener-tls-enable", false, "Whether or not to use TLS listener")
106+
Server.Flags().DurationVar(&c.Proxy.TLS.Refresh, "proxy-listener-tls-refresh", 0*time.Second, "Interval for refreshing server TLS certificates. If set to zero, the refresh watch is disabled")
106107
Server.Flags().StringVar(&c.Proxy.TLS.ListenerCertFile, "proxy-listener-cert-file", "", "PEM encoded file with server certificate")
107108
Server.Flags().StringVar(&c.Proxy.TLS.ListenerKeyFile, "proxy-listener-key-file", "", "PEM encoded file with private key for the server certificate")
108109
Server.Flags().StringVar(&c.Proxy.TLS.ListenerKeyPassword, "proxy-listener-key-password", os.Getenv("PROXY_LISTENER_KEY_PASSWORD"), "Password to decrypt rsa private key")
109-
Server.Flags().StringVar(&c.Proxy.TLS.CAChainCertFile, "proxy-listener-ca-chain-cert-file", "", "PEM encoded CA's certificate file. If provided, client certificate is required and verified")
110+
Server.Flags().StringVar(&c.Proxy.TLS.ListenerCAChainCertFile, "proxy-listener-ca-chain-cert-file", "", "PEM encoded CA's certificate file. If provided, client certificate is required and verified")
111+
Server.Flags().StringVar(&c.Proxy.TLS.ListenerCRLFile, "proxy-listener-crl-file", "", "PEM encoded X509 CRLs file")
110112
Server.Flags().StringSliceVar(&c.Proxy.TLS.ListenerCipherSuites, "proxy-listener-cipher-suites", []string{}, "List of supported cipher suites")
111113
Server.Flags().StringSliceVar(&c.Proxy.TLS.ListenerCurvePreferences, "proxy-listener-curve-preferences", []string{}, "List of curve preferences")
112114

config/config.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,12 @@ type Config struct {
8888

8989
TLS struct {
9090
Enable bool
91+
Refresh time.Duration
9192
ListenerCertFile string
9293
ListenerKeyFile string
9394
ListenerKeyPassword string
94-
CAChainCertFile string
95+
ListenerCAChainCertFile string
96+
ListenerCRLFile string
9597
ListenerCipherSuites []string
9698
ListenerCurvePreferences []string
9799
ClientCert struct {

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ require (
1212
github.com/fsnotify/fsnotify v1.4.9
1313
github.com/go-ldap/ldap/v3 v3.2.3
1414
github.com/google/uuid v1.6.0
15+
github.com/grepplabs/cert-source v0.0.6
1516
github.com/hashicorp/go-hclog v1.6.3
1617
github.com/hashicorp/go-multierror v0.0.0-20171204182908-b7773ae21874
1718
github.com/hashicorp/go-plugin v1.6.3
@@ -26,7 +27,7 @@ require (
2627
github.com/spf13/viper v1.0.2
2728
github.com/stretchr/testify v1.10.0
2829
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c
29-
github.com/youmark/pkcs8 v0.0.0-20240424034433-3c2c7870ae76
30+
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78
3031
golang.org/x/net v0.34.0
3132
golang.org/x/oauth2 v0.24.0
3233
google.golang.org/api v0.126.0

go.sum

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cU
137137
github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI=
138138
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
139139
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
140+
github.com/grepplabs/cert-source v0.0.6 h1:FjrFco5wQrMqGI4wzCvkIksK0xOoyIC6FV2Cg53thHg=
141+
github.com/grepplabs/cert-source v0.0.6/go.mod h1:gs3IoykME1cFfZ6/h6hch8yg8ktUInsR9OY2xSHA2r4=
140142
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
141143
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce h1:prjrVgOk2Yg6w+PflHoszQNLTUh4kaByUcEWM/9uin4=
142144
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -281,8 +283,8 @@ github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV
281283
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
282284
github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0=
283285
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
284-
github.com/youmark/pkcs8 v0.0.0-20240424034433-3c2c7870ae76 h1:tBiBTKHnIjovYoLX/TPkcf+OjqqKGQrPtGT3Foz+Pgo=
285-
github.com/youmark/pkcs8 v0.0.0-20240424034433-3c2c7870ae76/go.mod h1:SQliXeA7Dhkt//vS29v3zpbEwoa+zb2Cn5xj5uO4K5U=
286+
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
287+
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
286288
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
287289
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
288290
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=

proxy/tls.go

Lines changed: 21 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,16 @@ import (
88
"crypto/x509"
99
"encoding/pem"
1010
"fmt"
11+
"log/slog"
1112
"net"
1213
"os"
1314
"reflect"
1415
"strings"
1516
"time"
1617

18+
tlsconfig "github.com/grepplabs/cert-source/config"
19+
tlsserver "github.com/grepplabs/cert-source/tls/server"
20+
tlsserverconfig "github.com/grepplabs/cert-source/tls/server/config"
1721
"github.com/grepplabs/kafka-proxy/config"
1822
"github.com/pkg/errors"
1923
"github.com/youmark/pkcs8"
@@ -59,25 +63,6 @@ var (
5963
func newTLSListenerConfig(conf *config.Config) (*tls.Config, error) {
6064
opts := conf.Proxy.TLS
6165

62-
if opts.ListenerKeyFile == "" || opts.ListenerCertFile == "" {
63-
return nil, errors.New("Listener key and cert files must not be empty")
64-
}
65-
certPEMBlock, err := os.ReadFile(opts.ListenerCertFile)
66-
if err != nil {
67-
return nil, err
68-
}
69-
keyPEMBlock, err := os.ReadFile(opts.ListenerKeyFile)
70-
if err != nil {
71-
return nil, err
72-
}
73-
keyPEMBlock, err = decryptPEM(keyPEMBlock, opts.ListenerKeyPassword)
74-
if err != nil {
75-
return nil, err
76-
}
77-
cert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock)
78-
if err != nil {
79-
return nil, err
80-
}
8166
cipherSuites, err := getCipherSuites(opts.ListenerCipherSuites)
8267
if err != nil {
8368
return nil, err
@@ -86,35 +71,27 @@ func newTLSListenerConfig(conf *config.Config) (*tls.Config, error) {
8671
if err != nil {
8772
return nil, err
8873
}
89-
90-
cfg := &tls.Config{
91-
Certificates: []tls.Certificate{cert},
92-
ClientAuth: tls.NoClientCert,
93-
PreferServerCipherSuites: true,
94-
MinVersion: tls.VersionTLS12,
95-
CurvePreferences: curvePreferences,
96-
CipherSuites: cipherSuites,
97-
}
98-
if opts.CAChainCertFile != "" {
99-
caCertPEMBlock, err := os.ReadFile(opts.CAChainCertFile)
100-
if err != nil {
101-
return nil, err
102-
}
103-
clientCAs := x509.NewCertPool()
104-
if ok := clientCAs.AppendCertsFromPEM(caCertPEMBlock); !ok {
105-
return nil, errors.New("Failed to parse listener root certificate")
106-
}
107-
cfg.ClientCAs = clientCAs
108-
cfg.ClientAuth = tls.RequireAndVerifyClientCert
109-
}
110-
11174
tlsValidateFunc, err := tlsClientCertVerificationFunc(conf)
11275
if err != nil {
11376
return nil, err
11477
}
115-
cfg.VerifyPeerCertificate = tlsValidateFunc
116-
117-
return cfg, nil
78+
tlsConfig, err := tlsserverconfig.GetServerTLSConfig(slog.Default(),
79+
&tlsconfig.TLSServerConfig{
80+
Enable: true,
81+
Refresh: opts.Refresh,
82+
KeyPassword: opts.ListenerKeyPassword,
83+
File: tlsconfig.TLSServerFiles{
84+
Key: opts.ListenerKeyFile,
85+
Cert: opts.ListenerCertFile,
86+
ClientCAs: opts.ListenerCAChainCertFile,
87+
ClientCRL: opts.ListenerCRLFile,
88+
},
89+
},
90+
tlsserver.WithTLSServerVerifyPeerCertificate(tlsValidateFunc),
91+
tlsserver.WithTLSServerCipherSuites(cipherSuites),
92+
tlsserver.WithTLSServerCurvePreferences(curvePreferences),
93+
)
94+
return tlsConfig, nil
11895
}
11996

12097
func getCipherSuites(enabledCipherSuites []string) ([]uint16, error) {

proxy/tls_client_cert_validate_test.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func TestValidEnabledClientCertSubjectValidate(t *testing.T) {
3636

3737
c.Proxy.TLS.ListenerCertFile = bundle.ServerCert.Name()
3838
c.Proxy.TLS.ListenerKeyFile = bundle.ServerKey.Name()
39-
c.Proxy.TLS.CAChainCertFile = bundle.CACert.Name()
39+
c.Proxy.TLS.ListenerCAChainCertFile = bundle.CACert.Name()
4040

4141
c.Kafka.TLS.CAChainCertFile = bundle.CACert.Name()
4242
c.Kafka.TLS.ClientCertFile = bundle.ClientCert.Name()
@@ -71,7 +71,7 @@ func TestInvalidEnabledClientCertSubjectValidate(t *testing.T) {
7171
}
7272
c.Proxy.TLS.ListenerCertFile = bundle.ServerCert.Name()
7373
c.Proxy.TLS.ListenerKeyFile = bundle.ServerKey.Name()
74-
c.Proxy.TLS.CAChainCertFile = bundle.CACert.Name()
74+
c.Proxy.TLS.ListenerCAChainCertFile = bundle.CACert.Name()
7575

7676
c.Kafka.TLS.CAChainCertFile = bundle.CACert.Name()
7777
c.Kafka.TLS.ClientCertFile = bundle.ClientCert.Name()
@@ -106,7 +106,7 @@ func TestValidEnabledClientCertSubjectMayContainNotRequiredValues(t *testing.T)
106106
}
107107
c.Proxy.TLS.ListenerCertFile = bundle.ServerCert.Name()
108108
c.Proxy.TLS.ListenerKeyFile = bundle.ServerKey.Name()
109-
c.Proxy.TLS.CAChainCertFile = bundle.CACert.Name()
109+
c.Proxy.TLS.ListenerCAChainCertFile = bundle.CACert.Name()
110110

111111
c.Kafka.TLS.CAChainCertFile = bundle.CACert.Name()
112112
c.Kafka.TLS.ClientCertFile = bundle.ClientCert.Name()
@@ -135,7 +135,7 @@ func TestValidEnabledClientCertSubjectMayContainValuesInDifferentOrder(t *testin
135135
}
136136
c.Proxy.TLS.ListenerCertFile = bundle.ServerCert.Name()
137137
c.Proxy.TLS.ListenerKeyFile = bundle.ServerKey.Name()
138-
c.Proxy.TLS.CAChainCertFile = bundle.CACert.Name()
138+
c.Proxy.TLS.ListenerCAChainCertFile = bundle.CACert.Name()
139139

140140
c.Kafka.TLS.CAChainCertFile = bundle.CACert.Name()
141141
c.Kafka.TLS.ClientCertFile = bundle.ClientCert.Name()
@@ -179,7 +179,7 @@ func TestClientCertMultipleSubjects(t *testing.T) {
179179

180180
c.Proxy.TLS.ListenerCertFile = bundle.ServerCert.Name()
181181
c.Proxy.TLS.ListenerKeyFile = bundle.ServerKey.Name()
182-
c.Proxy.TLS.CAChainCertFile = bundle.CACert.Name()
182+
c.Proxy.TLS.ListenerCAChainCertFile = bundle.CACert.Name()
183183

184184
c.Kafka.TLS.CAChainCertFile = bundle.CACert.Name()
185185
c.Kafka.TLS.ClientCertFile = bundle.ClientCert.Name()
@@ -223,7 +223,7 @@ func TestClientCertMultipleSubjectsPatterns(t *testing.T) {
223223

224224
c.Proxy.TLS.ListenerCertFile = bundle.ServerCert.Name()
225225
c.Proxy.TLS.ListenerKeyFile = bundle.ServerKey.Name()
226-
c.Proxy.TLS.CAChainCertFile = bundle.CACert.Name()
226+
c.Proxy.TLS.ListenerCAChainCertFile = bundle.CACert.Name()
227227

228228
c.Kafka.TLS.CAChainCertFile = bundle.CACert.Name()
229229
c.Kafka.TLS.ClientCertFile = bundle.ClientCert.Name()
@@ -260,7 +260,7 @@ func TestClientCertMultiplePatternMatchingFields(t *testing.T) {
260260

261261
c.Proxy.TLS.ListenerCertFile = bundle.ServerCert.Name()
262262
c.Proxy.TLS.ListenerKeyFile = bundle.ServerKey.Name()
263-
c.Proxy.TLS.CAChainCertFile = bundle.CACert.Name()
263+
c.Proxy.TLS.ListenerCAChainCertFile = bundle.CACert.Name()
264264

265265
c.Kafka.TLS.CAChainCertFile = bundle.CACert.Name()
266266
c.Kafka.TLS.ClientCertFile = bundle.ClientCert.Name()
@@ -297,7 +297,7 @@ func TestClientCertMultiplePatternNotMatchingFields(t *testing.T) {
297297

298298
c.Proxy.TLS.ListenerCertFile = bundle.ServerCert.Name()
299299
c.Proxy.TLS.ListenerKeyFile = bundle.ServerKey.Name()
300-
c.Proxy.TLS.CAChainCertFile = bundle.CACert.Name()
300+
c.Proxy.TLS.ListenerCAChainCertFile = bundle.CACert.Name()
301301

302302
c.Kafka.TLS.CAChainCertFile = bundle.CACert.Name()
303303
c.Kafka.TLS.ClientCertFile = bundle.ClientCert.Name()
@@ -334,7 +334,7 @@ func TestClientCertMultiplePatternMatchingFieldsOrderDoesNotMatter(t *testing.T)
334334

335335
c.Proxy.TLS.ListenerCertFile = bundle.ServerCert.Name()
336336
c.Proxy.TLS.ListenerKeyFile = bundle.ServerKey.Name()
337-
c.Proxy.TLS.CAChainCertFile = bundle.CACert.Name()
337+
c.Proxy.TLS.ListenerCAChainCertFile = bundle.CACert.Name()
338338

339339
c.Kafka.TLS.CAChainCertFile = bundle.CACert.Name()
340340
c.Kafka.TLS.ClientCertFile = bundle.ClientCert.Name()

proxy/tls_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ func TestTLSVerifyClientCertDifferentCAs(t *testing.T) {
312312
c := new(config.Config)
313313
c.Proxy.TLS.ListenerCertFile = bundle1.ServerCert.Name()
314314
c.Proxy.TLS.ListenerKeyFile = bundle1.ServerKey.Name()
315-
c.Proxy.TLS.CAChainCertFile = bundle2.CACert.Name() // client CA
315+
c.Proxy.TLS.ListenerCAChainCertFile = bundle2.CACert.Name() // client CA
316316

317317
c.Kafka.TLS.CAChainCertFile = bundle1.ServerCert.Name()
318318
c.Kafka.TLS.ClientCertFile = bundle2.ClientCert.Name()
@@ -335,7 +335,7 @@ func TestTLSVerifyClientCertSameCAs(t *testing.T) {
335335
c := new(config.Config)
336336
c.Proxy.TLS.ListenerCertFile = bundle1.ServerCert.Name()
337337
c.Proxy.TLS.ListenerKeyFile = bundle1.ServerKey.Name()
338-
c.Proxy.TLS.CAChainCertFile = bundle1.CACert.Name() // client CA
338+
c.Proxy.TLS.ListenerCAChainCertFile = bundle1.CACert.Name() // client CA
339339

340340
c.Kafka.TLS.CAChainCertFile = bundle1.ServerCert.Name()
341341
c.Kafka.TLS.ClientCertFile = bundle1.ClientCert.Name()
@@ -358,7 +358,7 @@ func TestTLSMissingClientCert(t *testing.T) {
358358
c := new(config.Config)
359359
c.Proxy.TLS.ListenerCertFile = bundle1.ServerCert.Name()
360360
c.Proxy.TLS.ListenerKeyFile = bundle1.ServerKey.Name()
361-
c.Proxy.TLS.CAChainCertFile = bundle1.CACert.Name() // client CA
361+
c.Proxy.TLS.ListenerCAChainCertFile = bundle1.CACert.Name() // client CA
362362

363363
c.Kafka.TLS.CAChainCertFile = bundle1.ServerCert.Name()
364364

@@ -379,7 +379,7 @@ func TestTLSBadClientCert(t *testing.T) {
379379
c := new(config.Config)
380380
c.Proxy.TLS.ListenerCertFile = bundle1.ServerCert.Name()
381381
c.Proxy.TLS.ListenerKeyFile = bundle1.ServerKey.Name()
382-
c.Proxy.TLS.CAChainCertFile = bundle1.CACert.Name() // client CA
382+
c.Proxy.TLS.ListenerCAChainCertFile = bundle1.CACert.Name() // client CA
383383

384384
c.Kafka.TLS.CAChainCertFile = bundle1.ServerCert.Name()
385385
c.Kafka.TLS.ClientCertFile = bundle2.ClientCert.Name()
@@ -431,7 +431,7 @@ func configWithCertToCompare(bundle1 *CertsBundle, bundle2 *CertsBundle, sameCer
431431

432432
c.Proxy.TLS.ListenerCertFile = bundle1.ServerCert.Name()
433433
c.Proxy.TLS.ListenerKeyFile = bundle1.ServerKey.Name()
434-
c.Proxy.TLS.CAChainCertFile = bundle2.CACert.Name() // client CA
434+
c.Proxy.TLS.ListenerCAChainCertFile = bundle2.CACert.Name() // client CA
435435

436436
c.Kafka.TLS.CAChainCertFile = bundle1.ServerCert.Name()
437437
c.Kafka.TLS.ClientCertFile = bundle2.ClientCert.Name()

0 commit comments

Comments
 (0)