mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 01:18:42 +00:00
Feature 6242: Use oval to detect vulnerabilities on Fedora hosts (#6330)
* Feature 6242: Scan Fedora hosts using OVAL definitions
This commit is contained in:
parent
c4aeebed1b
commit
79bf51b03c
7 changed files with 92 additions and 29 deletions
1
changes/feature-6242-add-Fedora-oval-support
Normal file
1
changes/feature-6242-add-Fedora-oval-support
Normal file
|
|
@ -0,0 +1 @@
|
|||
- Add support for scanning Fedora hosts using OVAL definitions.
|
||||
|
|
@ -240,7 +240,6 @@ func cronVulnerabilities(
|
|||
recentVulns,
|
||||
appConfig,
|
||||
time.Now()); err != nil {
|
||||
|
||||
errHandler(ctx, logger, "triggering vulnerabilities webhook", err)
|
||||
}
|
||||
|
||||
|
|
@ -276,7 +275,6 @@ func cronVulnerabilities(
|
|||
if err := ds.SyncHostsSoftware(ctx, time.Now()); err != nil {
|
||||
errHandler(ctx, logger, "calculating hosts count per software", err)
|
||||
}
|
||||
|
||||
level.Debug(logger).Log("loop", "done")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import (
|
|||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
oval_parsed "github.com/fleetdm/fleet/v4/server/vulnerabilities/oval/parsed"
|
||||
)
|
||||
|
||||
type Platform string
|
||||
|
|
@ -45,6 +47,7 @@ func format(platform string, major string, minor string) string {
|
|||
if platform == "ubuntu" {
|
||||
return fmt.Sprintf("%s_%s%s", platform, major, minor)
|
||||
}
|
||||
// RHEL based platforms only use the major version for their OVAL definitions
|
||||
return fmt.Sprintf("%s_%s", platform, major)
|
||||
}
|
||||
|
||||
|
|
@ -55,6 +58,7 @@ func format(platform string, major string, minor string) string {
|
|||
// ('rhel', 'CentOS Linux 7.9.2009') => 'rhel_07'.
|
||||
func NewPlatform(hostPlatform, hostOsVersion string) Platform {
|
||||
nPlatform := strings.Trim(strings.ToLower(hostPlatform), " ")
|
||||
hostOsVersion = oval_parsed.ReplaceFedoraOSVersion(hostOsVersion)
|
||||
major, minor := getMajorMinorVer(strings.Trim(hostOsVersion, " "))
|
||||
return Platform(format(nPlatform, major, minor))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,10 +26,35 @@ func TestOvalPlatform(t *testing.T) {
|
|||
{"ubuntu", "Ubuntu 18.4.0 ", "ubuntu_1804"},
|
||||
{"rhel", "CentOS Linux 7.9.2009", "rhel_07"},
|
||||
{"amzn", "Amazon Linux 2.0.0", "amzn_02"},
|
||||
{"rhel", "Fedora Linux 12.0.0", "rhel_06"},
|
||||
{"rhel", "Fedora Linux 13.0.0", "rhel_06"},
|
||||
{"rhel", "Fedora Linux 14.0.0", "rhel_06"},
|
||||
{"rhel", "Fedora Linux 15.0.0", "rhel_06"},
|
||||
{"rhel", "Fedora Linux 16.0.0", "rhel_06"},
|
||||
{"rhel", "Fedora Linux 17.0.0", "rhel_06"},
|
||||
{"rhel", "Fedora Linux 18.0.0", "rhel_06"},
|
||||
{"rhel", "Fedora Linux 19.0.0", "rhel_07"},
|
||||
{"rhel", "Fedora Linux 20.0.0", "rhel_07"},
|
||||
{"rhel", "Fedora Linux 21.0.0", "rhel_07"},
|
||||
{"rhel", "Fedora Linux 22.0.0", "rhel_07"},
|
||||
{"rhel", "Fedora Linux 23.0.0", "rhel_07"},
|
||||
{"rhel", "Fedora Linux 24.0.0", "rhel_07"},
|
||||
{"rhel", "Fedora Linux 25.0.0", "rhel_07"},
|
||||
{"rhel", "Fedora Linux 26.0.0", "rhel_07"},
|
||||
{"rhel", "Fedora Linux 27.0.0", "rhel_07"},
|
||||
{"rhel", "Fedora Linux 28.0.0", "rhel_08"},
|
||||
{"rhel", "Fedora Linux 29.0.0", "rhel_08"},
|
||||
{"rhel", "Fedora Linux 30.0.0", "rhel_08"},
|
||||
{"rhel", "Fedora Linux 31.0.0", "rhel_08"},
|
||||
{"rhel", "Fedora Linux 32.0.0", "rhel_08"},
|
||||
{"rhel", "Fedora Linux 33.0.0", "rhel_08"},
|
||||
{"rhel", "Fedora Linux 34.0.0", "rhel_09"},
|
||||
{"rhel", "Fedora Linux 35.0.0", "rhel_09"},
|
||||
{"rhel", "Fedora Linux 36.0.0", "rhel_09"},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
require.Equal(t, c.expected, string(NewPlatform(c.platform, c.osVersion)))
|
||||
require.Equal(t, c.expected, string(NewPlatform(c.platform, c.osVersion)), c)
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -130,7 +130,8 @@ func (sta ObjectInfoState) EvalOSVersion(version fleet.OSVersion) (bool, error)
|
|||
if sta.Version != nil {
|
||||
var pVer string
|
||||
if version.Platform == "rhel" {
|
||||
pName := strings.Trim(version.Name, " ")
|
||||
version := ReplaceFedoraOSVersion(version.Name)
|
||||
pName := strings.Trim(version, " ")
|
||||
pVer = pName[strings.LastIndex(pName, " ")+1:]
|
||||
}
|
||||
|
||||
|
|
|
|||
33
server/vulnerabilities/oval/parsed/utils.go
Normal file
33
server/vulnerabilities/oval/parsed/utils.go
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
package oval_parsed
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ReplaceFedoraOSVersion Replaces `version` with the equivalent RHEL version, this is so that we
|
||||
// can use RHEL OVAL definitions when scanning/running tests - note that even though Fedora is the
|
||||
// upstream of RHEL, there is no 1:1 mapping between Fedora's versions and RHEL (for example RHEL 6
|
||||
// is based on both Fedora 12 and 13) - so this is an approximation.
|
||||
// Examples:
|
||||
// Red Hat Enterprise Linux 8.1.0
|
||||
// 'Fedora Linux 36.0.0' => 'Red Hat Enterprise Linux 9.0.0'
|
||||
// 'Fedora Linux 12.0.0' => 'Red Hat Enterprise Linux 6.0.0'
|
||||
// 'Fedora Linux 13.0.0' => 'Red Hat Enterprise Linux 6.0.0'
|
||||
func ReplaceFedoraOSVersion(version string) string {
|
||||
if strings.Index(version, "Fedora") != -1 {
|
||||
rules := map[string]*regexp.Regexp{
|
||||
"Red Hat Enterprise Linux 6.0.0": regexp.MustCompile(`Fedora Linux (12|13|14|15|16|17|18)\.`),
|
||||
"Red Hat Enterprise Linux 7.0.0": regexp.MustCompile(`Fedora Linux (19|20|21|22|23|24|25|26|27)\.`),
|
||||
"Red Hat Enterprise Linux 8.0.0": regexp.MustCompile(`Fedora Linux (28|29|30|31|32|33)\.`),
|
||||
"Red Hat Enterprise Linux 9.0.0": regexp.MustCompile(`Fedora Linux (34|35|36)\.`),
|
||||
}
|
||||
for rep, pattern := range rules {
|
||||
if pattern.ReplaceAllString(version, rep) != version {
|
||||
return rep
|
||||
}
|
||||
}
|
||||
return "Red Hat Enterprise Linux 9.0.0"
|
||||
}
|
||||
return version
|
||||
}
|
||||
|
|
@ -641,7 +641,7 @@ func TestOvalParser(t *testing.T) {
|
|||
require.Equal(t, *testFour.States[0].SignatureKeyId, oval_parsed.NewObjectStateString("equals", "199e2f91fd431d51"))
|
||||
})
|
||||
|
||||
t.Run("RHEL OVAL definitions work with CentOS", func(t *testing.T) {
|
||||
t.Run("RHEL OVAL definitions work with RHEL based distros", func(t *testing.T) {
|
||||
r := strings.NewReader(rhelOvalXML)
|
||||
|
||||
xmlResult, err := parseRhelXML(r)
|
||||
|
|
@ -650,32 +650,33 @@ func TestOvalParser(t *testing.T) {
|
|||
result, err := mapToRhelResult(xmlResult)
|
||||
require.NoError(t, err)
|
||||
|
||||
centOS := fleet.OSVersion{
|
||||
Platform: "rhel",
|
||||
Name: "CentOS Linux 7.9.2009",
|
||||
testCases := []fleet.OSVersion{
|
||||
{
|
||||
Platform: "rhel",
|
||||
Name: "CentOS Linux 7.9.2009",
|
||||
},
|
||||
{
|
||||
Platform: "amzn",
|
||||
Name: "Amazon Linux 2.0.0",
|
||||
},
|
||||
{
|
||||
Platform: "rhel",
|
||||
Name: "Fedora Linux 19.0.0",
|
||||
},
|
||||
{
|
||||
Platform: "rhel",
|
||||
Name: "Fedora Linux 20.0.0",
|
||||
},
|
||||
{
|
||||
Platform: "rhel",
|
||||
Name: "Fedora Linux 21.0.0",
|
||||
},
|
||||
}
|
||||
|
||||
rEval, err := result.RpmVerifyFileTests[20221728047].Eval(centOS)
|
||||
require.NoError(t, err)
|
||||
require.True(t, rEval)
|
||||
})
|
||||
|
||||
t.Run("RHEL OVAL definitions work with Amazon Distro", func(t *testing.T) {
|
||||
r := strings.NewReader(rhelOvalXML)
|
||||
|
||||
xmlResult, err := parseRhelXML(r)
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err := mapToRhelResult(xmlResult)
|
||||
require.NoError(t, err)
|
||||
|
||||
amzDistro := fleet.OSVersion{
|
||||
Platform: "amzn",
|
||||
Name: "Amazon Linux 2.0.0",
|
||||
for _, tCase := range testCases {
|
||||
rEval, err := result.RpmVerifyFileTests[20221728047].Eval(tCase)
|
||||
require.NoError(t, err)
|
||||
require.True(t, rEval, tCase)
|
||||
}
|
||||
|
||||
rEval, err := result.RpmVerifyFileTests[20221728047].Eval(amzDistro)
|
||||
require.NoError(t, err)
|
||||
require.True(t, rEval)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue