diff --git a/models/models.go b/models/models.go index 16f43d1080..e80e4462d9 100644 --- a/models/models.go +++ b/models/models.go @@ -82,6 +82,8 @@ type ScanResult struct { Container Container + Platform Platform + // Fqdn string // NWLinks []NWLink KnownCves []CveInfo @@ -322,3 +324,12 @@ type Container struct { ContainerID string Name string } + +// Platform has platform information +type Platform struct { + gorm.Model `json:"-"` + ScanResultID uint `json:"-"` + + Name string // aws or azure or gcp or other... + InstanceID string +} diff --git a/scan/linux.go b/scan/linux.go index e7e9058bf2..585e28af35 100644 --- a/scan/linux.go +++ b/scan/linux.go @@ -31,11 +31,12 @@ import ( type linux struct { ServerInfo config.ServerInfo - Family string - Release string + Family string + Release string + Platform models.Platform osPackages - log *logrus.Entry + log *logrus.Entry errs []error } @@ -56,10 +57,18 @@ func (l *linux) setDistributionInfo(fam, rel string) { l.Release = rel } -func (l *linux) getDistributionInfo() string { +func (l linux) getDistributionInfo() string { return fmt.Sprintf("%s %s", l.Family, l.Release) } +func (l *linux) setPlatform(p models.Platform) { + l.Platform = p +} + +func (l linux) getPlatform() models.Platform { + return l.Platform +} + func (l linux) allContainers() (containers []config.Container, err error) { switch l.ServerInfo.Container.Type { case "", "docker": @@ -131,6 +140,56 @@ func (l *linux) parseDockerPs(stdout string) (containers []config.Container, err return } +func (l *linux) detectPlatform() error { + ok, instanceID, err := l.detectRunningOnAws() + if err != nil { + return err + } + if ok { + l.setPlatform(models.Platform{ + Name: "aws", + InstanceID: instanceID, + }) + return nil + } + + //TODO Azure, GCP... + l.setPlatform(models.Platform{ + Name: "other", + }) + return nil +} + +func (l linux) detectRunningOnAws() (ok bool, instanceID string, err error) { + if r := l.ssh("type curl", noSudo); r.isSuccess() { + cmd := "curl --max-time 1 --retry 3 --noproxy 169.254.169.254 http://169.254.169.254/latest/meta-data/instance-id" + if r := l.ssh(cmd, noSudo); r.isSuccess() { + id := strings.TrimSpace(r.Stdout) + return true, id, nil + } else if r.ExitStatus == 28 || r.ExitStatus == 7 { + // Not running on AWS + // 7 Failed to connect to host. + // 28 operation timeout. + return false, "", nil + } + } + + if r := l.ssh("type wget", noSudo); r.isSuccess() { + cmd := "wget --tries=3 --timeout=1 --no-proxy -q -O - http://169.254.169.254/latest/meta-data/instance-id" + if r := l.ssh(cmd, noSudo); r.isSuccess() { + id := strings.TrimSpace(r.Stdout) + return true, id, nil + } else if r.ExitStatus == 4 { + // Not running on AWS + // 4 Network failure + return false, "", nil + } + } + return false, "", fmt.Errorf( + "Failed to curl or wget to AWS instance metadata on %s. container: %s", + l.ServerInfo.ServerName, l.ServerInfo.Container.Name) +} + func (l *linux) convertToModel() (models.ScanResult, error) { var scoredCves, unscoredCves models.CveInfos for _, p := range l.UnsecurePackages { @@ -171,6 +230,7 @@ func (l *linux) convertToModel() (models.ScanResult, error) { Family: l.Family, Release: l.Release, Container: container, + Platform: l.Platform, KnownCves: scoredCves, UnknownCves: unscoredCves, }, nil diff --git a/scan/serverapi.go b/scan/serverapi.go index 308b886a0e..d3a685d62a 100644 --- a/scan/serverapi.go +++ b/scan/serverapi.go @@ -15,12 +15,17 @@ var Log *logrus.Entry var servers []osTypeInterface -// Base Interface of redhat, debian +// Base Interface of redhat, debian, freebsd type osTypeInterface interface { setServerInfo(config.ServerInfo) getServerInfo() config.ServerInfo + setDistributionInfo(string, string) getDistributionInfo() string + + detectPlatform() error + getPlatform() models.Platform + checkRequiredPackagesInstalled() error scanPackages() error scanVulnByCpeName() error @@ -136,6 +141,30 @@ func InitServers(localLogger *logrus.Entry) error { return fmt.Errorf("Failed to detect Container OSes. err: %s", err) } servers = append(servers, containers...) + + Log.Info("Detecting Platforms...") + errs := detectPlatforms() + if 0 < len(errs) { + // Only logging + Log.Errorf("Failed to detect platforms. err: %v", errs) + } + for i, s := range servers { + if s.getServerInfo().IsContainer() { + Log.Infof("(%d/%d) %s on %s is running on %s", + i+1, len(servers), + s.getServerInfo().Container.Name, + s.getServerInfo().ServerName, + s.getPlatform().Name, + ) + + } else { + Log.Infof("(%d/%d) %s is running on %s", + i+1, len(servers), + s.getServerInfo().ServerName, + s.getPlatform().Name, + ) + } + } return nil } @@ -328,6 +357,13 @@ func detectContainerOSesOnServer(containerHost osTypeInterface) (oses []osTypeIn return oses } +func detectPlatforms() []error { + timeoutSec := 1 * 60 + return parallelSSHExec(func(o osTypeInterface) error { + return o.detectPlatform() + }, timeoutSec) +} + // Prepare installs requred packages to scan vulnerabilities. func Prepare() []error { return parallelSSHExec(func(o osTypeInterface) error {