package cmd
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/aquasecurity/kube-bench/check"
"github.com/golang/glog"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
func init ( ) {
RootCmd . AddCommand ( runCmd )
runCmd . Flags ( ) . StringSliceP ( "targets" , "s" , [ ] string { } ,
` Specify targets of the benchmark to run . These names need to match the filenames in the cfg / < version > directory .
For example , to run the tests specified in master . yaml and etcd . yaml , specify -- targets = master , etcd
If no targets are specified , run tests from all files in the cfg / < version > directory .
` )
}
// runCmd represents the run command
var runCmd = & cobra . Command {
Use : "run" ,
Short : "Run tests" ,
Long : ` Run tests. If no arguments are specified, runs tests from all files ` ,
Run : func ( cmd * cobra . Command , args [ ] string ) {
targets , err := cmd . Flags ( ) . GetStringSlice ( "targets" )
if err != nil {
exitWithError ( fmt . Errorf ( "unable to get `targets` from command line :%v" , err ) )
}
bv , err := getBenchmarkVersion ( kubeVersion , benchmarkVersion , getPlatformInfo ( ) , viper . GetViper ( ) )
if err != nil {
exitWithError ( fmt . Errorf ( "unable to get benchmark version. error: %v" , err ) )
}
glog . V ( 2 ) . Infof ( "Checking targets %v for %v" , targets , bv )
benchmarkVersionToTargetsMap , err := loadTargetMapping ( viper . GetViper ( ) )
if err != nil {
exitWithError ( fmt . Errorf ( "error loading targets: %v" , err ) )
}
valid , err := validTargets ( bv , targets , viper . GetViper ( ) )
if err != nil {
exitWithError ( fmt . Errorf ( "error validating targets: %v" , err ) )
}
if len ( targets ) > 0 && ! valid {
exitWithError ( fmt . Errorf ( fmt . Sprintf ( ` The specified --targets "%s" are not configured for the CIS Benchmark %s\n Valid targets %v ` , strings . Join ( targets , "," ) , bv , benchmarkVersionToTargetsMap [ bv ] ) ) )
}
// Merge version-specific config if any.
path := filepath . Join ( cfgDir , bv )
err = mergeConfig ( path )
if err != nil {
exitWithError ( fmt . Errorf ( "Error in mergeConfig: %v\n" , err ) )
}
err = run ( targets , bv )
if err != nil {
exitWithError ( fmt . Errorf ( "Error in run: %v\n" , err ) )
}
os . Exit ( exitCodeSelection ( controlsCollection ) )
} ,
}
func run ( targets [ ] string , benchmarkVersion string ) ( err error ) {
yamlFiles , err := getTestYamlFiles ( targets , benchmarkVersion )
if err != nil {
return err
}
glog . V ( 3 ) . Infof ( "Running tests from files %v\n" , yamlFiles )
for _ , yamlFile := range yamlFiles {
_ , name := filepath . Split ( yamlFile )
testType := check . NodeType ( strings . Split ( name , "." ) [ 0 ] )
runChecks ( testType , yamlFile , detecetedKubeVersion )
}
writeOutput ( controlsCollection )
return nil
}
func getTestYamlFiles ( targets [ ] string , benchmarkVersion string ) ( yamlFiles [ ] string , err error ) {
// Check that the specified targets have corresponding YAML files in the config directory
configFileDirectory := filepath . Join ( cfgDir , benchmarkVersion )
for _ , target := range targets {
filename := translate ( target ) + ".yaml"
file := filepath . Join ( configFileDirectory , filename )
if _ , err := os . Stat ( file ) ; err != nil {
return nil , fmt . Errorf ( "file %s not found for version %s" , filename , benchmarkVersion )
}
yamlFiles = append ( yamlFiles , file )
}
// If no targets were specified, we will run tests from all the files in the directory
if len ( yamlFiles ) == 0 {
yamlFiles , err = getYamlFilesFromDir ( configFileDirectory )
if err != nil {
return nil , err
}
}
return yamlFiles , err
}
func translate ( target string ) string {
return strings . Replace ( strings . ToLower ( target ) , "worker" , "node" , - 1 )
}