This commit is contained in:
David Wertenteil
2022-09-05 11:46:21 +03:00
44 changed files with 575 additions and 201 deletions
+8 -9
View File
@@ -6,15 +6,14 @@ labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**</br>
> A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like.**</br>
> A clear and concise description of what you want to happen.
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered.**</br>
> A clear and concise description of any alternative solutions or features you've considered.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
**Additional context.**</br>
> Add any other context or screenshots about the feature request here.
+6 -2
View File
@@ -2,11 +2,15 @@
## Screenshots - If Any (Optional)
## Issue ticket number and link
## This PR fixes:
* Resolved #
## Checklist before requesting a review
<!-- put an [x] in the box to get it checked -->
- [ ] My code follows the style guidelines of this project
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have commented on my code, particularly in hard-to-understand areas
- [ ] I have performed a self-review of my code
- [ ] If it is a core feature, I have added thorough tests.
- [ ] New and existing unit tests pass locally with my changes
+13 -8
View File
@@ -3,16 +3,21 @@ on:
types: [opened, labeled]
jobs:
build:
if: ${{ github.event.label.name == 'typo' }}
open_PR_message:
if: github.event.label.name == 'typo'
runs-on: ubuntu-latest
steps:
- uses: ben-z/actions-comment-on-issue@1.0.2
with:
message: "Hello! :wave:\n\nThis issue is being automatically closed, Please open a PR with a relevant fix."
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
auto_close_issues:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Automatically close typo issues
uses: lucasbento/auto-close-issues@v1.0.2
- uses: lee-dohm/close-matching-issues@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
issue-close-message: "@${issue.user.login}: Hello! :wave:\n\nThis issue is being automatically closed, Please open a PR with a relevant fix."
query: 'label:typo'
token: ${{ secrets.GITHUB_TOKEN }}
+22
View File
@@ -0,0 +1,22 @@
on:
fork:
issues:
types: [opened]
issue_comment:
types: [created]
pull_request_target:
types: [opened]
pull_request_review_comment:
types: [created]
jobs:
welcome:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: EddieHubCommunity/gh-action-community/src/welcome@main
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
issue-message: '<h3>Hey, Welcome to this repo, Congratulations on opening your issue. Keep Contributing to Kubescape</h3>'
pr-message: '<h3>Hey, Welcome to this repo, Congratulations on opening your Pull Request. Keep Contributing to Kubescape</h3>'
footer: '<h4>We''ll try to review and add you work as soon as possible and a maintainer will get back to you soon!</h4>'
+4 -4
View File
@@ -3,13 +3,13 @@
First, it is awesome that you are considering contributing to Kubescape! Contributing is important and fun and we welcome your efforts.
When contributing, we categorize contributions into two:
* Small code changes or fixes, whose scope are limited to a single or two files
* Complex features and improvements, whose are not limited
* Small code changes or fixes, whose scope is limited to a single or two files
* Complex features and improvements, that are not limited
If you have a small change, feel free to fire up a Pull Request.
When planning a bigger change, please first discuss the change you wish to make via issue,
email, or any other method with the owners of this repository before making a change. Most likely your changes or features are great, but sometimes we might be already going to this direction (or the exact opposite ;-) ) and we don't want to waste your time.
email, or any other method with the owners of this repository before making a change. Most likely your changes or features are great, but sometimes we might be already going in this direction (or the exact opposite ;-) ) and we don't want to waste your time.
Please note we have a code of conduct, please follow it in all your interactions with the project.
@@ -27,7 +27,7 @@ Please note we have a code of conduct, please follow it in all your interactions
### Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
contributors and maintainers pledge to make participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
+15 -9
View File
@@ -1,7 +1,12 @@
<img src="docs/kubescape.png" width="300" alt="logo" align="center">
<div align="center">
<img src="docs/kubescape.png" width="300" alt="logo">
</div>
---
[![build](https://github.com/kubescape/kubescape/actions/workflows/build.yaml/badge.svg)](https://github.com/kubescape/kubescape/actions/workflows/build.yaml)
[![Go Report Card](https://goreportcard.com/badge/github.com/kubescape/kubescape)](https://goreportcard.com/report/github.com/kubescape/kubescape)
[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/kubescape/kubescape)
:sunglasses: [Want to contribute?](#being-a-part-of-the-team) :innocent:
@@ -46,19 +51,18 @@ kubescape scan --submit --enable-host-scan --verbose
</br>
### Click [👍](https://github.com/kubescape/kubescape/stargazers) if you want us to continue to develop and improve Kubescape 😀
### Please [star ⭐](https://github.com/kubescape/kubescape/stargazers) the repo if you want us to continue developing and improving Kubescape 😀
</br>
# Being a part of the team
We invite you to our team! We are excited about this project and want to return the love we get.
Want to contribute? Want to discuss something? Have an issue?
[Want to contribute?](https://github.com/kubescape/kubescape/blob/master/CONTRIBUTING.md) Want to discuss something? Have an issue? Please make sure that you follow our [Code Of Conduct](https://github.com/kubescape/kubescape/blob/master/CODE_OF_CONDUCT.md) .
* Feel free to pick a task from the [issues](https://github.com/kubescape/kubescape/issues?q=is%3Aissue+is%3Aopen+label%3A%22open+for+contribution%22), [roadmap](docs/roadmap.md) or suggest a feature of your own. [Contact us](MAINTAINERS.md) directly for more information :)
* Open an issue, we are trying to respond within 48 hours
* [Open an issue](https://github.com/kubescape/kubescape/issues/new/choose) , we are trying to respond within 48 hours
* [Join us](https://discord.com/invite/WKZRaCtBxN) in the discussion on our discord server!
[<img src="docs/discord-banner.png" width="100" alt="logo" align="center">](https://discord.com/invite/WKZRaCtBxN)
@@ -80,7 +84,9 @@ Want to contribute? Want to discuss something? Have an issue?
* [Scan Kubescape on an air-gapped environment (offline support)](https://youtu.be/IGXL9s37smM)
* [Managing exceptions in the Kubescape SaaS version](https://youtu.be/OzpvxGmCR80)
* [Configure and run customized frameworks](https://youtu.be/12Sanq_rEhs)
* Customize control configurations. [Kubescape CLI](https://youtu.be/955psg6TVu4), [Kubescape SaaS](https://youtu.be/lIMVSVhH33o)
* Customize control configurations:
- [Kubescape CLI](https://youtu.be/955psg6TVu4)
- [Kubescape SaaS](https://youtu.be/lIMVSVhH33o)
## Install on Windows
@@ -187,12 +193,12 @@ kubescape scan --include-namespaces development,staging,production
kubescape scan --exclude-namespaces kube-system,kube-public
```
#### Scan local `yaml`/`json` files before deploying. [Take a look at the demonstration](https://youtu.be/Ox6DaR7_4ZI) Submit the results in case the directory is a git repo. [docs](https://hub.armosec.io/docs/repository-scanning?utm_source=github&utm_medium=repository)
#### Scan local `yaml`/`json` files before deploying. [Take a look at the demonstration](https://youtu.be/Ox6DaR7_4ZI). Submit the results in case the directory is a git repo. [docs](https://hub.armosec.io/docs/repository-scanning?utm_source=github&utm_medium=repository)
```
kubescape scan *.yaml --submit
```
#### Scan kubernetes manifest files from a git repository [and submit the results](https://hub.armosec.io/docs/repository-scanning?utm_source=github&utm_medium=repository)
#### Scan Kubernetes manifest files from a git repository [and submit the results](https://hub.armosec.io/docs/repository-scanning?utm_source=github&utm_medium=repository)
```
kubescape scan https://github.com/kubescape/kubescape --submit
```
@@ -261,7 +267,7 @@ kubescape scan --use-artifacts-from path/to/local/dir
You can also download a single artifact and scan with the `--use-from` flag
1. Download and save in file, if file name is not specified, will save in `~/.kubescape/<framework name>.json`
1. Download and save in a file, if the file name is not specified, will save in `~/.kubescape/<framework name>.json`
```
kubescape download framework nsa --output /path/nsa.json
```
+1 -1
View File
@@ -25,7 +25,7 @@ def get_build_dir():
def get_package_name():
package_name = "kubescape"
# if platform.system() == "Windows": package_name += ".exe"
if platform.system() == "Windows": package_name += ".exe"
return package_name
+2 -3
View File
@@ -20,7 +20,6 @@ WORKDIR /work
ADD . .
# install libgit2
WORKDIR /work
RUN rm -rf git2go && make libgit2
# build kubescape server
@@ -34,16 +33,16 @@ RUN python build.py
RUN /work/build/ubuntu-latest/kubescape download artifacts -o /work/artifacts
FROM alpine
FROM alpine:3.16.2
RUN addgroup -S armo && adduser -S armo -G armo
RUN mkdir /home/armo/.kubescape
COPY --from=builder /work/artifacts/ /home/armo/.kubescape
RUN chown -R armo:armo /home/armo/.kubescape
USER armo
WORKDIR /home/armo
COPY --from=builder /work/httphandler/build/ubuntu-latest/kubescape /usr/bin/ksserver
-4
View File
@@ -43,7 +43,3 @@ func GetCompletionCmd() *cobra.Command {
}
return completionCmd
}
// func init() {
// rootCmd.AddCommand(completionCmd)
// }
+1
View File
@@ -63,6 +63,7 @@ func getRootCmd(ks meta.IKubescape) *cobra.Command {
rootCmd.PersistentFlags().StringVarP(&rootInfo.Logger, "logger", "l", helpers.InfoLevel.String(), fmt.Sprintf("Logger level. Supported: %s [$KS_LOGGER]", strings.Join(helpers.SupportedLevels(), "/")))
rootCmd.PersistentFlags().StringVar(&rootInfo.CacheDir, "cache-dir", getter.DefaultLocalStore, "Cache directory [$KS_CACHE_DIR]")
rootCmd.PersistentFlags().BoolVarP(&rootInfo.DisableColor, "disable-color", "", false, "Disable Color output for logging")
rootCmd.PersistentFlags().BoolVarP(&rootInfo.EnableColor, "enable-color", "", false, "Force enable Color output for logging")
cobra.OnInitialize(initLogger, initLoggerLevel, initEnvironment, initCacheDir)
+1
View File
@@ -16,6 +16,7 @@ const envFlagUsage = "Send report results to specific URL. Format:<ReportReceive
func initLogger() {
logger.DisableColor(rootInfo.DisableColor)
logger.EnableColor(rootInfo.EnableColor)
if rootInfo.LoggerName == "" {
if l := os.Getenv("KS_LOGGER_NAME"); l != "" {
+1 -1
View File
@@ -70,7 +70,7 @@ func getControlCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comman
if len(args) > 1 {
if len(args[1:]) == 0 || args[1] != "-" {
scanInfo.InputPatterns = []string{args[1]}
scanInfo.InputPatterns = args[1:]
} else { // store stdin to file - do NOT move to separate function !!
tempFile, err := os.CreateTemp(".", "tmp-kubescape*.yaml")
if err != nil {
+1 -1
View File
@@ -80,7 +80,7 @@ func getFrameworkCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comm
}
if len(args) > 1 {
if len(args[1:]) == 0 || args[1] != "-" {
scanInfo.InputPatterns = []string{args[1]}
scanInfo.InputPatterns = args[1:]
} else { // store stdin to file - do NOT move to separate function !!
tempFile, err := os.CreateTemp(".", "tmp-kubescape*.yaml")
if err != nil {
+2 -2
View File
@@ -182,11 +182,11 @@ TODO - supprot:
KS_CACHE // path to cached files
*/
type ClusterConfig struct {
backendAPI getter.IBackend
k8s *k8sinterface.KubernetesApi
configObj *ConfigObj
configMapName string
configMapNamespace string
backendAPI getter.IBackend
configObj *ConfigObj
}
func NewClusterConfig(k8s *k8sinterface.KubernetesApi, backendAPI getter.IBackend, credentials *Credentials, clusterName string) *ClusterConfig {
+19 -15
View File
@@ -5,6 +5,7 @@ import (
"github.com/kubescape/k8s-interface/workloadinterface"
"github.com/kubescape/opa-utils/reporthandling"
apis "github.com/kubescape/opa-utils/reporthandling/apis"
"github.com/kubescape/opa-utils/reporthandling/results/v1/prioritization"
"github.com/kubescape/opa-utils/reporthandling/results/v1/resourcesresults"
reporthandlingv2 "github.com/kubescape/opa-utils/reporthandling/v2"
)
@@ -14,15 +15,16 @@ type K8SResources map[string][]string
type KSResources map[string][]string
type OPASessionObj struct {
K8SResources *K8SResources // input k8s objects
ArmoResource *KSResources // input ARMO objects
Policies []reporthandling.Framework // list of frameworks to scan
AllResources map[string]workloadinterface.IMetadata // all scanned resources, map[<rtesource ID>]<resource>
ResourcesResult map[string]resourcesresults.Result // resources scan results, map[<rtesource ID>]<resource result>
ResourceSource map[string]reporthandling.Source // resources sources, map[<rtesource ID>]<resource result>
Report *reporthandlingv2.PostureReport // scan results v2 - Remove
Exceptions []armotypes.PostureExceptionPolicy // list of exceptions to apply on scan results
RegoInputData RegoInputData // input passed to rgo for scanning. map[<control name>][<input arguments>]
K8SResources *K8SResources // input k8s objects
ArmoResource *KSResources // input ARMO objects
Policies []reporthandling.Framework // list of frameworks to scan
AllResources map[string]workloadinterface.IMetadata // all scanned resources, map[<resource ID>]<resource>
ResourcesResult map[string]resourcesresults.Result // resources scan results, map[<resource ID>]<resource result>
ResourceSource map[string]reporthandling.Source // resources sources, map[<resource ID>]<resource result>
ResourcesPrioritized map[string]prioritization.PrioritizedResource // resources prioritization information, map[<resource ID>]<prioritized resource>
Report *reporthandlingv2.PostureReport // scan results v2 - Remove
Exceptions []armotypes.PostureExceptionPolicy // list of exceptions to apply on scan results
RegoInputData RegoInputData // input passed to rgo for scanning. map[<control name>][<input arguments>]
Metadata *reporthandlingv2.Metadata
InfoMap map[string]apis.StatusInfo // Map errors of resources to StatusInfo
ResourceToControlsMap map[string][]string // map[<apigroup/apiversion/resource>] = [<control_IDs>]
@@ -36,6 +38,7 @@ func NewOPASessionObj(frameworks []reporthandling.Framework, k8sResources *K8SRe
K8SResources: k8sResources,
AllResources: make(map[string]workloadinterface.IMetadata),
ResourcesResult: make(map[string]resourcesresults.Result),
ResourcesPrioritized: make(map[string]prioritization.PrioritizedResource),
InfoMap: make(map[string]apis.StatusInfo),
ResourceToControlsMap: make(map[string][]string),
ResourceSource: make(map[string]reporthandling.Source),
@@ -63,11 +66,12 @@ func (sessionObj *OPASessionObj) SetNumberOfWorkerNodes(n int) {
func NewOPASessionObjMock() *OPASessionObj {
return &OPASessionObj{
Policies: nil,
K8SResources: nil,
AllResources: make(map[string]workloadinterface.IMetadata),
ResourcesResult: make(map[string]resourcesresults.Result),
Report: &reporthandlingv2.PostureReport{},
Policies: nil,
K8SResources: nil,
AllResources: make(map[string]workloadinterface.IMetadata),
ResourcesResult: make(map[string]resourcesresults.Result),
ResourcesPrioritized: make(map[string]prioritization.PrioritizedResource),
Report: &reporthandlingv2.PostureReport{},
Metadata: &reporthandlingv2.Metadata{
ScanMetadata: reporthandlingv2.ScanMetadata{
ScanningTarget: 0,
@@ -94,6 +98,6 @@ type RegoInputData struct {
}
type Policies struct {
Frameworks []string
Controls map[string]reporthandling.Control // map[<control ID>]<control>
Frameworks []string
}
+5 -20
View File
@@ -47,7 +47,7 @@ func LoadResourcesFromHelmCharts(basePath string) (map[string][]workloadinterfac
if err == nil {
wls, errs := chart.GetWorkloadsWithDefaultValues()
if len(errs) > 0 {
logger.L().Error(fmt.Sprintf("Rendering of Helm chart template failed: %v", errs))
logger.L().Error(fmt.Sprintf("Rendering of Helm chart template '%s', failed: %v", chart.GetName(), errs))
continue
}
@@ -190,8 +190,10 @@ func readYamlFile(yamlFile []byte) ([]workloadinterface.IMetadata, error) {
}
if obj, ok := j.(map[string]interface{}); ok {
if o := objectsenvelopes.NewObject(obj); o != nil {
if o.GetKind() == "List" {
yamlObjs = append(yamlObjs, handleListObject(o)...)
if o.GetObjectType() == workloadinterface.TypeListWorkloads {
if list := workloadinterface.NewListWorkloadsObj(o.GetObject()); list != nil {
yamlObjs = append(yamlObjs, list.GetItems()...)
}
} else {
yamlObjs = append(yamlObjs, o)
}
@@ -323,20 +325,3 @@ func GetFileFormat(filePath string) FileFormat {
return FileFormat(filePath)
}
}
// handleListObject handle a List manifest
func handleListObject(obj workloadinterface.IMetadata) []workloadinterface.IMetadata {
yamlObjs := []workloadinterface.IMetadata{}
if i, ok := workloadinterface.InspectMap(obj.GetObject(), "items"); ok && i != nil {
if items, ok := i.([]interface{}); ok && items != nil {
for item := range items {
if m, ok := items[item].(map[string]interface{}); ok && m != nil {
if o := objectsenvelopes.NewObject(m); o != nil {
yamlObjs = append(yamlObjs, o)
}
}
}
}
}
return yamlObjs
}
+1 -1
View File
@@ -8,8 +8,8 @@ type FeLoginData struct {
type FeLoginResponse struct {
Token string `json:"accessToken"`
RefreshToken string `json:"refreshToken"`
ExpiresIn int32 `json:"expiresIn"`
Expires string `json:"expires"`
ExpiresIn int32 `json:"expiresIn"`
}
type KSCloudSelectCustomer struct {
+1 -1
View File
@@ -42,8 +42,8 @@ type KSCloudAPI struct {
accountID string
clientID string
secretKey string
feToken FeLoginResponse
authCookie string
feToken FeLoginResponse
loggedIn bool
}
+3 -1
View File
@@ -56,7 +56,9 @@ func controlReportV2ToV1(opaSessionObj *OPASessionObj, frameworkName string, con
rulesv1 := map[string]reporthandling.RuleReport{}
for _, resourceID := range crv2.ListResourcesIDs().All() {
iter := crv2.ListResourcesIDs().All()
for iter.HasNext() {
resourceID := iter.Next()
if result, ok := opaSessionObj.ResourcesResult[resourceID]; ok {
for _, rulev2 := range result.ListRulesOfControl(crv2.GetID(), "") {
+1
View File
@@ -5,6 +5,7 @@ type RootInfo struct {
LoggerName string // logger name ("pretty"/"zap"/"none")
CacheDir string // cached dir
DisableColor bool // Disable Color
EnableColor bool // Force enable Color
KSCloudBEURLs string // Kubescape Cloud URL
KSCloudBEURLsDep string // Kubescape Cloud URL
+7
View File
@@ -15,6 +15,7 @@ import (
"github.com/kubescape/kubescape/v2/core/pkg/opaprocessor"
"github.com/kubescape/kubescape/v2/core/pkg/policyhandler"
"github.com/kubescape/kubescape/v2/core/pkg/resourcehandler"
"github.com/kubescape/kubescape/v2/core/pkg/resourcesprioritization"
"github.com/kubescape/kubescape/v2/core/pkg/resultshandling"
"github.com/kubescape/kubescape/v2/core/pkg/resultshandling/printer"
"github.com/kubescape/kubescape/v2/core/pkg/resultshandling/reporter"
@@ -152,6 +153,12 @@ func (ks *Kubescape) Scan(scanInfo *cautils.ScanInfo) (*resultshandling.ResultsH
return resultsHandling, fmt.Errorf("%w", err)
}
// ======================== prioritization ===================
priotizationHandler := resourcesprioritization.NewResourcesPrioritizationHandler(true)
if err := priotizationHandler.PrioritizeResources(scanData); err != nil {
return resultsHandling, fmt.Errorf("%w", err)
}
// ========================= results handling =====================
resultsHandling.SetData(scanData)
+1 -1
View File
@@ -33,7 +33,7 @@ spec:
effect: NoSchedule
containers:
- name: host-sensor
image: quay.io/armosec/kube-host-sensor:latest
image: quay.io/kubescape/host-scanner:latest
securityContext:
privileged: true
readOnlyRootFilesystem: true
+7 -2
View File
@@ -122,7 +122,7 @@ func (opap *OPAProcessor) processControl(control *reporthandling.Control) (map[s
// ruleResults := make(map[string][]resourcesresults.ResourceAssociatedRule)
for i := range control.Rules {
resourceAssociatedRule, err := opap.processRule(&control.Rules[i])
resourceAssociatedRule, err := opap.processRule(&control.Rules[i], control.FixedInput)
if err != nil {
logger.L().Error(err.Error())
continue
@@ -150,10 +150,15 @@ func (opap *OPAProcessor) processControl(control *reporthandling.Control) (map[s
return resourcesAssociatedControl, errs
}
func (opap *OPAProcessor) processRule(rule *reporthandling.PolicyRule) (map[string]*resourcesresults.ResourceAssociatedRule, error) {
func (opap *OPAProcessor) processRule(rule *reporthandling.PolicyRule, fixedControlInputs map[string][]string) (map[string]*resourcesresults.ResourceAssociatedRule, error) {
postureControlInputs := opap.regoDependenciesData.GetFilteredPostureControlInputs(rule.ConfigInputs) // get store
// Merge configurable control input and fixed control input
for k, v := range fixedControlInputs {
postureControlInputs[k] = v
}
inputResources, err := reporthandling.RegoResourcesAggregator(rule, getAllSupportedObjects(opap.K8SResources, opap.ArmoResource, opap.AllResources, rule))
if err != nil {
return nil, fmt.Errorf("error getting aggregated k8sObjects: %s", err.Error())
@@ -42,7 +42,7 @@ func TestProcessResourcesResult(t *testing.T) {
assert.Equal(t, 1, len(opaSessionObj.ResourcesResult))
res := opaSessionObj.ResourcesResult[deployment.GetID()]
assert.Equal(t, 2, len(res.ListControlsIDs(nil).All()))
assert.Equal(t, 2, res.ListControlsIDs(nil).All().Len())
assert.Equal(t, 1, len(res.ListControlsIDs(nil).Failed()))
assert.Equal(t, 1, len(res.ListControlsIDs(nil).Passed()))
assert.True(t, res.GetStatus(nil).IsFailed())
@@ -51,8 +51,8 @@ func TestProcessResourcesResult(t *testing.T) {
opap.updateResults()
res = opaSessionObj.ResourcesResult[deployment.GetID()]
assert.Equal(t, 2, len(res.ListControlsIDs(nil).All()))
assert.Equal(t, 2, len(res.ListControlsIDs(nil).All()))
assert.Equal(t, 2, res.ListControlsIDs(nil).All().Len())
assert.Equal(t, 2, res.ListControlsIDs(nil).All().Len())
assert.Equal(t, 1, len(res.ListControlsIDs(nil).Failed()))
assert.Equal(t, 1, len(res.ListControlsIDs(nil).Passed()))
assert.True(t, res.GetStatus(nil).IsFailed())
@@ -67,13 +67,13 @@ func TestProcessResourcesResult(t *testing.T) {
assert.Equal(t, 0, summaryDetails.NumberOfResources().Passed())
// test resource listing
assert.Equal(t, 1, len(summaryDetails.ListResourcesIDs().All()))
assert.Equal(t, 1, summaryDetails.ListResourcesIDs().All().Len())
assert.Equal(t, 1, len(summaryDetails.ListResourcesIDs().Failed()))
assert.Equal(t, 0, len(summaryDetails.ListResourcesIDs().Excluded()))
assert.Equal(t, 0, len(summaryDetails.ListResourcesIDs().Passed()))
// test control listing
assert.Equal(t, len(res.ListControlsIDs(nil).All()), summaryDetails.NumberOfControls().All())
assert.Equal(t, res.ListControlsIDs(nil).All().Len(), summaryDetails.NumberOfControls().All())
assert.Equal(t, len(res.ListControlsIDs(nil).Passed()), summaryDetails.NumberOfControls().Passed())
assert.Equal(t, len(res.ListControlsIDs(nil).Failed()), summaryDetails.NumberOfControls().Failed())
assert.Equal(t, len(res.ListControlsIDs(nil).Excluded()), summaryDetails.NumberOfControls().Excluded())
@@ -83,7 +83,7 @@ func TestProcessResourcesResult(t *testing.T) {
opap.updateResults()
res = opaSessionObj.ResourcesResult[deployment.GetID()]
assert.Equal(t, 2, len(res.ListControlsIDs(nil).All()))
assert.Equal(t, 2, res.ListControlsIDs(nil).All().Len())
assert.Equal(t, 1, len(res.ListControlsIDs(nil).Excluded()))
assert.Equal(t, 1, len(res.ListControlsIDs(nil).Passed()))
assert.True(t, res.GetStatus(nil).IsExcluded())
@@ -93,7 +93,7 @@ func TestProcessResourcesResult(t *testing.T) {
// test resource listing
summaryDetails = opaSessionObj.Report.SummaryDetails
assert.Equal(t, 1, len(summaryDetails.ListResourcesIDs().All()))
assert.Equal(t, 1, summaryDetails.ListResourcesIDs().All().Len())
assert.Equal(t, 1, len(summaryDetails.ListResourcesIDs().Failed()))
assert.Equal(t, 0, len(summaryDetails.ListResourcesIDs().Excluded()))
assert.Equal(t, 0, len(summaryDetails.ListResourcesIDs().Passed()))
+49 -39
View File
@@ -37,19 +37,62 @@ func (fileHandler *FileResourceHandler) GetResources(sessionObj *cautils.OPASess
// map resources based on framework required resources: map["/group/version/kind"][]<k8s workloads ids>
k8sResources := setK8sResourceMap(sessionObj.Policies)
allResources := map[string]workloadinterface.IMetadata{}
workloadIDToSource := make(map[string]reporthandling.Source, 0)
ksResources := &cautils.KSResources{}
workloads := []workloadinterface.IMetadata{}
if len(fileHandler.inputPatterns) == 0 {
return nil, nil, nil, fmt.Errorf("missing input")
}
path := fileHandler.inputPatterns[0]
logger.L().Info("Accessing local objects")
cautils.StartSpinner()
for path := range fileHandler.inputPatterns {
workloadIDToSource, workloads, err := getResourcesFromPath(fileHandler.inputPatterns[path])
if err != nil {
return nil, allResources, nil, err
}
if len(workloads) == 0 {
logger.L().Debug("path ignored because contains only a non-kubernetes file", helpers.String("path", fileHandler.inputPatterns[path]))
}
for k, v := range workloadIDToSource {
sessionObj.ResourceSource[k] = v
}
// map all resources: map["/apiVersion/version/kind"][]<k8s workloads>
mappedResources := mapResources(workloads)
// save only relevant resources
for i := range mappedResources {
if _, ok := (*k8sResources)[i]; ok {
ids := []string{}
for j := range mappedResources[i] {
ids = append(ids, mappedResources[i][j].GetID())
allResources[mappedResources[i][j].GetID()] = mappedResources[i][j]
}
(*k8sResources)[i] = append((*k8sResources)[i], ids...)
}
}
}
if err := fileHandler.registryAdaptors.collectImagesVulnerabilities(k8sResources, allResources, ksResources); err != nil {
logger.L().Warning("failed to collect images vulnerabilities", helpers.Error(err))
}
cautils.StopSpinner()
logger.L().Success("Done accessing local objects")
return k8sResources, allResources, ksResources, nil
}
func getResourcesFromPath(path string) (map[string]reporthandling.Source, []workloadinterface.IMetadata, error) {
workloadIDToSource := make(map[string]reporthandling.Source, 0)
workloads := []workloadinterface.IMetadata{}
clonedRepo, err := cloneGitRepo(&path)
if err != nil {
return nil, allResources, nil, err
return nil, nil, err
}
if clonedRepo != "" {
defer os.RemoveAll(clonedRepo)
@@ -63,9 +106,6 @@ func (fileHandler *FileResourceHandler) GetResources(sessionObj *cautils.OPASess
}
// load resource from local file system
logger.L().Info("Accessing local objects")
cautils.StartSpinner()
sourceToWorkloads := cautils.LoadResourcesFromFiles(path, repoRoot)
// update workloads and workloadIDToSource
@@ -156,37 +196,7 @@ func (fileHandler *FileResourceHandler) GetResources(sessionObj *cautils.OPASess
logger.L().Debug("helm templates found in local storage", helpers.Int("helmTemplates", len(helmSourceToWorkloads)), helpers.Int("workloads", len(workloads)))
}
// addCommitData(fileHandler.inputPatterns[0], workloadIDToSource)
if len(workloads) == 0 {
return nil, allResources, nil, fmt.Errorf("empty list of workloads - no workloads found")
}
sessionObj.ResourceSource = workloadIDToSource
// map all resources: map["/apiVersion/version/kind"][]<k8s workloads>
mappedResources := mapResources(workloads)
// save only relevant resources
for i := range mappedResources {
if _, ok := (*k8sResources)[i]; ok {
ids := []string{}
for j := range mappedResources[i] {
ids = append(ids, mappedResources[i][j].GetID())
allResources[mappedResources[i][j].GetID()] = mappedResources[i][j]
}
(*k8sResources)[i] = ids
}
}
if err := fileHandler.registryAdaptors.collectImagesVulnerabilities(k8sResources, allResources, ksResources); err != nil {
logger.L().Warning("failed to collect images vulnerabilities", helpers.Error(err))
}
cautils.StopSpinner()
logger.L().Success("Accessed to local objects")
return k8sResources, allResources, ksResources, nil
return workloadIDToSource, workloads, nil
}
func (fileHandler *FileResourceHandler) GetClusterAPIServerInfo() *version.Info {
+1 -1
View File
@@ -18,7 +18,7 @@ func cloneGitRepo(path *string) (string, error) {
var clonedDir string
// Clone git repository if needed
gitURL, err := giturl.NewGitURL(*path)
gitURL, err := giturl.NewGitAPI(*path)
if err == nil {
logger.L().Info("cloning", helpers.String("repository url", gitURL.GetURL().String()))
cautils.StartSpinner()
@@ -238,8 +238,8 @@ func TestIsMasterNodeTaints(t *testing.T) {
},
{
"names": [
"quay.io/armosec/kube-host-sensor@sha256:82139d2561039726be060df2878ef023c59df7c536fbd7f6d766af5a99569fee",
"quay.io/armosec/kube-host-sensor:latest"
"quay.io/kubescape/host-scanner@sha256:82139d2561039726be060df2878ef023c59df7c536fbd7f6d766af5a99569fee",
"quay.io/kubescape/host-scanner:latest"
],
"sizeBytes": 11796788
},
@@ -503,8 +503,8 @@ func TestIsMasterNodeTaints(t *testing.T) {
},
{
"names": [
"quay.io/armosec/kube-host-sensor@sha256:82139d2561039726be060df2878ef023c59df7c536fbd7f6d766af5a99569fee",
"quay.io/armosec/kube-host-sensor:latest"
"quay.io/kubescape/host-scanner@sha256:82139d2561039726be060df2878ef023c59df7c536fbd7f6d766af5a99569fee",
"quay.io/kubescape/host-scanner:latest"
],
"sizeBytes": 11796788
},
+54 -3
View File
@@ -1,16 +1,45 @@
package resourcehandler
import (
"errors"
"fmt"
nethttp "net/http"
"os"
giturl "github.com/armosec/go-git-url"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/transport"
"github.com/go-git/go-git/v5/plumbing/transport/http"
)
// To Check if the given repository is Public(No Authentication needed), send a HTTP GET request to the URL
// If response code is 200, the repository is Public.
func isGitRepoPublic(URL string) bool {
resp, err := nethttp.Get(URL)
if err != nil {
return false
}
// if the status code is 200, our get request is successful.
// It only happens when the repository is public.
if resp.StatusCode == 200 {
return true
}
return false
}
// Check if the GITHUB_TOKEN is present
func isGitTokenPresent(gitURL giturl.IGitAPI) bool {
if token := gitURL.GetToken(); token == "" {
return false
}
return true
}
// cloneRepo clones a repository to a local temporary directory and returns the directory
func cloneRepo(gitURL giturl.IGitURL) (string, error) {
func cloneRepo(gitURL giturl.IGitAPI) (string, error) {
// Create temp directory
tmpDir, err := os.MkdirTemp("", "")
@@ -18,9 +47,31 @@ func cloneRepo(gitURL giturl.IGitURL) (string, error) {
return "", fmt.Errorf("failed to create temporary directory: %w", err)
}
// Clone option
// Get the URL to clone
cloneURL := gitURL.GetHttpCloneURL()
cloneOpts := git.CloneOptions{URL: cloneURL}
isGitRepoPublic := isGitRepoPublic(cloneURL)
// Declare the authentication variable required for cloneOptions
var auth transport.AuthMethod
if isGitRepoPublic {
// No authentication needed if repository is public
auth = nil
} else {
// Return Error if the GITHUB_TOKEN is not present
if isGitTokenPresent := isGitTokenPresent(gitURL); !isGitTokenPresent {
return "", fmt.Errorf("%w", errors.New("GITHUB_TOKEN is not present"))
}
auth = &http.BasicAuth{
Username: "anything Except Empty String",
Password: gitURL.GetToken(),
}
}
// Clone option
cloneOpts := git.CloneOptions{URL: cloneURL, Auth: auth}
if gitURL.GetBranchName() != "" {
cloneOpts.ReferenceName = plumbing.NewBranchReferenceName(gitURL.GetBranchName())
cloneOpts.SingleBranch = true
@@ -0,0 +1,91 @@
package resourcesprioritization
import (
"fmt"
"github.com/kubescape/k8s-interface/workloadinterface"
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/opa-utils/reporthandling/apis"
"github.com/kubescape/opa-utils/reporthandling/results/v1/prioritization"
)
type ResourcesPrioritizationHandler struct {
skipZeroScores bool
}
func NewResourcesPrioritizationHandler(skipZeroScore bool) *ResourcesPrioritizationHandler {
return &ResourcesPrioritizationHandler{
skipZeroScores: skipZeroScore,
}
}
func (handler *ResourcesPrioritizationHandler) PrioritizeResources(sessionObj *cautils.OPASessionObj) error {
for resourceId, result := range sessionObj.ResourcesResult {
resourcePriorityVector := []prioritization.ControlsVector{}
resource, exist := sessionObj.AllResources[resourceId]
if !exist {
return fmt.Errorf("expected to find resource id '%s' in scanned resources map", resourceId)
}
workload := workloadinterface.NewWorkloadObj(resource.GetObject())
if workload != nil && handler.isSupportedKind(workload) {
for _, resourceAssociatedControl := range result.ListControls() {
if !resourceAssociatedControl.GetStatus(nil).IsFailed() {
continue
}
controlSummary := sessionObj.Report.SummaryDetails.Controls.GetControl("ID", resourceAssociatedControl.ControlID)
if controlSummary == nil {
return fmt.Errorf("expected to find control id '%s' in summary details", resourceAssociatedControl.ControlID)
}
controlScoreFactor := controlSummary.GetScoreFactor()
replicaCount := float64(workload.GetReplicas())
cVector := prioritization.NewControlsVector()
cVector.AddControl(prioritization.PriorityVectorControl{
ControlID: resourceAssociatedControl.ControlID,
Category: "",
})
cVector.SetSeverity(apis.ControlSeverityToInt(controlScoreFactor))
cVector.SetScore(float64(controlScoreFactor) + (replicaCount / 10))
resourcePriorityVector = append(resourcePriorityVector, *cVector)
}
}
prioritizedResource := prioritization.PrioritizedResource{
ResourceID: resourceId,
PriorityVector: resourcePriorityVector,
}
prioritizedResource.SetSeverity(prioritizedResource.CalculateSeverity())
prioritizedResource.SetScore(prioritizedResource.CalculateScore())
if handler.skipZeroScores && prioritizedResource.GetScore() == 0 {
continue
}
sessionObj.ResourcesPrioritized[resourceId] = prioritizedResource
}
return nil
}
func (handler *ResourcesPrioritizationHandler) isSupportedKind(obj workloadinterface.IMetadata) bool {
if obj != nil {
switch obj.GetKind() {
case "Deployment",
"Pod",
"ReplicaSet",
"Node",
"DaemonSet",
"StatefulSet",
"Job",
"CronJob":
return true
}
}
return false
}
@@ -0,0 +1,150 @@
package resourcesprioritization
import (
"fmt"
"testing"
"github.com/kubescape/k8s-interface/workloadinterface"
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/opa-utils/reporthandling/apis"
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
"github.com/kubescape/opa-utils/reporthandling/results/v1/resourcesresults"
"github.com/stretchr/testify/assert"
)
func OPASessionObjMock(mockResults map[string]resourcesresults.Result, mockControlsSummary map[string]reportsummary.ControlSummary, mockAllResources map[string]workloadinterface.IMetadata) *cautils.OPASessionObj {
mock := cautils.NewOPASessionObjMock()
mock.Report.SummaryDetails.Controls = mockControlsSummary
mock.ResourcesResult = mockResults
mock.AllResources = mockAllResources
return mock
}
func WorkloadMockWithKind(kind string) workloadinterface.IMetadata {
mock := workloadinterface.NewWorkloadMock(nil)
mock.SetKind(kind)
return mock
}
func DeploymentWorkloadMock(replicas int) workloadinterface.IMetadata {
var deploymentMock = fmt.Sprintf(`{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"name":"privileged-deployment","labels":{"app":"nginx"}},"spec":{"replicas":%v,"selector":{"matchLabels":{"app":"nginx"}},"template":{"metadata":{"labels":{"app":"nginx"}},"spec":{"containers":[{"name":"nginx","image":"nginx:1.18.0","ports":[{"containerPort":80}],"securityContext":{"privileged":true}}]}}}}`, replicas)
w, _ := workloadinterface.NewWorkload([]byte(deploymentMock))
return w
}
func ResourceAssociatedControlMock(controlID string, status apis.ScanningStatus) resourcesresults.ResourceAssociatedControl {
return resourcesresults.ResourceAssociatedControl{
ControlID: controlID,
ResourceAssociatedRules: []resourcesresults.ResourceAssociatedRule{
{Name: "Test", Status: status},
},
}
}
func TestResourcesPrioritizationHandler_PrioritizeResources(t *testing.T) {
tests := []struct {
name string
results map[string]resourcesresults.Result
controls map[string]reportsummary.ControlSummary
resources map[string]workloadinterface.IMetadata
expectedScores map[string]float64
expectedSeverity map[string]int
expectedControlsInVector map[string][]string
}{
{
name: "non-empty report",
results: map[string]resourcesresults.Result{
"resource1": {
AssociatedControls: []resourcesresults.ResourceAssociatedControl{
ResourceAssociatedControlMock("C-001", apis.StatusFailed),
ResourceAssociatedControlMock("C-002", apis.StatusFailed),
},
},
"resource2": {
AssociatedControls: []resourcesresults.ResourceAssociatedControl{
ResourceAssociatedControlMock("C-001", apis.StatusFailed),
ResourceAssociatedControlMock("C-002", apis.StatusFailed),
ResourceAssociatedControlMock("C-003", apis.StatusPassed),
},
},
"resource3": {
AssociatedControls: []resourcesresults.ResourceAssociatedControl{
ResourceAssociatedControlMock("C-001", apis.StatusPassed),
ResourceAssociatedControlMock("C-002", apis.StatusPassed),
ResourceAssociatedControlMock("C-003", apis.StatusFailed),
},
},
},
controls: map[string]reportsummary.ControlSummary{
"C-001": {
ControlID: "C-001",
ScoreFactor: 3,
},
"C-002": {
ControlID: "C-002",
ScoreFactor: 4,
},
"C-003": {
ControlID: "C-003",
ScoreFactor: 10,
},
},
resources: map[string]workloadinterface.IMetadata{
"resource1": DeploymentWorkloadMock(20),
"resource2": DeploymentWorkloadMock(1),
"resource3": DeploymentWorkloadMock(1),
},
expectedScores: map[string]float64{
"resource1": float64(11),
"resource2": float64(7.199999999999999),
"resource3": float64(10.1),
},
expectedSeverity: map[string]int{
"resource1": apis.SeverityMedium,
"resource2": apis.SeverityMedium,
"resource3": apis.SeverityCritical,
},
expectedControlsInVector: map[string][]string{
"resource1": {"C-001", "C-002"},
"resource2": {"C-001", "C-002"},
"resource3": {"C-003"},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
handler := &ResourcesPrioritizationHandler{
skipZeroScores: false,
}
sessionObj := OPASessionObjMock(tt.results, tt.controls, tt.resources)
err := handler.PrioritizeResources(sessionObj)
assert.NoError(t, err, "expected to have no errors in PrioritizeResources()")
assert.Equalf(t, len(tt.results), len(sessionObj.ResourcesPrioritized), "expected prioritized resources to be not empty")
for rId, resource := range sessionObj.ResourcesPrioritized {
expectedScore := tt.expectedScores[rId]
assert.Equalf(t, expectedScore, resource.GetScore(), "expected score of resourceID '%s' to be '%v', got '%v'", rId, expectedScore, resource.GetScore())
expectedSeverity := tt.expectedSeverity[rId]
assert.Equalf(t, expectedSeverity, resource.GetSeverity(), "expected severity of resourceID '%s' to be '%v', got '%v'", rId, expectedSeverity, resource.GetSeverity())
expectedControlIDs := tt.expectedControlsInVector[rId]
assert.ElementsMatchf(t, expectedControlIDs, resource.ListControlsIDs(), "expected controls of resourceID '%s' to be '%v', got '%v'", rId, expectedControlIDs, resource.ListControlsIDs())
}
})
}
}
func TestResourcesPrioritizationHandler_isSupportedKind(t *testing.T) {
handler := &ResourcesPrioritizationHandler{}
assert.True(t, handler.isSupportedKind(WorkloadMockWithKind("Deployment")))
assert.True(t, handler.isSupportedKind(WorkloadMockWithKind("Pod")))
assert.True(t, handler.isSupportedKind(WorkloadMockWithKind("Node")))
assert.True(t, handler.isSupportedKind(WorkloadMockWithKind("DaemonSet")))
assert.True(t, handler.isSupportedKind(WorkloadMockWithKind("StatefulSet")))
assert.True(t, handler.isSupportedKind(WorkloadMockWithKind("Job")))
assert.True(t, handler.isSupportedKind(WorkloadMockWithKind("CronJob")))
assert.False(t, handler.isSupportedKind(nil))
assert.False(t, handler.isSupportedKind(WorkloadMockWithKind("ConfigMap")))
assert.False(t, handler.isSupportedKind(WorkloadMockWithKind("ServiceAccount")))
}
+3 -1
View File
@@ -155,7 +155,9 @@ func listTestsSuite(results *cautils.OPASessionObj) []JUnitTestSuite {
func testsCases(results *cautils.OPASessionObj, controls reportsummary.IControlsSummaries, classname string) []JUnitTestCase {
var testCases []JUnitTestCase
for _, cID := range controls.ListControlsIDs().All() {
iter := controls.ListControlsIDs().All()
for iter.HasNext() {
cID := iter.Next()
testCase := JUnitTestCase{}
control := results.Report.SummaryDetails.Controls.GetControl(reportsummary.EControlCriteriaID, cID)
@@ -261,7 +261,7 @@ func controlCountersForSummary(counters reportsummary.ICounters) string {
}
func controlCountersForResource(l *helpersv1.AllLists) string {
return fmt.Sprintf("Controls: %d (Failed: %d, Excluded: %d)", len(l.All()), len(l.Failed()), len(l.Excluded()))
return fmt.Sprintf("Controls: %d (Failed: %d, Excluded: %d)", l.All().Len(), len(l.Failed()), len(l.Excluded()))
}
func getSeparator(sep string) string {
s := ""
+8 -2
View File
@@ -6,6 +6,7 @@ import (
"github.com/kubescape/k8s-interface/workloadinterface"
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/opa-utils/reporthandling"
"github.com/kubescape/opa-utils/reporthandling/results/v1/prioritization"
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
"github.com/kubescape/opa-utils/reporthandling/results/v1/resourcesresults"
reporthandlingv2 "github.com/kubescape/opa-utils/reporthandling/v2"
@@ -24,16 +25,21 @@ func FinalizeResults(data *cautils.OPASessionObj) *reporthandlingv2.PostureRepor
}
report.Results = make([]resourcesresults.Result, len(data.ResourcesResult))
finalizeResults(report.Results, data.ResourcesResult)
finalizeResults(report.Results, data.ResourcesResult, data.ResourcesPrioritized)
report.Resources = finalizeResources(report.Results, data.AllResources, data.ResourceSource)
return &report
}
func finalizeResults(results []resourcesresults.Result, resourcesResult map[string]resourcesresults.Result) {
func finalizeResults(results []resourcesresults.Result, resourcesResult map[string]resourcesresults.Result, prioritizedResources map[string]prioritization.PrioritizedResource) {
index := 0
for resourceID := range resourcesResult {
results[index] = resourcesResult[resourceID]
// Add prioritization information to the result
if v, exist := prioritizedResources[resourceID]; exist {
results[index].PrioritizedResource = v
}
index++
}
}
@@ -14,6 +14,7 @@ import (
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/kubescape/v2/core/cautils/getter"
"github.com/kubescape/opa-utils/reporthandling"
"github.com/kubescape/opa-utils/reporthandling/results/v1/prioritization"
"github.com/kubescape/opa-utils/reporthandling/results/v1/resourcesresults"
reporthandlingv2 "github.com/kubescape/opa-utils/reporthandling/v2"
)
@@ -124,17 +125,36 @@ func (report *ReportEventReceiver) sendResources(host string, opaSessionObj *cau
counter := 0
reportCounter := 0
if err := report.setResources(splittedPostureReport, opaSessionObj.AllResources, opaSessionObj.ResourceSource, &counter, &reportCounter, host); err != nil {
if err := report.setResources(splittedPostureReport, opaSessionObj.AllResources, opaSessionObj.ResourceSource, opaSessionObj.ResourcesResult, &counter, &reportCounter, host); err != nil {
return err
}
if err := report.setResults(splittedPostureReport, opaSessionObj.ResourcesResult, &counter, &reportCounter, host); err != nil {
if err := report.setResults(splittedPostureReport, opaSessionObj.ResourcesResult, opaSessionObj.AllResources, opaSessionObj.ResourceSource, opaSessionObj.ResourcesPrioritized, &counter, &reportCounter, host); err != nil {
return err
}
return report.sendReport(host, splittedPostureReport, reportCounter, true)
}
func (report *ReportEventReceiver) setResults(reportObj *reporthandlingv2.PostureReport, results map[string]resourcesresults.Result, counter, reportCounter *int, host string) error {
func (report *ReportEventReceiver) setResults(reportObj *reporthandlingv2.PostureReport, results map[string]resourcesresults.Result, allResources map[string]workloadinterface.IMetadata, resourcesSource map[string]reporthandling.Source, prioritizedResources map[string]prioritization.PrioritizedResource, counter, reportCounter *int, host string) error {
for _, v := range results {
// set result.RawResource
resourceID := v.GetResourceID()
if _, ok := allResources[resourceID]; !ok {
return fmt.Errorf("expected to find raw resource object for '%s'", resourceID)
}
resource := reporthandling.NewResourceIMetadata(allResources[resourceID])
if r, ok := resourcesSource[resourceID]; ok {
resource.SetSource(&r)
}
v.RawResource = *resource
// set result.PrioritizedResource
if _, ok := prioritizedResources[resourceID]; ok {
v.PrioritizedResource = prioritizedResources[resourceID]
}
r, err := json.Marshal(v)
if err != nil {
return fmt.Errorf("failed to unmarshal resource '%s', reason: %v", v.GetResourceID(), err)
@@ -162,8 +182,13 @@ func (report *ReportEventReceiver) setResults(reportObj *reporthandlingv2.Postur
return nil
}
func (report *ReportEventReceiver) setResources(reportObj *reporthandlingv2.PostureReport, allResources map[string]workloadinterface.IMetadata, resourcesSource map[string]reporthandling.Source, counter, reportCounter *int, host string) error {
func (report *ReportEventReceiver) setResources(reportObj *reporthandlingv2.PostureReport, allResources map[string]workloadinterface.IMetadata, resourcesSource map[string]reporthandling.Source, results map[string]resourcesresults.Result, counter, reportCounter *int, host string) error {
for resourceID, v := range allResources {
// process only resources which have no result because these resources will be sent on the result object
if _, hasResult := results[resourceID]; hasResult {
continue
}
resource := reporthandling.NewResourceIMetadata(v)
if r, ok := resourcesSource[resourceID]; ok {
resource.SetSource(&r)
+2 -2
View File
@@ -15,10 +15,10 @@
</style>
<body style="text-align: center;">
<img src="kubescape.png" alt="Kubescap logo" style="width:20%">
<img src="kubescape.png" alt="Kubescape logo" style="width:20%">
<iframe src="https://discordapp.com/widget?id=893048809884643379&theme=dark" width="350" height="500"
allowtransparency="true" frameborder="0"
sandbox="allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts"></iframe>
</body>
</html>
</html>
@@ -6,7 +6,7 @@ source #287
### Big picture
* Kubescape team is planning to create controls which take into account image vulnerabilities, example: looking for public internet facing workloads with critical vulnerabilities. These are seriously affecting the security health of a cluster and therefore we think it is important to cover it. We think that most container registries are/will support image scanning like Harbor and therefore ,the ability to get information from them is important.
* Kubescape team is planning to create controls which take into account image vulnerabilities, example: looking for public internet facing workloads with critical vulnerabilities. These are seriously affecting the security health of a cluster and therefore we think it is important to cover it. We think that most container registries are/will support image scanning like Harbor and therefore, the ability to get information from them is important.
* There is information in the image repository which is important for the existing controls as well. They are incomplete without it, example see this issue: Non-root containers check is broken #19 . These are not necessarily image vulnerability related. Can be information in the image manifest (like the issue before), but it can be the image BOM related.
### Relation to this proposal
@@ -19,7 +19,7 @@ Multiple changes and design decisions need to be made before Kubescape will supp
* Controls and Rules: That actual control logic implementation, the "tests" themselves. Implemented in rego
* OPA engine: the [OPA](https://github.com/open-policy-agent/opa) rego interpreter
* Rules processor: Kubescape component, it enumerates and runs the controls while also preparing the all the input data that the controls need for running
* Rules processor: Kubescape component, it enumerates and runs the controls while also preparing all the input data that the controls need for running
* Data sources: Set of different modules providing data to the Rules processor so that it can run the controls with them. Examples: Kubernetes objects, cloud vendor API objects and adding the vulnerability information in this proposal
* Cloud Image Vulnerability adaption interface: The subject of this proposal, it gives a common interface for different registry/vulnerability vendors to adapt to.
* CIV adaptors: Specific implementation of the CIV interface, example Harbor adaption
+5 -5
View File
@@ -12,9 +12,9 @@ The features serve different stages of the workflow of the users:
The items in the Kubescape roadmap are split into 3 major groups based on the feature planning maturity:
* [Planning](#planning) - we have tickets open for these issues with a more or less clear vision of design.
* [Backlog](#backlog) - features that were discussed at a high level but are not ready for development
* [Wishlist](#wishlist) - features we are dreaming of in 😀 and want to push them gradually forward
* [Planning](#planning-) - we have tickets open for these issues with a more or less clear vision of design.
* [Backlog](#backlog-) - features that were discussed at a high level but are not ready for development
* [Wishlist](#wishlist-) - features we are dreaming of in 😀 and want to push them gradually forward
## Planning 👷
@@ -26,7 +26,7 @@ The items in the Kubescape roadmap are split into 3 major groups based on the fe
Implementing an eBPF agent (based on Falco or Tracee) which tracks file activity in workloads to prioritize container image vulnerabilities.
* ##### Prioritization engine using MITRE Attack matrix based attack chains
Create a security issue prioritization engine which scores resources based on control based attack chains. All of Kubescape controls can be arranged into attack categories of MITRE Attack matrix. The Attack matrix categories can be connected to each other based on a theoretical attack (ie. you can't have privilege escalation without initial access). Each of the Kubescape controls are to be categorized in these system and Kubescape will calculate priority score based on the interconnections between failed controls.
Create a security issue prioritization engine that scores resources based on control based attack chains. All Kubescape controls can be arranged into attack categories of the MITRE Attack matrix. The Attack matrix categories can be connected to each other based on a theoretical attack (ie. you can't have privilege escalation without initial access). Each of the Kubescape controls is to be categorized in these system and Kubescape will calculate a priority score based on the interconnections between failed controls.
* ##### Integration with image registries
We want to expand Kubescape to integrate with different image registries and read image vulnerability information from there. This will allow Kubescape to give contextual security information about vulnerabilities. Container registry integration
@@ -48,7 +48,7 @@ The items in the Kubescape roadmap are split into 3 major groups based on the fe
* ##### Integrate with other Kubernetes CLI tools
Use Kubescape as a YAML validator for `kubectl` and others.
* ##### Kubernetes audit log integration
Connect Kubescape to audit log stream to enable it to produce more contextual security information based on how the API service is used.
Connect Kubescape to the audit log stream to enable it to produce more contextual security information based on how the API service is used.
* ##### TUI for Kubescape
Interactive terminal based user interface which helps to analyze and fix issues
* ##### Scanning images with GO for vulnerabilities
+1 -1
View File
@@ -27,7 +27,7 @@ export cluster_name=$(echo "$cluster_arn" | awk -F'/' '{print $NF}')
echo 'Get cluster region'
export cluster_region=$(echo "$cluster_arn" | awk -F':' '{print $4}')
# First step, Create IAM OIDC provider for the cluster (Not required if the third step runs as is):
# First step, Create IAM OIDC provider for the cluster (Not required if the third step runs as it is):
echo 'Create IAM OIDC provider for the cluster'
eksctl utils associate-iam-oidc-provider --cluster $cluster_name --approve
+12 -12
View File
@@ -1,6 +1,6 @@
# Kubescape Exceptions
Kubescape Exceptions is the proper way of excluding failed resources from effecting the risk score.
Kubescape Exceptions is the proper way of excluding failed resources from affecting the risk score.
e.g. When a `kube-system` resource fails and it is ok, simply add the resource to the exceptions configurations.
@@ -9,7 +9,7 @@ e.g. When a `kube-system` resource fails and it is ok, simply add the resource t
* `name`- Exception name - unique name representing the exception
* `policyType`- Do not change
* `actions`- List of available actions. Currently alertOnly is supported
* `actions`- List of available actions. Currently, alertOnly is supported
* `resources`- List of resources to apply this exception on
* `designatorType: Attributes`- An attribute-based declaration {key: value}
Supported keys:
@@ -19,19 +19,19 @@ e.g. When a `kube-system` resource fails and it is ok, simply add the resource t
* `cluster`: k8s cluster name (usually it is the `current-context`) (case-sensitive, regex supported)
* resource labels as key value (case-sensitive, regex NOT supported)
* `posturePolicies`- An attribute-based declaration {key: value}
* `frameworkName` - Framework names can be find [here](https://github.com/armosec/regolibrary/tree/master/frameworks) (regex supported)
* `controlName` - Control names can be find [here](https://github.com/armosec/regolibrary/tree/master/controls) (regex supported)
* `controlID` - Control ID can be find [here](https://github.com/armosec/regolibrary/tree/master/controls) (regex supported)
* `ruleName` - Rule names can be find [here](https://github.com/armosec/regolibrary/tree/master/rules) (regex supported)
* `frameworkName` - Framework names can be found [here](https://github.com/armosec/regolibrary/tree/master/frameworks) (regex supported)
* `controlName` - Control names can be found [here](https://github.com/armosec/regolibrary/tree/master/controls) (regex supported)
* `controlID` - Control ID can be found [here](https://github.com/armosec/regolibrary/tree/master/controls) (regex supported)
* `ruleName` - Rule names can be found [here](https://github.com/armosec/regolibrary/tree/master/rules) (regex supported)
You can find [here](https://github.com/kubescape/kubescape/tree/master/examples/exceptions) some examples of exceptions files
## Usage
The `resources` list and `posturePolicies` list are design to be a combination of the resources and policies to exclude
The `resources` list and `posturePolicies` list are designed to be a combination of the resources and policies to exclude
> You must declare at least one resource and one policy
e.g. If you wish to exclude all namespaces with the label `"environment": "dev"`, the resource list should look as following:
e.g. If you wish to exclude all namespaces with the label `"environment": "dev"`, the resource list should look as follows:
```
"resources": [
{
@@ -44,7 +44,7 @@ e.g. If you wish to exclude all namespaces with the label `"environment": "dev"`
]
```
But if you wish to exclude all namespaces **OR** any resource with the label `"environment": "dev"`, the resource list should look as following:
But if you wish to exclude all namespaces **OR** any resource with the label `"environment": "dev"`, the resource list should look as follows:
```
"resources": [
{
@@ -64,7 +64,7 @@ But if you wish to exclude all namespaces **OR** any resource with the label `"e
Same works with the `posturePolicies` list ->
e.g. If you wish to exclude the resources declared in the `resources` list that failed when scanning the `NSA` framework **AND** failed the `Allowed hostPath` control, the `posturePolicies` list should look as following:
e.g. If you wish to exclude the resources declared in the `resources` list that failed when scanning the `NSA` framework **AND** failed the `Allowed hostPath` control, the `posturePolicies` list should look as follows:
```
"posturePolicies": [
{
@@ -74,7 +74,7 @@ e.g. If you wish to exclude the resources declared in the `resources` list that
]
```
But if you wish to exclude the resources declared in the `resources` list that failed when scanning the `NSA` framework **OR** failed the `Allowed hostPath` control, the `posturePolicies` list should look as following:
But if you wish to exclude the resources declared in the `resources` list that failed when scanning the `NSA` framework **OR** failed the `Allowed hostPath` control, the `posturePolicies` list should look as follows:
```
"posturePolicies": [
{
@@ -177,4 +177,4 @@ The resources
]
}
]
```
```
+5 -5
View File
@@ -14,9 +14,9 @@ require (
github.com/go-git/go-git/v5 v5.4.2
github.com/google/uuid v1.3.0
github.com/johnfercher/maroto v0.37.0
github.com/kubescape/go-logger v0.0.5
github.com/kubescape/k8s-interface v0.0.82
github.com/kubescape/opa-utils v0.0.172
github.com/kubescape/go-logger v0.0.6
github.com/kubescape/k8s-interface v0.0.83
github.com/kubescape/opa-utils v0.0.181
github.com/kubescape/rbac-utils v0.0.17
github.com/libgit2/git2go/v33 v33.0.9
github.com/mattn/go-isatty v0.0.14
@@ -141,9 +141,9 @@ require (
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.22.0 // indirect
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 // indirect
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d // indirect
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
+10 -9
View File
@@ -835,12 +835,12 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kubescape/go-logger v0.0.5 h1:lA25XvI4LT4JqwnNkIDUtwdYS4KVmnbWrVB7SRte2Es=
github.com/kubescape/go-logger v0.0.5/go.mod h1:DnVWEvC90LFY1nNMaNo6nBVOcqkLMK3S0qzXP1fzRvI=
github.com/kubescape/k8s-interface v0.0.82 h1:Gu09lQDG+Mw81OxA9MK1BSaqxV/FBRaMYX9jzVqOzzw=
github.com/kubescape/k8s-interface v0.0.82/go.mod h1:ihX96yqar+xogHl45mFE8zT9DLI06iy7XQPAP+j5KJE=
github.com/kubescape/opa-utils v0.0.172 h1:9BPN9phA9zQxhlYS+Nf4nQ0Y/gRRHfsKjMJnIwTLLLE=
github.com/kubescape/opa-utils v0.0.172/go.mod h1:aU4s1y+BWWxNwYw447TmHmNaKHxOWtYsFhZe5GyvOuE=
github.com/kubescape/go-logger v0.0.6 h1:ynhAmwrz0O7Jtqq1CdmCZUrKveji25hVP+B/FAb3QrA=
github.com/kubescape/go-logger v0.0.6/go.mod h1:DnVWEvC90LFY1nNMaNo6nBVOcqkLMK3S0qzXP1fzRvI=
github.com/kubescape/k8s-interface v0.0.83 h1:yQ1kWNZmKfBim/+NmxpPI/j7L9ASDq2h3mCNdmYgzqY=
github.com/kubescape/k8s-interface v0.0.83/go.mod h1:ihX96yqar+xogHl45mFE8zT9DLI06iy7XQPAP+j5KJE=
github.com/kubescape/opa-utils v0.0.181 h1:At3/4+yS7NqIKYXRj4iwdLmrGOR6B6SyYMALme9axAI=
github.com/kubescape/opa-utils v0.0.181/go.mod h1:jC5QrhS6WiFj/tXP2/YSDBnFlGsYUQokDGbKwMBgMpw=
github.com/kubescape/rbac-utils v0.0.17 h1:B78kjlTKqjYK/PXwmi4GPysHsFxIwVz1KFb4+IGT29w=
github.com/kubescape/rbac-utils v0.0.17/go.mod h1:pBwjpcrVeuH/no+DiCZWvlhYtCDzd3U0o/hEZKi+eM8=
github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo=
@@ -1458,8 +1458,8 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -1623,8 +1623,9 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d h1:Zu/JngovGLVi6t2J3nmAf3AoTDwuzw85YZ3b9o4yU7s=
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+6 -6
View File
@@ -5,14 +5,14 @@ go 1.18
replace github.com/kubescape/kubescape/v2 => ../
require (
github.com/kubescape/kubescape/v2 v2.0.0-00010101000000-000000000000
github.com/armosec/utils-go v0.0.12
github.com/go-openapi/runtime v0.24.1
github.com/google/uuid v1.3.0
github.com/gorilla/mux v1.8.0
github.com/gorilla/schema v1.2.0
github.com/kubescape/go-logger v0.0.5
github.com/kubescape/opa-utils v0.0.172
github.com/kubescape/go-logger v0.0.6
github.com/kubescape/kubescape/v2 v2.0.0-00010101000000-000000000000
github.com/kubescape/opa-utils v0.0.181
github.com/stretchr/testify v1.8.0
k8s.io/utils v0.0.0-20220706174534-f6158b442e7c
)
@@ -108,7 +108,7 @@ require (
github.com/json-iterator/go v1.1.12 // indirect
github.com/jung-kurt/gofpdf v1.16.2 // indirect
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
github.com/kubescape/k8s-interface v0.0.82 // indirect
github.com/kubescape/k8s-interface v0.0.83 // indirect
github.com/kubescape/rbac-utils v0.0.17 // indirect
github.com/libgit2/git2go/v33 v33.0.9 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
@@ -150,9 +150,9 @@ require (
go.uber.org/zap v1.22.0 // indirect
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 // indirect
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d // indirect
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
+10 -9
View File
@@ -891,12 +891,12 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kubescape/go-logger v0.0.5 h1:lA25XvI4LT4JqwnNkIDUtwdYS4KVmnbWrVB7SRte2Es=
github.com/kubescape/go-logger v0.0.5/go.mod h1:DnVWEvC90LFY1nNMaNo6nBVOcqkLMK3S0qzXP1fzRvI=
github.com/kubescape/k8s-interface v0.0.82 h1:Gu09lQDG+Mw81OxA9MK1BSaqxV/FBRaMYX9jzVqOzzw=
github.com/kubescape/k8s-interface v0.0.82/go.mod h1:ihX96yqar+xogHl45mFE8zT9DLI06iy7XQPAP+j5KJE=
github.com/kubescape/opa-utils v0.0.172 h1:9BPN9phA9zQxhlYS+Nf4nQ0Y/gRRHfsKjMJnIwTLLLE=
github.com/kubescape/opa-utils v0.0.172/go.mod h1:aU4s1y+BWWxNwYw447TmHmNaKHxOWtYsFhZe5GyvOuE=
github.com/kubescape/go-logger v0.0.6 h1:ynhAmwrz0O7Jtqq1CdmCZUrKveji25hVP+B/FAb3QrA=
github.com/kubescape/go-logger v0.0.6/go.mod h1:DnVWEvC90LFY1nNMaNo6nBVOcqkLMK3S0qzXP1fzRvI=
github.com/kubescape/k8s-interface v0.0.83 h1:yQ1kWNZmKfBim/+NmxpPI/j7L9ASDq2h3mCNdmYgzqY=
github.com/kubescape/k8s-interface v0.0.83/go.mod h1:ihX96yqar+xogHl45mFE8zT9DLI06iy7XQPAP+j5KJE=
github.com/kubescape/opa-utils v0.0.181 h1:At3/4+yS7NqIKYXRj4iwdLmrGOR6B6SyYMALme9axAI=
github.com/kubescape/opa-utils v0.0.181/go.mod h1:jC5QrhS6WiFj/tXP2/YSDBnFlGsYUQokDGbKwMBgMpw=
github.com/kubescape/rbac-utils v0.0.17 h1:B78kjlTKqjYK/PXwmi4GPysHsFxIwVz1KFb4+IGT29w=
github.com/kubescape/rbac-utils v0.0.17/go.mod h1:pBwjpcrVeuH/no+DiCZWvlhYtCDzd3U0o/hEZKi+eM8=
github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo=
@@ -1540,8 +1540,8 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -1710,8 +1710,9 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d h1:Zu/JngovGLVi6t2J3nmAf3AoTDwuzw85YZ3b9o4yU7s=
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+3 -3
View File
@@ -1,9 +1,9 @@
<html>
<head>
<title>
Kubscape Website
Kubescape Website
</title>
<h1>Kubscape Website</h1>
<h1>Kubescape Website</h1>
</head>
<body>
<h2>
@@ -11,4 +11,4 @@
<iframe src="https://discordapp.com/widget?id=893048809884643379&theme=dark" width="350" height="500" allowtransparency="true" frameborder="0" sandbox="allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts"></iframe>
</h2>
</body>
</html>
</html>