diff --git a/cmd/download/download.go b/cmd/download/download.go index 76c679bc..ad730154 100644 --- a/cmd/download/download.go +++ b/cmd/download/download.go @@ -36,6 +36,8 @@ var ( # Download the configured controls-inputs kubescape download controls-inputs + # Download the attack tracks + kubescape download attack-tracks ` ) diff --git a/core/cautils/getter/loadpolicy.go b/core/cautils/getter/loadpolicy.go index c75d4d4a..66700ab6 100644 --- a/core/cautils/getter/loadpolicy.go +++ b/core/cautils/getter/loadpolicy.go @@ -9,6 +9,7 @@ import ( "github.com/armosec/armoapi-go/armotypes" "github.com/kubescape/opa-utils/reporthandling" + "github.com/kubescape/opa-utils/reporthandling/attacktrack/v1alpha1" ) // ======================================================================================================================= @@ -152,3 +153,18 @@ func (lp *LoadPolicy) filePath() string { } return "" } + +func (lp *LoadPolicy) GetAttackTracks() ([]v1alpha1.AttackTrack, error) { + attackTracks := []v1alpha1.AttackTrack{} + + f, err := os.ReadFile(lp.filePath()) + + if err != nil { + return nil, err + } + + if err := json.Unmarshal(f, &attackTracks); err != nil { + return nil, err + } + return attackTracks, nil +} diff --git a/core/cautils/scaninfo.go b/core/cautils/scaninfo.go index 21bea2dc..999cafc8 100644 --- a/core/cautils/scaninfo.go +++ b/core/cautils/scaninfo.go @@ -40,6 +40,7 @@ const ( // ScanLocalFiles string = "yaml" localControlInputsFilename string = "controls-inputs.json" localExceptionsFilename string = "exceptions.json" + LocalAttackTracksFilename string = "attack-tracks.json" ) type BoolPtrFlag struct { diff --git a/core/core/download.go b/core/core/download.go index 9ef6869d..6b0115dc 100644 --- a/core/core/download.go +++ b/core/core/download.go @@ -19,6 +19,7 @@ var downloadFunc = map[string]func(*metav1.DownloadInfo) error{ "control": downloadControl, "framework": downloadFramework, "artifacts": downloadArtifacts, + "attack-tracks": downloadAttackTracks, } func DownloadSupportCommands() []string { @@ -70,6 +71,7 @@ func downloadArtifacts(downloadInfo *metav1.DownloadInfo) error { "controls-inputs": downloadConfigInputs, "exceptions": downloadExceptions, "framework": downloadFramework, + "attack-tracks": downloadAttackTracks, } for artifact := range artifacts { if err := downloadArtifact(&metav1.DownloadInfo{Target: artifact, Path: downloadInfo.Path, FileName: fmt.Sprintf("%s.json", artifact)}, artifacts); err != nil { @@ -126,6 +128,30 @@ func downloadExceptions(downloadInfo *metav1.DownloadInfo) error { return nil } +func downloadAttackTracks(downloadInfo *metav1.DownloadInfo) error { + var err error + tenant := getTenantConfig(&downloadInfo.Credentials, "", "", getKubernetesApi()) + + attackTracksGetter := getAttackTracksGetter(tenant.GetAccountID(), nil) + + attackTracks, err := attackTracksGetter.GetAttackTracks() + if err != nil { + return err + } + + if downloadInfo.FileName == "" { + downloadInfo.FileName = fmt.Sprintf("%s.json", downloadInfo.Target) + } + // save in file + err = getter.SaveInFile(attackTracks, filepath.Join(downloadInfo.Path, downloadInfo.FileName)) + if err != nil { + return err + } + logger.L().Success("Downloaded", helpers.String("attack tracks", downloadInfo.Target), helpers.String("path", filepath.Join(downloadInfo.Path, downloadInfo.FileName))) + return nil + +} + func downloadFramework(downloadInfo *metav1.DownloadInfo) error { tenant := getTenantConfig(&downloadInfo.Credentials, "", "", getKubernetesApi()) diff --git a/core/core/initutils.go b/core/core/initutils.go index 2bd4f8af..f73f99fa 100644 --- a/core/core/initutils.go +++ b/core/core/initutils.go @@ -247,8 +247,9 @@ func getAttackTracksGetter(accountID string, downloadReleasedPolicy *getter.Down if downloadReleasedPolicy == nil { downloadReleasedPolicy = getter.NewDownloadReleasedPolicy() } - if err := downloadReleasedPolicy.SetRegoObjects(); err != nil { - logger.L().Warning("failed to get attack tracks from github release, this may affect the scanning results", helpers.Error(err)) + if err := downloadReleasedPolicy.SetRegoObjects(); err != nil { // if failed to pull attack tracks, fallback to cache + logger.L().Warning("failed to get attack tracks from github release, loading attack tracks from cache", helpers.Error(err)) + return getter.NewLoadPolicy([]string{getter.GetDefaultPath(cautils.LocalAttackTracksFilename)}) } return downloadReleasedPolicy } diff --git a/core/pkg/resourcesprioritization/prioritizationhandler.go b/core/pkg/resourcesprioritization/prioritizationhandler.go index 77e97b18..8ab39b6e 100644 --- a/core/pkg/resourcesprioritization/prioritizationhandler.go +++ b/core/pkg/resourcesprioritization/prioritizationhandler.go @@ -21,7 +21,8 @@ func NewResourcesPrioritizationHandler(attackTracksGetter getter.IAttackTracksGe attackTracks: make([]v1alpha1.IAttackTrack, 0), } - if tracks, err := attackTracksGetter.GetAttackTracks(); err != nil { + tracks, err := attackTracksGetter.GetAttackTracks() + if err != nil { return nil, err } else { for _, attackTrack := range tracks { @@ -38,6 +39,12 @@ func NewResourcesPrioritizationHandler(attackTracksGetter getter.IAttackTracksGe return nil, fmt.Errorf("expected to find at least one attack track") } + // Store attack tracks in cache + cache := getter.GetDefaultPath(cautils.LocalAttackTracksFilename) + if err := getter.SaveInFile(tracks, cache); err != nil { + logger.L().Warning("failed to cache file", helpers.String("file", cache), helpers.Error(err)) + } + return handler, nil }