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
127 lines
3.8 KiB
Go
127 lines
3.8 KiB
Go
package main
|
|
|
|
/*
|
|
|
|
openstack - This file includes all of the logic necessary to interact with
|
|
OpenStack. This is extrapolated out so that an OpenStackActioner
|
|
interface can be passed to functions. Doing this allows testing by mock
|
|
classes to be created that can be passed to functions.
|
|
|
|
Since this is a wrapper around the gophercloud libraries, this does not need
|
|
testing.
|
|
|
|
*/
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
|
|
"github.com/rackspace/gophercloud"
|
|
"github.com/rackspace/gophercloud/openstack"
|
|
"github.com/rackspace/gophercloud/openstack/networking/v2/ports"
|
|
"github.com/rackspace/gophercloud/pagination"
|
|
)
|
|
|
|
// OpenStackActioner is an interface for an OpenStackActions class.
|
|
// Having this as an interface allows us to pass in a dummy class for testing
|
|
// that just returns mocked data.
|
|
type OpenStackActioner interface {
|
|
GetPortList() []OpenStackIPMap
|
|
Connect(string, string) error
|
|
}
|
|
|
|
// OpenStackActions is a class that handles all interactions directly with
|
|
// OpenStack. See the comment on OpenStackActioner for rationale.
|
|
type OpenStackActions struct {
|
|
gopherCloudClient *gophercloud.ProviderClient
|
|
neutronClient *gophercloud.ServiceClient
|
|
Options OpenStackOptions
|
|
}
|
|
|
|
// OpenStackOptions is a class to convey all of the configurable options for the
|
|
// OpenStackActions class.
|
|
type OpenStackOptions struct {
|
|
KeystoneURI string
|
|
Password string
|
|
RegionName string
|
|
TenantID string
|
|
UserName string
|
|
}
|
|
|
|
// OpenStackIPMap is a struct that is used to capture the mapping of IP address
|
|
// to security group. It is what is returned, in array form, from port list.
|
|
type OpenStackIPMap struct {
|
|
ipAddress string
|
|
securityGroup string
|
|
}
|
|
|
|
// GetPortList is a method that uses GopherCloud to query OpenStack for a
|
|
// list of ports, with their associated security group. It returns an array of
|
|
// OpenStackIPMap.
|
|
func (s OpenStackActions) GetPortList() []OpenStackIPMap {
|
|
// Make port list request to neutron
|
|
var ips []OpenStackIPMap
|
|
portListOpts := ports.ListOpts{
|
|
TenantID: s.Options.TenantID,
|
|
}
|
|
if s.neutronClient == nil {
|
|
log.Println("Error: neutronClient is nil")
|
|
}
|
|
pager := ports.List(s.neutronClient, portListOpts)
|
|
|
|
// Define an anonymous function to be executed on each page's iteration
|
|
pager.EachPage(func(page pagination.Page) (bool, error) {
|
|
portList, err := ports.ExtractPorts(page)
|
|
if err != nil {
|
|
// ignore ?
|
|
}
|
|
|
|
for _, p := range portList {
|
|
// "p" will be a ports.Port
|
|
for _, fixedIP := range p.FixedIPs {
|
|
for _, securityGroup := range p.SecurityGroups {
|
|
ips = append(ips, OpenStackIPMap{
|
|
ipAddress: fixedIP.IPAddress,
|
|
securityGroup: securityGroup,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
return true, err
|
|
})
|
|
return ips
|
|
}
|
|
|
|
// Connect is the method that establishes a connection to the OpenStack
|
|
// service.
|
|
func (s *OpenStackActions) Connect(tenantID string, username string) error {
|
|
var err error
|
|
keystoneOpts := gophercloud.AuthOptions{
|
|
IdentityEndpoint: s.Options.KeystoneURI,
|
|
TenantID: tenantID,
|
|
Username: username,
|
|
Password: s.Options.Password,
|
|
AllowReauth: true,
|
|
}
|
|
|
|
log.Println(fmt.Sprintf("Connecting to keystone %q in region %q for tenant %q with user %q", s.Options.KeystoneURI,
|
|
s.Options.RegionName, tenantID, username))
|
|
s.gopherCloudClient, err = openstack.AuthenticatedClient(keystoneOpts)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to connect to %s using user %s for tenant %s: %s",
|
|
s.Options.KeystoneURI, s.Options.UserName, s.Options.TenantID, err)
|
|
}
|
|
log.Println("Connected to gophercloud ", s.Options.KeystoneURI)
|
|
|
|
neutronOpts := gophercloud.EndpointOpts{
|
|
Name: "neutron",
|
|
Region: s.Options.RegionName,
|
|
}
|
|
s.neutronClient, err = openstack.NewNetworkV2(s.gopherCloudClient, neutronOpts)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to connect to neutron using user %s in region %s: %s",
|
|
s.Options.UserName, s.Options.RegionName, err)
|
|
}
|
|
return nil
|
|
}
|