Skip to content

Commit 2fbf93a

Browse files
authored
Merge pull request #196 from grepplabs/feature/listener-cert-rotation
cert rotation + refactoring
2 parents 2318bd6 + a7baef9 commit 2fbf93a

File tree

998 files changed

+117033
-26969
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

998 files changed

+117033
-26969
lines changed

.github/workflows/build.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
- name: Setup go
1515
uses: actions/setup-go@v4
1616
with:
17-
go-version: '1.22'
17+
go-version: '1.23'
1818
check-latest: true
1919
- run: go version
2020
- name: Run build

.github/workflows/release.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
- name: Setup go
2323
uses: actions/setup-go@v4
2424
with:
25-
go-version: '1.22'
25+
go-version: '1.23'
2626
check-latest: true
2727
- run: go version
2828
- name: Run build and test

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM --platform=$BUILDPLATFORM golang:1.22-alpine3.21 AS builder
1+
FROM --platform=$BUILDPLATFORM golang:1.23-alpine3.21 AS builder
22
RUN apk add alpine-sdk ca-certificates
33

44
ARG TARGETOS

Dockerfile.all

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM --platform=$BUILDPLATFORM golang:1.22-alpine3.21 AS builder
1+
FROM --platform=$BUILDPLATFORM golang:1.23-alpine3.21 AS builder
22
RUN apk add alpine-sdk ca-certificates
33

44
ARG TARGETOS

Makefile

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ VERSION ?= $(shell git describe --tags --always --dirty)
1010
GOPKGS = $(shell go list ./... | grep -v /vendor/)
1111
BUILD_FLAGS ?=
1212
LDFLAGS ?= -X github.com/grepplabs/kafka-proxy/config.Version=$(VERSION) -w -s
13-
TAG ?= "v0.3.12"
13+
TAG ?= "v0.4.0"
1414
GOOS ?= $(if $(TARGETOS),$(TARGETOS),linux)
1515
GOARCH ?= $(if $(TARGETARCH),$(TARGETARCH),amd64)
1616
GOARM ?= $(TARGETVARIANT)
@@ -22,6 +22,8 @@ PROTOC_VERSION ?= 22.2
2222
PROTOC_BIN_DIR := .tools
2323
PROTOC := $(PROTOC_BIN_DIR)/protoc
2424

25+
GOLANGCI_LINT = go run github.com/golangci/golangci-lint/cmd/[email protected]
26+
2527
default: build
2628

2729
test.race:
@@ -33,10 +35,17 @@ test:
3335
fmt:
3436
go fmt $(GOPKGS)
3537

36-
check:
37-
golint $(GOPKGS)
38+
check: lint-code
3839
go vet $(GOPKGS)
3940

41+
.PHONY: lint-code
42+
lint-code:
43+
$(GOLANGCI_LINT) run --timeout 5m
44+
45+
.PHONY: lint-fix
46+
lint-fix:
47+
$(GOLANGCI_LINT) run --fix
48+
4049
.PHONY: build
4150
build: build/$(BINARY)
4251

README.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ As not every Kafka release adds new messages/versions which are relevant to the
4848

4949
Linux
5050

51-
curl -Ls https://github.com/grepplabs/kafka-proxy/releases/download/v0.3.12/kafka-proxy-v0.3.12-linux-amd64.tar.gz | tar xz
51+
curl -Ls https://github.com/grepplabs/kafka-proxy/releases/download/v0.4.0/kafka-proxy-v0.4.0-linux-amd64.tar.gz | tar xz
5252

5353
macOS
5454

55-
curl -Ls https://github.com/grepplabs/kafka-proxy/releases/download/v0.3.12/kafka-proxy-v0.3.12-darwin-amd64.tar.gz | tar xz
55+
curl -Ls https://github.com/grepplabs/kafka-proxy/releases/download/v0.4.0/kafka-proxy-v0.4.0-darwin-amd64.tar.gz | tar xz
5656

5757
2. Move the binary in to your PATH.
5858

@@ -70,7 +70,7 @@ Docker images are available on [Docker Hub](https://hub.docker.com/r/grepplabs/k
7070
7171
You can launch a kafka-proxy container for trying it out with
7272
73-
docker run --rm -p 30001-30003:30001-30003 grepplabs/kafka-proxy:0.3.12 \
73+
docker run --rm -p 30001-30003:30001-30003 grepplabs/kafka-proxy:0.4.0 \
7474
server \
7575
--bootstrap-server-mapping "localhost:19092,0.0.0.0:30001" \
7676
--bootstrap-server-mapping "localhost:29092,0.0.0.0:30002" \
@@ -89,7 +89,7 @@ Docker images with precompiled plugins located in `/opt/kafka-proxy/bin/` are ta
8989
9090
You can launch a kafka-proxy container with auth-ldap plugin for trying it out with
9191
92-
docker run --rm -p 30001-30003:30001-30003 grepplabs/kafka-proxy:0.3.12-all \
92+
docker run --rm -p 30001-30003:30001-30003 grepplabs/kafka-proxy:0.4.0-all \
9393
server \
9494
--bootstrap-server-mapping "localhost:19092,0.0.0.0:30001" \
9595
--bootstrap-server-mapping "localhost:29092,0.0.0.0:30002" \
@@ -140,6 +140,7 @@ You can launch a kafka-proxy container with auth-ldap plugin for trying it out w
140140
--debug-enable Enable Debug endpoint
141141
--debug-listen-address string Debug listen address (default "0.0.0.0:6060")
142142
--default-listener-ip string Default listener IP (default "0.0.0.0")
143+
--deterministic-listeners Enable deterministic listeners (listener port = min port + broker id).
143144
--dial-address-mapping stringArray Mapping of target broker address to new one (host:port,host:port). The mapping is performed during connection establishment
144145
--dynamic-advertised-listener string Advertised address for dynamic listeners. If empty, default-listener-ip is used
145146
--dynamic-listeners-disable Disable dynamic listeners.
@@ -170,26 +171,30 @@ You can launch a kafka-proxy container with auth-ldap plugin for trying it out w
170171
--kafka-read-timeout duration How long to wait for a response (default 30s)
171172
--kafka-write-timeout duration How long to wait for a transmit (default 30s)
172173
--log-format string Log format text or json (default "text")
173-
--log-level string Log level debug, info, warning, error, fatal or panic (default "info")
174+
--log-level string Log level trace, debug, info, warning, error, fatal or panic (default "info")
174175
--log-level-fieldname string Log level fieldname for json format (default "@level")
175176
--log-msg-fieldname string Message fieldname for json format (default "@message")
176177
--log-time-fieldname string Time fieldname for json format (default "@timestamp")
177178
--producer-acks-0-disabled Assume fire-and-forget is never sent by the producer. Enabling this parameter will increase performance
178179
--proxy-listener-ca-chain-cert-file string PEM encoded CA's certificate file. If provided, client certificate is required and verified
179180
--proxy-listener-cert-file string PEM encoded file with server certificate
180181
--proxy-listener-cipher-suites strings List of supported cipher suites
182+
--proxy-listener-crl-file string PEM encoded X509 CRLs file
181183
--proxy-listener-curve-preferences strings List of curve preferences
182184
--proxy-listener-keep-alive duration Keep alive period for an active network connection. If zero, keep-alives are disabled (default 1m0s)
183185
--proxy-listener-key-file string PEM encoded file with private key for the server certificate
184186
--proxy-listener-key-password string Password to decrypt rsa private key
185187
--proxy-listener-read-buffer-size int Size of the operating system's receive buffer associated with the connection. If zero, system default is used
186188
--proxy-listener-tls-enable Whether or not to use TLS listener
189+
--proxy-listener-tls-refresh duration Interval for refreshing server TLS certificates. If set to zero, the refresh watch is disabled
187190
--proxy-listener-tls-required-client-subject strings Required client certificate subject common name; example; s:/CN=[value]/C=[state]/C=[DE,PL] or r:/CN=[^val.{2}$]/C=[state]/C=[DE,PL]; check manual for more details
188191
--proxy-listener-write-buffer-size int Sets the size of the operating system's transmit buffer associated with the connection. If zero, system default is used
189192
--proxy-request-buffer-size int Request buffer size pro tcp connection (default 4096)
190193
--proxy-response-buffer-size int Response buffer size pro tcp connection (default 4096)
194+
--sasl-aws-identity-lookup Verify AWS authentication identity
191195
--sasl-aws-profile string AWS profile
192196
--sasl-aws-region string Region for AWS IAM Auth
197+
--sasl-aws-role-arn string AWS Role ARN to assume
193198
--sasl-enable Connect using SASL
194199
--sasl-jaas-config-file string Location of JAAS config file with SASL username and password
195200
--sasl-method string SASL method to use (PLAIN, SCRAM-SHA-256, SCRAM-SHA-512, GSSAPI, AWS_MSK_IAM (default "PLAIN")
@@ -207,7 +212,9 @@ You can launch a kafka-proxy container with auth-ldap plugin for trying it out w
207212
--tls-client-key-password string Password to decrypt rsa private key
208213
--tls-enable Whether or not to use TLS when connecting to the broker
209214
--tls-insecure-skip-verify It controls whether a client verifies the server's certificate chain and host name
215+
--tls-refresh duration Interval for refreshing client TLS certificates. If set to zero, the refresh watch is disabled
210216
--tls-same-client-cert-enable Use only when mutual TLS is enabled on proxy and broker. It controls whether a proxy validates if proxy client certificate exactly matches brokers client cert (tls-client-cert-file)
217+
--tls-system-cert-pool Use system pool for root CAs
211218
212219
### Usage example
213220

cmd/kafka-proxy/server.go

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ package server
22

33
import (
44
"fmt"
5+
"log/slog"
56

67
"github.com/grepplabs/kafka-proxy/config"
78
"github.com/grepplabs/kafka-proxy/proxy"
89
"github.com/oklog/run"
910
"github.com/prometheus/client_golang/prometheus"
1011
"github.com/prometheus/client_golang/prometheus/promhttp"
12+
sloglogrus "github.com/samber/slog-logrus/v2"
1113
"github.com/sirupsen/logrus"
1214
"github.com/spf13/cobra"
1315

@@ -101,10 +103,12 @@ func initFlags() {
101103
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")
102104

103105
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")
104107
Server.Flags().StringVar(&c.Proxy.TLS.ListenerCertFile, "proxy-listener-cert-file", "", "PEM encoded file with server certificate")
105108
Server.Flags().StringVar(&c.Proxy.TLS.ListenerKeyFile, "proxy-listener-key-file", "", "PEM encoded file with private key for the server certificate")
106109
Server.Flags().StringVar(&c.Proxy.TLS.ListenerKeyPassword, "proxy-listener-key-password", os.Getenv("PROXY_LISTENER_KEY_PASSWORD"), "Password to decrypt rsa private key")
107-
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")
108112
Server.Flags().StringSliceVar(&c.Proxy.TLS.ListenerCipherSuites, "proxy-listener-cipher-suites", []string{}, "List of supported cipher suites")
109113
Server.Flags().StringSliceVar(&c.Proxy.TLS.ListenerCurvePreferences, "proxy-listener-curve-preferences", []string{}, "List of curve preferences")
110114

@@ -151,11 +155,13 @@ func initFlags() {
151155

152156
// TLS
153157
Server.Flags().BoolVar(&c.Kafka.TLS.Enable, "tls-enable", false, "Whether or not to use TLS when connecting to the broker")
158+
Server.Flags().DurationVar(&c.Kafka.TLS.Refresh, "tls-refresh", 0*time.Second, "Interval for refreshing client TLS certificates. If set to zero, the refresh watch is disabled")
154159
Server.Flags().BoolVar(&c.Kafka.TLS.InsecureSkipVerify, "tls-insecure-skip-verify", false, "It controls whether a client verifies the server's certificate chain and host name")
155160
Server.Flags().StringVar(&c.Kafka.TLS.ClientCertFile, "tls-client-cert-file", "", "PEM encoded file with client certificate")
156161
Server.Flags().StringVar(&c.Kafka.TLS.ClientKeyFile, "tls-client-key-file", "", "PEM encoded file with private key for the client certificate")
157162
Server.Flags().StringVar(&c.Kafka.TLS.ClientKeyPassword, "tls-client-key-password", os.Getenv("TLS_CLIENT_KEY_PASSWORD"), "Password to decrypt rsa private key")
158163
Server.Flags().StringVar(&c.Kafka.TLS.CAChainCertFile, "tls-ca-chain-cert-file", "", "PEM encoded CA's certificate file")
164+
Server.Flags().BoolVar(&c.Kafka.TLS.SystemCertPool, "tls-system-cert-pool", false, "Use system pool for root CAs")
159165

160166
//Same TLS client cert tls-same-client-cert-enable
161167
Server.Flags().BoolVar(&c.Kafka.TLS.SameClientCertEnable, "tls-same-client-cert-enable", false, "Use only when mutual TLS is enabled on proxy and broker. It controls whether a proxy validates if proxy client certificate exactly matches brokers client cert (tls-client-cert-file)")
@@ -181,6 +187,8 @@ func initFlags() {
181187
// SASL AWS_MSK_IAM
182188
Server.Flags().StringVar(&c.Kafka.SASL.AWSConfig.Region, "sasl-aws-region", "", "Region for AWS IAM Auth")
183189
Server.Flags().StringVar(&c.Kafka.SASL.AWSConfig.Profile, "sasl-aws-profile", "", "AWS profile")
190+
Server.Flags().StringVar(&c.Kafka.SASL.AWSConfig.RoleArn, "sasl-aws-role-arn", "", "AWS Role ARN to assume")
191+
Server.Flags().BoolVar(&c.Kafka.SASL.AWSConfig.IdentityLookup, "sasl-aws-identity-lookup", false, "Verify AWS authentication identity")
184192

185193
// SASL by Proxy plugin
186194
Server.Flags().BoolVar(&c.Kafka.SASL.Plugin.Enable, "sasl-plugin-enable", false, "Use plugin for SASL authentication")
@@ -202,7 +210,7 @@ func initFlags() {
202210

203211
// Logging
204212
Server.Flags().StringVar(&c.Log.Format, "log-format", "text", "Log format text or json")
205-
Server.Flags().StringVar(&c.Log.Level, "log-level", "info", "Log level debug, info, warning, error, fatal or panic")
213+
Server.Flags().StringVar(&c.Log.Level, "log-level", "info", "Log level trace, debug, info, warning, error, fatal or panic")
206214
Server.Flags().StringVar(&c.Log.LevelFieldName, "log-level-fieldname", "@level", "Log level fieldname for json format")
207215
Server.Flags().StringVar(&c.Log.TimeFiledName, "log-time-fieldname", "@timestamp", "Time fieldname for json format")
208216
Server.Flags().StringVar(&c.Log.MsgFiledName, "log-msg-fieldname", "@message", "Message fieldname for json format")
@@ -444,7 +452,7 @@ func Run(_ *cobra.Command, _ []string) {
444452
func NewHTTPHandler() http.Handler {
445453
m := http.NewServeMux()
446454
m.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
447-
w.Write([]byte(
455+
_, _ = w.Write([]byte(
448456
`<html>
449457
<head>
450458
<title>kafka-proxy service</title>
@@ -456,7 +464,7 @@ func NewHTTPHandler() http.Handler {
456464
</html>`))
457465
})
458466
m.HandleFunc(c.Http.HealthPath, func(w http.ResponseWriter, r *http.Request) {
459-
w.Write([]byte(`OK`))
467+
_, _ = w.Write([]byte(`OK`))
460468
})
461469
m.Handle(c.Http.MetricsPath, promhttp.Handler())
462470

@@ -483,6 +491,25 @@ func SetLogger() {
483491
level = logrus.InfoLevel
484492
}
485493
logrus.SetLevel(level)
494+
495+
slog.SetDefault(slog.New(sloglogrus.Option{Level: toSlogLevel(level), Logger: logrus.StandardLogger()}.NewLogrusHandler()))
496+
}
497+
498+
func toSlogLevel(level logrus.Level) slog.Level {
499+
switch level {
500+
case logrus.TraceLevel:
501+
return slog.LevelDebug
502+
case logrus.DebugLevel:
503+
return slog.LevelDebug
504+
case logrus.InfoLevel:
505+
return slog.LevelInfo
506+
case logrus.WarnLevel:
507+
return slog.LevelWarn
508+
case logrus.ErrorLevel, logrus.PanicLevel:
509+
return slog.LevelError
510+
default:
511+
return slog.LevelInfo
512+
}
486513
}
487514

488515
func NewPluginClient(handshakeConfig plugin.HandshakeConfig, plugins map[string]plugin.Plugin, logLevel string, command string, params []string) *plugin.Client {

cmd/plugin-auth-ldap/main.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,10 @@ func main() {
257257

258258
pluginMeta := &pluginMeta{}
259259
flags := pluginMeta.flagSet()
260-
flags.Parse(os.Args[1:])
260+
if err := flags.Parse(os.Args[1:]); err != nil {
261+
logrus.Errorf("error parsing flags: %v", err)
262+
os.Exit(1)
263+
}
261264

262265
urls, err := pluginMeta.getUrls()
263266
if err != nil {

cmd/plugin-auth-user/main.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ func (f *PasswordAuthenticator) flagSet() *flag.FlagSet {
3131
func main() {
3232
passwordAuthenticator := &PasswordAuthenticator{}
3333
flags := passwordAuthenticator.flagSet()
34-
flags.Parse(os.Args[1:])
34+
if err := flags.Parse(os.Args[1:]); err != nil {
35+
logrus.Errorf("error parsing flags: %v", err)
36+
os.Exit(1)
37+
}
3538

3639
if passwordAuthenticator.Password == "" {
3740
passwordAuthenticator.Password = os.Getenv(EnvSaslPassword)

0 commit comments

Comments
 (0)