Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AdditionalCA and InsecureSkipVerify #537

Merged
merged 2 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions config/serverconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ type ServerConfig struct {
TimezoneScript string `json:"timezoneScript"`
MaxUploadSizeBytes int `json:"maxUploadSizeBytes"`
Proxy string `json:"proxy"`
AdditionalCA string `json:"additionalCA"`
InsecureSkipVerify bool `json:"insecureSkipVerify"`
SrvKey string `json:"srvKey"`
SrvKeyBytes []byte
SrvExpSeconds int `json:"srvExpSeconds"`
Expand Down
25 changes: 15 additions & 10 deletions server/modules/detections/detengine_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"strings"
"time"

"github.com/security-onion-solutions/securityonion-soc/config"
"github.com/security-onion-solutions/securityonion-soc/model"

"github.com/apex/log"
Expand Down Expand Up @@ -112,7 +113,7 @@ type DirtyRepo struct {
Repo *model.RuleRepo
}

func UpdateRepos(isRunning *bool, baseRepoFolder string, rulesRepos []*model.RuleRepo, proxy string) (allRepos map[string]*DirtyRepo, anythingNew bool, err error) {
func UpdateRepos(isRunning *bool, baseRepoFolder string, rulesRepos []*model.RuleRepo, cfg *config.ServerConfig) (allRepos map[string]*DirtyRepo, anythingNew bool, err error) {
allRepos = map[string]*DirtyRepo{} // map[repoPath]repo

// read existing repos
Expand Down Expand Up @@ -154,9 +155,9 @@ func UpdateRepos(isRunning *bool, baseRepoFolder string, rulesRepos []*model.Rul
allRepos[repoPath] = dirty
reclone := false

proxyOpts, err := proxyToTransportOptions(proxy)
proxyOpts, err := proxyToTransportOptions(cfg.Proxy)
if err != nil {
log.WithError(err).WithField("proxy", proxy).Error("failed to parse proxy URL, not using the proxy")
log.WithError(err).WithField("proxy", cfg.Proxy).Error("failed to parse proxy URL, not using the proxy")
// no return here, not a bug
}

Expand Down Expand Up @@ -197,9 +198,11 @@ func UpdateRepos(isRunning *bool, baseRepoFolder string, rulesRepos []*model.Rul
defer cancel()

err = work.PullContext(ctx, &git.PullOptions{
Depth: 1,
SingleBranch: true,
ProxyOptions: proxyOpts,
Depth: 1,
SingleBranch: true,
ProxyOptions: proxyOpts,
CABundle: []byte(cfg.AdditionalCA),
InsecureSkipTLS: cfg.InsecureSkipVerify,
})
if err != nil && err != git.NoErrAlreadyUpToDate {
log.WithError(err).WithField("repoPath", repoPath).Error("failed to pull repo, doing nothing with it")
Expand Down Expand Up @@ -231,10 +234,12 @@ func UpdateRepos(isRunning *bool, baseRepoFolder string, rulesRepos []*model.Rul
if !ok || reclone {
// repo does not exist or was just deleted, clone
_, err = git.PlainClone(repoPath, false, &git.CloneOptions{
Depth: 1,
SingleBranch: true,
URL: repo.Repo,
ProxyOptions: proxyOpts,
Depth: 1,
SingleBranch: true,
URL: repo.Repo,
ProxyOptions: proxyOpts,
CABundle: []byte(cfg.AdditionalCA),
InsecureSkipTLS: cfg.InsecureSkipVerify,
})
if err != nil {
log.WithError(err).WithField("repoPath", repoPath).Error("failed to clone repo, doing nothing with it")
Expand Down
44 changes: 33 additions & 11 deletions server/modules/elastalert/elastalert.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"bytes"
"context"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"encoding/json"
Expand Down Expand Up @@ -617,7 +619,7 @@ func (e *ElastAlertEngine) startCommunityRuleImport() {

var dirtyRepos map[string]*detections.DirtyRepo

dirtyRepos, repoChanges, err = detections.UpdateRepos(&e.isRunning, e.reposFolder, e.rulesRepos, e.srv.Config.Proxy)
dirtyRepos, repoChanges, err = detections.UpdateRepos(&e.isRunning, e.reposFolder, e.rulesRepos, e.srv.Config)
if err != nil {
if strings.Contains(err.Error(), "module stopped") {
break
Expand Down Expand Up @@ -1662,7 +1664,8 @@ func (e *ElastAlertEngine) getDeployedPublicIds() (publicIds []string, err error
//go:generate mockgen -destination mock/mock_iomanager.go -package mock . IOManager

type ResourceManager struct {
Engine *ElastAlertEngine
Engine *ElastAlertEngine
_client *http.Client
}

func (_ *ResourceManager) ReadFile(path string) ([]byte, error) {
Expand All @@ -1682,27 +1685,46 @@ func (_ *ResourceManager) ReadDir(path string) ([]os.DirEntry, error) {
}

func (resman *ResourceManager) MakeRequest(req *http.Request) (*http.Response, error) {
client := resman.buildHttpClient()
return client.Do(req)
if resman._client == nil {
// cache for reuse, the config values can't change without a server restart
resman._client = resman.buildHttpClient()
}

return resman._client.Do(req)
}

func (resman *ResourceManager) buildHttpClient() *http.Client {
client := http.DefaultClient
transport := &http.Transport{}

if resman.Engine.srv.Config.Proxy != "" {
p, err := url.Parse(resman.Engine.srv.Config.Proxy)
if err != nil {
log.WithError(err).WithField("proxy", resman.Engine.srv.Config.Proxy).Error("unable to parse proxy URL, not using proxy")
} else {
client = &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyURL(p),
},
}
transport.Proxy = http.ProxyURL(p)
}
}

return client
if resman.Engine.srv.Config.InsecureSkipVerify {
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
}

if resman.Engine.srv.Config.AdditionalCA != "" {
if transport.TLSClientConfig == nil {
transport.TLSClientConfig = &tls.Config{}
}

pool, err := x509.SystemCertPool()
if err != nil {
pool = x509.NewCertPool()
}

pool.AppendCertsFromPEM([]byte(resman.Engine.srv.Config.AdditionalCA))

transport.TLSClientConfig.RootCAs = pool
}

return &http.Client{Transport: transport}
}

func (_ *ResourceManager) ExecCommand(cmd *exec.Cmd) (output []byte, exitCode int, runtime time.Duration, err error) {
Expand Down
74 changes: 57 additions & 17 deletions server/modules/elastalert/elastalert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1035,24 +1035,46 @@ func TestBuildHttpClient(t *testing.T) {
tests := []struct {
Name string
Proxy string
ExpectedTransportNil bool
ExpProxy *string
RootCA string
InsecureSkipVerify bool
ExpectEmptyTransport bool
}{
{
Name: "Empty",
Proxy: "",
ExpectedTransportNil: true,
ExpectEmptyTransport: true,
},
{
Name: "Has Proxy",
Proxy: "http://myProxy:3128",
ExpectedTransportNil: false,
ExpProxy: util.Ptr("http://myProxy:3128"),
Name: "Has Proxy",
Proxy: "http://myProxy:3128",
},
{
Name: "Has Root CA",
RootCA: "pubkey",
},
{
Name: "InvalidSkipVerify",
InsecureSkipVerify: true,
},
{
Name: "Proxy + Root CA",
Proxy: "http://myProxy:3128",
RootCA: "pubkey",
},
{
Name: "Proxy + InsecureSkipVerify",
Proxy: "http://myProxy:3128",
InsecureSkipVerify: true,
},
{
Name: "Proxy + Root CA + InsecureSkipVerify",
Proxy: "http://myProxy:3128",
RootCA: "pubkey",
InsecureSkipVerify: true,
},
{
Name: "Invalid Proxy",
Proxy: "%",
ExpectedTransportNil: true,
ExpectEmptyTransport: true,
},
}

Expand All @@ -1071,25 +1093,43 @@ func TestBuildHttpClient(t *testing.T) {
for _, test := range tests {
test := test
t.Run(test.Name, func(t *testing.T) {
t.Parallel()

resman.Engine.srv.Config.Proxy = test.Proxy
resman.Engine.srv.Config.AdditionalCA = test.RootCA
resman.Engine.srv.Config.InsecureSkipVerify = test.InsecureSkipVerify

client := resman.buildHttpClient()
transport := client.Transport.(*http.Transport)

if test.ExpectedTransportNil {
assert.Nil(t, client.Transport)
} else {
assert.NotNil(t, client.Transport)
assert.IsType(t, &http.Transport{}, client.Transport)
if test.ExpectEmptyTransport {
assert.Equal(t, &http.Transport{}, transport)
return
}

transport := client.Transport.(*http.Transport)
if test.Proxy != "" {
assert.NotNil(t, transport)
assert.NotNil(t, transport.Proxy)

proxyURL, err := transport.Proxy(nil)
assert.NoError(t, err)
assert.Equal(t, proxy, proxyURL.String())
}

if test.RootCA != "" {
assert.NotNil(t, transport.TLSClientConfig)
assert.NotNil(t, transport.TLSClientConfig.RootCAs)
} else {
if transport.TLSClientConfig != nil {
assert.Nil(t, transport.TLSClientConfig.RootCAs)
}
}

if test.InsecureSkipVerify {
assert.True(t, transport.TLSClientConfig.InsecureSkipVerify)
} else {
if transport.TLSClientConfig != nil {
assert.False(t, transport.TLSClientConfig.InsecureSkipVerify)
}
}
})
}
}
9 changes: 1 addition & 8 deletions server/modules/strelka/strelka.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"errors"
"fmt"
"io/fs"
"net/http"
"os"
"os/exec"
"path/filepath"
Expand Down Expand Up @@ -60,7 +59,6 @@ type IOManager interface {
WriteFile(path string, contents []byte, perm fs.FileMode) error
DeleteFile(path string) error
ReadDir(path string) ([]os.DirEntry, error)
MakeRequest(*http.Request) (*http.Response, error)
ExecCommand(cmd *exec.Cmd) ([]byte, int, time.Duration, error)
}

Expand Down Expand Up @@ -400,7 +398,7 @@ func (e *StrelkaEngine) startCommunityRuleImport() {

upToDate := map[string]*model.RuleRepo{}

allRepos, anythingNew, err := detections.UpdateRepos(&e.isRunning, e.reposFolder, e.rulesRepos, e.srv.Config.Proxy)
allRepos, anythingNew, err := detections.UpdateRepos(&e.isRunning, e.reposFolder, e.rulesRepos, e.srv.Config)
if err != nil {
if strings.Contains(err.Error(), "module stopped") {
break
Expand Down Expand Up @@ -1172,11 +1170,6 @@ func (_ *ResourceManager) DeleteFile(path string) error {
func (_ *ResourceManager) ReadDir(path string) ([]os.DirEntry, error) {
return os.ReadDir(path)
}

func (_ *ResourceManager) MakeRequest(req *http.Request) (*http.Response, error) {
return http.DefaultClient.Do(req)
}

func (_ *ResourceManager) ExecCommand(cmd *exec.Cmd) (output []byte, exitCode int, runtime time.Duration, err error) {
start := time.Now()
output, err = cmd.CombinedOutput()
Expand Down
Loading