diff --git a/Makefile b/Makefile index 5c821ee..3aa3185 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -GO_BUILD_TARGET=./cmd/ztsfc_http_environment/main.go -DOCKER_BUILD_TARGET=vs-uulm/ztsfc_http_environment:latest +GO_BUILD_TARGET=./cmd/ztsfc_http_pip/main.go +DOCKER_BUILD_TARGET=vs-uulm/ztsfc_http_pip:latest .PHONY: main main: go docker diff --git a/cmd/ztsfc_http_environment/main.go b/cmd/ztsfc_http_environment/main.go deleted file mode 100644 index e3bbd90..0000000 --- a/cmd/ztsfc_http_environment/main.go +++ /dev/null @@ -1,49 +0,0 @@ -package main - -import ( - "flag" - "log" - "github.com/vs-uulm/ztsfc_http_environment/internal/app/config" - yt "github.com/leobrada/yaml_tools" - logger "github.com/vs-uulm/ztsfc_http_logger" - confInit "github.com/vs-uulm/ztsfc_http_environment/internal/app/init" - ti "github.com/vs-uulm/ztsfc_http_environment/internal/app/threat_intelligence" -) - -var ( - sysLogger *logger.Logger -) - -func init() { - var confFilePath string - - flag.StringVar(&confFilePath, "c", "./config/conf.yml", "Path to user defined yaml config file") - flag.Parse() - - err := yt.LoadYamlFile(confFilePath, &config.Config) - if err != nil { - log.Fatalf("main: init(): could not load yaml file: %v", err) - } - - confInit.InitSysLoggerParams() - sysLogger, err = logger.New(config.Config.SysLogger.LogFilePath, - config.Config.SysLogger.LogLevel, - config.Config.SysLogger.IfTextFormatter, - logger.Fields{"type": "system"}, - ) - if err != nil { - log.Fatalf("main: init(): could not initialize logger: %v", err) - } - sysLogger.Debugf("loading logger configuration from %s - OK", confFilePath) - - if err = confInit.InitConfig(sysLogger); err != nil { - sysLogger.Fatalf("main: init(): could not initialize Environment params: %v", err) - } -} - -func main() { - go ti.RunThreatIntelligence(sysLogger) - - for { - } -} diff --git a/cmd/ztsfc_http_pip/main.go b/cmd/ztsfc_http_pip/main.go new file mode 100644 index 0000000..cacecb3 --- /dev/null +++ b/cmd/ztsfc_http_pip/main.go @@ -0,0 +1,57 @@ +package main + +import ( + "flag" + "log" + "github.com/vs-uulm/ztsfc_http_pip/internal/app/router" + "github.com/vs-uulm/ztsfc_http_pip/internal/app/config" + "github.com/vs-uulm/ztsfc_http_pip/internal/app/device" + yt "github.com/leobrada/yaml_tools" + logger "github.com/vs-uulm/ztsfc_http_logger" + confInit "github.com/vs-uulm/ztsfc_http_pip/internal/app/init" + ti "github.com/vs-uulm/ztsfc_http_pip/internal/app/threat_intelligence" +) + +//var ( +// SysLogger *logger.Logger +//) + +func init() { + var confFilePath string + + flag.StringVar(&confFilePath, "c", "./config/conf.yml", "Path to user defined yaml config file") + flag.Parse() + + err := yt.LoadYamlFile(confFilePath, &config.Config) + if err != nil { + log.Fatalf("main: init(): could not load yaml file: %v", err) + } + + confInit.InitSysLoggerParams() + config.SysLogger, err = logger.New(config.Config.SysLogger.LogFilePath, + config.Config.SysLogger.LogLevel, + config.Config.SysLogger.IfTextFormatter, + logger.Fields{"type": "system"}, + ) + if err != nil { + log.Fatalf("main: init(): could not initialize logger: %v", err) + } + config.SysLogger.Debugf("loading logger configuration from %s - OK", confFilePath) + + if err = confInit.InitConfig(); err != nil { + config.SysLogger.Fatalf("main: init(): could not initialize Environment params: %v", err) + } + + // For testing + device.LoadTestDevices() +} + +func main() { + go ti.RunThreatIntelligence() + + device.PrintDevices() + + pip := router.NewRouter() + + pip.ListenAndServeTLS() +} diff --git a/go.mod b/go.mod index daa194f..844b608 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,9 @@ -module github.com/vs-uulm/ztsfc_http_environment +module github.com/vs-uulm/ztsfc_http_pip go 1.17 require ( + github.com/leobrada/golang_convenience_tools v0.0.0-20220321082627-ef86f3abd9d1 github.com/leobrada/yaml_tools v0.0.0-20220115205103-7f6e1de7ab2e github.com/vs-uulm/ztsfc_http_logger v0.0.0-20220114090830-1511ee49f8df ) diff --git a/go.sum b/go.sum index 047bf08..7547aaa 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/leobrada/golang_convenience_tools v0.0.0-20220321082627-ef86f3abd9d1 h1:ZTCtV4j65XRjLfftWCuXrgHA7s0fnGXKzDRgZVZCv/Q= +github.com/leobrada/golang_convenience_tools v0.0.0-20220321082627-ef86f3abd9d1/go.mod h1:dFsd7aKdV12xS9hk+9raiGEYRBsuwbXRjm9mVq2cxoo= github.com/leobrada/yaml_tools v0.0.0-20220115205103-7f6e1de7ab2e h1:n4X/33vxeWGlhENDCMUKufuZifF47Qmo/9hOa8BwBrY= github.com/leobrada/yaml_tools v0.0.0-20220115205103-7f6e1de7ab2e/go.mod h1:S7LK9JN09inLOGGcXFCjFHkGaaBG3loTfg+cDfIKUfQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/internal/app/config/config.go b/internal/app/config/config.go index 926ad35..b5a3e93 100644 --- a/internal/app/config/config.go +++ b/internal/app/config/config.go @@ -1,14 +1,20 @@ package config import ( + "crypto/x509" + "crypto/tls" + + logger "github.com/vs-uulm/ztsfc_http_logger" ) var ( Config ConfigT + SysLogger *logger.Logger ) type ConfigT struct { SysLogger sysLoggerT `yaml:"system_logger"` + Pip PipT `yaml:"pip"` ThreatIntelligence ThreatIntelligenceT `yaml:"threat_intelligence"` } @@ -18,6 +24,16 @@ type sysLoggerT struct { IfTextFormatter string `yaml:"system_logger_format"` } +type PipT struct { + ListenAddr string `yaml:"listen_addr"` + CertsPipAcceptsWhenShownByPdp []string `yaml:"certs_pip_accepts_when_shown_by_pdp"` + CertShownByPipToPdp string `yaml:"cert_shown_by_pip_to_pdp"` + PrivkeyForCertShownByPipToPdp string `yaml:"privkey_for_cert_shown_by_pip_to_pdp"` + + CaCertPoolPipAcceptsFromPdp *x509.CertPool + X509KeyPairShownByPipToPdp tls.Certificate +} + type ThreatIntelligenceT struct { ListenAddr string `yaml:"listen_addr"` } diff --git a/internal/app/device/device.go b/internal/app/device/device.go new file mode 100644 index 0000000..82b8c61 --- /dev/null +++ b/internal/app/device/device.go @@ -0,0 +1,30 @@ +package device + +import ( + "github.com/vs-uulm/ztsfc_http_pip/internal/app/config" +) + +var ( + DevicesByID = make(map[string]*Device) + DevicesByIP = make(map[string]*Device) +) + +type Device struct { + DeviceID string `json:"deviceID"` + CurrentIP string `json:"currentIP"` + Revoked bool `json:"revoked"` +} + +func NewDevice(_deviceID, _currentIP string, _revoked bool) (*Device, error) { + newDevice := new(Device) + newDevice.DeviceID = _deviceID + newDevice.CurrentIP = _currentIP + newDevice.Revoked = _revoked + return newDevice, nil +} + +func PrintDevices() { + for _, deviceObj := range DevicesByID { + config.SysLogger.Infof("%v\n", deviceObj) + } +} diff --git a/internal/app/device/test_device.go b/internal/app/device/test_device.go new file mode 100644 index 0000000..0b7bfc3 --- /dev/null +++ b/internal/app/device/test_device.go @@ -0,0 +1,6 @@ +package device + +func LoadTestDevices() { + m1MacMini, _ := NewDevice("M1 Mac Mini", "", false) + DevicesByID[m1MacMini.DeviceID] = m1MacMini +} diff --git a/internal/app/init/init_config.go b/internal/app/init/init_config.go index 3056f11..1b6c599 100644 --- a/internal/app/init/init_config.go +++ b/internal/app/init/init_config.go @@ -2,13 +2,15 @@ package init import ( "fmt" - - logger "github.com/vs-uulm/ztsfc_http_logger" ) -func InitConfig(sysLogger *logger.Logger) error { - if err := initThreatIntelligence(sysLogger); err != nil { +func InitConfig() error { + if err := initThreatIntelligence(); err != nil { + return fmt.Errorf("init: InitConfig(): %v", err) + } + + if err := initPip(); err != nil { return fmt.Errorf("init: InitConfig(): %v", err) } diff --git a/internal/app/init/init_config_pip.go b/internal/app/init/init_config_pip.go new file mode 100644 index 0000000..91066fb --- /dev/null +++ b/internal/app/init/init_config_pip.go @@ -0,0 +1,44 @@ +package init + +import ( + "fmt" + "crypto/x509" + + "github.com/vs-uulm/ztsfc_http_pip/internal/app/config" + gct "github.com/leobrada/golang_convenience_tools" +) + +func initPip() error { + fields := "" + var err error + + if config.Config.Pip.ListenAddr == "" { + fields += "listen_addr" + } + + if config.Config.Pip.CertsPipAcceptsWhenShownByPdp == nil { + fields += "certs_pip_accepts_when_shown_by_pdp" + } + + + if config.Config.Pip.CertShownByPipToPdp == "" { + fields += "cert_shown_by_pip_to_pdp" + } + + if config.Config.Pip.PrivkeyForCertShownByPipToPdp == "" { + fields += "privkey_for_certs_shown_by_pip_to_pdp" + } + + // Read CA certs used for signing client certs and are accepted by the PEP + config.Config.Pip.CaCertPoolPipAcceptsFromPdp = x509.NewCertPool() + for _, acceptedPdpCert := range config.Config.Pip.CertsPipAcceptsWhenShownByPdp { + if err = gct.LoadCACertificate(acceptedPdpCert, config.Config.Pip.CaCertPoolPipAcceptsFromPdp); err != nil { + return fmt.Errorf("initPipParams(): error loading certificates PIP accepts from PDP: %w", err) + } + } + + config.Config.Pip.X509KeyPairShownByPipToPdp, err = gct.LoadX509KeyPair(config.Config.Pip.CertShownByPipToPdp, + config.Config.Pip.PrivkeyForCertShownByPipToPdp) + + return err +} diff --git a/internal/app/init/init_config_system_logger.go b/internal/app/init/init_config_system_logger.go index e8b3761..43d3f4b 100644 --- a/internal/app/init/init_config_system_logger.go +++ b/internal/app/init/init_config_system_logger.go @@ -4,7 +4,7 @@ package init import ( - "github.com/vs-uulm/ztsfc_http_environment/internal/app/config" + "github.com/vs-uulm/ztsfc_http_pip/internal/app/config" ) // InitSysLoggerParams() sets default values for the system logger parameters diff --git a/internal/app/init/init_config_threat_intelligence.go b/internal/app/init/init_config_threat_intelligence.go index 566675e..19536a7 100644 --- a/internal/app/init/init_config_threat_intelligence.go +++ b/internal/app/init/init_config_threat_intelligence.go @@ -3,12 +3,10 @@ package init import ( "fmt" "strings" - - logger "github.com/vs-uulm/ztsfc_http_logger" - "github.com/vs-uulm/ztsfc_http_environment/internal/app/config" + "github.com/vs-uulm/ztsfc_http_pip/internal/app/config" ) -func initThreatIntelligence(sysLogger *logger.Logger) error { +func initThreatIntelligence() error { fields := "" // TODO: Check if the field make sense as well! diff --git a/internal/app/router/router.go b/internal/app/router/router.go new file mode 100644 index 0000000..1bc026c --- /dev/null +++ b/internal/app/router/router.go @@ -0,0 +1,75 @@ +package router + +import ( + "crypto/tls" + "encoding/json" + "net/http" + + "github.com/vs-uulm/ztsfc_http_pip/internal/app/config" + "github.com/vs-uulm/ztsfc_http_pip/internal/app/device" +) + +const ( + // Request URIs for the API endpoint. + getDeviceEndpoint = "/get-device-attributes" +) + +type Router struct { + frontend_tls_config *tls.Config + frontend_server *http.Server +} + +func NewRouter() *Router { + + // Create new Router + router := new(Router) + + // Create TLS config for frontend server + router.frontend_tls_config = &tls.Config{ + Rand: nil, + Time: nil, + MinVersion: tls.VersionTLS13, + MaxVersion: tls.VersionTLS13, + SessionTicketsDisabled: true, + Certificates: []tls.Certificate{config.Config.Pip.X509KeyPairShownByPipToPdp}, + ClientAuth: tls.RequireAndVerifyClientCert, + ClientCAs: config.Config.Pip.CaCertPoolPipAcceptsFromPdp, + } + + // Create MUX server + http.HandleFunc(getDeviceEndpoint, handleGetDeviceRequests) + + // Create HTTP frontend server + router.frontend_server = &http.Server{ + Addr: config.Config.Pip.ListenAddr, + TLSConfig: router.frontend_tls_config, + } + + return router +} + +func handleGetDeviceRequests(w http.ResponseWriter, req *http.Request) { + q := req.URL.Query() + + dev := q.Get("device"); + if len(dev) == 0 { + config.SysLogger.Infof("router: handleGetDeviceRequests(): get device request did not contain a device") + w.WriteHeader(404) + return + } + + requestedDevice, ok := device.DevicesByID[dev] + if !ok { + config.SysLogger.Infof("router: handleGetDeviceRequests(): PDP requested a device that does not exist in the DB") + w.WriteHeader(404) + return + } + + config.SysLogger.Infof("router: handleGetDeviceRequests(): PDP requested the following device: %v", requestedDevice) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(requestedDevice) +} + +func (router *Router) ListenAndServeTLS() error { + return router.frontend_server.ListenAndServeTLS("", "") +} diff --git a/internal/app/threat_intelligence/threat_intelligence.go b/internal/app/threat_intelligence/threat_intelligence.go index 4f3b7cb..8d03122 100644 --- a/internal/app/threat_intelligence/threat_intelligence.go +++ b/internal/app/threat_intelligence/threat_intelligence.go @@ -3,24 +3,51 @@ package threat_intelligence import ( "fmt" "net/http" - "io/ioutil" + "encoding/json" + "net" + "encoding/base64" - logger "github.com/vs-uulm/ztsfc_http_logger" + "github.com/vs-uulm/ztsfc_http_pip/internal/app/config" ) +type flowAlert struct { + TimeReceived string `json:"TimeReceived"` + FlowDirection uint32 `json:"FlowDirection"` + TimeFlowStart string `json:"TimeFlowStart"` + TimeFlowEnd string `json:"TimeFlowEnd"` + Bytes string `json:"Bytes"` + Packets string `json:"Packets"` + SrcAddr string `json:"SrcAddr"` + DstAddr string `json:"DstAddr"` + Etype uint32 `json:"Etype"` + Proto uint32 `json:"Proto"` + SrcPort uint32 `json:"SrcPort"` + DstPort uint32 `json:"DstPort"` + InIf uint32 `json:"InIf"` + OutIf uint32 `json:"OutIf"` + IPTTL uint32 `json:"IPTTL"` + TCPFlags uint32 `json:"TCPFlags"` + RemoteAddr string `json:"RemoteAddr"` +} + func handleFlowAlert(w http.ResponseWriter, req *http.Request) { - alertBytes, err := ioutil.ReadAll(req.Body) + var alert flowAlert + err := json.NewDecoder(req.Body).Decode(&alert) if err != nil { - // TODO: Better error handling + config.SysLogger.Errorf("threat_intelligence: runThreatIntelligence(): handleFlowAlert(): %v\n", err) return } - //alert := ioutil.NopCloser(bytes.NewBuffer(body)) + addrIP, err := convertAddrFromStringToIP(alert.SrcAddr) + if err != nil { + config.SysLogger.Errorf("threat_intelligence: runThreatIntelligence(): handleFlowAlert(): %v\n", err) + return + } - fmt.Printf("Alert: %s", string(alertBytes)) + config.SysLogger.Infof("threat_intelligence: runThreatIntelligence(): handleFlowAlert(): exported suspicious IP %s\n", addrIP.String()) } -func RunThreatIntelligence(sysLogger *logger.Logger) error { +func RunThreatIntelligence() error { http.HandleFunc("/handleFlowAlert", handleFlowAlert) web_server := http.Server{ @@ -34,3 +61,15 @@ func RunThreatIntelligence(sysLogger *logger.Logger) error { return nil } + +// CONVENIENCE TOOLS +func convertAddrFromStringToIP(addr string) (net.IP, error) { + addrBytes, err := base64.StdEncoding.DecodeString(addr) + if err != nil { + return nil, fmt.Errorf("convertAddrFromStringToIP: error decoding alert from flow exporter: %v", err) + } + + addrIP := net.IP(addrBytes) + + return addrIP, nil +}