Skip to content

Commit fe9272d

Browse files
e-n-0eliottness
andauthored
envoyproxy: body parsing support (#3671)
Co-authored-by: Eliott Bouhana <[email protected]>
1 parent cb65a92 commit fe9272d

File tree

13 files changed

+1485
-515
lines changed

13 files changed

+1485
-515
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Unless explicitly stated otherwise all files in this repository are licensed
2+
// under the Apache License Version 2.0.
3+
// This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
// Copyright 2024 Datadog, Inc.
5+
6+
package gocontrolplane
7+
8+
// bodyBuffer manages the buffering of request/response bodies with size limits
9+
type bodyBuffer struct {
10+
Buffer []byte
11+
SizeLimit int
12+
Truncated bool
13+
}
14+
15+
// newBodyBuffer creates a new bodyBuffer with the specified size limit
16+
func newBodyBuffer(sizeLimit int) *bodyBuffer {
17+
return &bodyBuffer{
18+
SizeLimit: sizeLimit,
19+
Truncated: false,
20+
}
21+
}
22+
23+
// Append adds a chunk of data to the buffer, respecting the size limit
24+
func (b *bodyBuffer) Append(chunk []byte) {
25+
if b.Truncated || len(chunk) == 0 {
26+
return
27+
}
28+
29+
currentSize := len(b.Buffer)
30+
remainingCapacity := b.SizeLimit - currentSize
31+
32+
bytesToAdd := len(chunk)
33+
if bytesToAdd > remainingCapacity {
34+
bytesToAdd = remainingCapacity
35+
b.Truncated = true
36+
instr.Logger().Debug("external_processing: body size limit reached, truncating body to %d bytes", bytesToAdd)
37+
}
38+
39+
if b.Buffer == nil {
40+
b.Buffer = make([]byte, 0, bytesToAdd)
41+
}
42+
43+
b.Buffer = append(b.Buffer, chunk[:bytesToAdd]...)
44+
}

contrib/envoyproxy/go-control-plane/cmd/serviceextensions/main.go

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"time"
2020

2121
"golang.org/x/sync/errgroup"
22+
"google.golang.org/grpc/credentials"
2223

2324
gocontrolplane "github.com/DataDog/dd-trace-go/contrib/envoyproxy/go-control-plane/v2"
2425
"github.com/DataDog/dd-trace-go/v2/ddtrace/tracer"
@@ -27,7 +28,6 @@ import (
2728
extproc "github.com/envoyproxy/go-control-plane/envoy/service/ext_proc/v3"
2829
"github.com/gorilla/mux"
2930
"google.golang.org/grpc"
30-
"google.golang.org/grpc/credentials"
3131
)
3232

3333
// AppsecCalloutExtensionService defines the struct that follows the ExternalProcessorServer interface.
@@ -36,26 +36,29 @@ type AppsecCalloutExtensionService struct {
3636
}
3737

3838
type serviceExtensionConfig struct {
39-
extensionPort string
40-
extensionHost string
41-
healthcheckPort string
42-
observabilityMode bool
39+
extensionPort string
40+
extensionHost string
41+
healthcheckPort string
42+
observabilityMode bool
43+
bodyParsingSizeLimit int
4344
}
4445

4546
func loadConfig() serviceExtensionConfig {
4647
extensionPortInt := intEnv("DD_SERVICE_EXTENSION_PORT", 443)
4748
healthcheckPortInt := intEnv("DD_SERVICE_EXTENSION_HEALTHCHECK_PORT", 80)
4849
extensionHostStr := ipEnv("DD_SERVICE_EXTENSION_HOST", net.IP{0, 0, 0, 0}).String()
4950
observabilityMode := boolEnv("DD_SERVICE_EXTENSION_OBSERVABILITY_MODE", false)
51+
bodyParsingSizeLimit := intEnv("DD_APPSEC_BODY_PARSING_SIZE_LIMIT", 0)
5052

5153
extensionPortStr := strconv.FormatInt(int64(extensionPortInt), 10)
5254
healthcheckPortStr := strconv.FormatInt(int64(healthcheckPortInt), 10)
5355

5456
return serviceExtensionConfig{
55-
extensionPort: extensionPortStr,
56-
extensionHost: extensionHostStr,
57-
healthcheckPort: healthcheckPortStr,
58-
observabilityMode: observabilityMode,
57+
extensionPort: extensionPortStr,
58+
extensionHost: extensionHostStr,
59+
healthcheckPort: healthcheckPortStr,
60+
observabilityMode: observabilityMode,
61+
bodyParsingSizeLimit: bodyParsingSizeLimit,
5962
}
6063
}
6164

@@ -142,25 +145,24 @@ func startHealthCheck(ctx context.Context, config serviceExtensionConfig) error
142145
}
143146

144147
func startGPRCSsl(ctx context.Context, service extproc.ExternalProcessorServer, config serviceExtensionConfig) error {
145-
cert, err := tls.LoadX509KeyPair("localhost.crt", "localhost.key")
146-
if err != nil {
147-
return fmt.Errorf("failed to load key pair: %v", err)
148-
}
149-
150148
lis, err := net.Listen("tcp", config.extensionHost+":"+config.extensionPort)
151149
if err != nil {
152150
return fmt.Errorf("gRPC server: %v", err)
153151
}
154152

155-
grpcCredentials := credentials.NewServerTLSFromCert(&cert)
156-
grpcServer := grpc.NewServer(grpc.Creds(grpcCredentials))
153+
cert, err := tls.LoadX509KeyPair("localhost.crt", "localhost.key")
154+
if err != nil {
155+
return fmt.Errorf("failed to load key pair: %v", err)
156+
}
157157

158+
grpcServer := grpc.NewServer(grpc.Creds(credentials.NewServerTLSFromCert(&cert)))
158159
appsecEnvoyExternalProcessorServer := gocontrolplane.AppsecEnvoyExternalProcessorServer(
159160
service,
160161
gocontrolplane.AppsecEnvoyConfig{
161162
IsGCPServiceExtension: true,
162163
BlockingUnavailable: config.observabilityMode,
163164
Context: ctx,
165+
BodyParsingSizeLimit: config.bodyParsingSizeLimit,
164166
})
165167

166168
go func() {

0 commit comments

Comments
 (0)