Skip to content

Commit

Permalink
feat: move id generation from haproxy to app
Browse files Browse the repository at this point in the history
This allows us to not rely on the http header,
but instead use a variable inside the transaction.
  • Loading branch information
fionera committed Feb 19, 2024
1 parent 72a004a commit a551521
Show file tree
Hide file tree
Showing 7 changed files with 21 additions and 22 deletions.
4 changes: 2 additions & 2 deletions examples/coraza.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ spoe-agent coraza-agent
log global

spoe-message coraza-req
args app=str(sample_app) id=unique-id src-ip=src src-port=src_port dst-ip=dst dst-port=dst_port method=method path=path query=query version=req.ver headers=req.hdrs body=req.body
args app=str(sample_app) src-ip=src src-port=src_port dst-ip=dst dst-port=dst_port method=method path=path query=query version=req.ver headers=req.hdrs body=req.body
event on-frontend-http-request

spoe-message coraza-res
args app=str(sample_app) id=unique-id version=res.ver status=status headers=res.hdrs body=res.body
args app=str(sample_app) id=var(txn.e2e.id) version=res.ver status=status headers=res.hdrs body=res.body
event on-http-response


4 changes: 1 addition & 3 deletions examples/haproxy.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ defaults
frontend test
mode http
bind *:80

unique-id-format %[uuid()]
unique-id-header X-Unique-ID

filter spoe engine coraza config /etc/haproxy/coraza.cfg

# Currently haproxy cannot use variables to set the code or deny_status, so this needs to be manually configured here
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.21
require (
github.com/corazawaf/coraza/v3 v3.1.0
github.com/dropmorepackets/haproxy-go v0.0.5-0.20240218203010-94d697923f61
github.com/google/uuid v1.6.0
github.com/magefile/mage v1.15.0
github.com/mccutchen/go-httpbin/v2 v2.13.4
github.com/rs/zerolog v1.32.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ github.com/dropmorepackets/haproxy-go v0.0.5-0.20240218203010-94d697923f61/go.mo
github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI=
github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg=
github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
Expand Down
4 changes: 2 additions & 2 deletions internal/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func (a *Agent) HandleSPOE(ctx context.Context, writer *encoding.ActionWriter, m
messageCorazaResponse = "coraza-res"
)

var messageHandler func(*Application, context.Context, *encoding.Message) error
var messageHandler func(*Application, context.Context, *encoding.ActionWriter, *encoding.Message) error
switch name := string(message.NameBytes()); name {
case messageCorazaRequest:
messageHandler = (*Application).HandleRequest
Expand Down Expand Up @@ -65,7 +65,7 @@ func (a *Agent) HandleSPOE(ctx context.Context, writer *encoding.ActionWriter, m
return
}

err := messageHandler(app, ctx, message)
err := messageHandler(app, ctx, writer, message)
if err == nil {
return
}
Expand Down
21 changes: 11 additions & 10 deletions internal/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/corazawaf/coraza/v3"
"github.com/corazawaf/coraza/v3/types"
"github.com/dropmorepackets/haproxy-go/pkg/encoding"
"github.com/google/uuid"
"github.com/rs/zerolog"
"istio.io/istio/pkg/cache"
)
Expand All @@ -26,7 +27,6 @@ type Application struct {
}

type applicationRequest struct {
ID string
SrcIp netip.Addr
SrcPort int64
DstIp netip.Addr
Expand All @@ -39,15 +39,17 @@ type applicationRequest struct {
Body []byte
}

func (a *Application) HandleRequest(ctx context.Context, message *encoding.Message) error {
func init() {
uuid.EnableRandPool()
}

func (a *Application) HandleRequest(ctx context.Context, writer *encoding.ActionWriter, message *encoding.Message) error {
k := encoding.AcquireKVEntry()
defer encoding.ReleaseKVEntry(k)

var req applicationRequest
for message.KV.Next(k) {
switch name := string(k.NameBytes()); name {
case "id":
req.ID = string(k.ValueBytes())
case "src-ip":
req.SrcIp = k.ValueAddr()
case "src-port":
Expand Down Expand Up @@ -98,13 +100,12 @@ func (a *Application) HandleRequest(ctx context.Context, message *encoding.Messa
}
}

if req.ID == "" {
return fmt.Errorf("request id is empty")
}

tx := a.waf.NewTransactionWithID(req.ID)
tx := a.waf.NewTransactionWithID(uuid.Must(uuid.NewV7()).String())
// write transaction as early as possible to prevent cache misses
a.cache.SetWithExpiration(tx.ID(), tx, a.TransactionTTLMs*time.Millisecond)
if err := writer.SetString(encoding.VarScopeTransaction, "id", tx.ID()); err != nil {
return err
}

tx.ProcessConnection(req.SrcIp.String(), int(req.SrcPort), req.DstIp.String(), int(req.DstPort))

Expand Down Expand Up @@ -178,7 +179,7 @@ type applicationResponse struct {
Body []byte
}

func (a *Application) HandleResponse(ctx context.Context, message *encoding.Message) error {
func (a *Application) HandleResponse(ctx context.Context, writer *encoding.ActionWriter, message *encoding.Message) error {
if !a.ResponseCheck {
return fmt.Errorf("got response but response check is disabled")
}
Expand Down
7 changes: 2 additions & 5 deletions internal/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,6 @@ func withCoraza(t *testing.T, f func(*testing.T, testutil.HAProxyConfig, string)
EngineAddr: l.Addr().String(),
FrontendPort: fmt.Sprintf("%d", testutil.TCPPort(t)),
CustomFrontendConfig: `
unique-id-format %[uuid()]
unique-id-header X-Unique-ID
# Currently haproxy cannot use variables to set the code or deny_status, so this needs to be manually configured here
http-request redirect code 302 location %[var(txn.e2e.data)] if { var(txn.e2e.action) -m str redirect }
http-response redirect code 302 location %[var(txn.e2e.data)] if { var(txn.e2e.action) -m str redirect }
Expand Down Expand Up @@ -113,11 +110,11 @@ spoe-agent e2e
log global
spoe-message coraza-req
args app=str(default) id=unique-id src-ip=src src-port=src_port dst-ip=dst dst-port=dst_port method=method path=path query=query version=req.ver headers=req.hdrs body=req.body
args app=str(default) src-ip=src src-port=src_port dst-ip=dst dst-port=dst_port method=method path=path query=query version=req.ver headers=req.hdrs body=req.body
event on-frontend-http-request
spoe-message coraza-res
args app=str(default) id=unique-id version=res.ver status=status headers=res.hdrs body=res.body
args app=str(default) id=var(txn.e2e.id) version=res.ver status=status headers=res.hdrs body=res.body
event on-http-response
`,
BackendConfig: fmt.Sprintf(`
Expand Down

0 comments on commit a551521

Please sign in to comment.