ca0e1ca769
This is an initial import of the osel codebase. The osel tool is a tool that initiates external security scans (initially through Qualys) upon reciept of AMQP events that indicate certain sensitive events have occurred, like a security group rule change. The commit history had to be thrown away because it contained some non-public data, so I would like to call out the following contributors: This uses go 1.10 and vgo for dependency management. Co-Authored-By: Charles Bitter <Charles_Bitter@cable.comcast.com> Co-Authored-By: Olivier Gagnon <Olivier_Gagnon@cable.comcast.com> Co-Authored-By: Joseph Sleiman <Joseph_Sleiman@comcast.com> Change-Id: Ib6abe2024fd91978b783ceee4cff8bb4678d7b15
130 lines
4.9 KiB
Go
130 lines
4.9 KiB
Go
package main // import "git.openstack.org/openstack/osel"
|
|
|
|
import (
|
|
"log"
|
|
"net/url"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/fsnotify/fsnotify"
|
|
"github.com/nate-johnston/viper"
|
|
)
|
|
|
|
// OselVersion is exposed in the logged JSON in the "source_type" field. This
|
|
// will allow us to track the version of the logging specification.
|
|
// 1.0: Initial revision
|
|
// 1.1: Added qualys_scan_id and qualys_scan_error
|
|
const OselVersion = "osel1.1"
|
|
|
|
// Debug is a global variable to toggle debug logging
|
|
var Debug bool
|
|
|
|
// RabbitMQ URI
|
|
var rabbitURI string
|
|
|
|
func main() {
|
|
// Declare the configuration
|
|
viperConfigs := []ViperConfig{
|
|
ViperConfig{Key: "batch_interval", Description: "Interval of time in minutes for message batching"},
|
|
ViperConfig{Key: "debug", Description: "Output additional messages for debugging"},
|
|
ViperConfig{Key: "rabbit_uri", Description: "AMQP connection uri. See: https://www.rabbitmq.com/uri-spec.html"},
|
|
ViperConfig{Key: "openstack.identity_endpoint", Description: "Openstack Keystone Endpoint"},
|
|
ViperConfig{Key: "openstack.user", Description: "Openstack user that has at least read only access to all tenants/ports/security groups in the region."},
|
|
ViperConfig{Key: "openstack.password", Description: "Password for the Openstack user"},
|
|
ViperConfig{Key: "openstack.region", Description: "The name of the region running this process"},
|
|
ViperConfig{Key: "qualys.drop6", Description: "Should IPv6 addresses be incorporated in Qualys scans? true or false."},
|
|
ViperConfig{Key: "qualys.username", Description: "Username for credentials for the Qualys external scanning service"},
|
|
ViperConfig{Key: "qualys.password", Description: "Password for credentials for the Qualys external scanning service"},
|
|
ViperConfig{Key: "qualys.url", Description: "URL for thw Qualys service"},
|
|
ViperConfig{Key: "qualys.proxy_url", Description: "URL for an HTTP proxy that will permit access to the Qualys service"},
|
|
ViperConfig{Key: "syslog_server", Description: "FQDN of the server for events to log to over the network"},
|
|
ViperConfig{Key: "syslog_port", Description: "Port for communication to syslog, defaults to 514"},
|
|
ViperConfig{Key: "syslog_protocol", Description: "tcp or udp, defaults to tcp"},
|
|
ViperConfig{Key: "retry_syslog", Description: "Should the process keep trying if it cannot reach syslog? true or false."},
|
|
}
|
|
configPath := os.Getenv("EL_CONFIG") //The config path comes from ENV.
|
|
if configPath == "" {
|
|
log.Fatalln("Fatal Error: The Config file was not set to EL_CONFIG.")
|
|
}
|
|
if err := InitViper(configPath, viperConfigs); err != nil {
|
|
log.Fatalf("Fatal Error: (%s) while reading config file %s", err, configPath)
|
|
}
|
|
|
|
// Set defaults
|
|
viper.SetDefault("batch_interval", 60)
|
|
viper.SetDefault("debug", true)
|
|
viper.SetDefault("qualys.drop6", true)
|
|
viper.SetDefault("qualys.url", "https://qualysapi.qualys.com/api/2.0/fo/scan/")
|
|
viper.SetDefault("syslog_port", "514")
|
|
viper.SetDefault("syslog_protocol", "tcp")
|
|
|
|
// Watch for config changes
|
|
viper.WatchConfig()
|
|
viper.OnConfigChange(func(fsnotify.Event) {
|
|
if err := ValidateConfig(viperConfigs); err != nil {
|
|
log.Printf("Fatal Error: %s while refreshing config file %s\n", err, configPath)
|
|
}
|
|
})
|
|
|
|
batchInterval := viper.GetInt("batch_interval")
|
|
Debug = viper.GetBool("debug")
|
|
|
|
// Initialize AMQP
|
|
rabbitURI = viper.GetString("rabbit_uri")
|
|
amqpBus := new(AmqpActions)
|
|
amqpBus.Options = AmqpOptions{
|
|
RabbitURI: rabbitURI,
|
|
}
|
|
amqpIncoming, amqpErrorNotify, err := amqpBus.Connect()
|
|
if err != nil {
|
|
log.Fatalln(err)
|
|
}
|
|
|
|
// Initialize Qualys
|
|
qualysURL, err := url.Parse(viper.GetString("qualys.url"))
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
qualysProxyURL, err := url.Parse(viper.GetString("qualys.proxy_url"))
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
qualys := new(QualysActions)
|
|
qualys.Options = QualysOptions{
|
|
DropIPv6: viper.GetBool("qualys.drop6"),
|
|
Password: viper.GetString("qualys.password"),
|
|
ProxyURL: qualysProxyURL,
|
|
QualysURL: qualysURL,
|
|
ScanOptionName: viper.GetString("qualys.option"),
|
|
MinRemaining: viper.GetInt("qualys.min_remaining"),
|
|
UserName: viper.GetString("qualys.username"),
|
|
}
|
|
|
|
// Initialize OpenStack
|
|
openstack := new(OpenStackActions)
|
|
openstack.Options = OpenStackOptions{
|
|
KeystoneURI: viper.GetString("openstack.identity_endpoint"),
|
|
Password: viper.GetString("openstack.password"),
|
|
RegionName: viper.GetString("openstack.region"),
|
|
UserName: viper.GetString("openstack.user"),
|
|
}
|
|
|
|
// Initialize Syslog
|
|
logger := new(SyslogActions)
|
|
logger.Options = SyslogOptions{
|
|
Host: viper.GetString("syslog_server"),
|
|
Port: viper.GetString("syslog_port"),
|
|
Protocol: viper.GetString("syslog_protocol"),
|
|
Retry: viper.GetBool("retry_syslog"),
|
|
}
|
|
err = logger.Connect()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
// run main loop
|
|
batchDuration := time.Duration(batchInterval) * time.Minute
|
|
mainLoop(batchDuration, amqpIncoming, amqpErrorNotify, openstack, logger, qualys)
|
|
defer amqpBus.Close()
|
|
}
|