diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4437d210e825e62fc9f1e0099e692e052cf7008d..c6c369b49dc46e1b174c8505b748c6443f597854 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,6 +11,7 @@ build_and_tag_image: - /kaniko/executor --context "${CI_PROJECT_DIR}" --dockerfile "${CI_PROJECT_DIR}/Dockerfile" + --build-arg "VERSION=${CI_COMMIT_TAG}" --destination "${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG}" rules: - if: $CI_COMMIT_TAG @@ -26,6 +27,7 @@ build_latest: - /kaniko/executor --context "${CI_PROJECT_DIR}" --dockerfile "${CI_PROJECT_DIR}/Dockerfile" + --build-arg "VERSION=master-"$(date "+%Y.%m.%d") --destination "${CI_REGISTRY_IMAGE}:latest" - cp /canary/gocanary $CI_PROJECT_DIR/ rules: diff --git a/Dockerfile b/Dockerfile index ef2b410cbff3af4743a6eb7fe473232baf728d3c..83a216d4385a56180dd2d9ac6edb8f5627102c41 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,5 @@ FROM golang:1.22.3 as builder +ARG VERSION MAINTAINER Jose Carlos Luna <Jose.Carlos.Luna@cern.ch> ARG MUSL_VERSION=1.2.5 RUN wget https://www.musl-libc.org/releases/musl-${MUSL_VERSION}.tar.gz && \ @@ -8,7 +9,7 @@ RUN wget https://www.musl-libc.org/releases/musl-${MUSL_VERSION}.tar.gz && \ make && make install COPY . /build -RUN cd /build; CGO_ENABLED=1 CC=/usr/local/musl/bin/musl-gcc go build --ldflags '-linkmode external -extldflags=-static' +RUN cd /build; CGO_ENABLED=1 CC=/usr/local/musl/bin/musl-gcc go build --ldflags '-X main.Version=${VERSION} -linkmode external -extldflags=-static' RUN strip /build/gocanary FROM scratch diff --git a/configtools.go b/configtools.go index 09f39561e1e7ff592a6dc4e84c93fbd52cde6784..adfc333bac17c161610ae9531e1c8a9d2aff43b2 100644 --- a/configtools.go +++ b/configtools.go @@ -14,9 +14,8 @@ import ( chttp "gitlab.cern.ch/ComputerSecurity/gocanary/server/http" ) -const version = "v0.1" - // Parameters +var version string var bindAddr string var slackHook string var slackSilence uint16 @@ -34,6 +33,8 @@ var syslogEnabled bool var hardeningEnabled bool var domains []string var binPath string +var autocertDomains []string +var cacheDir string func getDNSConfig() cdns.DNSServerConfig { return cdns.DNSServerConfig{ @@ -46,17 +47,15 @@ func getDNSConfig() cdns.DNSServerConfig { func getHTTPConfig() chttp.HTTPServerConfig { return chttp.HTTPServerConfig{ - BindAddr: server.GetBindAddr(bindAddr, httpPort), - Domains: domains, - } -} - -func getHTTPSConfig() chttp.HTTPSServerConfig { - return chttp.HTTPSServerConfig{ - BindAddr: server.GetBindAddr(bindAddr, httpsPort), - CertFile: httpsCert, - CertKeyFile: httpsKey, - Domains: domains, + EnableHttp: httpEnabled, + EnableHttps: httpsEnabled, + HttpBindAddr: server.GetBindAddr(bindAddr, httpPort), + HttpsBindAddr: server.GetBindAddr(bindAddr, httpsPort), + CertFile: httpsCert, + CertKeyFile: httpsKey, + Domains: domains, + AutocertDomains: autocertDomains, + CacheDir: cacheDir, } } @@ -73,12 +72,14 @@ func init() { gocanaryCmd.PersistentFlags().BoolVar(&dnsNotAnswer, "dns-not-answer", false, "Do not answer with any response") gocanaryCmd.PersistentFlags().StringVar(&httpsCert, "https-cert", "cert.pem", "File contained the certificate in PEM format") gocanaryCmd.PersistentFlags().StringVar(&httpsKey, "https-key", "cert.key", "File contained the certificate key in PEM format") + gocanaryCmd.PersistentFlags().StringVar(&cacheDir, "cache-dir", "./cache", "Writable directory for holding up autocertificates") gocanaryCmd.PersistentFlags().BoolVar(&httpsEnabled, "enable-https", false, "Enable HTTPS listener") gocanaryCmd.PersistentFlags().BoolVar(&httpEnabled, "enable-http", true, "Enable HTTP listener") gocanaryCmd.PersistentFlags().BoolVar(&dnsEnabled, "enable-dns", true, "Enable DNS listeners (tcp and udp)") gocanaryCmd.PersistentFlags().BoolVar(&syslogEnabled, "enable-syslog", false, "Enable logging to syslog") gocanaryCmd.PersistentFlags().BoolVar(&hardeningEnabled, "enable-hardening", true, "Enable hardening measures") gocanaryCmd.PersistentFlags().StringArrayVar(&domains, "domain", []string{}, "Only respond to this domain (can be specified multiple times)") + gocanaryCmd.PersistentFlags().StringArrayVar(&autocertDomains, "autocert-domain", []string{}, "Enable let's encrypt autocertificate (can be specified multiple times), this will ignore https-cert and http-key options") _, filename, _, _ := runtime.Caller(1) binPath = path.Dir(filename) @@ -86,10 +87,11 @@ func init() { } var gocanaryCmd = &cobra.Command{ - Use: "gocanary", - Short: "gocanary is a honeytoken/canary collector implementing multiple listeners like http/https/dns", + Use: "gocanary", + Version: version, + Short: "gocanary is a honeytoken/canary collector implementing multiple listeners like http/https/dns", Long: `gocanary is a honeytoken/canary collector daemon that listens for http/https/dns requests. -Aalerts will be generated when a predefined haystack is detected.`, +Alerts will be generated when a predefined haystack is detected.`, PersistentPreRunE: initializeConfig, Run: runCanary, } diff --git a/docker-compose-with-build.yml b/docker-compose-with-build.yml new file mode 100644 index 0000000000000000000000000000000000000000..cff5bb31a5f4ccf074b886401d4a7c5297889731 --- /dev/null +++ b/docker-compose-with-build.yml @@ -0,0 +1,16 @@ +services: + gocanary: + build: . + ports: + - "53:53/udp" + - "53:53/tcp" + - "443:443" + - "80:80" + volumes: + - ./canary.yaml:/canary/canary.yaml + - ./config.yaml:/canary/config.yaml + - ./cert.pem:/canary/cert.pem + - ./cert.key:/canary/cert.key + container_name: gocanary + restart: always + diff --git a/docker-compose.yml b/docker-compose.yml index cff5bb31a5f4ccf074b886401d4a7c5297889731..5443c946de8484e96500dade09a3e71e7782ae80 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ services: gocanary: - build: . + image: gitlab-registry.cern.ch/computersecurity/gocanary:latest ports: - "53:53/udp" - "53:53/tcp" diff --git a/go.mod b/go.mod index caf345f79c897ff1493059577c3f11da02d19021..80a1edbff2abda9373232321c84f763a8398d85b 100644 --- a/go.mod +++ b/go.mod @@ -2,13 +2,21 @@ module gitlab.cern.ch/ComputerSecurity/gocanary go 1.18 -require github.com/miekg/dns v1.1.59 +require ( + github.com/landlock-lsm/go-landlock v0.0.0-20240216195629-efb66220540a + github.com/miekg/dns v1.1.59 + github.com/spf13/cobra v1.8.0 + github.com/spf13/pflag v1.0.5 + github.com/spf13/viper v1.18.2 + github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 + golang.org/x/crypto v0.21.0 + gopkg.in/yaml.v2 v2.4.0 +) require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/landlock-lsm/go-landlock v0.0.0-20240216195629-efb66220540a // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect @@ -17,11 +25,7 @@ require ( github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect - github.com/spf13/cobra v1.8.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.18.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect @@ -31,7 +35,6 @@ require ( golang.org/x/text v0.14.0 // indirect golang.org/x/tools v0.19.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect kernel.org/pub/linux/libs/security/libcap/psx v1.2.69 // indirect ) diff --git a/go.sum b/go.sum index e6b1c7ee2d9e232c9f517c54bd044f933dd4dc0c..f5b9ced89755f9d936cd087789c5e719627a4817 100644 --- a/go.sum +++ b/go.sum @@ -1,12 +1,17 @@ github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/landlock-lsm/go-landlock v0.0.0-20240216195629-efb66220540a h1:dz+a1MiMQksVhejeZwqJuzPawYQBwug74J8PPtkLl9U= github.com/landlock-lsm/go-landlock v0.0.0-20240216195629-efb66220540a/go.mod h1:1NY/VPO8xm3hXw3f+M65z+PJDLUaZA5cu7OfanxoUzY= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= @@ -18,6 +23,8 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= @@ -41,6 +48,7 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= @@ -50,6 +58,8 @@ go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= @@ -64,6 +74,7 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= diff --git a/main.go b/main.go index d6752af653f2b1dc5132deb5e1a4cf1aca7a8be4..e44f5603fd61d67f9b8816f259ac38d0b7bfbe4a 100644 --- a/main.go +++ b/main.go @@ -12,6 +12,7 @@ import ( "log" "log/slog" "os" + "time" "github.com/spf13/cobra" "gitlab.cern.ch/ComputerSecurity/gocanary/alert" @@ -40,24 +41,27 @@ func runCanary(cmd *cobra.Command, args []string) { serverEnabled = true } //Start HTTP/HTTPS servers - if httpEnabled { + if httpEnabled || httpsEnabled { chttp.StartHTTP(getHTTPConfig()) serverEnabled = true } - if httpsEnabled { - chttp.StartHTTPS(getHTTPSConfig()) - serverEnabled = true - } - //Read token description tokens.Initialize(canaryPath) //Drop to nobody and LandLock if hardeningEnabled { + //TODO: Probably better to use a mutex/channel to wait until listeners are really listening... + time.Sleep(1 * time.Second) + harden.DropPrivs() slog.Debug("LandLocking") - harden.LandLock(binPath) + //If autocert we need a writable cache directory by the dropped uid + if len(autocertDomains) > 0 { + harden.LandLock(binPath, cacheDir) + } else { + harden.LandLock(binPath, "") + } } // Block forever if any server is running diff --git a/server/dns/dns.go b/server/dns/dns.go index 5d2793260f0a988cd51c2d5047fe6d4b9f02ed79..bf2ec169b32aa3adfb2f0e65d2bf0d092a7d7d84 100644 --- a/server/dns/dns.go +++ b/server/dns/dns.go @@ -21,7 +21,7 @@ type DNSServerConfig struct { var serverConfig DNSServerConfig -func getCanaryInfo(t tokens.CanaryRecord, w dns.ResponseWriter, r *dns.Msg) alert.DNSCanary { +func getCanaryInfo(t tokens.CanaryRecord, w dns.ResponseWriter) alert.DNSCanary { return alert.DNSCanary{ Canary: alert.Canary{ Key: t.Key, @@ -43,7 +43,7 @@ func checkAndAlert(q dns.Question, w dns.ResponseWriter, r *dns.Msg) bool { if len(serverConfig.Domains) == 0 || slices.Contains(serverConfig.Domains, qDomain) { canary, err := tokens.GetToken(qFirst) if err == nil { - alert.DNSAlert(getCanaryInfo(canary, w, r), canary.Alert) + alert.DNSAlert(getCanaryInfo(canary, w), canary.Alert) return true } } diff --git a/server/http/http.go b/server/http/http.go index 406c6108ac652c237c22b9d2411814532f6300d2..d40a203a678c77ead8529365d07b952c98eba4c1 100644 --- a/server/http/http.go +++ b/server/http/http.go @@ -1,6 +1,7 @@ package http import ( + "crypto/tls" "fmt" "log" "log/slog" @@ -9,26 +10,29 @@ import ( "path" "slices" "strings" + "time" "gitlab.cern.ch/ComputerSecurity/gocanary/alert" "gitlab.cern.ch/ComputerSecurity/gocanary/tokens" + "golang.org/x/crypto/acme/autocert" ) type HTTPServerConfig struct { - BindAddr string - Domains []string + EnableHttp bool + EnableHttps bool + HttpBindAddr string + HttpsBindAddr string + CertFile string + CertKeyFile string + Domains []string + AutocertDomains []string + CacheDir string } -type HTTPSServerConfig struct { - BindAddr string - CertFile string - CertKeyFile string - Domains []string -} - -var httpsServerConfig HTTPSServerConfig var httpServerConfig HTTPServerConfig +var autocertManager *autocert.Manager +// Returns http or https string func getSchema(r *http.Request) string { schema := "http" if r.TLS != nil { @@ -37,12 +41,13 @@ func getSchema(r *http.Request) string { return schema } +// Returns full URL of request, including schema func getFullUrl(r *http.Request) string { return fmt.Sprintf("%s://%s%s", getSchema(r), r.Host, r.URL.Path) } +// Builds the canary alert info func getCanaryInfo(t tokens.CanaryRecord, r *http.Request) alert.HTTPCanary { - return alert.HTTPCanary{ Canary: alert.Canary{ Key: t.Key, @@ -57,6 +62,7 @@ func getCanaryInfo(t tokens.CanaryRecord, r *http.Request) alert.HTTPCanary { } } +// Adds final dot on domains func getNormalizedHostDomain(rHost string) (string, string) { rComponents := strings.Split(rHost, ":") serverHost := rComponents[0] @@ -72,6 +78,7 @@ func getNormalizedHostDomain(rHost string) (string, string) { return hFirst, hDomain } +// Log all requests func logRequest(r *http.Request) { slog.Info("http-request", "Type", "http-request", @@ -85,7 +92,6 @@ func logRequest(r *http.Request) { ) } -// use info in https://gist.github.com/crgimenes/752efa64ef36d94569a694bf940a7b03 func handleRequest(w http.ResponseWriter, r *http.Request) { // Get path part and look for a token lastPath := path.Base(r.URL.Path) @@ -112,34 +118,96 @@ func handleRequest(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, " ") } -func StartHTTP(config HTTPServerConfig) { - mux := http.NewServeMux() - httpServerConfig = config +// Generate TLS config both for certificates given or autocert with let's encrypt +func getTlsConfig(config HTTPServerConfig) *tls.Config { + if len(config.AutocertDomains) > 0 { + return &tls.Config{ + GetCertificate: autocertManager.GetCertificate, + } + } else { + cer, err := tls.LoadX509KeyPair(config.CertFile, config.CertKeyFile) + if err != nil { + log.Fatalf("Error loading certificates") + } + return &tls.Config{Certificates: []tls.Certificate{cer}} + } - // Handle HTTP - mux.HandleFunc("/", handleRequest) +} + +// Initialize autocert manager for let's encrypt certificates +func initializeAutocertManager(autocertDomains []string, cacheDir string) { + if len(autocertDomains) > 0 { + //Autocert domains need to get certificate from let's encrypt + autocertManager = &autocert.Manager{ + Prompt: autocert.AcceptTOS, + HostPolicy: autocert.HostWhitelist(autocertDomains...), + Cache: autocert.DirCache(cacheDir), + } + } +} +func listenHTTP(config HTTPServerConfig, mux *http.ServeMux) { // Start HTTP server go func() { - log.Printf("Starting HTTP server on %s", config.BindAddr) - if err := http.ListenAndServe(config.BindAddr, mux); err != nil { + log.Printf("Starting HTTP server on %s", config.HttpBindAddr) + srv := &http.Server{ + Addr: config.HttpBindAddr, + Handler: mux, + IdleTimeout: 5 * time.Second, + ReadTimeout: 5 * time.Second, + WriteTimeout: 10 * time.Second, + } + + //If autocert, we should override the handler to get let's encrypt callbacks + if len(config.AutocertDomains) > 0 { + srv.Handler = autocertManager.HTTPHandler(srv.Handler) + + } + + if err := srv.ListenAndServe(); err != nil { log.Fatalf("HTTP server failed: %s", err) } }() } -func StartHTTPS(config HTTPSServerConfig) { - mux := http.NewServeMux() - httpsServerConfig = config - - // Handle HTTPS - mux.HandleFunc("/", handleRequest) - +func listenHTTPS(config HTTPServerConfig, mux *http.ServeMux) { // Start HTTPS server go func() { - log.Printf("Starting HTTPS server on %s", config.BindAddr) - if err := http.ListenAndServeTLS(config.BindAddr, config.CertFile, config.CertKeyFile, mux); err != nil { + log.Printf("Starting HTTPS server on %s", config.HttpsBindAddr) + tlsConfig := getTlsConfig(config) + srv := &http.Server{ + Addr: config.HttpsBindAddr, + Handler: mux, + TLSConfig: tlsConfig, + IdleTimeout: 5 * time.Second, + ReadTimeout: 5 * time.Second, + WriteTimeout: 10 * time.Second, + } + + if err := srv.ListenAndServeTLS("", ""); err != nil { log.Fatalf("HTTPS server failed: %s", err) } + }() } + +func StartHTTP(config HTTPServerConfig) { + mux := http.NewServeMux() + httpServerConfig = config + + // Handle HTTP + mux.HandleFunc("/", handleRequest) + + //Autocert? + if len(config.AutocertDomains) > 0 { + initializeAutocertManager(config.AutocertDomains, config.CacheDir) + } + + if config.EnableHttp { + listenHTTP(config, mux) + } + + if config.EnableHttps { + listenHTTPS(config, mux) + } +} diff --git a/utils/harden/harden.go b/utils/harden/harden.go index 05397a14c69389e7517542f34cc4a476db9067d1..a1b73e5ad4edba771a1c6354c7d779aa38c1ab27 100644 --- a/utils/harden/harden.go +++ b/utils/harden/harden.go @@ -83,13 +83,22 @@ func DropRoot() { } // Locks this process to be able to read/write on certain file/paths -func LandLock(extraPath string) { - err := landlock.V4.BestEffort().RestrictPaths( +func LandLock(extraPath string, cacheDir string) { + + defaults := []landlock.Rule{ landlock.RODirs("/etc"), landlock.RODirs("/proc"), landlock.RODirs("/run"), landlock.RODirs("."), landlock.RODirs(extraPath), + } + + if cacheDir != "" { + defaults = append(defaults, landlock.RWDirs(cacheDir)) + } + + err := landlock.V4.BestEffort().RestrictPaths( + defaults..., ) if err != nil { log.Fatal("Failed LandLock : " + err.Error())