2017-05-26 09:25:29 +00:00
|
|
|
// Copyright © 2017 Aqua Security Software Ltd. <info@aquasec.com>
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package check
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
yaml "gopkg.in/yaml.v2"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Controls holds all controls to check for master nodes.
|
|
|
|
type Controls struct {
|
2018-07-30 12:16:28 +00:00
|
|
|
ID string `yaml:"id" json:"id"`
|
|
|
|
Version string `json:"version"`
|
|
|
|
Text string `json:"text"`
|
2017-11-29 16:31:55 +00:00
|
|
|
Type NodeType `json:"node_type"`
|
|
|
|
Groups []*Group `json:"tests"`
|
2017-05-26 09:25:29 +00:00
|
|
|
Summary
|
|
|
|
}
|
|
|
|
|
|
|
|
// Group is a collection of similar checks.
|
|
|
|
type Group struct {
|
2017-11-29 16:31:55 +00:00
|
|
|
ID string `yaml:"id" json:"section"`
|
|
|
|
Pass int `json:"pass"`
|
|
|
|
Fail int `json:"fail"`
|
|
|
|
Warn int `json:"warn"`
|
2019-01-29 14:33:58 +00:00
|
|
|
Info int `json:"info"`
|
2017-11-29 16:31:55 +00:00
|
|
|
Text string `json:"desc"`
|
|
|
|
Checks []*Check `json:"results"`
|
2017-05-26 09:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Summary is a summary of the results of control checks run.
|
|
|
|
type Summary struct {
|
2018-07-30 12:16:28 +00:00
|
|
|
Pass int `json:"total_pass"`
|
|
|
|
Fail int `json:"total_fail"`
|
|
|
|
Warn int `json:"total_warn"`
|
2019-01-29 14:33:58 +00:00
|
|
|
Info int `json:"total_info"`
|
2017-05-26 09:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewControls instantiates a new master Controls object.
|
2017-06-23 11:04:46 +00:00
|
|
|
func NewControls(t NodeType, in []byte) (*Controls, error) {
|
2017-05-26 09:25:29 +00:00
|
|
|
c := new(Controls)
|
|
|
|
|
2017-06-23 11:04:46 +00:00
|
|
|
err := yaml.Unmarshal(in, c)
|
2017-05-26 09:25:29 +00:00
|
|
|
if err != nil {
|
2017-06-23 11:04:46 +00:00
|
|
|
return nil, fmt.Errorf("failed to unmarshal YAML: %s", err)
|
2017-05-26 09:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if t != c.Type {
|
2017-06-23 11:04:46 +00:00
|
|
|
return nil, fmt.Errorf("non-%s controls file specified", t)
|
2017-05-26 09:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Prepare audit commands
|
|
|
|
for _, group := range c.Groups {
|
|
|
|
for _, check := range group.Checks {
|
|
|
|
check.Commands = textToCommand(check.Audit)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-23 11:04:46 +00:00
|
|
|
return c, nil
|
2017-05-26 09:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// RunGroup runs all checks in a group.
|
2017-07-25 00:34:07 +00:00
|
|
|
func (controls *Controls) RunGroup(gids ...string) Summary {
|
2017-05-26 09:25:29 +00:00
|
|
|
g := []*Group{}
|
2019-01-29 14:33:58 +00:00
|
|
|
controls.Summary.Pass, controls.Summary.Fail, controls.Summary.Warn, controls.Info = 0, 0, 0, 0
|
2017-05-26 09:25:29 +00:00
|
|
|
|
|
|
|
// If no groupid is passed run all group checks.
|
|
|
|
if len(gids) == 0 {
|
|
|
|
gids = controls.getAllGroupIDs()
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, group := range controls.Groups {
|
|
|
|
|
|
|
|
for _, gid := range gids {
|
|
|
|
if gid == group.ID {
|
|
|
|
for _, check := range group.Checks {
|
2017-07-25 00:34:07 +00:00
|
|
|
check.Run()
|
2017-11-29 16:31:55 +00:00
|
|
|
check.TestInfo = append(check.TestInfo, check.Remediation)
|
2017-05-26 09:25:29 +00:00
|
|
|
summarize(controls, check)
|
2017-11-29 16:31:55 +00:00
|
|
|
summarizeGroup(group, check)
|
2017-05-26 09:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
g = append(g, group)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
controls.Groups = g
|
|
|
|
return controls.Summary
|
|
|
|
}
|
|
|
|
|
|
|
|
// RunChecks runs the checks with the supplied IDs.
|
2017-07-25 00:34:07 +00:00
|
|
|
func (controls *Controls) RunChecks(ids ...string) Summary {
|
2017-05-26 09:25:29 +00:00
|
|
|
g := []*Group{}
|
|
|
|
m := make(map[string]*Group)
|
2019-01-29 14:33:58 +00:00
|
|
|
controls.Summary.Pass, controls.Summary.Fail, controls.Summary.Warn, controls.Info = 0, 0, 0, 0
|
2017-05-26 09:25:29 +00:00
|
|
|
|
|
|
|
// If no groupid is passed run all group checks.
|
|
|
|
if len(ids) == 0 {
|
|
|
|
ids = controls.getAllCheckIDs()
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, group := range controls.Groups {
|
|
|
|
for _, check := range group.Checks {
|
|
|
|
for _, id := range ids {
|
|
|
|
if id == check.ID {
|
2017-07-25 00:34:07 +00:00
|
|
|
check.Run()
|
2017-11-29 16:31:55 +00:00
|
|
|
check.TestInfo = append(check.TestInfo, check.Remediation)
|
2017-05-26 09:25:29 +00:00
|
|
|
summarize(controls, check)
|
|
|
|
|
|
|
|
// Check if we have already added this checks group.
|
|
|
|
if v, ok := m[group.ID]; !ok {
|
|
|
|
// Create a group with same info
|
|
|
|
w := &Group{
|
|
|
|
ID: group.ID,
|
|
|
|
Text: group.Text,
|
|
|
|
Checks: []*Check{},
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add this check to the new group
|
|
|
|
w.Checks = append(w.Checks, check)
|
|
|
|
|
|
|
|
// Add to groups we have visited.
|
|
|
|
m[w.ID] = w
|
|
|
|
g = append(g, w)
|
|
|
|
} else {
|
|
|
|
v.Checks = append(v.Checks, check)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
controls.Groups = g
|
|
|
|
return controls.Summary
|
|
|
|
}
|
|
|
|
|
|
|
|
// JSON encodes the results of last run to JSON.
|
|
|
|
func (controls *Controls) JSON() ([]byte, error) {
|
|
|
|
return json.Marshal(controls)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (controls *Controls) getAllGroupIDs() []string {
|
|
|
|
var ids []string
|
|
|
|
|
|
|
|
for _, group := range controls.Groups {
|
|
|
|
ids = append(ids, group.ID)
|
|
|
|
}
|
|
|
|
return ids
|
|
|
|
}
|
|
|
|
|
|
|
|
func (controls *Controls) getAllCheckIDs() []string {
|
|
|
|
var ids []string
|
|
|
|
|
|
|
|
for _, group := range controls.Groups {
|
|
|
|
for _, check := range group.Checks {
|
|
|
|
ids = append(ids, check.ID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ids
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func summarize(controls *Controls, check *Check) {
|
|
|
|
switch check.State {
|
|
|
|
case PASS:
|
|
|
|
controls.Summary.Pass++
|
|
|
|
case FAIL:
|
|
|
|
controls.Summary.Fail++
|
|
|
|
case WARN:
|
|
|
|
controls.Summary.Warn++
|
2019-01-29 14:33:58 +00:00
|
|
|
case INFO:
|
|
|
|
controls.Summary.Info++
|
2017-05-26 09:25:29 +00:00
|
|
|
}
|
|
|
|
}
|
2017-11-29 16:31:55 +00:00
|
|
|
|
|
|
|
func summarizeGroup(group *Group, check *Check) {
|
|
|
|
switch check.State {
|
|
|
|
case PASS:
|
|
|
|
group.Pass++
|
|
|
|
case FAIL:
|
|
|
|
group.Fail++
|
|
|
|
case WARN:
|
|
|
|
group.Warn++
|
2019-01-29 14:33:58 +00:00
|
|
|
case INFO:
|
|
|
|
group.Info++
|
2017-11-29 16:31:55 +00:00
|
|
|
}
|
|
|
|
}
|