Skip to content

Commit f09ffde

Browse files
authored
refact pkg/acquisition: split http.go (#4030)
1 parent 409c15a commit f09ffde

File tree

7 files changed

+554
-521
lines changed

7 files changed

+554
-521
lines changed

pkg/acquisition/http.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ import (
88

99
var (
1010
// verify interface compliance
11-
_ DataSource = (*httpacquisition.HTTPSource)(nil)
12-
_ Tailer = (*httpacquisition.HTTPSource)(nil)
13-
_ MetricsProvider = (*httpacquisition.HTTPSource)(nil)
11+
_ DataSource = (*httpacquisition.Source)(nil)
12+
_ Tailer = (*httpacquisition.Source)(nil)
13+
_ MetricsProvider = (*httpacquisition.Source)(nil)
1414
)
1515

1616
//nolint:gochecknoinits
1717
func init() {
18-
registerDataSource("http", func() DataSource { return &httpacquisition.HTTPSource{} })
18+
registerDataSource("http", func() DataSource { return &httpacquisition.Source{} })
1919
}
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
package httpacquisition
2+
3+
import (
4+
"context"
5+
"crypto/tls"
6+
"crypto/x509"
7+
"errors"
8+
"fmt"
9+
"net/http"
10+
"os"
11+
"time"
12+
13+
log "github.com/sirupsen/logrus"
14+
"gopkg.in/yaml.v3"
15+
16+
"github.com/crowdsecurity/crowdsec/pkg/acquisition/configuration"
17+
"github.com/crowdsecurity/crowdsec/pkg/metrics"
18+
)
19+
20+
type Configuration struct {
21+
// IPFilter []string `yaml:"ip_filter"`
22+
// ChunkSize *int64 `yaml:"chunk_size"`
23+
ListenAddr string `yaml:"listen_addr"`
24+
ListenSocket string `yaml:"listen_socket"`
25+
Path string `yaml:"path"`
26+
AuthType string `yaml:"auth_type"`
27+
BasicAuth *BasicAuthConfig `yaml:"basic_auth"`
28+
Headers *map[string]string `yaml:"headers"`
29+
TLS *TLSConfig `yaml:"tls"`
30+
CustomStatusCode *int `yaml:"custom_status_code"`
31+
CustomHeaders *map[string]string `yaml:"custom_headers"`
32+
MaxBodySize *int64 `yaml:"max_body_size"`
33+
Timeout *time.Duration `yaml:"timeout"`
34+
configuration.DataSourceCommonCfg `yaml:",inline"`
35+
}
36+
37+
type BasicAuthConfig struct {
38+
Username string `yaml:"username"`
39+
Password string `yaml:"password"`
40+
}
41+
42+
type TLSConfig struct {
43+
InsecureSkipVerify bool `yaml:"insecure_skip_verify"`
44+
ServerCert string `yaml:"server_cert"`
45+
ServerKey string `yaml:"server_key"`
46+
CaCert string `yaml:"ca_cert"`
47+
}
48+
49+
func (s *Source) UnmarshalConfig(yamlConfig []byte) error {
50+
s.Config = Configuration{}
51+
52+
err := yaml.Unmarshal(yamlConfig, &s.Config)
53+
if err != nil {
54+
return fmt.Errorf("cannot parse %s datasource configuration: %w", s.GetName(), err)
55+
}
56+
57+
if s.Config.Mode == "" {
58+
s.Config.Mode = configuration.TAIL_MODE
59+
}
60+
61+
return nil
62+
}
63+
64+
func (c *Configuration) Validate() error {
65+
if c.ListenAddr == "" && c.ListenSocket == "" {
66+
return errors.New("listen_addr or listen_socket is required")
67+
}
68+
69+
if c.Path == "" {
70+
c.Path = "/"
71+
}
72+
73+
if c.Path[0] != '/' {
74+
return errors.New("path must start with /")
75+
}
76+
77+
switch c.AuthType {
78+
case "basic_auth":
79+
baseErr := "basic_auth is selected, but"
80+
if c.BasicAuth == nil {
81+
return errors.New(baseErr + " basic_auth is not provided")
82+
}
83+
84+
if c.BasicAuth.Username == "" {
85+
return errors.New(baseErr + " username is not provided")
86+
}
87+
88+
if c.BasicAuth.Password == "" {
89+
return errors.New(baseErr + " password is not provided")
90+
}
91+
case "headers":
92+
if c.Headers == nil {
93+
return errors.New("headers is selected, but headers is not provided")
94+
}
95+
case "mtls":
96+
if c.TLS == nil || c.TLS.CaCert == "" {
97+
return errors.New("mtls is selected, but ca_cert is not provided")
98+
}
99+
default:
100+
return errors.New("invalid auth_type: must be one of basic_auth, headers, mtls")
101+
}
102+
103+
if c.TLS != nil {
104+
if c.TLS.ServerCert == "" {
105+
return errors.New("server_cert is required")
106+
}
107+
108+
if c.TLS.ServerKey == "" {
109+
return errors.New("server_key is required")
110+
}
111+
}
112+
113+
if c.MaxBodySize != nil && *c.MaxBodySize <= 0 {
114+
return errors.New("max_body_size must be positive")
115+
}
116+
117+
/*
118+
if hc.ChunkSize != nil && *hc.ChunkSize <= 0 {
119+
return errors.New("chunk_size must be positive")
120+
}
121+
*/
122+
123+
if c.CustomStatusCode != nil {
124+
statusText := http.StatusText(*c.CustomStatusCode)
125+
if statusText == "" {
126+
return errors.New("invalid HTTP status code")
127+
}
128+
}
129+
130+
return nil
131+
}
132+
133+
func (s *Source) Configure(_ context.Context, yamlConfig []byte, logger *log.Entry, metricsLevel metrics.AcquisitionMetricsLevel) error {
134+
s.logger = logger
135+
s.metricsLevel = metricsLevel
136+
137+
err := s.UnmarshalConfig(yamlConfig)
138+
if err != nil {
139+
return err
140+
}
141+
142+
if err := s.Config.Validate(); err != nil {
143+
return fmt.Errorf("invalid configuration: %w", err)
144+
}
145+
146+
return nil
147+
}
148+
149+
func (c *Configuration) NewTLSConfig() (*tls.Config, error) {
150+
tlsConfig := tls.Config{
151+
InsecureSkipVerify: c.TLS.InsecureSkipVerify,
152+
}
153+
154+
if c.TLS.ServerCert != "" && c.TLS.ServerKey != "" {
155+
cert, err := tls.LoadX509KeyPair(c.TLS.ServerCert, c.TLS.ServerKey)
156+
if err != nil {
157+
return nil, fmt.Errorf("failed to load server cert/key: %w", err)
158+
}
159+
160+
tlsConfig.Certificates = []tls.Certificate{cert}
161+
}
162+
163+
if c.AuthType == "mtls" && c.TLS.CaCert != "" {
164+
caCert, err := os.ReadFile(c.TLS.CaCert)
165+
if err != nil {
166+
return nil, fmt.Errorf("failed to read ca cert: %w", err)
167+
}
168+
169+
caCertPool, err := x509.SystemCertPool()
170+
if err != nil {
171+
return nil, fmt.Errorf("failed to load system cert pool: %w", err)
172+
}
173+
174+
if caCertPool == nil {
175+
caCertPool = x509.NewCertPool()
176+
}
177+
178+
caCertPool.AppendCertsFromPEM(caCert)
179+
tlsConfig.ClientCAs = caCertPool
180+
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
181+
}
182+
183+
return &tlsConfig, nil
184+
}
185+

0 commit comments

Comments
 (0)