Compare commits

...

549 Commits
dev ... v3.0.0

Author SHA1 Message Date
David Wertenteil
3e2314a269 Bump v3 (#1449)
* bump version

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* change default view

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* fixed tests

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* fixed go mod

Signed-off-by: David Wertenteil <dwertent@armosec.io>

---------

Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-10-22 17:43:51 +03:00
David Wertenteil
c143d10130 Cloud provider detection (#1448)
* set cloud provider using nodes

* use scan metadata for scanning scope

* code cleanup

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* handle error

Signed-off-by: David Wertenteil <dwertent@armosec.io>

---------

Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-10-22 15:47:57 +03:00
David Wertenteil
d5407466d5 Preparing Kubescape for v3 (#1403)
* wip: minor cli fixes

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* wip: change default view

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* wip: reduce default topWorkloadsNumber to 3

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* update gif

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* default view for controls and frameworks

---------

Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-10-22 15:39:58 +03:00
rcohencyberarmor
052c042dac Support backend access key (#1404)
Support backend access key

Signed-off-by: Amir Malka <amirm@armosec.io>
2023-10-22 15:10:08 +03:00
Daniel Grunberger
72b64127c7 Restructure img cmd (#1398)
* feat: add kubescape patch command

Signed-off-by: Anubhav Gupta <mail.anubhav06@gmail.com>

* update patch command output format

Signed-off-by: Anubhav Gupta <mail.anubhav06@gmail.com>

* fix patch command logic

Signed-off-by: Anubhav Gupta <mail.anubhav06@gmail.com>

* update docs & minor changes

Signed-off-by: Anubhav Gupta <mail.anubhav06@gmail.com>

* restructure cmd

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* fix tests

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* readme

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* fix version code

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* go mod

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

---------

Signed-off-by: Anubhav Gupta <mail.anubhav06@gmail.com>
Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
Co-authored-by: Anubhav Gupta <mail.anubhav06@gmail.com>
Co-authored-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-10-22 14:51:39 +03:00
Matthias Bertschy
a938b3523f Merge pull request #1446 from kubescape/deps-policy
add env-dependencies-policy to security insights
2023-10-20 09:32:51 +02:00
Matthias Bertschy
915d5d993b add env-dependencies-policy to security insights
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-10-20 09:30:41 +02:00
rcohencyberarmor
e2044338c8 print result to stdout when format argument specified (#1438)
* print result to stdout when format argument specified

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* print pretty format to stdout if format is not specified

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* remove not relevant log

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

---------

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>
Co-authored-by: rcohencyberarmor <rcohen@armosec.io>
2023-10-19 13:07:58 +03:00
Matthias Bertschy
e4110837c7 Merge pull request #1443 from kubescape/sarif-format
image scanning - replace driver name in sarif format
2023-10-18 14:33:40 +02:00
Matthias Bertschy
33452517fe Merge pull request #1444 from kubescape/actions
add more missing permissions for actions
2023-10-18 14:32:29 +02:00
Matthias Bertschy
df602af7cf add more missing permissions for actions
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-10-18 12:41:04 +02:00
Daniel Grunberger
bc327a0d86 set log to error
Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-10-18 12:23:46 +03:00
Daniel Grunberger
77888c12a0 rm if statement
Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-10-18 12:22:59 +03:00
Daniel Grunberger
df56af843e replace driver name
Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-10-18 12:18:53 +03:00
David Wertenteil
1f6ffdfd24 Merge pull request #1441 from kubescape/act
actions needs write on id-token in pr-scanner
2023-10-18 09:21:28 +03:00
Matthias Bertschy
6a0a7b84a2 actions needs write on id-token in pr-scanner
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-10-18 07:28:52 +02:00
Matthias Bertschy
f4bb8485cd Merge pull request #1436 from kubescape/ghactions
use distroless debug as entrypoint.sh requires a shell
2023-10-17 16:25:32 +02:00
David Wertenteil
33ec257aa8 Merge pull request #1439 from kubescape/bump
bump deps for vulnerabilities
2023-10-17 15:54:15 +03:00
Matthias Bertschy
f31304db7e bump deps for vulnerabilities
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-10-17 14:36:26 +02:00
Matthias Bertschy
b98d80a912 Merge pull request #1421 from kubescape/winwin
build windows exec without libgit
2023-10-17 10:09:32 +02:00
Matthias Bertschy
ae7b25a9ae Merge pull request #1437 from kubescape/act
fixing GH actions permissions
2023-10-17 10:05:49 +02:00
Matthias Bertschy
4f2d13b151 fixing GH actions permissions
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-10-17 09:53:46 +02:00
Matthias Bertschy
b6b4d6bb46 use distroless debug as entrypoint.sh requires a shell
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-10-17 09:42:59 +02:00
Matthias Bertschy
de76c98231 Merge pull request #1435 from kubescape/act
remove extra permissions on GH action
2023-10-17 08:31:07 +02:00
Matthias Bertschy
0b7d8cd45e remove extra permissions on GH action
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-10-17 07:36:38 +02:00
Matthias Bertschy
48c86037fd Merge pull request #1433 from kubescape/artifacthub
add ArtifactHub to README
2023-10-16 17:36:45 +02:00
Matthias Bertschy
69b28823d9 add ArtifactHub to README
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-10-16 16:27:38 +02:00
Matthias Bertschy
554286e803 Merge pull request #1432 from kubescape/fossa
add FOSSA badge to README
2023-10-16 14:32:38 +02:00
Matthias Bertschy
971e775476 add FOSSA badge to README
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-10-16 14:20:12 +02:00
Matthias Bertschy
95133af9f4 build windows exec without libgit
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-10-16 11:16:30 +02:00
Matthias Bertschy
3efa40e808 use go-gitlog as an alternative to git2go (#1393)
* use go-gitlog as an alternative to git2go

Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>

* set RELEASE to something to avoid failing binary-build step

Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>

---------

Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-10-15 15:16:05 +03:00
David Wertenteil
a5d1fa3f66 Merge pull request #1274 from nvuillam/patch-1
Update installation.md to add instructions to install a previous version
2023-10-15 12:02:30 +03:00
David Wertenteil
3d71246580 Merge pull request #1430 from kubescape/token
add top level permissions: read-all for openssf
2023-10-15 11:58:54 +03:00
YiscahLevySilas1
31a0bd9266 use ControlConfigInputs, deprecate ConfigInputs (#1419)
* use ControlConfigInputs, deprecate ConfigInputs

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* update opa-utils version

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

---------

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>
2023-10-15 11:58:10 +03:00
Matthias Bertschy
143a4d9818 add top level permissions: read-all for openssf
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-10-13 15:20:52 +02:00
Matthias Bertschy
0d889bf454 Merge pull request #1429 from kubescape/ssf
correct security-insights stage -> status
2023-10-13 07:41:07 +02:00
Matthias Bertschy
f7a5f76285 correct security-insights stage -> status
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-10-13 07:31:55 +02:00
Matthias Bertschy
1e527b4174 Merge pull request #1428 from slashben/security-slam
Fix in the README for changelog name
2023-10-13 07:08:24 +02:00
Ben
5bf1d6b3c4 Fix in the README for changelog name
Signed-off-by: Ben <ben@armosec.io>
2023-10-12 22:24:36 +03:00
Matthias Bertschy
f622bd0a0e Merge pull request #1422 from kubescape/dependabot/go_modules/httphandler/golang.org/x/net-0.17.0
Bump golang.org/x/net from 0.14.0 to 0.17.0 in /httphandler
2023-10-12 16:59:01 +02:00
Ben Hirschberg
f70cf68e4d Merge pull request #1427 from slashben/security-slam
Adding project security and governance as per maintainer decision
2023-10-12 17:19:19 +03:00
Ben
accc8a3834 Adding project security and governance as per maintainer decision
Signed-off-by: Ben <ben@armosec.io>
2023-10-12 17:14:28 +03:00
Matthias Bertschy
83b6686496 Merge pull request #1426 from kubescape/Adding-scorecard-badge
Adding scorecard badge
2023-10-12 15:56:26 +02:00
David Wertenteil
934f72203e Update README.md
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-10-12 16:50:43 +03:00
David Wertenteil
506da9dc22 Merge pull request #1425 from kubescape/scorecard
Create scorecard.yml
2023-10-12 16:40:49 +03:00
David Wertenteil
2cfd4f3b31 Create scorecard.yml
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-10-12 16:39:38 +03:00
dependabot[bot]
7aa7a9bbda Bump golang.org/x/net from 0.14.0 to 0.17.0 in /httphandler
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.14.0 to 0.17.0.
- [Commits](https://github.com/golang/net/compare/v0.14.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-12 12:25:57 +00:00
Matthias Bertschy
5968f97583 Merge pull request #1417 from kubescape/fixtests
drop build tags for tests (will soon deprecate them)
2023-10-11 17:25:54 +02:00
Matthias Bertschy
6070f0f126 Merge pull request #1418 from kubescape/fixci
use correct variable for IMAGE_TAG
2023-10-11 16:17:23 +02:00
Matthias Bertschy
a52ca0e47d use correct variable for IMAGE_TAG
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-10-11 16:05:55 +02:00
Matthias Bertschy
2da0293ee2 Merge pull request #1416 from kubescape/fixci
add missing dependency on retag in binary-build
2023-10-11 14:18:59 +02:00
Matthias Bertschy
ed1219baf1 drop build tags for tests (will soon deprecate them)
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-10-11 14:03:53 +02:00
Matthias Bertschy
f073ce0f42 add missing dependency on retag in binary-build
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-10-11 13:56:50 +02:00
Matthias Bertschy
9e6efd04ce Merge pull request #1413 from VaibhavMalik4187/remove-codesee-workflow
Removed the Codesee workflow
2023-10-10 07:29:11 +02:00
VaibhavMalik4187
8908a4e8cf Removed the Codesee workflow
Fixes: https://github.com/kubescape/kubescape/issues/1405

Signed-off-by: VaibhavMalik4187 <vaibhavmalik2018@gmail.com>
2023-10-10 07:38:51 +05:30
Matthias Bertschy
425f278300 Merge pull request #1412 from kubescape/fixci
force docker-build in absence of release label
2023-10-09 11:04:59 +02:00
Matthias Bertschy
5b1aa1501f force docker-build in absence of release label
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-10-09 10:13:53 +02:00
David Wertenteil
9bb2136ada Merge pull request #1411 from kubescape/fixed-wf
Adding check-secret to build image wf
2023-10-08 12:42:14 +03:00
David Wertenteil
bbabd5373a Adding check-secret to build image wf
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-10-08 12:18:19 +03:00
Matthias Bertschy
24c48ab58f Merge pull request #1407 from kubescape/dependabot/go_modules/github.com/cyphar/filepath-securejoin-0.2.4
Bump github.com/cyphar/filepath-securejoin from 0.2.3 to 0.2.4
2023-10-05 10:26:13 +02:00
dependabot[bot]
fd6347fac2 Bump github.com/cyphar/filepath-securejoin from 0.2.3 to 0.2.4
Bumps [github.com/cyphar/filepath-securejoin](https://github.com/cyphar/filepath-securejoin) from 0.2.3 to 0.2.4.
- [Release notes](https://github.com/cyphar/filepath-securejoin/releases)
- [Commits](https://github.com/cyphar/filepath-securejoin/compare/v0.2.3...v0.2.4)

---
updated-dependencies:
- dependency-name: github.com/cyphar/filepath-securejoin
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-10-02 17:41:05 +02:00
YiscahLevySilas1
269945c08c split failedPath to deletePaths and reviewPaths (#1402)
* support delete paths and review paths

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* update armoapi + opa-utils

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* fix test

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* go mod tidy

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* support failedPaths until all controls replace with review/delete paths

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* fix test

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* fix test

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

---------

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>
2023-10-02 17:03:02 +03:00
Rotem Refael
10c7c428e4 add Openssf badge (#1400)
* add Openssf badge

Signed-off-by: rotemamsa <rotem@armosec.io>
2023-09-28 13:23:17 +02:00
Matthias Bertschy
34f0b64946 Merge pull request #1399 from kubescape/noratelimit
disable rate limiting for storage client
2023-09-27 17:07:45 +02:00
rcohencyberarmor
884af50c0b Support control cluster from cli (#1391)
* adding operator CLI to kubescape

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* support http requet for trigger in cluster operator

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* create interface for create request payload

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* logs + go mod update

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* docs

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* add relevant system tests

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* linter corrections

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* code review corrections

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* remove non relevant system tests - after code review corrections

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* PR corrections

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* PR corrections

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* change log

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* remove from examples

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* change log

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* test correction

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

---------

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>
Co-authored-by: rcohencyberarmor <rcohen@armosec.io>
2023-09-27 16:31:04 +03:00
Matthias Bertschy
e97103494f disable rate limiting for storage client
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-09-21 16:32:28 +02:00
Matthias Bertschy
3e7a6b516b Separate docker builds for kubescape and kubescape-cli (#1390)
* create a separate Dockerfile for httphandler

Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>

* add Dockerfile for cli, edit README

Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>

* modify gh action to use new cli Dockerfile

Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>

---------

Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-09-18 17:13:08 +03:00
Amir Malka
8257e31232 Save scan results in storage and support scanning a deleted resource (#1376)
* store scan results in storage

Signed-off-by: Amir Malka <amirm@armosec.io>

* store scan results in storage

Signed-off-by: Amir Malka <amirm@armosec.io>

* save resources in their namespaces, load namespace from env var, extend the config obj

Signed-off-by: Amir Malka <amirm@armosec.io>

* setting context name

Signed-off-by: Amir Malka <amirm@armosec.io>

* updated k8s-interface

Signed-off-by: Amir Malka <amirm@armosec.io>

* scanning a deleted resource

Signed-off-by: Amir Malka <amirm@armosec.io>

* cr changes

Signed-off-by: Amir Malka <amirm@armosec.io>

* cr changes

Signed-off-by: Amir Malka <amirm@armosec.io>

* fix

Signed-off-by: Amir Malka <amirm@armosec.io>

* remove unused constants

Signed-off-by: Amir Malka <amirm@armosec.io>

* use t.Setenv

Signed-off-by: Amir Malka <amirm@armosec.io>

* added tests for rbac triplet slugs

Signed-off-by: Amir Malka <amirm@armosec.io>

* updated namespace logic

Signed-off-by: Amir Malka <amirm@armosec.io>

* fix test

Signed-off-by: Amir Malka <amirm@armosec.io>

---------

Signed-off-by: Amir Malka <amirm@armosec.io>
2023-09-14 10:03:36 +03:00
David Wertenteil
bfc2304a95 Merge pull request #1388 from kubescape/remove-armo-url
Remove ARMO server url
2023-09-13 14:26:41 +03:00
Daniel Grunberger
96337edc67 add new line (#1389)
* add new line

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* rename ks-cloud-operator

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

---------

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
Co-authored-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-09-13 14:26:11 +03:00
DRAGON2002
a3f80d91bf fix: format headers (#1383)
Signed-off-by: DRAGON <anantvijay3@gmail.com>
2023-09-13 13:27:56 +03:00
Amir Malka
69c84cdf56 remove ARMO server url
Signed-off-by: Amir Malka <amirm@armosec.io>
2023-09-13 09:43:38 +03:00
David Wertenteil
a6cca30eb0 Merge pull request #1381 from XDRAGON2002/issue_1380
feat: darken table borders
2023-09-11 12:09:17 +03:00
DRAGON
c74c5f1970 feat: darken table borders
Signed-off-by: DRAGON <anantvijay3@gmail.com>
2023-09-10 21:48:15 +05:30
David Wertenteil
e611cec238 Merge pull request #1379 from kubescape/fix-kubecontext-for-httphandler
fix setting context name in httphandler
2023-09-10 16:17:36 +03:00
Amir Malka
4372ca320a fix setting context name in httphandler
Signed-off-by: Amir Malka <amirm@armosec.io>
2023-09-10 16:16:01 +03:00
David Wertenteil
c490dcc9cb Merge pull request #1372 from kubescape/fix-image-printer
Print up until 4 images in vulnerability summary
2023-09-07 10:08:04 +03:00
Amir Malka
c914ab1034 revert e2e test branch (#1373)
Signed-off-by: Amir Malka <amirm@armosec.io>
2023-09-05 14:31:56 +03:00
Daniel Grunberger
b39ce4caae print up until 4 imgs
Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-09-05 11:47:44 +03:00
David Wertenteil
076aa7f8fe Merge pull request #1370 from kubescape/provide-log-msg
validate sarif format
2023-09-03 18:41:10 +03:00
Daniel Grunberger
df035ea5fc Fix scan command (#1369)
* bump version

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* bump version for httphandler

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* fix args validation

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* errors as const

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

---------

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
Co-authored-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-09-03 17:22:14 +03:00
Daniel Grunberger
58553688e9 validate sarif format
Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-09-03 16:51:52 +03:00
Daniel Grunberger
776173653d bump version (#1368)
* bump version

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* bump version for httphandler

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

---------

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
Co-authored-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-09-03 15:31:57 +03:00
Daniel Grunberger
26c47d501c move context flag to root (#1367)
* move context flag to root

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* rm from httphandler

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

---------

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
Co-authored-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-09-03 10:39:15 +03:00
Vicky Aryan
6a8a338945 Error Fixed when downloading on azure cloud vm environment (#720)
* install.ps1 is modified

* cloud vm error fixed
2023-09-01 08:03:12 +03:00
Daniel Grunberger
53f23b663b Logger fixes (#1362)
* fix rbac log

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* fix logger logic

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* use const

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* use const for zap

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

---------

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
Co-authored-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-08-30 19:17:41 +03:00
Amir Malka
592e0e2b43 Service discovery (#1359)
* remove hardcoded urls

Signed-off-by: Amir Malka <amirm@armosec.io>

* update

Signed-off-by: Amir Malka <amirm@armosec.io>

* fix test

Signed-off-by: Amir Malka <amirm@armosec.io>

* update providers docs

Signed-off-by: Amir Malka <amirm@armosec.io>

* fix

Signed-off-by: Amir Malka <amirm@armosec.io>

* hardcoded systests branch

Signed-off-by: Amir Malka <amirm@armosec.io>

* fix

Signed-off-by: Amir Malka <amirm@armosec.io>

* added logs

Signed-off-by: Amir Malka <amirm@armosec.io>

* added logs

Signed-off-by: Amir Malka <amirm@armosec.io>

* create config path if it does not exist

Signed-off-by: Amir Malka <amirm@armosec.io>

* fix

Signed-off-by: Amir Malka <amirm@armosec.io>

* fix

Signed-off-by: Amir Malka <amirm@armosec.io>

---------

Signed-off-by: Amir Malka <amirm@armosec.io>
2023-08-30 09:54:50 +03:00
David Wertenteil
92449bf564 core(cmd): adding corrections to cmd (#1357)
* adding corrections to cmd

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* remove decorative line

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* wip: changed results indicator

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* replace status test with icons

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* print workloads in a different line

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* update display

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* deprecate commands

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* removed unused functions

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* fixed tests

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* update cloud provider detection

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* rename column name

Signed-off-by: David Wertenteil <dwertent@armosec.io>

---------

Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-08-29 09:50:22 +03:00
David Wertenteil
8d1547163b Beautify install.sh script logs (#1356)
* Check k8s access before running

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* refactor script

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* fixed color background

Signed-off-by: David Wertenteil <dwertent@armosec.io>

---------

Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-08-24 15:18:10 +03:00
David Wertenteil
d16abf376d Merge pull request #1335 from kubescape/dwertent-patch-1
Create dependabot.yaml
2023-08-24 10:27:58 +03:00
Amir Malka
150967eae8 Refactor backend integration (#1355)
* refactor BE integration

Signed-off-by: Amir Malka <amirm@armosec.io>
2023-08-23 15:36:08 +03:00
Daniel Grunberger
150dc61ec7 fix panic & provide msg (#1353)
* fix pani & provide msgf

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* support sarif

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* new line

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* validate format

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* refactor

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* validate printer tests

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* use sarif const

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* small refactor

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* unify switch

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

---------

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
Co-authored-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-08-22 15:22:57 +03:00
Daniel Grunberger
7b46cdd480 Improve cluster scan cli (#1352)
* start improvements

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* cta

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* refactor

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* fixes

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* http handler go mod

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* set control type

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* move to func

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* move to func

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* use color for vuln summary

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

---------

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
Co-authored-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-08-22 15:21:01 +03:00
YiscahLevySilas1
b67fd95e31 support paths from related resources (#1351)
* support paths from related resources

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* fix test

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

---------

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>
2023-08-22 08:06:45 +03:00
Daniel Grunberger
f7b3cdcf35 Improve logs (#1349)
* use stop-success

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* improve logger

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* RBAC

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

---------

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
Co-authored-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-08-17 14:18:40 +03:00
Daniel Grunberger
d6a47a82d2 improve cli output (#1347)
Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
Co-authored-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-08-16 13:01:32 +03:00
Daniel Grunberger
936cb26c06 fix panic and improve logs (#1344)
Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
Co-authored-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-08-16 13:00:52 +03:00
DRAGON2002
9265a5d6d0 fix: icons formatting (#1343)
Signed-off-by: DRAGON <anantvijay3@gmail.com>
2023-08-16 12:58:55 +03:00
Daniel Grunberger
e6f5c7e0dd bump k8s-interface version (#1345)
* bump version

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* bump httphandler

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

---------

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
Co-authored-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-08-15 10:34:45 +03:00
rcohencyberarmor
4e48148d40 Support unified configuration (#1304)
* support scanning scope

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update go mod

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update white list

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update go mod

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* scope empty return control should tested

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update rego scope for system test

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update test + mock

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* add comment

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update rego library

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update k8s-interface

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update opa utils - lots of file changes in this commit since armoapi-go bump up in opa-utils

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* move to temp k8s-interface - till PR in k8s-interface repo will approved

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update k8s-interface with released tag

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update go mod in httphandler

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* support unified configuration

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* unitest adjustment

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* config-unified

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* CR corrections

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* remove system test till it will be merged

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* add relevant system test

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* remove delete test

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* return config delete system test

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

---------

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>
Co-authored-by: rcohencyberarmor <rcohen@armosec.io>
2023-08-15 10:34:23 +03:00
David Wertenteil
3648ef286d Merge pull request #1341 from XDRAGON2002/issue_1339
feat: migrate fatih/color to gchalk
2023-08-13 07:56:05 +03:00
DRAGON
d946662e57 feat: migrate fatih/color to gchalk
Signed-off-by: DRAGON <anantvijay3@gmail.com>
2023-08-11 04:31:39 +05:30
David Wertenteil
51b37d5cbf Update logs (#1340)
* update logger

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* fixed logger

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* bump go-logger version

Signed-off-by: David Wertenteil <dwertent@armosec.io>

---------

Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-08-10 19:15:14 +03:00
DRAGON2002
9afae713ba feat: add table heading colors (#1321)
Signed-off-by: DRAGON <anantvijay3@gmail.com>
2023-08-10 19:14:38 +03:00
Matthias Bertschy
1d64522607 use distroless base image (#1338)
* use distroless base image

Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>

* bump cosign to v2

Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>

---------

Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-08-10 15:46:07 +03:00
DRAGON2002
225a923006 feat: improve pretty logger (#1311)
* feat: improve pretty logger

Signed-off-by: DRAGON <anantvijay3@gmail.com>

* fixed logger

Signed-off-by: David Wertenteil <dwertent@armosec.io>

---------

Signed-off-by: DRAGON <anantvijay3@gmail.com>
Signed-off-by: Craig Box <craigb@armosec.io>
Signed-off-by: David Wertenteil <dwertent@armosec.io>
Co-authored-by: Craig Box <craigb@armosec.io>
Co-authored-by: David Wertenteil <dwertent@armosec.io>
2023-08-09 17:30:04 +03:00
DRAGON2002
6c1a3fb89b feat: add short table (#1292)
Signed-off-by: DRAGON <anantvijay3@gmail.com>
Signed-off-by: DRAGON2002 <81813720+XDRAGON2002@users.noreply.github.com>
2023-08-09 16:56:58 +03:00
DRAGON2002
df5f7db51d feat: change colors library (#1316)
Signed-off-by: DRAGON <anantvijay3@gmail.com>
2023-08-09 09:48:34 +03:00
DRAGON2002
35c593a624 chore: update docs build.ps1 (#1299)
* chore: update docs build.ps1

Signed-off-by: DRAGON <anantvijay3@gmail.com>

* Fix build.ps1 for CI

Signed-off-by: Songlin Jiang <songlin.jiang@csc.fi>

---------

Signed-off-by: DRAGON <anantvijay3@gmail.com>
Signed-off-by: Songlin Jiang <songlin.jiang@csc.fi>
Co-authored-by: Songlin Jiang <songlin.jiang@csc.fi>
2023-08-09 09:27:35 +03:00
DRAGON2002
869f0ea109 feat: add unicode table (#1285)
Signed-off-by: DRAGON <anantvijay3@gmail.com>
2023-08-09 09:26:37 +03:00
David Wertenteil
cf08daf7fb scan per namespace (#1337)
* scan per namespace

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* disable unit test

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* Adding build image wf

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* removing unused channels

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* adding scopes

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* update

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* fixed cluster size

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* update rbac deps

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* aggregate resources

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* Delete build-image.yaml

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* adding scan image logs

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* update cmd message

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* update logs

Signed-off-by: David Wertenteil <dwertent@armosec.io>

---------

Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-08-08 10:47:15 +03:00
Ben Hirschberg
266029eb23 Implementing container image name normalization built-in function for Rego (#1334)
* Implementing container image name normalization built-in function for Rego

Signed-off-by: Ben <ben@armosec.io>

* updating go.mod t include docker/distribution

Signed-off-by: Ben <ben@armosec.io>

* fix test

Signed-off-by: Ben <ben@armosec.io>

---------

Signed-off-by: Ben <ben@armosec.io>
2023-08-08 09:35:32 +03:00
rcohencyberarmor
4c9fec8ef4 Support scanning scope (#1293)
* support scanning scope

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update go mod

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update white list

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update go mod

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* scope empty return control should tested

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update rego scope for system test

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update test + mock

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* add comment

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update rego library

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update k8s-interface

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update opa utils - lots of file changes in this commit since armoapi-go bump up in opa-utils

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* move to temp k8s-interface - till PR in k8s-interface repo will approved

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update k8s-interface with released tag

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update go mod in httphandler

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* PR review corrections

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* change test name

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* scanning scope support for framework

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* test/mock adjustments after merge

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* add more informative log to the user

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update go.mod and go.sum of the http handler

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* remove framework just scanning scope not matched to framework config scope

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* add system tests to workflow

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* add system test to github workflow

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

---------

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>
Signed-off-by: David Wertenteil <dwertent@armosec.io>
Co-authored-by: rcohencyberarmor <rcohen@armosec.io>
Co-authored-by: David Wertenteil <dwertent@armosec.io>
2023-08-07 19:11:14 +03:00
David Wertenteil
b88e4f6169 Create dependabot.yaml
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-08-07 16:48:46 +03:00
David Wertenteil
6f07e63d3f Hotfix for version 2.3.8 (#1333)
* update wf

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* fixed tag

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* build arm64

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* wip: revert release changes

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* wip: adding build-image wf

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* adding platforms to wf

Signed-off-by: David Wertenteil <dwertent@armosec.io>

---------

Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-08-06 12:23:49 +03:00
David Wertenteil
addd66bf72 Merge pull request #1327 from dwertent/hot-fix-submit-timestamp
Fix submit time
2023-08-04 19:24:27 +03:00
Amir Malka
e2f96200e0 Code refactor (follow up to PR #1300) (#1323)
* code refactor

Signed-off-by: Amir Malka <amirm@armosec.io>

* use scaninfo object in resource handler

Signed-off-by: Amir Malka <amirm@armosec.io>

---------

Signed-off-by: Amir Malka <amirm@armosec.io>
2023-08-03 17:50:33 +03:00
David Wertenteil
f799b63684 Merge pull request #1331 from kubescape/fix-httphandler-go-mod-anchore
fix(httphandler): pin breaking anchore dependency
2023-08-03 17:49:41 +03:00
Vlad Klokun
a088219954 fix(httphandler): pin breaking anchore dependency
Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>
2023-08-03 17:36:27 +03:00
David Wertenteil
1a2e16b895 Update PR workflow (#1330)
* fixed wf call

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* do not wait for pr checks

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* fixed typo

Signed-off-by: David Wertenteil <dwertent@armosec.io>

---------

Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-08-03 17:25:22 +03:00
David Wertenteil
7444acae11 Merge pull request #1312 from XDRAGON2002/issue_1282
fix: negative compliance score
2023-08-03 14:32:47 +03:00
David Wertenteil
8294694e09 Merge pull request #1277 from XDRAGON2002/issue_1176
fix: kubescape list controls
2023-08-03 14:30:12 +03:00
David Wertenteil
12d7f18b79 Merge pull request #1329 from kubescape/codesee-wf
Update codesee-arch-diagram.yml
2023-08-03 14:05:34 +03:00
David Wertenteil
83279484bd Merge pull request #1328 from kubescape/remove-label-condition
Remove label condition in PR scanner workflow
2023-08-03 14:05:08 +03:00
David Wertenteil
ba134ebc32 Update codesee-arch-diagram.yml
Run codesee only on `.go` files

Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-08-03 13:52:27 +03:00
David Wertenteil
b44f0a76c9 Update 00-pr-scanner.yaml
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-08-03 13:49:34 +03:00
David Wertenteil
226b4772a2 fix submit time
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-08-03 13:26:49 +03:00
Daniel Grunberger
5379b9b0a6 New output (#1320)
* phase-1

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* factory

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* wip: feat(cli): add an image scanning command

Add a CLI command that launches an image scan. Does not scan images yet.

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>

* wip: feat: add image scanning service

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>

* chore: include dependencies

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>

* wip: adjust image scanning service

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>

* wip: feat: use scanning service in CLI

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>

* use iface

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* touches

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* continue

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* add cmd

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* support single workload scan

Signed-off-by: Amir Malka <amirm@armosec.io>

* fix conflict

Signed-off-by: Amir Malka <amirm@armosec.io>

* identifiers

* go mod

* feat(imagescan): add an image scanning command

This commit adds a CLI command and an associated package that scan
images for vulnerabilities.

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>

feat(imagescan): fail on exceeding the severity threshold

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>

* chore(imagescan): include dependencies

This commit adds the dependencies necessary for image scanning.

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>

* chore(imagescan): add dependencies to httphandler

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>

* added unit tests

Signed-off-by: Amir Malka <amirm@armosec.io>

* merge

* more

* integrate img scan

* added unit tests

Signed-off-by: Amir Malka <amirm@armosec.io>

* more refactoring

Signed-off-by: Amir Malka <amirm@armosec.io>

* add scanned workload reference to opasessionobj

Signed-off-by: Amir Malka <amirm@armosec.io>

* fix GetWorkloadParentKind

Signed-off-by: Amir Malka <amirm@armosec.io>

* remove namespace argument from pullSingleResource, using field selector instead

Signed-off-by: Amir Malka <amirm@armosec.io>

* removed designators (unused) field from PolicyIdentifier, and designators argument from GetResources function

Signed-off-by: Amir Malka <amirm@armosec.io>

* changes

* changes

* fixes

* changes

* feat(imagescan): add an image scanning command

This commit adds a CLI command and an associated package that scan
images for vulnerabilities.

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>

feat(imagescan): fail on exceeding the severity threshold

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>

* chore(imagescan): include dependencies

This commit adds the dependencies necessary for image scanning.

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>

* chore(imagescan): add dependencies to httphandler

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>

* chore(imagescan): create vuln db with dedicated function

Remove commented out code, too.

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>

* docs(imagescan): provide package-level docs

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>

* finish merge

* image scan tests

* continue

* fixes

* refactor

* rm duplicate

* start fixes

* update gh actions

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* pr fixes

* fix test

* improvements

---------

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>
Signed-off-by: Amir Malka <amirm@armosec.io>
Signed-off-by: David Wertenteil <dwertent@armosec.io>
Co-authored-by: Daniel Grunberger <danielgrunberger@armosec.io>
Co-authored-by: Vlad Klokun <vklokun@protonmail.ch>
Co-authored-by: Amir Malka <amirm@armosec.io>
Co-authored-by: David Wertenteil <dwertent@armosec.io>
2023-08-03 12:09:33 +03:00
David Wertenteil
98f68d8097 Merge pull request #1319 from kubescape/codesee-arch-diagram-workflow-1690964652908
Install the CodeSee workflow.
2023-08-03 10:14:47 +03:00
David Wertenteil
f8057b5c79 Merge pull request #1322 from kubescape/add-ai-workflow
Adding pr-agent
2023-08-02 16:29:25 +03:00
David Wertenteil
f36d8c31b0 Adding pr-agent
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-08-02 16:27:16 +03:00
Vlad Klokun
3abf18acb7 Merge pull request #1288 from kubescape/feat-image-scan-svc
feat: add an image scanning service and CLI command
2023-08-02 14:03:50 +03:00
codesee-maps[bot]
28200b2744 Install the CodeSee workflow. Learn more at https://docs.codesee.io 2023-08-02 08:24:13 +00:00
David Wertenteil
678f21e33c Merge pull request #1317 from kubescape/add-prints-to-smoketest
add prints to smoketest
2023-08-02 09:55:43 +03:00
Amir Malka
467a84ddac add prints to smoketest
Signed-off-by: Amir Malka <amirm@armosec.io>
2023-08-02 09:52:01 +03:00
Vlad Klokun
925145724e docs(imagescan): provide package-level docs
Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>
2023-08-02 09:50:18 +03:00
Vlad Klokun
e3677fc45c chore(imagescan): create vuln db with dedicated function
Remove commented out code, too.

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>
2023-08-02 09:50:17 +03:00
Vlad Klokun
704de5bfc1 chore(imagescan): add dependencies to httphandler
Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>
2023-08-02 09:50:17 +03:00
Vlad Klokun
2494c1971c chore(imagescan): include dependencies
This commit adds the dependencies necessary for image scanning.

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>
2023-08-02 09:50:17 +03:00
Vlad Klokun
3b8bd7735e feat(imagescan): add an image scanning command
This commit adds a CLI command and an associated package that scan
images for vulnerabilities.

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>

feat(imagescan): fail on exceeding the severity threshold

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>
2023-08-02 09:50:17 +03:00
David Wertenteil
602591e7f2 Merge pull request #1315 from kubescape/remove-workload-cmd
remove scan workload command
2023-08-02 08:44:15 +03:00
Amir Malka
e276e54d2b remove scan workload command
Signed-off-by: Amir Malka <amirm@armosec.io>
2023-08-01 14:11:16 +03:00
Amir Malka
0c019819ff Scanning a single resource (#1300)
* add cmd

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>

* support single workload scan

Signed-off-by: Amir Malka <amirm@armosec.io>

* fix conflict

Signed-off-by: Amir Malka <amirm@armosec.io>

* added unit tests

Signed-off-by: Amir Malka <amirm@armosec.io>

* added unit tests

Signed-off-by: Amir Malka <amirm@armosec.io>

* more refactoring

Signed-off-by: Amir Malka <amirm@armosec.io>

* add scanned workload reference to opasessionobj

Signed-off-by: Amir Malka <amirm@armosec.io>

* fix GetWorkloadParentKind

Signed-off-by: Amir Malka <amirm@armosec.io>

* remove namespace argument from pullSingleResource, using field selector instead

Signed-off-by: Amir Malka <amirm@armosec.io>

* removed designators (unused) field from PolicyIdentifier, and designators argument from GetResources function

Signed-off-by: Amir Malka <amirm@armosec.io>

* fix tests

Signed-off-by: Amir Malka <amirm@armosec.io>

* use ScanObject instead of workload identifier

Signed-off-by: Amir Malka <amirm@armosec.io>

* refactor logic after CR

Signed-off-by: Amir Malka <amirm@armosec.io>

---------

Signed-off-by: Daniel Grunberger <danielgrunberger@armosec.io>
Signed-off-by: Amir Malka <amirm@armosec.io>
Co-authored-by: Daniel Grunberger <danielgrunberger@armosec.io>
2023-08-01 14:07:31 +03:00
David Wertenteil
d9e946cf6d reset head (#1306)
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-08-01 10:47:07 +03:00
David Wertenteil
e3a8ebfe05 Merge pull request #1297 from dwertent/update-armo-docs
docs(providers): Update ARMO docs
2023-07-31 19:37:01 +03:00
David Wertenteil
fd3703b21b Merge pull request #1296 from kubescape/error-handle-for-empty-resource-scan
Error handle for empty resource scan
2023-07-31 16:13:42 +03:00
David Wertenteil
6bcdda7d56 Merge pull request #1309 from amirmalka/bump-dependencies
bump opa-utils
2023-07-31 12:11:26 +03:00
Amir Malka
981430d65f bump opa-utils
Signed-off-by: Amir Malka <amirm@armosec.io>
2023-07-31 12:00:52 +03:00
David Wertenteil
e91ec69832 Merge pull request #1307 from amirmalka/bump-dependencies
Bump dependencies
2023-07-31 11:02:05 +03:00
Amir Malka
bbfa5d356a bump opa-utils, k8s-interface and armoapi-go
Signed-off-by: Amir Malka <amirm@armosec.io>
2023-07-31 10:39:03 +03:00
DRAGON
d2af7f47db fix: negative compliance score
Signed-off-by: DRAGON <anantvijay3@gmail.com>
2023-07-31 00:21:01 +05:30
rcohencyberarmor
d28afcb00c linter correction
Signed-off-by: rcohencyberarmor <rcohen@armosec.io>
2023-07-30 15:46:54 +03:00
rcohencyberarmor
ca6bdb0bef review corrections
Signed-off-by: rcohencyberarmor <rcohen@armosec.io>
2023-07-30 12:06:03 +03:00
Raziel Cohen
e424bfa81b Merge branch 'master' of github.com:kubescape/kubescape into error-handle-for-empty-resource-scan 2023-07-30 11:21:53 +03:00
David Wertenteil
9f1ff4c090 Merge pull request #1279 from XDRAGON2002/issue_760
feat: add build.ps1
2023-07-25 14:41:00 +03:00
David Wertenteil
1a2dda700b Merge pull request #1291 from XDRAGON2002/issue_1290
fix: yamlhandler error handling
2023-07-25 14:39:26 +03:00
rcohencyberarmor
c4e5611c7f add print in the cli to which version the kubescape was update (#1295)
* add print in the cli to which version the kubescape was update

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

* update will suggest to our user to update by following kubescape installation guide

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>

---------

Signed-off-by: rcohencyberarmor <rcohen@armosec.io>
Co-authored-by: rcohencyberarmor <rcohen@armosec.io>
2023-07-25 14:37:44 +03:00
DRAGON
d8e913fb9f feat: add build.ps1
Signed-off-by: DRAGON <anantvijay3@gmail.com>
2023-07-25 14:36:57 +05:30
David Wertenteil
a37b1f7319 update armo docs
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-07-25 11:01:48 +03:00
rcohencyberarmor
b730ef5154 git recognition for empty directory for test
Signed-off-by: rcohencyberarmor <rcohen@armosec.io>
2023-07-24 17:24:13 +03:00
rcohencyberarmor
3280173e95 add error handle when there are no scan to trigger since the directory not contain any relevant scanning files
Signed-off-by: rcohencyberarmor <rcohen@armosec.io>
2023-07-24 17:17:06 +03:00
DRAGON
d0ae4f1c1a fix: yamlhandler error handling
Signed-off-by: DRAGON <anantvijay3@gmail.com>
2023-07-22 13:26:40 +05:30
Vlad Klokun
e4faad8284 Merge pull request #1287 from XDRAGON2002/issue_1255
fix: --- kubescape fix
2023-07-21 21:19:04 +03:00
Vlad Klokun
bc131efd91 tests(fixhandler): remove tests of an unexported sanitization method
Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>
2023-07-21 20:29:04 +03:00
Vlad Klokun
4763f0d69d docs(fixhandler): follow Go Doc comments convention in sanitization func
Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>
2023-07-21 20:28:18 +03:00
Vlad Klokun
22c412ce7f refactor(fixhandler): sanitize YAML inside ApplyFixToContent
External observers don’t need to be aware of the fact we need to
sanitize leading document separators in YAML files. This should be
hidden inside our public function - `ApplyFixToContent()`.

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>
2023-07-21 20:17:33 +03:00
Vlad Klokun
1503e984f8 tests(fixhandler): fail test if unable to open test data file
Previously when there was a typo in a test file name, we silently
failed. This commit makes the test explicitly fail if a test data file
was not found.

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>
2023-07-21 19:55:03 +03:00
Vlad Klokun
a4478ba899 style(fixhandler): newlines and spacing
Ran with `go fmt`.

Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>
2023-07-21 19:45:43 +03:00
David Wertenteil
fcbcb53995 Merge pull request #1276 from amirmalka/time-based-cached-policies
Time-based cached policies
2023-07-20 16:56:39 +03:00
YiscahLevySilas1
17c43fd366 support related objects (#1272)
* support related objects

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* update pkg versions

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* update go mod

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* fix test

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* fix test

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* only add ids of related resource

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* fixes following review

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* add test for processRule

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

---------

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>
2023-07-20 16:23:58 +03:00
YiscahLevySilas1
d44746cb85 allow adding a fw name when running all (#1286)
* allow adding a fw name when running all

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

clean code

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* fix following review

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

---------

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>
2023-07-20 14:07:38 +03:00
DRAGON
912035662b fix: --- kubescape fix
Signed-off-by: DRAGON <anantvijay3@gmail.com>
2023-07-20 00:05:23 +05:30
Matthias Bertschy
61dac76369 Merge pull request #1283 from kubescape/remove-website
Remove website folder
2023-07-19 16:29:34 +02:00
Amir Malka
bacf15eeb8 cache control inputs
Signed-off-by: Amir Malka <amirm@armosec.io>
2023-07-18 15:56:16 +03:00
Craig Box
0a5af235e3 Remove website folder
Signed-off-by: Craig Box <craigb@armosec.io>
2023-07-17 20:09:34 +12:00
David Wertenteil
6fec02caff Merge pull request #1281 from XDRAGON2002/issue_1280
fix: stuck spinner
2023-07-17 09:27:26 +03:00
DRAGON
067655d003 fix: stuck spinner
Signed-off-by: DRAGON <anantvijay3@gmail.com>
2023-07-14 01:24:46 +05:30
DRAGON
d55a74c6b2 fix: kubescape list controls
Signed-off-by: DRAGON <anantvijay3@gmail.com>
2023-07-11 21:08:24 +05:30
Amir Malka
e470fce6ed initial implementation of OpenTelemetry metrics collection (#1269)
Signed-off-by: Amir Malka <amirm@armosec.io>
2023-07-10 14:22:26 +03:00
Amir Malka
ea3172eda6 time-based cached policies
Signed-off-by: Amir Malka <amirm@armosec.io>
2023-07-10 10:54:56 +03:00
Nicolas Vuillamy
31c4badf1c Update installation.md to add instructions to install a previous version via SH 2023-07-09 21:22:47 +02:00
David Wertenteil
f060d02fbc Merge pull request #1267 from dwertent/submit-untracked-files
feat(file scanning): Submit untracked files
2023-07-06 09:40:21 +03:00
David Wertenteil
43975ddafe Merge pull request #1266 from batazor/patch-1
Update grafana-kubescape-dashboard.json
2023-07-06 09:40:06 +03:00
David Wertenteil
abe0477249 Merge pull request #1265 from dwertent/update-submit-message
Update submit message
2023-07-06 09:39:04 +03:00
David Wertenteil
5f197eb27c submit file scanning
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-07-06 09:25:34 +03:00
Victor Login
84b43d2b03 Update grafana-kubescape-dashboard.json
Signed-off-by: Victor Login <batazor@evrone.com>
2023-07-05 19:03:27 +02:00
David Wertenteil
b149e00d1a Merge pull request #1264 from dwertent/deprecate-image-controls
core(adaptors): Ignore adaptors when credentials are not set
2023-07-05 17:48:12 +03:00
David Wertenteil
f98b394ec2 Merge pull request #1254 from kubescape/rbac-fix
initialize ns in case we don't have one in YAML
2023-07-05 17:47:42 +03:00
David Wertenteil
492b08c995 Merge pull request #1259 from kubescape/update_regolibrary_version
Update regolibrary version
2023-07-05 17:46:35 +03:00
David Wertenteil
8fa15688fb Merge pull request #1260 from dwertent/deprecate-host-scanner
Deprecated host-scanner from CLI
2023-07-05 17:46:12 +03:00
David Wertenteil
1a3e140e56 Merge pull request #1261 from Oshratn/master
English language fix on Kubescape output
2023-07-05 12:59:19 +03:00
David Wertenteil
72f6988bb4 update messaging based on Oshrats comments
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-07-05 10:40:22 +03:00
David Wertenteil
780be45392 update submit message
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-07-05 10:38:59 +03:00
David Wertenteil
676771e8b3 deprecate the login flags
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-07-05 10:16:09 +03:00
David Wertenteil
06f5c24b7d ignore adaptors if credentials are not set
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-07-05 10:13:21 +03:00
David Wertenteil
c17415d6e9 deprecate host-scan-yaml flag
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-07-05 09:02:21 +03:00
David Wertenteil
b5bed7bfbb remove unused file
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-07-05 08:59:57 +03:00
Oshrat Nir
3c38021f7c Changed Assistance Remediation to Assited Remediation
Signed-off-by: Oshrat Nir <oshratn@gmail.com>
2023-07-04 13:13:50 +03:00
David Wertenteil
8989cc1679 Deprecated host-scanner
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-07-04 09:43:10 +03:00
kooomix
0ab9c32715 fxi test jsons 2023-07-02 13:29:28 +03:00
kooomix
868db91801 update regolibrary to v1.0.286-rc.0 2023-07-02 13:25:37 +03:00
Craig Box
aa0fe21a2e Merge pull request #1257 from dwertent/update-armo-landing-page
docs(Installation): update installation steps
2023-06-27 08:22:58 +01:00
David Wertenteil
1b181a47ef Update docs/providers/armo.md
Co-authored-by: Craig Box <craig.box@gmail.com>
2023-06-27 07:42:42 +03:00
David Wertenteil
30487dcd0e Update docs/providers/armo.md
Co-authored-by: Craig Box <craig.box@gmail.com>
2023-06-27 07:42:33 +03:00
David Wertenteil
46ad069fe5 Updating overview
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-06-26 13:54:00 +03:00
David Wertenteil
05d5de17d5 fixed wording
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-06-26 09:49:00 +03:00
David Wertenteil
6bc79458b0 Split the installation command from scanning
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-06-26 09:46:13 +03:00
David Wertenteil
ab85ca2b28 update installation steps
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-06-26 09:40:21 +03:00
Matthias Bertschy
99938ecbee initialize ns in case we don't have one in YAML
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-06-19 07:47:29 +02:00
Matthias Bertschy
e2f8e273ad Merge pull request #1252 from testwill/ioutil
chore: remove refs to deprecated io/ioutil
2023-06-15 08:00:05 +02:00
guoguangwu
be63e1ef7c chore: remove refs to deprecated io/ioutil
Signed-off-by: guoguangwu <guoguangwu@magic-shield.com>
2023-06-14 16:33:24 +08:00
guangwu
5e5b9d564c fix: CVE-2023-28840 CVE-2023-28841 CVE-2023-28842 CVE-2022-41723 etc. (#1221)
* fix: CVE-2023-28840 CVE-2023-28841 CVE-2023-28842 CVE-2022-41723GHSA-vvpx-j8f3-3w6h CVE-2022-23524 CVE-2022-23525 CVE-2022-23526 CVE-2022-36055 CVE-2023-25165

Signed-off-by: guoguangwu <guoguangwu@magic-shield.com>

* restore go.sum

Signed-off-by: David Wertenteil <dwertent@armosec.io>

---------

Signed-off-by: guoguangwu <guoguangwu@magic-shield.com>
Signed-off-by: David Wertenteil <dwertent@armosec.io>
Co-authored-by: David Wertenteil <dwertent@armosec.io>
2023-06-13 11:39:25 +03:00
YiscahLevySilas1
8ee72895b9 Fix statuses - Manual review and Requires configuration (#1251)
* fix statuses - req. review, configurations, manual

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* update opa-utils version

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* update opa-utils version

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* update opa-utils version

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* use const for inner info

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

---------

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>
2023-06-12 10:38:35 +03:00
Nitish Chauhan
6cefada215 correcting the formating of the table in pdf output (#1244)
* correcting the formatting of the table in pdf output

Signed-off-by: ntishchauhan0022 <nitishchauhan0022@gmail.com>

* adding some starting unit tests

Signed-off-by: ntishchauhan0022 <nitishchauhan0022@gmail.com>

* resolving the mod error

Signed-off-by: ntishchauhan0022 <nitishchauhan0022@gmail.com>

---------

Signed-off-by: ntishchauhan0022 <nitishchauhan0022@gmail.com>
2023-06-04 15:21:07 +03:00
David Wertenteil
211ee487b3 core(metrics api): Update API default behavior (#1250)
* scan default frameworks

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* wip: update context

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* do not trigger host scan

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* adding unitests

Signed-off-by: David Wertenteil <dwertent@armosec.io>

---------

Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-06-04 15:12:31 +03:00
David Wertenteil
bbe46c9fab Merge pull request #1247 from kubescape/fix/remove-kubelet-command-line-endpoint
fix: remove deprecated endpoint
2023-05-31 17:17:09 +03:00
Alessio Greggi
ce7fde582c fix: update host-scanner version
Signed-off-by: Alessio Greggi <ale_grey_91@hotmail.it>
2023-05-31 14:14:29 +02:00
David Wertenteil
1c31e1f015 Merge pull request #1246 from dwertent/cli-updates
core(cmd): Minor CLI updates
2023-05-30 11:55:38 +03:00
Alessio Greggi
9e2fe607d8 fix: remove deprecated endpoint
Signed-off-by: Alessio Greggi <ale_grey_91@hotmail.it>
2023-05-30 10:50:31 +02:00
David Wertenteil
5a5ec9b641 wip: remove secretKey and clientID from list cmd
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-05-28 22:37:48 +03:00
David Wertenteil
24c608e204 wip: add example for exclude-namespaces flag
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-05-28 22:35:45 +03:00
David Wertenteil
ac43036b4a Merge pull request #1241 from kubescape/hostsensor-improvements
host-scanner improvements
2023-05-28 08:57:11 +03:00
David Wertenteil
03b89047f8 Merge pull request #1243 from anubhav06/update-go-git-url
update kubescape/go-git-url version
2023-05-28 08:46:22 +03:00
Anubhav Gupta
07a5c6488b update kubescape/go-git-url version
Signed-off-by: Anubhav Gupta <mail.anubhav06@gmail.com>
2023-05-26 18:13:39 +05:30
Alessio Greggi
c486b4fed7 feat: add log coupling for hostsensorutils
Signed-off-by: Alessio Greggi <ale_grey_91@hotmail.it>
2023-05-24 14:46:34 +02:00
Alessio Greggi
00c48d756d fix(hostsensorutils): add finalizers deletion
Signed-off-by: Alessio Greggi <ale_grey_91@hotmail.it>
2023-05-24 11:49:15 +02:00
Alessio Greggi
b49563ae8c fix(hostsensorutils): reduce periods of readiness probe
Signed-off-by: Alessio Greggi <ale_grey_91@hotmail.it>
2023-05-24 11:34:04 +02:00
Alessio Greggi
7840ecb5da fix: move host-scanner to kubescape namespace
Signed-off-by: Alessio Greggi <ale_grey_91@hotmail.it>
2023-05-24 09:45:12 +02:00
David Wertenteil
e151c5bf81 Merge pull request #1240 from amirmalka/memory-optimizations
bump opa-utils version for memory optimizations
2023-05-23 20:37:27 +03:00
Amir Malka
225545476c update opa-utils
Signed-off-by: Amir Malka <amirm@armosec.io>
2023-05-23 19:18:45 +03:00
Amir Malka
987f97102d bump opa-utils version for memory optimizations
Signed-off-by: Amir Malka <amirm@armosec.io>
2023-05-22 16:44:11 +03:00
Craig Box
7bffed2afe Merge pull request #1239 from yrs147/master 2023-05-18 16:39:25 +03:00
Hollow Man
3357713903 Add back new line at the end of the file
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-05-18 13:38:35 +03:00
Yash Raj Singh
efd48eab08 Removed instructions and added the wiki link
Co-authored-by: Hollow Man <hollowman@opensuse.org>

Signed-off-by: Yash Raj Singh <98258627+yrs147@users.noreply.github.com>
2023-05-18 13:38:27 +03:00
Yash Raj
231d9c231a Added instructions to setup kubescape locally
Signed-off-by: Yash Raj <yashraj14700728@gmail.com>
2023-05-18 13:34:13 +05:30
Craig Box
91e705a3eb Merge pull request #1238 from HollowMan6/macm1 2023-05-17 16:37:13 +03:00
Songlin Jiang
a92d573cb8 Fix downloading arm64 binary for kubescape
Signed-off-by: Songlin Jiang <songlin.jiang@csc.fi>
2023-05-17 15:34:32 +03:00
David Wertenteil
e8c72b9883 Merge pull request #1235 from kubescape/revert-1213-windows-latest
Revert "Deprecate kubescape-windows-latest"
2023-05-16 10:07:39 +03:00
David Wertenteil
d380b2cb00 Revert "Deprecate kubescape-windows-latest" 2023-05-16 10:03:41 +03:00
Yuval Leibovich
50b3d0f313 Merge pull request #1233 from kubescape/update-compliance-score-with-readme
updating readme file to support compliance
2023-05-15 17:31:40 +03:00
David Wertenteil
474b6d07ed Merge pull request #1234 from kubescape/timeout
start with a new context, extracting span from request
2023-05-15 16:47:25 +03:00
Matthias Bertschy
2cddc4b395 start with a new context, extracting span from request
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-05-15 14:55:46 +02:00
Yuval Leibovich
b5fb355a22 updating readme file to support compliance 2023-05-15 15:31:14 +03:00
David Wertenteil
d1bc6d0190 Merge pull request #1213 from HollowMan6/windows-latest
Deprecate kubescape-windows-latest
2023-05-15 13:23:32 +03:00
Amir Malka
0a0ef10d50 Control parallelism of opa rule processing by env var (#1230)
* control parallelism of opa rule processing by env var

Signed-off-by: Amir Malka <amirm@armosec.io>

* go 1.20

Signed-off-by: Amir Malka <amirm@armosec.io>

* update go.mod go.sum

Signed-off-by: Amir Malka <amirm@armosec.io>

---------

Signed-off-by: Amir Malka <amirm@armosec.io>
2023-05-14 14:59:21 +03:00
David Wertenteil
4523dc8456 Merge pull request #1232 from amirmalka/update-golang-version
Update go version 1.19->1.20
2023-05-14 11:18:18 +03:00
Amir Malka
b26f83d0bd update go version 1.19->1.20
Signed-off-by: Amir Malka <amirm@armosec.io>
2023-05-14 10:04:30 +03:00
David Wertenteil
9cc3053d74 Merge pull request #1214 from HollowMan6/dispatch
Add ref to workflow dispatch
2023-05-11 15:13:24 +01:00
Yuval Leibovich
84842a6a91 Merge pull request #1219 from kubescape/add-system-test
add compliance score system test
2023-05-08 10:26:00 +03:00
YiscahLevySilas1
aff8cc480e add compliance score system test
Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>
2023-05-07 16:07:39 +03:00
David Wertenteil
7feea43421 Merge pull request #1216 from HollowMan6/install
Make powershell Windows installation user path available immediately
2023-05-03 10:58:47 +03:00
David Wertenteil
04ec32c9f4 Merge pull request #1218 from dwertent/hot-fix-2.3.0
fix(adaptors) Check response size
2023-05-03 10:05:17 +03:00
David Wertenteil
b805f22038 add test
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-05-03 08:58:12 +03:00
David Wertenteil
092f37a636 if the response is empty, return an empty string
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-05-03 08:39:59 +03:00
Hollow Man
9a2eb46f65 Make powershell Windows installation user path available immediately
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-05-02 00:23:01 +03:00
Hollow Man
c637c1a589 Add ref to workflow dispatch
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-05-01 22:07:50 +03:00
David Wertenteil
7609a4aa5d Merge pull request #1199 from HollowMan6/install
Update installation script
2023-05-01 21:53:16 +03:00
Hollow Man
75d31c22d9 Deprecate kubescape-windows-latest
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-05-01 17:38:46 +03:00
David Wertenteil
b93a97a8c8 Merge pull request #1186 from HollowMan6/dispatch
Invoke packaging workflow to update after release
2023-05-01 16:45:10 +03:00
David Wertenteil
88696ca233 Merge pull request #1169 from HollowMan6/exe
Add kubescape.exe to the release assets
2023-05-01 16:40:04 +03:00
David Wertenteil
87d94d16ff Merge pull request #1212 from kubescape/token
change basic auth username to x-token-auth
2023-05-01 14:56:36 +03:00
Hollow Man
1843bcdaf8 invoke only if the repository owner is kubescape
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-05-01 13:46:39 +03:00
Hollow Man
cdaff7ddbe Revert install.ps1 change, to update after release
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-05-01 13:24:40 +03:00
Hollow Man
ec7bc26f64 Add kubescape.exe to the release assets
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-05-01 13:24:35 +03:00
Matthias Bertschy
75b64d58f3 change basic auth username to x-token-auth
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-05-01 10:55:07 +02:00
David Wertenteil
dce1d762c6 Merge pull request #1209 from kubescape/new-threshold-flag
Add compliance score to controls
2023-05-01 11:23:20 +03:00
YiscahLevySilas1
f3225855d0 rerun workflows
Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>
2023-05-01 09:19:09 +03:00
David Wertenteil
5ae421dbc2 Merge pull request #1210 from HollowMan6/master
ci: update before install packages
2023-04-30 15:09:55 +03:00
Hollow Man
d4b75dcb0c ci: update before install packages
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-27 15:50:21 +00:00
YiscahLevySilas1
b7935276e3 Merge branch 'master' of github.com:kubescape/kubescape into new-threshold-flag
Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>
2023-04-27 15:56:12 +03:00
YiscahLevySilas1
d6edd818b8 add compliance score to new field in controls for backward compatibility
Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>
2023-04-27 15:53:47 +03:00
David Wertenteil
a73081c816 Merge pull request #1203 from kubescape/fix/remove-outdated-endpoints
fix: remove outdated enpoints
2023-04-27 11:23:18 +03:00
David Wertenteil
dd961b9e55 Merge pull request #1208 from kubescape/fix/hostsensor-http-probe-attributes
fix(hostsensorutils): fix indentation of probe attributes
2023-04-27 11:22:50 +03:00
Alessio Greggi
76ced13a26 fix(hostsensorutils): fix indentation of probe attributes
Signed-off-by: Alessio Greggi <ale_grey_91@hotmail.it>
2023-04-26 16:16:29 +02:00
YiscahLevySilas1
95e88f8581 add compliance-threshold, deprecate fail-threshold (#1197)
* add compliance-threshold, deprecate fail-threshold

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* update opa-utils version

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

* update opa-utils version for fix in compliance score

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>

---------

Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>
2023-04-24 15:33:30 +03:00
David Wertenteil
5955247f01 Merge pull request #1207 from dwertent/fix-workflow
fix(workflow): Fix workflow
2023-04-23 13:26:48 +03:00
David Wertenteil
c0530b4f88 wip: fixed github actions
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-04-23 11:47:54 +03:00
David Wertenteil
c23d6a17cc wip: update fix command example
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-04-23 11:45:46 +03:00
David Wertenteil
d448de131f Merge pull request #1148 from HollowMan6/master
arm64 release binaries for CI and Krew
2023-04-23 09:48:05 +03:00
Alessio Greggi
b48c04da63 fix: remove outdated enpoints
Signed-off-by: Alessio Greggi <ale_grey_91@hotmail.it>
2023-04-21 19:47:24 +02:00
David Wertenteil
ecf770c756 Merge pull request #1189 from dwertent/hotfix-2.2.6-add_data
fix(submit): set default report time
2023-04-20 16:39:51 +03:00
Hollow Man
6e33f37aee Update installation script
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-20 13:05:51 +03:00
Hollow Man
03f792e968 Revert change to install.sh
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-20 11:21:34 +03:00
David Wertenteil
b017d77b86 Merge pull request #1184 from HollowMan6/sarif-fix
feat(sarif): add fix object in generated reports
2023-04-20 11:15:49 +03:00
Craig Box
2cde591180 Merge pull request #1196 from HollowMan6/doc
Move building instructions to wiki, add more installation instructions
2023-04-20 14:55:52 +12:00
YiscahLevySilas1
f25d573f32 update opa-utils version for fix in compliance score
Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>
2023-04-19 18:34:10 +03:00
Hollow Man
ebf3e49f53 Update snap installation
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-18 02:02:43 +03:00
YiscahLevySilas1
acaf6e78da update opa-utils version
Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>
2023-04-17 20:25:27 +03:00
YiscahLevySilas1
344e9188f6 add compliance-threshold, deprecate fail-threshold
Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>
2023-04-17 16:08:38 +03:00
Hollow Man
3f69f06df1 Move Building to wiki and installation back to docs
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-17 14:10:47 +03:00
Hollow Man
e0b296c124 Move installation instructions to wiki
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-16 19:35:11 +03:00
David Wertenteil
108bbd8bc4 Merge pull request #1193 from suhasgumma/master
Fix: Empty Frameworks Column when listing controls
2023-04-16 09:13:38 +03:00
Hollow Man
5c1a41e920 nit
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-13 10:54:25 +03:00
Hollow Man
0b8d207615 Add more error check
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-13 10:54:25 +03:00
Hollow Man
539b6c51b9 Add unit testcase
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-13 10:54:25 +03:00
Hollow Man
19ca590e2f S1023: redundant break statement (gosimple)
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-13 10:54:25 +03:00
Hollow Man
4de50f82c0 feat(sarif): add fix object in generated reports
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-13 10:54:19 +03:00
Hollow Man
ab41d5dbf4 Invoke workflow to update github action
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-12 22:33:02 +03:00
Matthias Bertschy
fa6de6dc3f Merge pull request #1192 from Sindhuinti/Sindhuinti/broken-link
fix: broken link
2023-04-11 14:14:27 +02:00
Suhas Gumma
96e959c3b7 Fix: Empty Frameworks Column when listing controls
Signed-off-by: Suhas Gumma <suhasgumma2001@gmail.com>
2023-04-11 15:20:07 +05:30
Sindhu Inti
28fdee0dd2 fix: broken link
Signed-off-by: Sindhuinti <iamsindhuinti23@gmail.com>
2023-04-11 13:10:31 +05:30
Sindhu Inti
9ce25c45fe fix: broken link 2023-04-11 13:01:49 +05:30
MathoAvito
d44b9f7a31 Change wf (#1190)
* added coveralls coverage tests 

Signed-off-by: Matan Avital <matavital13@gmail.com>
2023-04-09 18:29:23 +03:00
David Wertenteil
c7af6266fd Merge pull request #1185 from HollowMan6/fix-changes
fix(fix): mixed up change summary list
2023-04-09 11:19:44 +02:00
David Wertenteil
91c13381b2 set default report time
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-04-09 11:15:06 +02:00
Hollow Man
30ad3adbb6 Invoke workflow to update after release
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-07 15:49:25 +03:00
Hollow Man
64e3b08641 fix(fix): mixed up change list
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-07 01:07:49 +03:00
Hollow Man
6d7a89bb74 Add ARM64 binary installation
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-07 00:47:40 +03:00
Hollow Man
e8d92ffd43 Resume test core pkg under ubuntu arm64
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-07 00:47:40 +03:00
Hollow Man
48a15e1a8d Disable multi-platform test with commits
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-07 00:47:40 +03:00
Hollow Man
d02f15ef6f merge pr scanner build into binary-build-and-e2e-tests
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-07 00:47:40 +03:00
Hollow Man
9327f70e1a Fix naming
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-07 00:47:40 +03:00
Hollow Man
c498026208 Disable core pkg test for ubuntu arm64
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-07 00:47:40 +03:00
Hollow Man
3238555df3 add cross compilation for ubuntu arm64
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-07 00:47:40 +03:00
Hollow Man
0c77d89bfc add cross compilation for mac m1
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-04-07 00:47:40 +03:00
yuleib
875deb7ec3 adding compliance score updates (#1181)
Signed-off-by: Yuval Leibovich <yuvall@armosec.io>
2023-04-04 16:03:40 +03:00
David Wertenteil
eae234136b Merge pull request #1178 from YiscahLevySilas1/update-k8s-interface
update version k8s-interface for cloud resources
2023-04-03 13:54:02 +03:00
YiscahLevySilas1
93a35fffbd comment failing test because of many requests
Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>
2023-04-03 10:45:51 +03:00
David Wertenteil
fc97b0ad19 Merge pull request #1179 from kubescape/change_wf
delete BUILD_AND_TEST_LOCAL_KUBESCAPE_CLI input for b-binary-build-an…
2023-04-03 10:26:56 +03:00
YiscahLevySilas1
9a3767ef72 update version k8s-interface for cloud resources
Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>
2023-04-03 09:53:22 +03:00
Matan Shkalim
173eac552c delete BUILD_AND_TEST_LOCAL_KUBESCAPE_CLI input for b-binary-build-and-e2e-tests wf
Signed-off-by: Matan Shkalim <shekel8@gmail.com>
2023-04-03 07:40:09 +01:00
YiscahLevySilas1
9420fd5e79 update version k8s-interface for cloud resources
Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>
2023-04-03 09:34:22 +03:00
Matthias Bertschy
eeda903c76 Merge pull request #1177 from kubescape/update-meeting
Add new meeting location
2023-04-03 07:27:08 +02:00
Craig Box
fd17a87788 Add new meeting location
Changed Zoom URL and added timezone calculator.

Signed-off-by: Craig Box <craigb@armosec.io>
2023-04-03 16:45:26 +12:00
David Wertenteil
1de14ce1e3 Merge pull request #1171 from kubescape/feat/add-progress-bar-during-cloud-resources-download
feat: add progress bar during cloud resources download
2023-04-02 13:53:44 +03:00
David Wertenteil
143d1bb601 Merge pull request #1161 from kubescape/change_wf
change trigger for wf
2023-04-02 13:51:54 +03:00
Alessio Greggi
feb39ed130 test: fix test with new function argument
Signed-off-by: Alessio Greggi <ale_grey_91@hotmail.it>
2023-03-28 16:39:00 +02:00
David Wertenteil
83363d68e6 Merge pull request #1170 from dwertent/fix-get-account-id
fix(config): Load account details
2023-03-28 17:19:56 +03:00
Alessio Greggi
f010364c98 feat: add progress bar during cloud resources download
Signed-off-by: Alessio Greggi <ale_grey_91@hotmail.it>
2023-03-28 16:10:55 +02:00
David Wertenteil
64b8f48469 clean code
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-03-28 16:54:02 +03:00
David Wertenteil
de8d365919 load account details
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-03-28 16:03:31 +03:00
David Wertenteil
db2259d3d0 Merge pull request #1167 from dwertent/update-host-scanner-tag
core(host-scanner): Update host scanner image tag
2023-03-26 22:59:12 +03:00
David Wertenteil
7b9ad26e8e update host scanner image tag
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-03-26 15:07:06 +03:00
Amir Malka
e35029934b updated createTenant path (#1166)
Signed-off-by: Amir Malka <amirm@armosec.io>
2023-03-26 13:21:30 +03:00
Matthias Bertschy
181ebc27e1 Merge pull request #1154 from fredbi/refact/refacf-host-sensor-exports
refact(hostsensorutils): refactors host sensor exports
2023-03-25 09:56:33 +01:00
Frédéric BIDON
a090a296fa refact(hostsensorutils): unexported fields that don't need to be exposed
Also:
* declared scanner resources as an enum type
* replaced stdlib json, added uit tests for skipped resources
* unexported worker pool
* more unexported methods (i.e. everything that is not part of the interface)
* refact(core): clarified mock injection logic and added a few unit tests at the caller's (CLI init utils)

Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
2023-03-25 09:37:24 +01:00
Matthias Bertschy
1e1a48bd9a Merge pull request #1064 from fredbi/perf/opaprocessor-process
perf(opaprocessor): run OPA rule compilation and evaluation in parallel
2023-03-24 15:38:14 +01:00
Matthias Bertschy
5923ce5703 Merge pull request #1147 from HollowMan6/install
Change installation path to ~/.kubescape/bin
2023-03-24 12:46:13 +01:00
Hollow Man
d2dcd29089 fix shellcheck warning and info
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-03-24 13:39:15 +02:00
Matthias Bertschy
8a40bab43a Merge pull request #1165 from fredbi/refact/test-utils
Refact(test utils): introduce internal/testutils
2023-03-24 12:38:14 +01:00
Frederic BIDON
dee3a10bac test(utils): introduced internal/testutils package to factorize testing utilities
Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>

Conflicts:
	core/pkg/hostsensorutils/hostsensordeploy_test.go
2023-03-24 11:15:25 +01:00
Matthias Bertschy
9e3ac4b0f7 Merge pull request #1118 from fredbi/chore/refact-kscloud-client
refact(getter): refactor the KS Cloud client
2023-03-24 11:01:31 +01:00
Matthias Bertschy
58f29523a8 Merge pull request #1141 from fredbi/refact/factorize-hostsensor-api-calls
refact(hostsensorutils): refactors the host sensor
2023-03-24 10:52:52 +01:00
Frédéric BIDON
5b62b0b749 addressed review from David: reverted on unconditional loop exit
Signed-off-by: Frédéric BIDON <fredbi@yahoo.com>
2023-03-23 16:56:37 +01:00
Frédéric BIDON
e4f34f6173 refact(host-sensor): refactors the host sensor
This PR factorizes the list of calls to the host-scanner API in a loop.

More godoc-friendly doc strings are added.

Signed-off-by: Frédéric BIDON <fredbi@yahoo.com>
2023-03-23 16:56:37 +01:00
Frédéric BIDON
4a9f26b27c perf(opaprocessor): run OPA rule compilation and evaluation in parallel
This parallelize the Process() portion of the OPA processor.

The main change is that called methods to evaluate a rule no longer
mutate the internal state of the opaprocessor and allocate maps (less
often, in larger chunks) that are merged at the end of the processing.

Signed-off-by: Frédéric BIDON <fredbi@yahoo.com>
2023-03-23 16:56:21 +01:00
Frederic BIDON
548955fc16 refact(getter): refactor the KS Cloud client
* Interfaces are unchanged

* Deprecated: low-level API funcs marked for deprecation:
  HttpPost, HttpGetter, HttpDelete (an augmented version of the KS Cloud
  client will expose the post report API, which is currently the sole
  use-case of low-level API)

* Doc: the package is now godoc-friendly

* Style & code layout:
  * listed all exposed types via aliases, for clarity/less confusing
    imports
  * unexported private types
  * factorized query param logic
  * factorized type <-> JSON using generic func & io.Reader
  * "utils" are now limited to a few common utility functions
  * centralized hard-coded strings as (unexported) constants
  * concision: use higher-level http definitions such as constants,
    cookie methods, etc
  * included type-safety guards to verify that interfaces are
    actually implemented by the exported types

* Tests: existing test assertions are unchanged
  * tests are beefed-up to assert proper authentication flow (token & cookie).
  * added unit tests for utility methods

* Perf:
  * unmarshalling API responses is now flowing without extraneous memory allocation via string representation
  * request headers are now passed withot extraneous map allocation
  * JSON operations are now fully supported by jsoniter (no longer use encoding/json)

* Changes in functionality:
  * the client is now fully extensible with KSCloudOption
  * use the option functor idiom to keep constructors short
  * methods that used to mute errors (i.e. return nil, nil) now bubble up errors
  * the captured cookie is now captured in full, not just its value
  (other cookie parameters returned are stored)
  * added a request/response dump option, for debugging
  * added support for SubmitReport and retrieval of UI url's
  * backported utm changes (reports use case)

Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
2023-03-23 16:47:23 +01:00
David Wertenteil
ac2bc6c950 Merge to master - PR number: 1164 2023-03-23 12:49:52 +02:00
MathoAvito
ea27c619d4 Revert "added validation for if ORIGIN_TAG=null" 2023-03-23 12:47:42 +02:00
matanshk
e4150b2bb4 Merge pull request #1163 from kubescape/change-wf
added validation for if ORIGIN_TAG=null
2023-03-23 11:17:06 +02:00
Matan Avital
86c7215a72 added validation for if ORIGIN_TAG=null
Signed-off-by: Matan Avital <matavital13@gmail.com>
2023-03-23 11:16:03 +02:00
Hollow Man
5c24267ee9 check KUBESCAPE_EXEC is not empty before deletion
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-03-21 13:15:21 +02:00
Matan Shkalim
bb576610ff change concurrency in 00-pr-scanner
Signed-off-by: Matan Shkalim <shekel8@gmail.com>
2023-03-21 08:05:40 +00:00
Matan Shkalim
085be86197 remove merge action
Signed-off-by: Matan Shkalim <shekel8@gmail.com>
2023-03-21 08:01:59 +00:00
David Wertenteil
b4180b34e7 core(logs): Enhance logs (#1158)
* adding ks version

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* Initialize scanInfo

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* print if logger level is lower than warning

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* wip: scan default frameworks when scanning files

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* change print to log

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* wip: Add end-line after last log

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* wip: silent spinner when logger is warn

Signed-off-by: David Wertenteil <dwertent@armosec.io>

---------

Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-03-20 17:49:51 +02:00
Matan Shkalim
6a750671c3 change trigger for wf
Signed-off-by: Matan Shkalim <shekel8@gmail.com>
2023-03-20 15:40:52 +00:00
David Wertenteil
bb5fedc661 Merge to master - PR number: 1160 2023-03-20 17:36:17 +02:00
Matan Avital
678ef2b787 changed ks_branch to release
Signed-off-by: Matan Avital <matavital13@gmail.com>
2023-03-20 17:34:48 +02:00
David Wertenteil
8c238232a1 Merge to master - PR number: 1159 2023-03-20 17:25:56 +02:00
Matan Avital
2ea9e1a596 moved the output TEST_NAMES to wf-preparation job (was check-secret job) and added step export_tests..
Signed-off-by: Matan Avital <matavital13@gmail.com>
2023-03-20 17:22:52 +02:00
matanshk
e788d68f2c Merge pull request #1157 from kubescape/change-wf
Change wf
2023-03-20 14:12:28 +02:00
Matan Avital
62e3d3263d fixed syntax error
Signed-off-by: Matan Avital <matavital13@gmail.com>
2023-03-20 14:11:09 +02:00
Matan Avital
650d489c26 fixed syntax error
Signed-off-by: Matan Avital <matavital13@gmail.com>
2023-03-20 14:09:04 +02:00
matanshk
ea4914057e Merge pull request #1156 from kubescape/change-wf
added input to make the binary build and test dynamic
2023-03-20 13:49:50 +02:00
Matan Avital
100822f48d added input to make the binary build and test dynamic
Signed-off-by: Matan Avital <matavital13@gmail.com>
2023-03-20 13:45:31 +02:00
matanshk
a5f254bebd Merge pull request #1155 from kubescape/change-wf
added CHECKOUT_REPO input parameter
2023-03-19 18:22:12 +02:00
Matan Avital
e3d5a8c3c6 added CHECKOUT_REPO input parameter
Signed-off-by: Matan Avital <matavital13@gmail.com>
2023-03-19 18:19:48 +02:00
Matthias Bertschy
63ff0f5dc9 Merge pull request #1151 from docwhat/patch-1
fix references to kubectl in completion help
2023-03-18 21:55:38 +01:00
David Wertenteil
5173016a1e Merge pull request #1152 from dwertent/update-otel-events
fix(otel): Update otel events
2023-03-16 14:09:58 +02:00
David Wertenteil
4a95e29d5d Merge to master - PR number: 1150 2023-03-16 10:28:44 +02:00
David Wertenteil
d0b5c7c2c2 update host scanner image tag
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-03-16 09:45:12 +02:00
David Wertenteil
6671ac46f4 change failed to submit message
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-03-16 09:42:39 +02:00
David Wertenteil
28531859f3 Signed-off-by: David Wertenteil <dwertent@armosec.io>
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-03-15 21:26:10 +02:00
Christian Höltje
4ee209c1ea fix references to kubectl in completion help
Signed-off-by: Christian Höltje <docwhat@gerf.org>
2023-03-15 14:30:38 -04:00
David Wertenteil
4edeec146a Set scanning event
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-03-15 18:34:02 +02:00
David Wertenteil
ec4a098b1c replace error by warning
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-03-15 17:17:29 +02:00
David Wertenteil
a29fe367dc Added context to HandleResults
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-03-15 16:58:02 +02:00
Avraham Shalev
aceb4eb0de add dependencies to httphandler
Signed-off-by: Avraham Shalev <8184528+avrahams@users.noreply.github.com>
2023-03-15 14:49:47 +02:00
David Wertenteil
e7afe45706 Merge to master - PR number: 1149 2023-03-15 14:26:56 +02:00
Avraham Shalev
55ce7086d7 upgrade opa-utils and armo api
Signed-off-by: Avraham Shalev <8184528+avrahams@users.noreply.github.com>
2023-03-15 13:53:30 +02:00
Hollow Man
bb04e98d69 Add prompt for removing old way of installation
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-03-15 00:04:21 +02:00
Hollow Man
0ae4ef2244 Clean uninstall of old installation
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-03-14 22:23:29 +02:00
Hollow Man
f9e38fd6a2 Change installation path to ~/.kubescape/bin
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-03-14 21:16:25 +02:00
Amir Malka
106db84a66 bump go-logger (#1144)
Signed-off-by: Amir Malka <amirm@armosec.io>
2023-03-14 10:00:08 +02:00
David Wertenteil
1930004e60 Merge to master - PR number: 1146 2023-03-14 08:17:49 +02:00
Craig Box
015476bf97 Update CONTRIBUTING.md
Fix the link to correcting the DCO.

Signed-off-by: Craig Box <craigb@armosec.io>
2023-03-14 16:33:26 +13:00
David Wertenteil
1e0b9563a1 Merge to master - PR number: 1129 2023-03-13 13:43:07 +02:00
Alessio Greggi
5aa56b1c0a feat: integrate support to retrieve eks policies
Signed-off-by: Alessio Greggi <ale_grey_91@hotmail.it>
2023-03-13 11:35:07 +01:00
David Wertenteil
fd92411593 Merge pull request #1140 from HollowMan6/master
ci(release): fix publishing krew plugin; add '.exe' extension to Windows binary
2023-03-13 10:42:54 +02:00
David Wertenteil
cb97a424fd Merge pull request #1139 from matthyx/fixcontext
initialize context in Prometheus handler
2023-03-12 16:37:50 +02:00
Hollow Man
2542692f25 Revert add '.exe' to Win release binary
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-03-12 11:58:43 +02:00
Hollow Man
640483e991 ci(release): fix publishing krew plugin; add .exe suffix to Win binary
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-03-12 00:39:34 +02:00
Matthias Bertschy
1004902f51 initialize context in Prometheus handler
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-03-09 14:05:26 +01:00
Matthias Bertschy
3b9ce494f5 Merge pull request #1131 from fredbi/test/more-tests-report-receiver
test(reports): adds unit test to the report receiver
2023-03-08 16:56:51 +01:00
Matthias Bertschy
5a37045d9b Merge pull request #1138 from fredbi/test/unit-tests-hostsensorutils
test(hostsensorutils): added unit tests to the hostsensorutils package
2023-03-08 11:12:26 +01:00
Frederic BIDON
91af277a1c fixup unit test: error handling
Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
2023-03-08 08:53:28 +01:00
Frederic BIDON
556962a7e1 test(hostsensorutils): added unit tests to the hostsensorutils package
This PR introduces a (limited) mock for the kubernetes client API.

Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
2023-03-07 20:35:29 +01:00
Frederic BIDON
306da021db test(reports): adds unit test to the report receiver
Signed-off-by: Frederic BIDON <fredbi@yahoo.com>

replace mock

Signed-off-by: Daniel-GrunbergerCA@armosec.com
2023-03-07 19:59:31 +01:00
David Wertenteil
03b0147e39 Merge pull request #1130 from dwertent/update-utm-link-v2
docs(links): Update URLs
2023-03-06 14:08:25 +02:00
Matthias Bertschy
ff9652bd77 Merge pull request #1136 from fredbi/chore/linting-again
chore(linting): run another pass of linting with the rules already in place
2023-03-05 21:17:45 +01:00
Frederic BIDON
7174f49f87 chore(lintin): run another pass of linting with the rules already in place
Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
2023-03-05 20:16:37 +01:00
David Wertenteil
7dfbbe7e39 Merge pull request #1133 from amirmalka/remove-otel-middleware-from-some-endpoints
Removed otel middleware from some APIs
2023-03-05 14:26:40 +02:00
Amir Malka
b3079df8ae removed otel middleware from some APIs
Signed-off-by: Amir Malka <amirm@armosec.io>
2023-03-05 11:49:00 +02:00
David Wertenteil
0698c99241 wip: update UTMs & display UTM only on first scan
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-03-04 23:05:38 +02:00
David Wertenteil
2cda4864e7 wip: do not add message when account ID is empty
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-03-04 23:05:02 +02:00
David Wertenteil
c2b0e5c0a2 Do not display URL when message is empty
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-03-04 23:04:26 +02:00
David Wertenteil
6c54aff451 wip: removed unused code
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-03-04 22:46:20 +02:00
David Wertenteil
dea5649e01 wip: update link in docs
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-03-04 22:34:08 +02:00
Matthias Bertschy
9e6c9e0f65 Merge pull request #1127 from irLinja/master
refactor: update node scanner daemonset tolerations
2023-03-03 11:49:25 +01:00
Arash Haghighat
3dfd758a82 refactor: update node scanner daemonset tolerations
Signed-off-by: Arash Haghighat <arash@linja.pro>
2023-03-01 16:36:08 +01:00
David Wertenteil
0526f58657 Merge to master - PR number: 1121 2023-02-28 07:40:20 +02:00
Alessio Greggi
e419af6c03 ci: pin workflows versions to fixed commits
Signed-off-by: Alessio Greggi <ale_grey_91@hotmail.it>
2023-02-27 21:43:09 +01:00
Matthias Bertschy
03766ec0cd Merge pull request #1120 from alegrey91/fix/remove-hostnetwork-and-hostport-from-host-scanner-deployment
fix(hostsensorsutils): remove hostNetwork and hostPort from deployment
2023-02-27 19:12:05 +01:00
Alessio Greggi
39e2e34fc0 fix(hostsensorsutils): remove hostNet and hostPort from deployment
Signed-off-by: Alessio Greggi <ale_grey_91@hotmail.it>
2023-02-27 18:20:55 +01:00
David Wertenteil
245331b82a Merge pull request #1119 from amirmalka/added-cluster-name-to-otel-init
added clusterName to otel initialization
2023-02-26 19:27:14 +02:00
Amir Malka
cec4e5ca39 added clusterName to otel initialization
Signed-off-by: Amir Malka <amirm@armosec.io>
2023-02-26 18:07:38 +02:00
David Wertenteil
b772588e96 Merge pull request #1117 from dwertent/v2.2.1-patches
V2.2.1 patches
2023-02-26 16:25:13 +02:00
David Wertenteil
5d6ac80c38 Move GITHUB_REF to the krew step
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-26 14:47:25 +02:00
David Wertenteil
33df0e5462 add unitsests to new behavior
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-24 09:49:32 +02:00
David Wertenteil
26ab049622 Do not print table when logger level is warn
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-24 09:19:43 +02:00
David Wertenteil
ac2aa764a4 marking structs that are implementing IPrinter
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-24 09:18:54 +02:00
David Wertenteil
d02bef62d3 wip: re-arange struct
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-24 09:17:31 +02:00
David Wertenteil
46682dfe16 Override GITHUB_REF env when releasing krew
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-24 00:34:18 +02:00
David Wertenteil
01c65194a8 removing host scanner otel env
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-24 00:13:22 +02:00
David Wertenteil
25e42ee4b6 Update rbac-utils pkg
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-23 23:33:35 +02:00
David Wertenteil
7e5abbdd73 Merge pull request #1054 from fredbi/fix/1051-gc-pressure
fix(processorhandler): reduce GC pressure
2023-02-23 23:15:22 +02:00
David Wertenteil
56183ba369 Merge to master - PR number: 1115 2023-02-23 17:32:48 +02:00
David Wertenteil
a9c1ecd3b8 Merge pull request #1104 from alegrey91/fix/improve-namespace-removing-in-host-sensor-lifecycle
fix(hostsensorutils): improve namespace deletion in host-scanner lifecycle
2023-02-23 16:54:09 +02:00
Alessio Greggi
d900ce6146 fix(hostsensorutils): improve namespace deletion in host-scanner lifecycle
Signed-off-by: Alessio Greggi <ale_grey_91@hotmail.it>
2023-02-23 14:41:57 +01:00
David Wertenteil
3a80ff00b6 update opa pkg to 238
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-23 14:25:21 +02:00
David Wertenteil
b989c4c21f update opa pkg
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-23 09:48:52 +02:00
Frédéric BIDON
65c26e22cf fix(processorhandler): reduce GC pressure
* this onboards an optimization from the opa-utils package (caching
exceptions processing)

Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
2023-02-22 20:53:02 +01:00
David Wertenteil
915fa919b2 Fix HTML output (#1111)
* Fixed HTML template

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* Adding HTML output format example

Signed-off-by: David Wertenteil <dwertent@armosec.io>

---------

Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-21 13:55:12 +02:00
Matthias Bertschy
8102dd93ba bump go-git-url (#1110)
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-02-21 11:42:59 +02:00
David Wertenteil
35cafa9eb4 Merge pull request #1113 from amirmalka/fix-macos-build
Fix macos build - add missing pkg-config
2023-02-21 10:19:06 +02:00
Amir Malka
cc823d7559 fix macos build - add missing pkg-config
Signed-off-by: Amir Malka <amirm@armosec.io>
2023-02-21 10:13:08 +02:00
David Wertenteil
eaa74487c2 Merge pull request #1103 from matthyx/enable-krew
enable krew plugin publishing action
2023-02-20 17:55:44 +02:00
David Wertenteil
e8a4c2033f Merge pull request #1084 from fredbi/test/download-release-policy
test(getter): more unit tests
2023-02-20 17:55:08 +02:00
Rotem Refael
8fd9258efa Merge pull request #1101 from alegrey91/fix/improve-cloud-provider-detection 2023-02-16 15:25:38 +02:00
Alessio Greggi
159d3907b5 style(hostsensorutils): simplify code with gofmt
Signed-off-by: Alessio Greggi <ale_grey_91@hotmail.it>
2023-02-16 11:38:55 +01:00
Matthias Bertschy
cde916bec8 Merge pull request #1095 from HollowMan6/master
fix(build): LICENSE file in release tarballs
2023-02-15 15:48:25 +01:00
Matthias Bertschy
8d289bd924 Merge pull request #1105 from HollowMan6/readme
fix(README): broken links
2023-02-15 13:33:59 +01:00
Hollow Man
fda1c83d01 fix(build): LICENSE file
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-02-15 14:21:42 +02:00
Hollow Man
31b6a3c571 fix(README): broken links
Signed-off-by: Hollow Man <hollowman@opensuse.org>
2023-02-15 14:15:38 +02:00
Matthias Bertschy
31a693e9b6 enable krew plugin publishing action
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-02-15 08:02:24 +01:00
Matthias Bertschy
5de228ce0f Merge pull request #1102 from johnmanjiro13/remove-ds-store
chore: Remove an unwanted file
2023-02-15 07:14:02 +01:00
johnmanjiro13
ed27641f04 chore: Remove an unwanted file
Signed-off-by: johnmanjiro13 <28798279+johnmanjiro13@users.noreply.github.com>
2023-02-15 00:07:12 +09:00
Amir Malka
df39e10300 Statuses (#1016) (#1082)
New statuses
2023-02-14 15:00:21 +02:00
Alessio Greggi
c7d1292c7d fix(hostsensorutils): improve cloud provider detection
Signed-off-by: Alessio Greggi <ale_grey_91@hotmail.it>
2023-02-14 13:46:09 +01:00
Matthias Bertschy
a52f13b8c9 Merge pull request #1100 from matthyx/krew-fix
modify plugin description for krew approval
2023-02-14 10:23:00 +01:00
Matthias Bertschy
16e34002f5 modify plugin description for krew approval
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-02-14 08:47:43 +01:00
Rotem Refael
3242de8a28 Merge pull request #1099 from kubescape/revert-1098-fix/controlplaneinfo-issue
Revert "fix: add check to skip controlplaneinfo in case of cloud providers"
2023-02-14 09:02:02 +02:00
yuleib
ca2730cd85 Revert "fix: add check to skip controlplaneinfo in case of cloud providers" 2023-02-14 08:59:03 +02:00
Rotem Refael
88b55cd6c3 Merge pull request #1098 from alegrey91/fix/controlplaneinfo-issue
fix: add check to skip controlplaneinfo in case of cloud providers
2023-02-14 08:56:35 +02:00
Alessio Greggi
46ca5036c4 fix: add check to skip controlplaneinfo in case of cloud providers
Signed-off-by: Alessio Greggi <ale_grey_91@hotmail.it>
2023-02-13 17:16:53 +01:00
Frederic BIDON
d8f1a25ab7 generated rego policy json fixture file, short-circuited call to github when fixture is here
Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
2023-02-10 17:29:46 +01:00
Frederic BIDON
56cfb4fcef test(getters): added unit tests for utilities
Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
2023-02-10 17:29:46 +01:00
Frederic BIDON
894d436274 test(getters): added unit tests to the kubescape API client
Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
2023-02-10 17:29:45 +01:00
Frederic BIDON
39166d40bf tests(cautils): added unit tests for released policy
Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
2023-02-10 17:29:45 +01:00
David Wertenteil
2ba3f78bfc Merge pull request #1094 from alegrey91/master
docs(contributing): add semantic commit messages best practice
2023-02-09 16:09:36 +02:00
Alessio Greggi
1d68d1ba67 docs(contributing): add semantic commit messages best practice
Signed-off-by: Alessio Greggi <ale_grey_91@hotmail.it>
2023-02-09 11:37:24 +01:00
David Wertenteil
6cc5116999 Loading kubeconfig name from env when running ms (#1089)
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-09 09:32:13 +02:00
David Wertenteil
7706c1264c removed unwnated span (#1088)
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-08 18:47:01 +02:00
Craig Box
2f299b6201 fix #1025 (#1087)
Signed-off-by: Craig Box <craigb@armosec.io>
2023-02-08 13:20:59 +02:00
David Wertenteil
f1af9d5687 Merge to master - PR number: 1086 2023-02-08 09:44:10 +02:00
David Wertenteil
d3abd66aa3 Default frameworks (#1085)
* Update default frameworks names

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* Remove error loggers, print debug instead.

Signed-off-by: David Wertenteil <dwertent@armosec.io>

---------

Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-08 08:59:10 +02:00
YiscahLevySilas1
2a0a2cf95a update logs in some resource getters (#1071)
* change warning to debug

Signed-off-by: yiscah <yiscahls@armosec.io>

* update log

Signed-off-by: yiscah <yiscahls@armosec.io>

---------

Signed-off-by: yiscah <yiscahls@armosec.io>
Co-authored-by: David Wertenteil <dwertent@armosec.io>
2023-02-07 22:37:13 +02:00
YiscahLevySilas1
e90f08968f don't add host scanner as excluded ns, use exception instead (#1083)
Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>
2023-02-07 22:36:32 +02:00
Matthias Bertschy
e6b7086961 Fixes for krew plugin submission (#1081)
* use tar.gz file for krew plugin

Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>

* add LICENSE to tar.gz archive

Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>

---------

Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-02-07 22:35:54 +02:00
kooomix
4ea35eec00 GitRegoStore moved to Regolibrary (#1058)
* GitRegoStore moved to Regolibrary

* httphandler go mod

* update go.mod

* test old regostorlibrary

* restore gitRegoStore from regolibrary

* Update 	github.com/kubescape/regolibrary to ver 249

Signed-off-by: kooomix <eranm@armosec.io>

* update go mod

Signed-off-by: kooomix <eranm@armosec.io>

* print scan_control_id mesg

Signed-off-by: kooomix <eranm@armosec.io>

* Update regolibrary version - windows host fix

Signed-off-by: kooomix <eranm@armosec.io>

---------

Signed-off-by: kooomix <eranm@armosec.io>
Co-authored-by: David Wertenteil <dwertent@armosec.io>
2023-02-07 13:18:51 +02:00
David Wertenteil
e8253d4193 Renaming the files (#1079)
* Renaming the files

Signed-off-by: David Wertenteil <dwertent@armosec.io>

* Removing un-used code

Signed-off-by: David Wertenteil <dwertent@armosec.io>

---------

Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-06 19:01:53 +02:00
David Wertenteil
8b8fe92072 Merge pull request #1078 from dwertent/master
Prepare for release
2023-02-06 16:31:54 +02:00
David Wertenteil
bcf9a10131 Remove host scanner warning message
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-06 15:49:13 +02:00
David Wertenteil
b6d21ffd01 removed comments
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-06 15:49:13 +02:00
David Wertenteil
086144c3da JSON version default v2
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-06 15:49:13 +02:00
David Wertenteil
a45ee8ed42 update compliance url
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-06 15:49:13 +02:00
David Wertenteil
129b0f3ee3 fix dockerbuild paths
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-06 15:49:13 +02:00
David Wertenteil
01a8a34637 list files for upload
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-06 15:49:13 +02:00
David Wertenteil
bcb6c06e73 update artifacts location
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-06 15:49:13 +02:00
David Wertenteil
da03022b94 Change artifacts dir
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-06 15:49:13 +02:00
David Wertenteil
17f313177c release with new tag
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-06 15:49:13 +02:00
David Wertenteil
a81353aa15 Leave release var empty for tests
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-06 15:49:12 +02:00
David Wertenteil
e0b82edd1e rename download dir
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-06 15:49:12 +02:00
David Wertenteil
b675d09fe2 rename build dir
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-06 15:49:12 +02:00
David Wertenteil
29b9448dc0 leaving release empty when testing PRs
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-06 15:49:12 +02:00
David Wertenteil
e1020dd1a6 saving file under build dir
Signed-off-by: David Wertenteil <dwertent@armosec.io>
2023-02-06 15:49:12 +02:00
David Wertenteil
9b734b1fa4 Merge pull request #1060 from kubescape/CIS-EKS-support
CIS EKS Support
2023-02-05 17:01:21 +02:00
YiscahLevySilas1
9f97f91f32 add context
Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>
2023-02-05 12:03:10 +02:00
YiscahLevySilas1
c6eff8cbaa minor change 2023-02-05 11:54:21 +02:00
David Wertenteil
af9df548d6 Merge branch 'master' into CIS-EKS-support 2023-02-05 09:43:41 +02:00
David Wertenteil
786f3e6b41 Merge pull request #1074 from kubescape/add-otel-client
Add otel client
2023-02-05 09:35:54 +02:00
David Wertenteil
904751e117 Merge pull request #1075 from kubescape/revert-1073-new-wf-trigger
Revert "change wf trigger"
2023-02-02 16:40:09 +02:00
David Wertenteil
ce43661307 Revert "change wf trigger" 2023-02-02 16:39:16 +02:00
David Wertenteil
cd4b601557 Merge pull request #1044 from matthyx/otel
add otel with uptrace client
2023-02-02 16:37:18 +02:00
David Wertenteil
f34f1449db Merge pull request #1073 from kubescape/new-wf-trigger
change wf trigger
2023-02-01 21:16:40 +02:00
Matan Shkalim
16c74a228f change wf trigger
Signed-off-by: Matan Shkalim <shekel8@gmail.com>
2023-02-01 16:24:11 +00:00
David Wertenteil
ad01f01a6c Merge branch 'master' into otel 2023-01-31 23:09:02 +02:00
David Wertenteil
da0b9883ea Merge to master - PR number: 1070 2023-01-31 15:19:25 +02:00
Matan Shkalim
ac60dbed5e add new workflows + action
Signed-off-by: Matan Shkalim <shekel8@gmail.com>
2023-01-31 13:01:22 +00:00
Matthias Bertschy
3a90682c9e remove otel from CLI part
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-01-31 10:03:56 +01:00
Matthias Bertschy
160ac0db7c add otel with uptrace client
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-01-31 08:06:33 +01:00
David Wertenteil
7ec4fb75e3 Merge pull request #1067 from matthyx/fix-dockerfile
fix ksserver name in Dockerfile
2023-01-31 08:28:26 +02:00
Matthias Bertschy
7e88357940 fix ksserver name in Dockerfile
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-01-31 07:26:18 +01:00
YiscahLevySilas1
1ac808a935 Merge pull request #1063 from YiscahLevySilas1/dev
add unit test
2023-01-30 11:06:31 +02:00
yiscah
45fcc59b5f add unit test
Signed-off-by: yiscah <yiscahls@armosec.io>
2023-01-30 11:03:10 +02:00
YiscahLevySilas1
7875c14adf Merge pull request #1062 from YiscahLevySilas1/dev
update k8s-interface - fix in get region
2023-01-29 20:44:45 +02:00
yiscah
5cddba77aa update k8s-interface - fix in get region
Signed-off-by: yiscah <yiscahls@armosec.io>
2023-01-29 20:42:44 +02:00
YiscahLevySilas1
f3058bf168 Merge pull request #1061 from YiscahLevySilas1/dev
update k8s-interface - fix in get region
2023-01-29 20:34:46 +02:00
yiscah
0d1b92c2ee update k8s-interface - fix in get region
Signed-off-by: yiscah <yiscahls@armosec.io>
2023-01-29 20:32:12 +02:00
yiscah
8de308a5b1 go mod tidy 2023-01-29 09:44:28 +02:00
YiscahLevySilas1
a7f810f0d1 Merge pull request #1043 from YiscahLevySilas1/dev
Get cloud provider resources
2023-01-29 08:59:01 +02:00
Matthias Bertschy
e4e3071f5f Merge pull request #1057 from slashben/master
Progress bar in CLI
2023-01-27 17:52:08 +01:00
yiscah
9a7e61edd1 add cloud resource ListEntitiesForPolicies 2023-01-27 13:42:15 +02:00
Ben
5368330df9 updating httphandler
Signed-off-by: Ben <ben@armosec.io>
2023-01-26 09:40:36 +02:00
Ben
5e6a4cfb3f Checking for nil interface
Signed-off-by: Ben <ben@armosec.io>
2023-01-25 16:23:03 +02:00
Matthias Bertschy
052773b0dc Merge pull request #1022 from matthyx/krew
add kubectl plugin with krew
2023-01-25 08:44:28 +01:00
Matthias Bertschy
d462224b7a add kubectl plugin with krew
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2023-01-25 08:07:31 +01:00
yiscah
de1d8a9d86 improve cloud resources getters 2023-01-24 17:18:39 +02:00
Ben
d346b05b76 Fixing system test after API change
Signed-off-by: Ben <ben@armosec.io>
2023-01-24 14:13:19 +02:00
Ben
a3a61d65e9 Limiting the size of the name of controls in the pretty print of the tabel
Signed-off-by: Ben <ben@armosec.io>
2023-01-24 11:55:08 +02:00
Ben
606b0e77ca fixing progress to work on stderr
Signed-off-by: Ben <ben@armosec.io>
2023-01-24 11:55:08 +02:00
Ben
2a82d6cd21 Implementing progress bar for control processing
Signed-off-by: Ben <ben@armosec.io>
2023-01-24 11:55:08 +02:00
yiscah
530ffde50d Merge branch 'master' of https://github.com/kubescape/kubescape into dev 2023-01-23 18:52:43 +02:00
yiscah
7cf23e9730 Merge branch 'dev' of https://github.com/kubescape/kubescape into dev 2023-01-23 18:35:27 +02:00
David Wertenteil
8d5a8f8e22 Merge pull request #1056 from amirmalka/master
fixed a bug in install.sh script
2023-01-23 13:21:51 +02:00
Amir Malka
b820ce1311 fixed a bug in install.sh script in which default install directory /usr/local/bin was missing and not created
Signed-off-by: Amir Malka <amirm@armosec.io>
2023-01-23 11:30:29 +02:00
kooomix
dae2458867 Merge pull request #1055 from kooomix/hostsensor
Support in CNIInfo hostscanner API
2023-01-23 11:02:08 +02:00
David Wertenteil
d45e636b52 Merge pull request #1050 from vladklokun/retarget-1040-empty-framework-name
chore: retarget a ListFrameworks fix, suggest targeting master in PRs
2023-01-23 10:43:05 +02:00
kooomix
8810631d5c Support in CNIInfo 2023-01-23 09:50:07 +02:00
yiscah
6cddce7399 minor improvements in getting cloud resources 2023-01-22 12:11:58 +02:00
Vlad Klokun
5d5c4f2c9f docs: suggest targeting master instead of dev
Signed-off-by: Vlad Klokun <vklokun@protonmail.ch>
2023-01-20 17:30:50 +02:00
Frédéric BIDON
e37049f68e fix ListFrameworks (could return an empty element)
Signed-off-by: Frédéric BIDON <fredbi@yahoo.com>
2023-01-20 17:26:27 +02:00
David Wertenteil
0622a474eb Merge pull request #1045 from kubescape/cosign-controls
Cosign controls
2023-01-19 18:45:04 +02:00
Daniel-GrunbergerCA
c357f12c82 add cosign functions for signature checking 2023-01-19 17:21:00 +01:00
yiscah
2cec58384a update go mod 2023-01-18 09:36:36 +02:00
yiscah
5e4bc5ddb8 get new cloud resource - DescribeRepositories 2023-01-18 09:25:50 +02:00
yiscah
f30752d9c3 Merge branch 'dev' of https://github.com/kubescape/kubescape into dev 2023-01-17 13:56:25 +02:00
David Wertenteil
a586549c57 Merge pull request #1039 from kubescape/release-on-new-tag
Update release flow
2023-01-15 14:50:54 +02:00
David Wertenteil
7c67a54230 Adding a screenshot 2023-01-15 11:20:56 +02:00
David Wertenteil
0006d7d8e7 Update release flow 2023-01-15 11:11:29 +02:00
David Wertenteil
63083ae48a Merge pull request #1037 from kubescape/dev
Release
2023-01-13 15:27:50 +02:00
yiscah
571a68fb58 Merge branch 'dev' of https://github.com/YiscahLevySilas1/kubescape into dev 2023-01-12 14:10:30 +02:00
YiscahLevySilas1
ef306ca0bf Merge branch 'kubescape:dev' into dev 2023-01-12 14:10:20 +02:00
yiscah
1a011f4968 Merge branch 'dev' of https://github.com/kubescape/kubescape into dev 2023-01-12 14:09:35 +02:00
YiscahLevySilas1
3cece6cf35 Merge branch 'kubescape:dev' into dev 2023-01-11 12:25:16 +02:00
yiscah
7fc10e8213 revert changes 2023-01-11 12:05:56 +02:00
yiscah
bb8f0e3c46 Revert "start developing port forward to host scanner (doesn't work yet)"
This reverts commit 87e2986024.
2023-01-11 12:02:23 +02:00
yiscah
cfd85eadab Merge branch 'dev' of https://github.com/YiscahLevySilas1/kubescape into dev 2023-01-11 11:59:16 +02:00
yiscah
87e2986024 start developing port forward to host scanner (doesn't work yet) 2022-12-15 19:03:44 +02:00
363 changed files with 166465 additions and 8910 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -41,7 +41,4 @@ put an [x] in the box to get it checked
- [ ] If it is a core feature, I have added thorough tests.
- [ ] New and existing unit tests pass locally with my changes
**Please open the PR against the `dev` branch (Unless the PR contains only documentation changes)**
-->
-->

44
.github/actions/tag-action/action.yaml vendored Normal file
View File

@@ -0,0 +1,44 @@
name: 'Tag validator and retag'
description: 'This action will check if the tag is rc and create a new tag for release'
inputs:
ORIGINAL_TAG: # id of input
description: 'Original tag'
required: true
default: ${{ github.ref_name }}
SUB_STRING:
description: 'Sub string for rc tag'
required: true
default: "-rc"
outputs:
NEW_TAG:
description: "The new tag for release"
value: ${{ steps.retag.outputs.NEW_TAG }}
runs:
using: "composite"
steps:
- run: |
if [[ -z "${{ inputs.ORIGINAL_TAG }}" ]]; then
echo "The value of ORIGINAL_TAG is ${{ inputs.ORIGINAL_TAG }}"
echo "Setting the value of ORIGINAL_TAG to ${{ github.ref_name }}"
echo ORIGINAL_TAG="${{ github.ref_name }}" >> $GITHUB_ENV
fi
shell: bash
- run: |
if [[ "${{ inputs.ORIGINAL_TAG }}" == *"${{ inputs.SUB_STRING }}"* ]]; then
echo "Release candidate tag found."
else
echo "Release candidate tag not found."
exit 1
fi
shell: bash
- id: retag
run: |
NEW_TAG=
echo "Original tag: ${{ inputs.ORIGINAL_TAG }}"
NEW_TAG=$(echo ${{ inputs.ORIGINAL_TAG }} | awk -F '-rc' '{print $1}')
echo "New tag: $NEW_TAG"
echo "NEW_TAG=$NEW_TAG" >> $GITHUB_OUTPUT
shell: bash

11
.github/dependabot.yaml vendored Normal file
View File

@@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"

68
.github/workflows/00-pr-scanner.yaml vendored Normal file
View File

@@ -0,0 +1,68 @@
name: 00-pr_scanner
permissions: read-all
on:
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
paths-ignore:
- '**.yaml'
- '**.yml'
- '**.md'
- '**.sh'
- 'website/*'
- 'examples/*'
- 'docs/*'
- 'build/*'
- '.github/*'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
pr-scanner:
permissions:
actions: read
checks: read
contents: read
deployments: read
id-token: write
issues: read
discussions: read
packages: read
pages: read
pull-requests: write
repository-projects: read
security-events: read
statuses: read
uses: ./.github/workflows/a-pr-scanner.yaml
with:
RELEASE: ""
CLIENT: test
secrets: inherit
binary-build:
permissions:
actions: read
checks: read
contents: read
deployments: read
discussions: read
id-token: write
issues: read
packages: write
pages: read
pull-requests: read
repository-projects: read
security-events: read
statuses: read
uses: ./.github/workflows/b-binary-build-and-e2e-tests.yaml
with:
COMPONENT_NAME: kubescape
CGO_ENABLED: 1
GO111MODULE: ""
GO_VERSION: "1.20"
RELEASE: "latest"
CLIENT: test
ARCH_MATRIX: '[ "" ]'
OS_MATRIX: '[ "ubuntu-20.04" ]'
secrets: inherit

View File

@@ -1,64 +0,0 @@
name: golangci-lint
on:
push:
branches:
- dev
pull_request:
types: [ edited, opened, synchronize, reopened ]
branches:
- 'master'
- 'main'
- 'dev'
paths-ignore:
- '**.yaml'
- '**.md'
- '**.sh'
- 'website/*'
- 'examples/*'
- 'docs/*'
- 'build/*'
- '.github/*'
permissions:
contents: read
# Optional: allow read access to pull request. Use with `only-new-issues` option.
pull-requests: read
jobs:
golangci:
name: lint
runs-on: ubuntu-20.04
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.19
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Install libgit2
run: make libgit2
- name: golangci-lint
continue-on-error: true
uses: golangci/golangci-lint-action@v3
with:
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
version: latest
# Optional: working directory, useful for monorepos
# working-directory: somedir
# Optional: golangci-lint command line arguments.
# args: --issues-exit-code=0
args: --timeout 10m --build-tags=static
#--new-from-rev dev
# Optional: show only new issues if it's a pull request. The default value is `false`.
only-new-issues: true
# Optional: if set to true then the all caching functionality will be complete disabled,
# takes precedence over all other caching options.
# skip-cache: true
# Optional: if set to true then the action don't cache or restore ~/go/pkg.
# skip-pkg-cache: true
# Optional: if set to true then the action don't cache or restore ~/.cache/go-build.
# skip-build-cache: true

88
.github/workflows/02-release.yaml vendored Normal file
View File

@@ -0,0 +1,88 @@
name: 02-create_release
permissions: read-all
on:
push:
tags:
- 'v*.*.*-rc.*'
jobs:
retag:
outputs:
NEW_TAG: ${{ steps.tag-calculator.outputs.NEW_TAG }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # ratchet:actions/checkout@v3
- id: tag-calculator
uses: ./.github/actions/tag-action
with:
SUB_STRING: "-rc"
binary-build:
permissions:
actions: read
checks: read
contents: read
deployments: read
discussions: read
id-token: write
issues: read
packages: write
pages: read
pull-requests: read
repository-projects: read
security-events: read
statuses: read
needs: [retag]
uses: ./.github/workflows/b-binary-build-and-e2e-tests.yaml
with:
COMPONENT_NAME: kubescape
CGO_ENABLED: 1
GO111MODULE: ""
GO_VERSION: "1.20"
RELEASE: ${{ needs.retag.outputs.NEW_TAG }}
CLIENT: release
secrets: inherit
create-release:
permissions:
actions: read
checks: read
contents: write
deployments: read
discussions: read
id-token: write
issues: read
packages: read
pages: read
pull-requests: read
repository-projects: read
statuses: read
security-events: read
needs: [retag, binary-build]
uses: ./.github/workflows/c-create-release.yaml
with:
RELEASE_NAME: "Release ${{ needs.retag.outputs.NEW_TAG }}"
TAG: ${{ needs.retag.outputs.NEW_TAG }}
DRAFT: false
secrets: inherit
publish-image:
permissions:
actions: read
checks: read
contents: read
deployments: read
discussions: read
id-token: write
issues: read
packages: write
pages: read
pull-requests: read
repository-projects: read
security-events: read
statuses: read
uses: ./.github/workflows/d-publish-image.yaml
needs: [create-release, retag]
with:
client: "image-release"
image_name: "quay.io/${{ github.repository_owner }}/kubescape-cli"
image_tag: ${{ needs.retag.outputs.NEW_TAG }}
support_platforms: true
cosign: true
secrets: inherit

42
.github/workflows/03-post-release.yaml vendored Normal file
View File

@@ -0,0 +1,42 @@
name: 03-post_release
permissions: read-all
on:
release:
types: [published]
branches:
- 'master'
- 'main'
jobs:
post_release:
name: Post release jobs
runs-on: ubuntu-latest
steps:
- name: Digest
uses: MCJack123/ghaction-generate-release-hashes@c03f3111b39432dde3edebe401c5a8d1ffbbf917 # ratchet:MCJack123/ghaction-generate-release-hashes@v1
with:
hash-type: sha1
file-name: kubescape-release-digests
- name: Invoke workflow to update packaging
uses: benc-uk/workflow-dispatch@v1
if: github.repository_owner == 'kubescape'
with:
workflow: release.yml
repo: kubescape/packaging
ref: refs/heads/main
token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}
- name: Invoke workflow to update homebrew tap
uses: benc-uk/workflow-dispatch@v1
if: github.repository_owner == 'kubescape'
with:
workflow: release.yml
repo: kubescape/homebrew-tap
ref: refs/heads/main
token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}
- name: Invoke workflow to update github action
uses: benc-uk/workflow-dispatch@v1
if: github.repository_owner == 'kubescape'
with:
workflow: release.yaml
repo: kubescape/github-action
ref: refs/heads/main
token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}

View File

@@ -0,0 +1,17 @@
name: 04-publish_krew_plugin
permissions: read-all
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
jobs:
publish_krew_plugin:
name: Publish Krew plugin
runs-on: ubuntu-latest
if: github.repository_owner == 'kubescape'
steps:
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # ratchet:actions/checkout@v3
with:
submodules: recursive
- name: Update new version in krew-index
uses: rajatjindal/krew-release-bot@92da038bbf995803124a8e50ebd438b2f37bbbb0 # ratchet:rajatjindal/krew-release-bot@v0.0.43

52
.github/workflows/README.md vendored Normal file
View File

@@ -0,0 +1,52 @@
# Kubescape workflows
Tag terminology: `v<major>.<minor>.<patch>`
## Developing process
Kubescape's main branch is `main`, any PR will be opened against the main branch.
### Opening a PR
When a user opens a PR, this will trigger some basic tests (units, license, etc.)
### Reviewing a PR
The reviewer/maintainer of a PR will decide whether the PR introduces changes that require running the E2E system tests. If so, the reviewer will add the `trigger-integration-test` label.
### Approving a PR
Once a maintainer approves the PR, if the `trigger-integration-test` label was added to the PR, the GitHub actions will trigger the system test. The PR will be merged only after the system tests passed successfully. If the label was not added, the PR can be merged.
### Merging a PR
The code is merged, no other actions are needed
## Release process
Every two weeks, we will create a new tag by bumping the minor version, this will create the release and publish the artifacts.
If we are introducing breaking changes, we will update the `major` version instead.
When we wish to push a hot-fix/feature within the two weeks, we will bump the `patch`.
### Creating a new tag
Every two weeks or upon the decision of the maintainers, a maintainer can create a tag.
The tag should look as follows: `v<A>.<B>.<C>-rc.D` (release candidate).
When creating a tag, GitHub will trigger the following actions:
1. Basic tests - unit tests, license, etc.
2. System tests (integration tests). If the tests fail, the actions will stop here.
3. Create a new tag: `v<A>.<B>.<C>` (same tag just without the `rc` suffix)
4. Create a release
5. Publish artifacts
6. Build and publish the docker image (this is meanwhile until we separate the microservice code from the LCI codebase)
## Additional Information
The "callers" have the alphabetic prefix and the "executes" have the numeric prefix
## Screenshot
<img width="1469" alt="image" src="https://user-images.githubusercontent.com/64066841/212532727-e82ec9e7-263d-408b-b4b0-a8c943f0109a.png">

90
.github/workflows/a-pr-scanner.yaml vendored Normal file
View File

@@ -0,0 +1,90 @@
name: a-pr-scanner
permissions: read-all
on:
workflow_call:
inputs:
RELEASE:
description: 'release'
required: true
type: string
CLIENT:
description: 'Client name'
required: true
type: string
UNIT_TESTS_PATH:
required: false
type: string
default: "./..."
jobs:
scanners:
env:
GITGUARDIAN_API_KEY: ${{ secrets.GITGUARDIAN_API_KEY }}
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
name: PR Scanner
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # ratchet:actions/checkout@v3
with:
fetch-depth: 0
submodules: recursive
- uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # Install go because go-licenses use it ratchet:actions/setup-go@v3
name: Installing go
with:
go-version: '1.20'
cache: true
- name: Scanning - Forbidden Licenses (go-licenses)
id: licenses-scan
continue-on-error: true
run: |
echo "## Installing go-licenses tool"
go install github.com/google/go-licenses@latest
echo "## Scanning for forbiden licenses ##"
go-licenses check .
- name: Scanning - Credentials (GitGuardian)
if: ${{ env.GITGUARDIAN_API_KEY }}
continue-on-error: true
id: credentials-scan
uses: GitGuardian/ggshield-action@4ab2994172fadab959240525e6b833d9ae3aca61 # ratchet:GitGuardian/ggshield-action@master
with:
args: -v --all-policies
env:
GITHUB_PUSH_BEFORE_SHA: ${{ github.event.before }}
GITHUB_PUSH_BASE_SHA: ${{ github.event.base }}
GITHUB_PULL_BASE_SHA: ${{ github.event.pull_request.base.sha }}
GITHUB_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
GITGUARDIAN_API_KEY: ${{ secrets.GITGUARDIAN_API_KEY }}
- name: Scanning - Vulnerabilities (Snyk)
if: ${{ env.SNYK_TOKEN }}
id: vulnerabilities-scan
continue-on-error: true
uses: snyk/actions/golang@806182742461562b67788a64410098c9d9b96adb # ratchet:snyk/actions/golang@master
with:
command: test --all-projects
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
- name: Test coverage
id: unit-test
run: go test -v ${{ inputs.UNIT_TESTS_PATH }} -covermode=count -coverprofile=coverage.out
- name: Convert coverage count to lcov format
uses: jandelgado/gcov2lcov-action@v1
- name: Submit coverage tests to Coveralls
continue-on-error: true
uses: coverallsapp/github-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: coverage.lcov
- name: Comment results to PR
continue-on-error: true # Warning: This might break opening PRs from forks
uses: peter-evans/create-or-update-comment@5adcb0bb0f9fb3f95ef05400558bdb3f329ee808 # ratchet:peter-evans/create-or-update-comment@v2.1.0
with:
issue-number: ${{ github.event.pull_request.number }}
body: |
Scan results:
- License scan: ${{ steps.licenses-scan.outcome }}
- Credentials scan: ${{ steps.credentials-scan.outcome }}
- Vulnerabilities scan: ${{ steps.vulnerabilities-scan.outcome }}
reactions: 'eyes'

View File

@@ -0,0 +1,387 @@
name: b-binary-build-and-e2e-tests
permissions: read-all
on:
workflow_dispatch:
inputs:
COMPONENT_NAME:
required: false
type: string
default: "kubescape"
RELEASE:
required: false
type: string
default: ""
CLIENT:
required: false
type: string
default: "test"
GO_VERSION:
required: false
type: string
default: "1.20"
GO111MODULE:
required: false
type: string
default: ""
CGO_ENABLED:
type: number
default: 1
required: false
OS_MATRIX:
type: string
required: false
default: '[ "ubuntu-20.04", "macos-latest", "windows-latest"]'
ARCH_MATRIX:
type: string
required: false
default: '[ "", "arm64"]'
BINARY_TESTS:
type: string
required: false
default: '[ "scan_nsa", "scan_mitre", "scan_with_exceptions", "scan_repository", "scan_local_file", "scan_local_glob_files", "scan_local_list_of_files", "scan_nsa_and_submit_to_backend", "scan_mitre_and_submit_to_backend", "scan_local_repository_and_submit_to_backend", "scan_repository_from_url_and_submit_to_backend", "scan_with_exception_to_backend", "scan_with_custom_framework", "scan_customer_configuration", "host_scanner", "scan_compliance_score", "control_cluster_from_CLI_config_scan_exclude_namespaces", "control_cluster_from_CLI_config_scan_include_namespaces", "control_cluster_from_CLI_config_scan_host_scanner_enabled", "control_cluster_from_CLI_config_scan_MITRE_framework", "control_cluster_from_CLI_vulnerabilities_scan_default", "control_cluster_from_CLI_vulnerabilities_scan_include_namespaces" ]'
workflow_call:
inputs:
COMPONENT_NAME:
required: true
type: string
RELEASE:
required: true
type: string
CLIENT:
required: true
type: string
GO_VERSION:
type: string
default: "1.20"
GO111MODULE:
required: true
type: string
CGO_ENABLED:
type: number
default: 1
BINARY_TESTS:
type: string
default: '[ "scan_nsa", "scan_mitre", "scan_with_exceptions", "scan_repository", "scan_local_file", "scan_local_glob_files", "scan_local_list_of_files", "scan_nsa_and_submit_to_backend", "scan_mitre_and_submit_to_backend", "scan_local_repository_and_submit_to_backend", "scan_repository_from_url_and_submit_to_backend", "scan_with_exception_to_backend", "scan_with_custom_framework", "scan_customer_configuration", "host_scanner", "scan_compliance_score", "scan_custom_framework_scanning_file_scope_testing", "scan_custom_framework_scanning_cluster_scope_testing", "scan_custom_framework_scanning_cluster_and_file_scope_testing", "unified_configuration_config_view", "unified_configuration_config_set", "unified_configuration_config_delete" ]'
OS_MATRIX:
type: string
required: false
default: '[ "ubuntu-20.04", "macos-latest", "windows-latest"]'
ARCH_MATRIX:
type: string
required: false
default: '[ "", "arm64"]'
jobs:
wf-preparation:
name: secret-validator
runs-on: ubuntu-latest
outputs:
TEST_NAMES: ${{ steps.export_tests_to_env.outputs.TEST_NAMES }}
OS_MATRIX: ${{ steps.export_os_to_env.outputs.OS_MATRIX }}
ARCH_MATRIX: ${{ steps.export_arch_to_env.outputs.ARCH_MATRIX }}
is-secret-set: ${{ steps.check-secret-set.outputs.is-secret-set }}
steps:
- name: check if the necessary secrets are set in github secrets
id: check-secret-set
env:
CUSTOMER: ${{ secrets.CUSTOMER }}
USERNAME: ${{ secrets.USERNAME }}
PASSWORD: ${{ secrets.PASSWORD }}
CLIENT_ID: ${{ secrets.CLIENT_ID_PROD }}
SECRET_KEY: ${{ secrets.SECRET_KEY_PROD }}
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
run: "echo \"is-secret-set=${{ env.CUSTOMER != '' && \n env.USERNAME != '' &&\n env.PASSWORD != '' &&\n env.CLIENT_ID != '' &&\n env.SECRET_KEY != '' &&\n env.REGISTRY_USERNAME != '' &&\n env.REGISTRY_PASSWORD != ''\n }}\" >> $GITHUB_OUTPUT\n"
- id: export_os_to_env
name: set test name
run: |
echo "OS_MATRIX=$input" >> $GITHUB_OUTPUT
env:
input: ${{ inputs.OS_MATRIX }}
- id: export_tests_to_env
name: set test name
run: |
echo "TEST_NAMES=$input" >> $GITHUB_OUTPUT
env:
input: ${{ inputs.BINARY_TESTS }}
- id: export_arch_to_env
name: set test name
run: |
echo "ARCH_MATRIX=$input" >> $GITHUB_OUTPUT
env:
input: ${{ inputs.ARCH_MATRIX }}
check-secret:
name: check if QUAYIO_REGISTRY_USERNAME & QUAYIO_REGISTRY_PASSWORD is set in github secrets
runs-on: ubuntu-latest
outputs:
is-secret-set: ${{ steps.check-secret-set.outputs.is-secret-set }}
steps:
- name: check if QUAYIO_REGISTRY_USERNAME & QUAYIO_REGISTRY_PASSWORD is set in github secrets
id: check-secret-set
env:
QUAYIO_REGISTRY_USERNAME: ${{ secrets.QUAYIO_REGISTRY_USERNAME }}
QUAYIO_REGISTRY_PASSWORD: ${{ secrets.QUAYIO_REGISTRY_PASSWORD }}
run: |
echo "is-secret-set=${{ env.QUAYIO_REGISTRY_USERNAME != '' && env.QUAYIO_REGISTRY_PASSWORD != '' }}" >> $GITHUB_OUTPUT
binary-build:
name: Create cross-platform build
needs: wf-preparation
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GOARCH: ${{ matrix.arch }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: ${{ fromJson(needs.wf-preparation.outputs.OS_MATRIX) }}
arch: ${{ fromJson(needs.wf-preparation.outputs.ARCH_MATRIX) }}
exclude:
- os: windows-latest
arch: arm64
steps:
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # ratchet:actions/checkout@v3
with:
fetch-depth: 0
submodules: recursive
- name: Cache Go modules (Linux)
if: matrix.os == 'ubuntu-20.04'
uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0 # ratchet:actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Cache Go modules (macOS)
if: matrix.os == 'macos-latest'
uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0 # ratchet:actions/cache@v3
with:
path: |
~/Library/Caches/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Cache Go modules (Windows)
if: matrix.os == 'windows-latest'
uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0 # ratchet:actions/cache@v3
with:
path: |
~\AppData\Local\go-build
~\go\pkg\mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # ratchet:actions/setup-go@v3
name: Installing go
with:
go-version: ${{ inputs.GO_VERSION }}
cache: true
- name: start ${{ matrix.arch }} environment in container
run: |
sudo apt-get update
sudo apt-get install -y binfmt-support qemu-user-static
sudo docker run --platform linux/${{ matrix.arch }} -e RELEASE=${{ inputs.RELEASE }} \
-e CLIENT=${{ inputs.CLIENT }} -e CGO_ENABLED=${{ inputs.CGO_ENABLED }} \
-e KUBESCAPE_SKIP_UPDATE_CHECK=true -e GOARCH=${{ matrix.arch }} -v ${PWD}:/work \
-w /work -v ~/go/pkg/mod:/root/go/pkg/mod -v ~/.cache/go-build:/root/.cache/go-build \
-d --name build golang:${{ inputs.GO_VERSION }}-bullseye sleep 21600
sudo docker ps
DOCKER_CMD="sudo docker exec build"
${DOCKER_CMD} apt update
${DOCKER_CMD} apt install -y cmake python3
${DOCKER_CMD} git config --global --add safe.directory '*'
echo "DOCKER_CMD=${DOCKER_CMD}" >> $GITHUB_ENV;
if: matrix.os == 'ubuntu-20.04' && matrix.arch != ''
- name: Install pkg-config (macOS)
run: brew install pkg-config
if: matrix.os == 'macos-latest'
- name: Install libgit2 (Linux/macOS)
run: ${{ env.DOCKER_CMD }} make libgit2${{ matrix.arch }}
if: matrix.os != 'windows-latest'
- name: Test core pkg
run: ${{ env.DOCKER_CMD }} go test -v ./...
if: "!startsWith(github.ref, 'refs/tags') && matrix.os == 'ubuntu-20.04' && matrix.arch == '' || startsWith(github.ref, 'refs/tags') && (matrix.os != 'macos-latest' || matrix.arch != 'arm64')"
- name: Test httphandler pkg
run: ${{ env.DOCKER_CMD }} sh -c 'cd httphandler && go test -v ./...'
if: "!startsWith(github.ref, 'refs/tags') && matrix.os == 'ubuntu-20.04' && matrix.arch == '' || startsWith(github.ref, 'refs/tags') && (matrix.os != 'macos-latest' || matrix.arch != 'arm64')"
- name: Build
env:
RELEASE: ${{ inputs.RELEASE }}
CLIENT: ${{ inputs.CLIENT }}
CGO_ENABLED: ${{ inputs.CGO_ENABLED }}
run: ${{ env.DOCKER_CMD }} python3 --version && ${{ env.DOCKER_CMD }} python3 build.py
- name: Smoke Testing (Windows / MacOS)
env:
RELEASE: ${{ inputs.RELEASE }}
KUBESCAPE_SKIP_UPDATE_CHECK: "true"
run: python3 smoke_testing/init.py ${PWD}/build/kubescape-${{ matrix.os }}
if: startsWith(github.ref, 'refs/tags') && matrix.os != 'ubuntu-20.04' && matrix.arch == ''
- name: Smoke Testing (Linux amd64)
env:
RELEASE: ${{ inputs.RELEASE }}
KUBESCAPE_SKIP_UPDATE_CHECK: "true"
run: ${{ env.DOCKER_CMD }} python3 smoke_testing/init.py ${PWD}/build/kubescape-ubuntu-latest
if: matrix.os == 'ubuntu-20.04' && matrix.arch == ''
- name: Smoke Testing (Linux ${{ matrix.arch }})
env:
RELEASE: ${{ inputs.RELEASE }}
KUBESCAPE_SKIP_UPDATE_CHECK: "true"
run: ${{ env.DOCKER_CMD }} python3 smoke_testing/init.py ./build/kubescape-${{ matrix.arch }}-ubuntu-latest
if: startsWith(github.ref, 'refs/tags') && matrix.os == 'ubuntu-20.04' && matrix.arch != ''
- name: golangci-lint
if: matrix.os == 'ubuntu-20.04'
continue-on-error: true
uses: golangci/golangci-lint-action@08e2f20817b15149a52b5b3ebe7de50aff2ba8c5 # ratchet:golangci/golangci-lint-action@v3
with:
version: latest
args: --timeout 10m --build-tags=static
only-new-issues: true
- uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # ratchet:actions/upload-artifact@v3.1.1
name: Upload artifact (Linux)
if: matrix.os == 'ubuntu-20.04'
with:
name: kubescape${{ matrix.arch }}-ubuntu-latest
path: build/
if-no-files-found: error
- uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # ratchet:actions/upload-artifact@v3.1.1
name: Upload artifact (MacOS, Win)
if: matrix.os != 'ubuntu-20.04'
with:
name: kubescape${{ matrix.arch }}-${{ matrix.os }}
path: build/
if-no-files-found: error
build-http-image:
permissions:
contents: read
id-token: write
packages: write
pull-requests: read
needs: [check-secret]
uses: kubescape/workflows/.github/workflows/incluster-comp-pr-merged.yaml@main
with:
IMAGE_NAME: quay.io/${{ github.repository_owner }}/kubescape
IMAGE_TAG: ${{ inputs.RELEASE }}
COMPONENT_NAME: kubescape
CGO_ENABLED: 0
GO111MODULE: "on"
BUILD_PLATFORM: linux/amd64,linux/arm64
GO_VERSION: "1.20"
REQUIRED_TESTS: '[
"ks_microservice_create_2_cronjob_mitre_and_nsa_proxy",
"ks_microservice_triggering_with_cron_job",
"ks_microservice_update_cronjob_schedule",
"ks_microservice_delete_cronjob",
"ks_microservice_create_2_cronjob_mitre_and_nsa",
"ks_microservice_ns_creation",
"ks_microservice_on_demand",
"ks_microservice_mitre_framework_on_demand",
"ks_microservice_nsa_and_mitre_framework_demand",
"scan_compliance_score"
]'
COSIGN: true
HELM_E2E_TEST: true
FORCE: true
secrets: inherit
run-tests:
strategy:
fail-fast: false
matrix:
TEST: ${{ fromJson(needs.wf-preparation.outputs.TEST_NAMES) }}
needs: [wf-preparation, binary-build]
if: ${{ (needs.wf-preparation.outputs.is-secret-set == 'true') && (always() && (contains(needs.*.result, 'success') || contains(needs.*.result, 'skipped')) && !(contains(needs.*.result, 'failure')) && !(contains(needs.*.result, 'cancelled'))) }}
runs-on: ubuntu-latest # This cannot change
steps:
- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # ratchet:actions/download-artifact@v3.0.2
id: download-artifact
with:
name: kubescape-ubuntu-latest
path: "~"
- run: ls -laR
- name: chmod +x
run: chmod +x -R ${{steps.download-artifact.outputs.download-path}}/kubescape-ubuntu-latest
- name: Checkout systests repo
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # ratchet:actions/checkout@v3
with:
repository: armosec/system-tests
path: .
- uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # ratchet:actions/setup-python@v4
with:
python-version: '3.8.13'
cache: 'pip'
- name: create env
run: ./create_env.sh
- name: Generate uuid
id: uuid
run: |
echo "RANDOM_UUID=$(uuidgen)" >> $GITHUB_OUTPUT
- name: Create k8s Kind Cluster
id: kind-cluster-install
uses: helm/kind-action@d08cf6ff1575077dee99962540d77ce91c62387d # ratchet:helm/kind-action@v1.3.0
with:
cluster_name: ${{ steps.uuid.outputs.RANDOM_UUID }}
- name: run-tests-on-local-built-kubescape
env:
CUSTOMER: ${{ secrets.CUSTOMER }}
USERNAME: ${{ secrets.USERNAME }}
PASSWORD: ${{ secrets.PASSWORD }}
CLIENT_ID: ${{ secrets.CLIENT_ID_PROD }}
SECRET_KEY: ${{ secrets.SECRET_KEY_PROD }}
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
run: |
echo "Test history:"
echo " ${{ matrix.TEST }} " >/tmp/testhistory
cat /tmp/testhistory
source systests_python_env/bin/activate
python3 systest-cli.py \
-t ${{ matrix.TEST }} \
-b production \
-c CyberArmorTests \
--duration 3 \
--logger DEBUG \
--kwargs kubescape=${{steps.download-artifact.outputs.download-path}}/kubescape-ubuntu-latest
deactivate
- name: Test Report
uses: mikepenz/action-junit-report@6e9933f4a97f4d2b99acef4d7b97924466037882 # ratchet:mikepenz/action-junit-report@v3.6.1
if: always() # always run even if the previous step fails
with:
report_paths: '**/results_xml_format/**.xml'
commit: ${{github.event.workflow_run.head_sha}}

View File

@@ -1,89 +1,41 @@
name: build
name: build-image
permissions: read-all
on:
workflow_call:
inputs:
client:
description: 'client name'
required: true
type: string
image_tag:
description: 'image tag'
required: true
type: string
image_name:
description: 'image registry and name'
required: true
type: string
cosign:
required: false
default: false
type: boolean
description: 'run cosign on released image'
support_platforms:
required: false
default: true
type: boolean
description: 'support amd64/arm64'
workflow_dispatch:
inputs:
CLIENT:
required: false
type: string
default: "test"
IMAGE_TAG:
required: true
type: string
CO_SIGN:
type: boolean
required: false
default: false
PLATFORMS:
type: boolean
required: false
default: false
jobs:
check-secret:
name: check if QUAYIO_REGISTRY_USERNAME & QUAYIO_REGISTRY_PASSWORD is set in github secrets
runs-on: ubuntu-latest
outputs:
is-secret-set: ${{ steps.check-secret-set.outputs.is-secret-set }}
steps:
- name: Check whether unity activation requests should be done
id: check-secret-set
env:
QUAYIO_REGISTRY_USERNAME: ${{ secrets.QUAYIO_REGISTRY_USERNAME }}
QUAYIO_REGISTRY_PASSWORD: ${{ secrets.QUAYIO_REGISTRY_PASSWORD }}
run: |
echo "is-secret-set=${{ env.QUAYIO_REGISTRY_USERNAME != '' && env.QUAYIO_REGISTRY_PASSWORD != '' }}" >> $GITHUB_OUTPUT
build-image:
needs: [check-secret]
if: needs.check-secret.outputs.is-secret-set == 'true'
name: Build image and upload to registry
runs-on: ubuntu-latest
build-http-image:
permissions:
id-token: write
packages: write
contents: read
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Quay.io
env:
QUAY_PASSWORD: ${{ secrets.QUAYIO_REGISTRY_PASSWORD }}
QUAY_USERNAME: ${{ secrets.QUAYIO_REGISTRY_USERNAME }}
run: docker login -u="${QUAY_USERNAME}" -p="${QUAY_PASSWORD}" quay.io
- name: Build and push image
if: ${{ inputs.support_platforms }}
run: docker buildx build . --file build/Dockerfile --tag ${{ inputs.image_name }}:${{ inputs.image_tag }} --tag ${{ inputs.image_name }}:latest --build-arg image_version=${{ inputs.image_tag }} --build-arg client=${{ inputs.client }} --push --platform linux/amd64,linux/arm64
- name: Build and push image without amd64/arm64 support
if: ${{ !inputs.support_platforms }}
run: docker buildx build . --file build/Dockerfile --tag ${{ inputs.image_name }}:${{ inputs.image_tag }} --tag ${{ inputs.image_name }}:latest --build-arg image_version=${{ inputs.image_tag }} --build-arg client=${{ inputs.client }} --push
- name: Install cosign
uses: sigstore/cosign-installer@main
with:
cosign-release: 'v1.12.0'
- name: sign kubescape container image
if: ${{ inputs.cosign }}
env:
COSIGN_EXPERIMENTAL: "true"
run: |
cosign sign --force ${{ inputs.image_name }}
pull-requests: read
uses: kubescape/workflows/.github/workflows/incluster-comp-pr-merged.yaml@main
with:
IMAGE_NAME: quay.io/${{ github.repository_owner }}/kubescape
IMAGE_TAG: ${{ inputs.IMAGE_TAG }}
COMPONENT_NAME: kubescape
CGO_ENABLED: 0
GO111MODULE: "on"
BUILD_PLATFORM: ${{ inputs.PLATFORMS && 'linux/amd64,linux/arm64' || 'linux/amd64' }}
GO_VERSION: "1.20"
REQUIRED_TESTS: '[]'
COSIGN: ${{ inputs.CO_SIGN }}
HELM_E2E_TEST: false
FORCE: true
secrets: inherit

View File

@@ -1,124 +0,0 @@
name: build
on:
push:
branches:
- 'master'
- 'main'
paths-ignore:
- '**.yaml'
- '**.md'
- '**.sh'
- 'website/*'
- 'examples/*'
- 'docs/*'
- 'build/*'
- '.github/*'
jobs:
test:
uses: ./.github/workflows/test.yaml
with:
release: "v2.0.${{ github.run_number }}"
client: test
create-release:
uses: ./.github/workflows/release.yaml
needs: test
with:
release_name: "Release v2.0.${{ github.run_number }}"
tag_name: "v2.0.${{ github.run_number }}"
secrets: inherit
publish-artifacts:
name: Build and publish artifacts
needs: create-release
runs-on: ${{ matrix.os }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
strategy:
matrix:
os: [ubuntu-20.04, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.19
- name: Install MSYS2 & libgit2 (Windows)
shell: cmd
run: .\build.bat all
if: matrix.os == 'windows-latest'
- name: Install libgit2 (Linux/macOS)
run: make libgit2
if: matrix.os != 'windows-latest'
- name: Build
env:
RELEASE: v2.0.${{ github.run_number }}
CLIENT: release
CGO_ENABLED: 1
run: python3 --version && python3 build.py
- name: Upload release binaries (Windows / MacOS)
id: upload-release-asset-win-macos
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: build/${{ matrix.os }}/kubescape
asset_name: kubescape-${{ matrix.os }}
asset_content_type: application/octet-stream
if: matrix.os != 'ubuntu-20.04'
- name: Upload release binaries (Linux)
id: upload-release-asset-linux
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: build/ubuntu-latest/kubescape
asset_name: kubescape-ubuntu-latest
asset_content_type: application/octet-stream
if: matrix.os == 'ubuntu-20.04'
- name: Upload release hash (Windows / MacOS)
id: upload-release-hash-win-macos
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: build/${{ matrix.os }}/kubescape.sha256
asset_name: kubescape-${{ matrix.os }}-sha256
asset_content_type: application/octet-stream
if: matrix.os != 'ubuntu-20.04'
- name: Upload release hash (Linux)
id: upload-release-hash-linux
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: build/ubuntu-latest/kubescape.sha256
asset_name: kubescape-ubuntu-latest-sha256
asset_content_type: application/octet-stream
if: matrix.os == 'ubuntu-20.04'
publish-image:
uses: ./.github/workflows/build-image.yaml
needs: create-release
with:
client: "image-release"
image_name: "quay.io/${{ github.repository_owner }}/kubescape"
image_tag: "v2.0.${{ github.run_number }}"
support_platforms: true
cosign: true
secrets: inherit

View File

@@ -1,31 +0,0 @@
name: build-dev
on:
push:
branches: [ dev ]
paths-ignore:
- '**.yaml'
- '**.md'
- '**.sh'
- 'website/*'
- 'examples/*'
- 'docs/*'
- 'build/*'
- '.github/*'
jobs:
test:
uses: ./.github/workflows/test.yaml
with:
release: "v2.0.${{ github.run_number }}"
client: test
# publish-dev-image:
# uses: ./.github/workflows/build-image.yaml
# needs: test
# with:
# client: "image-dev"
# image_name: "quay.io/${{ github.repository_owner }}/kubescape"
# image_tag: "dev-v2.0.${{ github.run_number }}"
# support_platforms: true
# cosign: true
# secrets: inherit

73
.github/workflows/c-create-release.yaml vendored Normal file
View File

@@ -0,0 +1,73 @@
name: c-create_release
permissions: read-all
on:
workflow_call:
inputs:
RELEASE_NAME:
description: 'Release name'
required: true
type: string
TAG:
description: 'Tag name'
required: true
type: string
DRAFT:
description: 'Create draft release'
required: false
type: boolean
default: false
jobs:
create-release:
name: create-release
runs-on: ubuntu-latest
env:
MAC_OS: macos-latest
UBUNTU_OS: ubuntu-latest
WINDOWS_OS: windows-latest
# permissions:
# contents: write
steps:
- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # ratchet:actions/download-artifact@v3.0.2
id: download-artifact
with:
path: .
# TODO: kubescape-windows-latest is deprecated and should be removed
- name: Get kubescape.exe from kubescape-windows-latest
run: cp ./kubescape-${{ env.WINDOWS_OS }}/kubescape-${{ env.WINDOWS_OS }} ./kubescape-${{ env.WINDOWS_OS }}/kubescape.exe
- name: Set release token
run: |
if [ "${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}" != "" ]; then
echo "TOKEN=${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}" >> $GITHUB_ENV;
else
echo "TOKEN=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV;
fi
- name: Release
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # ratchet:softprops/action-gh-release@v1
with:
token: ${{ env.TOKEN }}
name: ${{ inputs.RELEASE_NAME }}
tag_name: ${{ inputs.TAG }}
body: ${{ github.event.pull_request.body }}
draft: ${{ inputs.DRAFT }}
fail_on_unmatched_files: true
prerelease: false
# TODO: kubescape-windows-latest is deprecated and should be removed
files: |
./kubescape-${{ env.WINDOWS_OS }}/kubescape-${{ env.WINDOWS_OS }}
./kubescape-${{ env.MAC_OS }}/kubescape-${{ env.MAC_OS }}
./kubescape-${{ env.MAC_OS }}/kubescape-${{ env.MAC_OS }}.sha256
./kubescape-${{ env.MAC_OS }}/kubescape-${{ env.MAC_OS }}.tar.gz
./kubescape-${{ env.UBUNTU_OS }}/kubescape-${{ env.UBUNTU_OS }}
./kubescape-${{ env.UBUNTU_OS }}/kubescape-${{ env.UBUNTU_OS }}.sha256
./kubescape-${{ env.UBUNTU_OS }}/kubescape-${{ env.UBUNTU_OS }}.tar.gz
./kubescape-${{ env.WINDOWS_OS }}/kubescape.exe
./kubescape-${{ env.WINDOWS_OS }}/kubescape-${{ env.WINDOWS_OS }}.sha256
./kubescape-${{ env.WINDOWS_OS }}/kubescape-${{ env.WINDOWS_OS }}.tar.gz
./kubescapearm64-${{ env.MAC_OS }}/kubescape-arm64-${{ env.MAC_OS }}
./kubescapearm64-${{ env.MAC_OS }}/kubescape-arm64-${{ env.MAC_OS }}.sha256
./kubescapearm64-${{ env.MAC_OS }}/kubescape-arm64-${{ env.MAC_OS }}.tar.gz
./kubescapearm64-${{ env.UBUNTU_OS }}/kubescape-arm64-${{ env.UBUNTU_OS }}
./kubescapearm64-${{ env.UBUNTU_OS }}/kubescape-arm64-${{ env.UBUNTU_OS }}.sha256
./kubescapearm64-${{ env.UBUNTU_OS }}/kubescape-arm64-${{ env.UBUNTU_OS }}.tar.gz

20
.github/workflows/comments.yaml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: pr-agent
permissions: read-all
on:
issue_comment:
jobs:
pr_agent:
permissions:
issues: write
pull-requests: write
runs-on: ubuntu-latest
name: Run pr agent on every pull request, respond to user comments
steps:
- name: PR Agent action step
continue-on-error: true
id: pragent
uses: Codium-ai/pr-agent@main
env:
OPENAI_KEY: ${{ secrets.OPENAI_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

80
.github/workflows/d-publish-image.yaml vendored Normal file
View File

@@ -0,0 +1,80 @@
name: d-publish-image
permissions: read-all
on:
workflow_call:
inputs:
client:
description: 'client name'
required: true
type: string
image_tag:
description: 'image tag'
required: true
type: string
image_name:
description: 'image registry and name'
required: true
type: string
cosign:
required: false
default: false
type: boolean
description: 'run cosign on released image'
support_platforms:
required: false
default: true
type: boolean
description: 'support amd64/arm64'
jobs:
check-secret:
name: check if QUAYIO_REGISTRY_USERNAME & QUAYIO_REGISTRY_PASSWORD is set in github secrets
runs-on: ubuntu-latest
outputs:
is-secret-set: ${{ steps.check-secret-set.outputs.is-secret-set }}
steps:
- name: check if QUAYIO_REGISTRY_USERNAME & QUAYIO_REGISTRY_PASSWORD is set in github secrets
id: check-secret-set
env:
QUAYIO_REGISTRY_USERNAME: ${{ secrets.QUAYIO_REGISTRY_USERNAME }}
QUAYIO_REGISTRY_PASSWORD: ${{ secrets.QUAYIO_REGISTRY_PASSWORD }}
run: |
echo "is-secret-set=${{ env.QUAYIO_REGISTRY_USERNAME != '' && env.QUAYIO_REGISTRY_PASSWORD != '' }}" >> $GITHUB_OUTPUT
build-cli-image:
needs: [check-secret]
if: needs.check-secret.outputs.is-secret-set == 'true'
name: Build image and upload to registry
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # ratchet:actions/checkout@v3
with:
submodules: recursive
- name: Set up QEMU
uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # ratchet:docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f03ac48505955848960e80bbb68046aa35c7b9e7 # ratchet:docker/setup-buildx-action@v2
- name: Login to Quay.io
env:
QUAY_PASSWORD: ${{ secrets.QUAYIO_REGISTRY_PASSWORD }}
QUAY_USERNAME: ${{ secrets.QUAYIO_REGISTRY_USERNAME }}
run: docker login -u="${QUAY_USERNAME}" -p="${QUAY_PASSWORD}" quay.io
- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # ratchet:actions/download-artifact@v3.0.2
id: download-artifact
with:
path: .
- name: chmod +x
run: chmod +x -v kubescape-*/kubescape-*
- name: Build and push image for linux/amd64
run: docker buildx build . --file build/kubescape-cli.Dockerfile --tag ${{ inputs.image_name }}:${{ inputs.image_tag }} --tag ${{ inputs.image_name }}:latest --build-arg image_version=${{ inputs.image_tag }} --build-arg client=${{ inputs.client }} --build-arg ks_binary=kubescape-ubuntu-latest/kubescape-ubuntu-latest --push --platform linux/amd64
- name: Build and push image for linux/arm64
run: docker buildx build . --file build/kubescape-cli.Dockerfile --tag ${{ inputs.image_name }}:${{ inputs.image_tag }} --tag ${{ inputs.image_name }}:latest --build-arg image_version=${{ inputs.image_tag }} --build-arg client=${{ inputs.client }} --build-arg ks_binary=kubescape-arm64-ubuntu-latest/kubescape-arm64-ubuntu-latest --push --platform linux/arm64
- name: Install cosign
uses: sigstore/cosign-installer@4079ad3567a89f68395480299c77e40170430341 # ratchet:sigstore/cosign-installer@main
with:
cosign-release: 'v1.12.0'
- name: sign kubescape container image
if: ${{ inputs.cosign }}
env:
COSIGN_EXPERIMENTAL: "true"
run: |
cosign sign --force ${{ inputs.image_name }}

View File

@@ -1,19 +0,0 @@
name: create release digests
on:
release:
types: [ published]
branches:
- 'master'
- 'main'
jobs:
once:
name: Creating digests
runs-on: ubuntu-latest
steps:
- name: Digest
uses: MCJack123/ghaction-generate-release-hashes@v1
with:
hash-type: sha1
file-name: kubescape-release-digests

View File

@@ -1,24 +0,0 @@
name: pr-checks
on:
pull_request:
types: [ edited, opened, synchronize, reopened ]
branches:
- 'master'
- 'main'
- 'dev'
paths-ignore:
- '**.yaml'
- '**.md'
- '**.sh'
- 'website/*'
- 'examples/*'
- 'docs/*'
- 'build/*'
- '.github/*'
jobs:
test:
uses: ./.github/workflows/test.yaml
with:
release: "v2.0.${{ github.run_number }}"
client: test

View File

@@ -1,41 +0,0 @@
name: build
on:
workflow_call:
inputs:
release_name:
description: 'release'
required: true
type: string
tag_name:
description: 'tag'
required: true
type: string
draft:
description: 'create draft release'
required: false
type: boolean
default: false
outputs:
upload_url:
description: "The first output string"
value: ${{ jobs.release.outputs.upload_url }}
jobs:
release:
name: Create release
runs-on: ubuntu-latest
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
steps:
- name: Create a release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ inputs.tag_name }}
release_name: ${{ inputs.release_name }}
draft: ${{ inputs.draft }}
prerelease: false

72
.github/workflows/scorecard.yml vendored Normal file
View File

@@ -0,0 +1,72 @@
# This workflow uses actions that are not certified by GitHub. They are provided
# by a third-party and are governed by separate terms of service, privacy
# policy, and support documentation.
name: Scorecard supply-chain security
on:
# For Branch-Protection check. Only the default branch is supported. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
branch_protection_rule:
# To guarantee Maintained check is occasionally updated. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
schedule:
- cron: '0 00 * * 1'
push:
branches: [ "master" ]
# Declare default permissions as read only.
permissions: read-all
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
permissions:
# Needed to upload the results to code-scanning dashboard.
security-events: write
# Needed to publish results and get a badge (see publish_results below).
id-token: write
# Uncomment the permissions below if installing in a private repository.
# contents: read
# actions: read
steps:
- name: "Checkout code"
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@e38b1902ae4f44df626f11ba0734b14fb91f8f86 # v2.1.2
with:
results_file: results.sarif
results_format: sarif
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
# - you want to enable the Branch-Protection check on a *public* repository, or
# - you are installing Scorecard on a *private* repository
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
# Public repositories:
# - Publish results to OpenSSF REST API for easy access by consumers
# - Allows the repository to include the Scorecard badge.
# - See https://github.com/ossf/scorecard-action#publishing-results.
# For private repositories:
# - `publish_results` will always be set to `false`, regardless
# of the value entered here.
publish_results: true
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0
with:
name: SARIF file
path: results.sarif
retention-days: 5
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@17573ee1cc1b9d061760f3a006fc4aac4f944fd5 # v2.2.4
with:
sarif_file: results.sarif

View File

@@ -1,100 +0,0 @@
name: test
on:
workflow_call:
inputs:
release:
description: 'release'
required: true
type: string
client:
description: 'Client name'
required: true
type: string
jobs:
build:
name: Create cross-platform build
runs-on: ${{ matrix.os }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
strategy:
matrix:
os: [ubuntu-20.04, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Cache Go modules (Linux)
if: matrix.os == 'ubuntu-20.04'
uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Cache Go modules (macOS)
if: matrix.os == 'macos-latest'
uses: actions/cache@v3
with:
path: |
~/Library/Caches/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Cache Go modules (Windows)
if: matrix.os == 'windows-latest'
uses: actions/cache@v3
with:
path: |
~\AppData\Local\go-build
~\go\pkg\mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.19
- name: Install MSYS2 & libgit2 (Windows)
shell: cmd
run: .\build.bat all
if: matrix.os == 'windows-latest'
- name: Install libgit2 (Linux/macOS)
run: make libgit2
if: matrix.os != 'windows-latest'
- name: Test core pkg
run: go test "-tags=static,gitenabled" -v ./...
- name: Test httphandler pkg
run: cd httphandler && go test "-tags=static,gitenabled" -v ./...
- name: Build
env:
RELEASE: ${{ inputs.release }}
CLIENT: test
CGO_ENABLED: 1
run: python3 --version && python3 build.py
- name: Smoke Testing (Windows / MacOS)
env:
RELEASE: ${{ inputs.release }}
KUBESCAPE_SKIP_UPDATE_CHECK: "true"
run: python3 smoke_testing/init.py ${PWD}/build/${{ matrix.os }}/kubescape
if: matrix.os != 'ubuntu-20.04'
- name: Smoke Testing (Linux)
env:
RELEASE: ${{ inputs.release }}
KUBESCAPE_SKIP_UPDATE_CHECK: "true"
run: python3 smoke_testing/init.py ${PWD}/build/ubuntu-latest/kubescape
if: matrix.os == 'ubuntu-20.04'

View File

@@ -1,23 +1,20 @@
permissions: read-all
on:
issues:
types: [opened, labeled]
jobs:
open_PR_message:
if: github.event.label.name == 'typo'
runs-on: ubuntu-latest
steps:
- uses: ben-z/actions-comment-on-issue@1.0.2
- uses: ben-z/actions-comment-on-issue@10be23f9c43ac792663043420fda29dde07e2f0f # ratchet: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:
- uses: lee-dohm/close-matching-issues@v2
- uses: lee-dohm/close-matching-issues@e9e43aad2fa6f06a058cedfd8fb975fd93b56d8f # ratchet:lee-dohm/close-matching-issues@v2
with:
query: 'label:typo'
token: ${{ secrets.GITHUB_TOKEN }}

2
.gitignore vendored
View File

@@ -1,5 +1,6 @@
*.vs*
*kubescape*
!*Dockerfile*
*debug*
*vendor*
*.pyc*
@@ -7,3 +8,4 @@
.history
ca.srl
*.out
ks

42
.krew.yaml Normal file
View File

@@ -0,0 +1,42 @@
apiVersion: krew.googlecontainertools.github.com/v1alpha2
kind: Plugin
metadata:
name: kubescape
spec:
homepage: https://github.com/kubescape/kubescape/
shortDescription: Scan resources and cluster configs against security frameworks.
version: {{ .TagName }}
description: |
It includes risk analysis, security compliance, and misconfiguration scanning
with an easy-to-use CLI interface, flexible output formats, and automated scanning capabilities.
platforms:
- selector:
matchLabels:
os: darwin
arch: amd64
{{ addURIAndSha "https://github.com/kubescape/kubescape/releases/download/{{ .TagName }}/kubescape-macos-latest.tar.gz" .TagName }}
bin: kubescape
- selector:
matchLabels:
os: darwin
arch: arm64
{{ addURIAndSha "https://github.com/kubescape/kubescape/releases/download/{{ .TagName }}/kubescape-arm64-macos-latest.tar.gz" .TagName }}
bin: kubescape
- selector:
matchLabels:
os: linux
arch: amd64
{{ addURIAndSha "https://github.com/kubescape/kubescape/releases/download/{{ .TagName }}/kubescape-ubuntu-latest.tar.gz" .TagName }}
bin: kubescape
- selector:
matchLabels:
os: linux
arch: arm64
{{ addURIAndSha "https://github.com/kubescape/kubescape/releases/download/{{ .TagName }}/kubescape-arm64-ubuntu-latest.tar.gz" .TagName }}
bin: kubescape
- selector:
matchLabels:
os: windows
arch: amd64
{{ addURIAndSha "https://github.com/kubescape/kubescape/releases/download/{{ .TagName }}/kubescape-windows-latest.tar.gz" .TagName }}
bin: kubescape.exe

23
ADOPTERS.md Normal file
View File

@@ -0,0 +1,23 @@
# Adopters
# Well-known companies
Well-known companies who are using and/or contributing to Kubescape are (in alphabetical order):
* Accenture
* Amazon.com
* IBM
* Intel
* Meetup
* RedHat
* Scaleway
# Users
If you want to be listed here and share with others your experience, open a PR and add the bellow table:
| Name | Company | Use case | Contact for questions (optional) |
| ---- | ------- | -------- | -------------------------------- |
| Yonathan Amzallag | ARMO | Vulnerability monitoring | yonatana@armosec.io |

View File

@@ -15,13 +15,17 @@ so the maintainers are able to help guide you and let you know if you are going
Please follow our [code of conduct](CODE_OF_CONDUCT.md) in all of your interactions within the project.
## Build and test locally
Please follow the [instructions here](https://github.com/kubescape/kubescape/wiki/Building).
## Pull Request Process
1. Ensure any install or build dependencies are removed before the end of the layer when doing a
build.
2. Update the README.md with details of changes to the interface, this includes new environment
variables, exposed ports, useful file locations and container parameters.
3. Open Pull Request to `dev` branch - we test the component before merging into the `master` branch
3. Open Pull Request to the `master` branch.
4. We will merge the Pull Request once you have the sign-off.
## Developer Certificate of Origin
@@ -47,7 +51,7 @@ Add [`-s`](https://git-scm.com/docs/git-commit#Documentation/git-commit.txt--s)
```git commit -s -m "Fix issue 64738"```
This is tedious, and if you forget, you'll have to [amend your commit](#f)
This is tedious, and if you forget, you'll have to [amend your commit](#fixing-a-commit-where-the-dco-failed).
### Configure a repository to always include sign off
@@ -59,6 +63,36 @@ curl -Ls https://gist.githubusercontent.com/dixudx/7d7edea35b4d91e1a2a8fbf41d095
chmod +x .git/hooks/prepare-commit-msg
```
### Use semantic commit messages (optional)
When contributing, you could consider using [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/), in order to improve logs readability and help us to automatically generate `CHANGELOG`s.
Format: `<type>(<scope>): <subject>`
`<scope>` is optional
#### Example
```
feat(cmd): add kubectl plugin
^--^ ^-^ ^----------------^
| | |
| | +-> subject: summary in present tense.
| |
| +-------> scope: point of interest
|
+-------> type: chore, docs, feat, fix, refactor, style, or test.
```
More Examples:
* `feat`: new feature for the user, not a new feature for build script
* `fix`: bug fix for the user, not a fix to a build script
* `docs`: changes to the documentation
* `style`: formatting, missing semi colons, etc; no production code change
* `refactor`: refactoring production code, eg. renaming a variable
* `test`: adding missing tests, refactoring tests; no production code change
* `chore`: updating grunt tasks etc; no production code change
## Fixing a commit where the DCO failed
Check out [this guide](https://github.com/src-d/guide/blob/master/developer-community/fix-DCO.md).

65
GOVERNANCE.md Normal file
View File

@@ -0,0 +1,65 @@
# Governance of Kubescape
## Overview
The Kubescape project is an open-source initiative dedicated to improve security and best practices in Kubernetes environments. This document outlines the governance structure of the Kubescape project and provides guidance for its community contributors.
## Decision Making
### Maintainers
- Maintainers are responsible for the smooth operation of the project.
- They review and merge pull requests, manage releases, and ensure the quality and stability of the codebase.
- Maintainers are chosen based on their ongoing contributions and their demonstrated commitment to the project.
- Everyone who had at least 5 code contribution in the last 12 month can submit her/himself for joining the maintainer team
- Maintainers who are not taken part in the project work (code, reviews, discussions) for 12 month are automaticaly removed from the maintainer team
### Committers
- Committers are contributors who have made significant and consistent contributions to the project.
- They have the ability to merge minor pull requests if assigned by maintainers.
- A contributor can be proposed as a committer by any existing maintainer. The proposal will be reviewed and voted on by the existing maintainers.
### Community Members
- Anyone can become a community member by contributing to the project. This can be in the form of code contributions, documentation, or any other form of project support.
## Processes
### Proposing Changes
1. Open an issue on the project repository to discuss the proposed change.
2. Once there is consensus around the proposed change, create a pull request.
3. Pull requests will be reviewed by committers and/or maintainers.
4. Once the pull request has received approval, it can be merged into the main codebase.
### Conflict Resolution
1. In case of any conflicts, it is primarily the responsibility of the parties involved to resolve it.
2. If the conflict cannot be resolved, it will be escalated to the maintainers for resolution.
3. Maintainers' decision will be final in case of unresolved conflicts.
## Roles and Responsibilities
### Maintainers
- Ensure the quality and stability of the project.
- Resolve conflicts.
- Provide direction and set priorities for the project.
### Committers
- Review and merge minor pull requests.
- Assist maintainers in project tasks.
- Promote best practices within the community.
### Community Members
- Contribute to the project in any form.
- Participate in discussions and provide feedback.
- Respect the code of conduct and governance of the project.
## Changes to the Governance Document
Proposed changes to this governance document should follow the same process as any other code change to the Kubescape project (see "Proposing Changes").

View File

@@ -1,11 +1,12 @@
# Maintainers
The following table lists the Kubescape project maintainers:
The following table lists the Kubescape project core maintainers:
| Name | GitHub | Organization | Added/Renewed On |
| --- | --- | --- | --- |
| [Matthias Bertschy](https://www.linkedin.com/in/matthias-bertschy-b427b815/) | [@matthyx](https://github.com/matthyx) | [ARMO](https://www.armosec.io/) | 2023-01-01 |
| [Craig Box](https://www.linkedin.com/in/crbnz/) | [@craigbox](https://github.com/craigbox) | [ARMO](https://www.armosec.io/) | 2022-10-31 |
| [Ben Hirschberg](https://www.linkedin.com/in/benyamin-ben-hirschberg-66141890) | [@slashben](https://github.com/slashben) | [ARMO](https://www.armosec.io/) | 2021-09-01 |
| [Rotem Refael](https://www.linkedin.com/in/rotem-refael) | [@rotemamsa](https://github.com/rotemamsa) | [ARMO](https://www.armosec.io/) | 2021-10-11 |
| [David Wertenteil](https://www.linkedin.com/in/david-wertenteil-0ba277b9) | [@dwertent](https://github.com/dwertent) | [ARMO](https://www.armosec.io/) | 2021-09-01 |
| [Bezalel Brandwine](https://www.linkedin.com/in/bezalel-brandwine) | [@Bezbran](https://github.com/Bezbran) | [ARMO](https://www.armosec.io/) | 2021-09-01 |
| [Craig Box](https://www.linkedin.com/in/crbnz/) | [@craigbox](https://github.com/craigbox) | [ARMO](https://www.armosec.io/) | 2022-10-31 |

View File

@@ -10,6 +10,14 @@ libgit2:
-git submodule update --init --recursive
cd git2go; make install-static
# build and install libgit2 for macOS m1
libgit2arm64:
git submodule update --init --recursive
if [ "$(shell uname -s)" = "Darwin" ]; then \
sed -i '' 's/cmake -D/cmake -DCMAKE_OSX_ARCHITECTURES="arm64" -D/' git2go/script/build-libgit2.sh; \
fi
cd git2go; make install-static
# go build tags
TAGS = "gitenabled,static"

View File

@@ -1,9 +1,13 @@
[![Version](https://img.shields.io/github/v/release/kubescape/kubescape)](releases)
[![build](https://github.com/kubescape/kubescape/actions/workflows/build.yaml/badge.svg)](https://github.com/kubescape/kubescape/actions/workflows/build.yaml)
[![Version](https://img.shields.io/github/v/release/kubescape/kubescape)](https://github.com/kubescape/kubescape/releases)
[![build](https://github.com/kubescape/kubescape/actions/workflows/02-release.yaml/badge.svg)](https://github.com/kubescape/kubescape/actions/workflows/02-release.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)
[![GitHub](https://img.shields.io/github/license/kubescape/kubescape)](https://github.com/kubescape/kubescape/blob/master/LICENSE)
[![CNCF](https://shields.io/badge/CNCF-Sandbox%20project-blue?logo=linux-foundation&style=flat)](https://landscape.cncf.io/card-mode?project=sandbox&selected=kubescape)
[![Artifact HUB](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/kubescape)](https://artifacthub.io/packages/search?repo=kubescape)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fkubescape%2Fkubescape.svg?type=shield&issueType=license)](https://app.fossa.com/projects/git%2Bgithub.com%2Fkubescape%2Fkubescape?ref=badge_shield&issueType=license)
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/6944/badge)](https://www.bestpractices.dev/projects/6944)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/kubescape/kubescape/badge)](https://securityscorecards.dev/viewer/?uri=github.com/kubescape/kubescape)
[![Twitter Follow](https://img.shields.io/twitter/follow/kubescape?style=social)](https://twitter.com/kubescape)
# Kubescape
@@ -23,7 +27,7 @@ Kubescape scans clusters, YAML files, and Helm charts. It detects misconfigurati
Kubescape was created by [ARMO](https://www.armosec.io/?utm_source=github&utm_medium=repository) and is a [Cloud Native Computing Foundation (CNCF) sandbox project](https://www.cncf.io/sandbox-projects/).
## Demo
<img src="docs/img/demo.gif">
<img src="docs/img/demo-v3.gif">
_Please [star ⭐](https://github.com/kubescape/kubescape/stargazers) the repo if you want us to continue developing and improving Kubescape! 😀_
@@ -37,11 +41,11 @@ curl -s https://raw.githubusercontent.com/kubescape/kubescape/master/install.sh
Learn more about:
* [Installing Kubescape](docs/getting-started.md#install-kubescape)
* [Installing Kubescape](docs/installation.md)
* [Running your first scan](docs/getting-started.md#run-your-first-scan)
* [Usage](docs/getting-started.md#examples)
* [Architecture](docs/architecture.md)
* [Building Kubescape from source](docs/building.md)
* [Building Kubescape from source](https://github.com/kubescape/kubescape/wiki/Building)
_Did you know you can use Kubescape in all these places?_
@@ -65,11 +69,15 @@ It retrieves Kubernetes objects from the API server and runs a set of [Rego snip
Kubescape is an open source project, we welcome your feedback and ideas for improvement. We are part of the Kubernetes community and are building more tests and controls as the ecosystem develops.
We hold [community meetings](https://us02web.zoom.us/j/84020231442) on Zoom, on the first Tuesday of every month, at 14:00 GMT.
We hold [community meetings](https://zoom.us/j/95174063585) on Zoom, on the first Tuesday of every month, at 14:00 GMT. ([See that in your local time zone](https://time.is/compare/1400_in_GMT)).
The Kubescape project follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).
## Contributions
### Adopters
See [here](ADOPTERS.md) a list of adopters.
## Contributions
Thanks to all our contributors! Check out our [CONTRIBUTING](CONTRIBUTING.md) file to learn how to join them.
@@ -83,6 +91,10 @@ Thanks to all our contributors! Check out our [CONTRIBUTING](CONTRIBUTING.md) f
<img src = "https://contrib.rocks/image?repo=kubescape/kubescape"/>
</a>
## Changelog
Kubescape changes are tracked on the [release](https://github.com/kubescape/kubescape/releases) page
## License
Copyright 2021-2023, the Kubescape Authors. All rights reserved. Kubescape is released under the Apache 2.0 license. See the [LICENSE](LICENSE) file for details.

52
SECURITY-INSIGHTS.yml Normal file
View File

@@ -0,0 +1,52 @@
header:
schema-version: 1.0.0
last-updated: '2023-10-12'
last-reviewed: '2023-10-12'
expiration-date: '2024-10-12T01:00:00.000Z'
project-url: https://github.com/kubescape/kubescape/
project-release: '1.0.0'
project-lifecycle:
status: active
bug-fixes-only: false
core-maintainers:
- github:slashben
- github:craigbox
- github:matthyx
- github:dwertent
contribution-policy:
accepts-pull-requests: true
accepts-automated-pull-requests: false
code-of-conduct: https://github.com/kubescape/kubescape/blob/master/CODE_OF_CONDUCT.md
dependencies:
third-party-packages: true
dependencies-lists:
- https://github.com/kubescape/kubescape/blob/master/go.mod
- https://github.com/kubescape/kubescape/blob/master/httphandler/go.mod
env-dependencies-policy:
policy-url: https://github.com/kubescape/kubescape/blob/master/docs/environment-dependencies-policy.md
documentation:
- https://github.com/kubescape/kubescape/tree/master/docs
distribution-points:
- https://github.com/kubescape/kubescape/
security-artifacts:
threat-model:
threat-model-created: false
security-testing:
- tool-type: sca
tool-name: Dependabot
tool-version: latest
integration:
ad-hoc: false
ci: true
before-release: true
comment: |
Dependabot is enabled for this repo.
security-contacts:
- type: email
value: cncf-kubescape-maintainers@lists.cncf.io
vulnerability-reporting:
accepts-vulnerability-reports: true
security-policy: https://github.com/kubescape/kubescape/security/policy
email-contact: cncf-kubescape-maintainers@lists.cncf.io
comment: |
The first and best way to report a vulnerability is by using private security issues in GitHub.

7
SECURITY.md Normal file
View File

@@ -0,0 +1,7 @@
# Reporting Security Issues
To report a security issue or vulnerability, submit a [private vulnerability report via GitHub](https://github.com/kubescape/kubescape/security/advisories/new) to the repository maintainers with a description of the issue, the steps you took to create the issue, affected versions, and, if known, mitigations for the issue.
The maintainers will respond within 7 working days of your report. If the issue is confirmed as a vulnerability, we will open a Security Advisory and acknowledge your contributions as part of it. This project follows a 90 day disclosure timeline.
Other contacts: cncf-kubescape-maintainers@lists.cncf.io

View File

@@ -1,51 +0,0 @@
@ECHO OFF
IF "%1"=="install" goto Install
IF "%1"=="build" goto Build
IF "%1"=="all" goto All
IF "%1"=="" goto Error ELSE goto Error
:Install
if exist C:\MSYS64\ (
echo "MSYS2 already installed"
) else (
mkdir temp_install & cd temp_install
echo "Downloading MSYS2..."
curl -L https://github.com/msys2/msys2-installer/releases/download/2022-06-03/msys2-x86_64-20220603.exe > msys2-x86_64-20220603.exe
echo "Installing MSYS2..."
msys2-x86_64-20220603.exe install --root C:\MSYS64 --confirm-command
cd .. && rmdir /s /q temp_install
)
echo "Adding MSYS2 to path..."
SET "PATH=C:\MSYS64\mingw64\bin;C:\MSYS64\usr\bin;%PATH%"
echo %PATH%
echo "Installing MSYS2 packages..."
pacman -S --needed --noconfirm make
pacman -S --needed --noconfirm mingw-w64-x86_64-cmake
pacman -S --needed --noconfirm mingw-w64-x86_64-gcc
pacman -S --needed --noconfirm mingw-w64-x86_64-pkg-config
pacman -S --needed --noconfirm msys2-w32api-runtime
IF "%1"=="all" GOTO Build
GOTO End
:Build
SET "PATH=C:\MSYS2\mingw64\bin;C:\MSYS2\usr\bin;%PATH%"
make libgit2
GOTO End
:All
GOTO Install
:Error
echo "Error: Unknown option"
GOTO End
:End

78
build.ps1 Normal file
View File

@@ -0,0 +1,78 @@
# Defining input params
param (
[string]$mode = "error"
)
# Function to install MSYS
function Install {
Write-Host "Starting install..." -ForegroundColor Cyan
# Check to see if already installed
if (Test-Path "C:\MSYS64\") {
Write-Host "MSYS2 already installed" -ForegroundColor Green
} else {
# Create a temp directory
New-Item -Path "$PSScriptRoot\temp_install" -ItemType Directory > $null
# Download MSYS
Write-Host "Downloading MSYS2..." -ForegroundColor Cyan
$bitsJobObj = Start-BitsTransfer "https://github.com/msys2/msys2-installer/releases/download/2022-06-03/msys2-x86_64-20220603.exe" -Destination "$PSScriptRoot\temp_install\msys2-x86_64-20220603.exe"
switch ($bitsJobObj.JobState) {
"Transferred" {
Complete-BitsTransfer -BitsJob $bitsJobObj
break
}
"Error" {
throw "Error downloading"
}
}
Write-Host "MSYS2 download complete" -ForegroundColor Green
# Install MSYS
Write-Host "Installing MSYS2..." -ForegroundColor Cyan
Start-Process -Filepath "$PSScriptRoot\temp_install\msys2-x86_64-20220603.exe" -ArgumentList @("install", "--root", "C:\MSYS64", "--confirm-command") -Wait
Write-Host "MSYS2 install complete" -ForegroundColor Green
# Remove temp directory
Remove-Item "$PSScriptRoot\temp_install" -Recurse
}
# Set PATH
$env:Path = "C:\MSYS64\mingw64\bin;C:\MSYS64\usr\bin;" + $env:Path
# Install MSYS packages
Write-Host "Installing MSYS2 packages..." -ForegroundColor Cyan
Start-Process -Filepath "pacman" -ArgumentList @("-S", "--needed", "--noconfirm", "make") -Wait
Start-Process -Filepath "pacman" -ArgumentList @("-S", "--needed", "--noconfirm", "mingw-w64-x86_64-cmake") -Wait
Start-Process -Filepath "pacman" -ArgumentList @("-S", "--needed", "--noconfirm", "mingw-w64-x86_64-gcc") -Wait
Start-Process -Filepath "pacman" -ArgumentList @("-S", "--needed", "--noconfirm", "mingw-w64-x86_64-pkg-config") -Wait
Start-Process -Filepath "pacman" -ArgumentList @("-S", "--needed", "--noconfirm", "msys2-w32api-runtime") -Wait
Write-Host "MSYS2 packages install complete" -ForegroundColor Green
Write-Host "Install complete" -ForegroundColor Green
}
# Function to build libgit2
function Build {
Write-Host "Starting build..." -ForegroundColor Cyan
# Set PATH
$env:Path = "C:\MSYS64\mingw64\bin;C:\MSYS64\usr\bin;" + $env:Path
# Build
Start-Process -Filepath "make" -ArgumentList @("libgit2") -Wait -NoNewWindow
Write-Host "Build complete" -ForegroundColor Green
}
# Check user call mode
if ($mode -eq "all") {
Install
Build
} elseif ($mode -eq "install") {
Install
} elseif ($mode -eq "build") {
Build
} else {
Write-Host "Error: -mode should be one of (all|install|build)" -ForegroundColor Red
}

View File

@@ -3,8 +3,16 @@ import sys
import hashlib
import platform
import subprocess
import tarfile
BASE_GETTER_CONST = "github.com/kubescape/kubescape/v2/core/cautils/getter"
BASE_GETTER_CONST = "github.com/kubescape/kubescape/v3/core/cautils/getter"
CURRENT_PLATFORM = platform.system()
platformSuffixes = {
"Windows": "windows-latest",
"Linux": "ubuntu-latest",
"Darwin": "macos-latest",
}
def check_status(status, msg):
if status != 0:
@@ -13,21 +21,19 @@ def check_status(status, msg):
def get_build_dir():
current_platform = platform.system()
build_dir = ""
if current_platform == "Windows": build_dir = "windows-latest"
elif current_platform == "Linux": build_dir = "ubuntu-latest"
elif current_platform == "Darwin": build_dir = "macos-latest"
else: raise OSError("Platform %s is not supported!" % (current_platform))
return os.path.join("build", build_dir)
return "build"
def get_package_name():
package_name = "kubescape"
if CURRENT_PLATFORM not in platformSuffixes: raise OSError("Platform %s is not supported!" % (CURRENT_PLATFORM))
return package_name
# # TODO: kubescape-windows-latest is deprecated and should be removed
# if CURRENT_PLATFORM == "Windows": return "kubescape.exe"
package_name = "kubescape-"
if os.getenv("GOARCH"):
package_name += os.getenv("GOARCH") + "-"
return package_name + platformSuffixes[CURRENT_PLATFORM]
def main():
@@ -35,10 +41,10 @@ def main():
# Set some variables
package_name = get_package_name()
build_url = "github.com/kubescape/kubescape/v2/core/cautils.BuildNumber"
build_url = "github.com/kubescape/kubescape/v3/core/cautils.BuildNumber"
release_version = os.getenv("RELEASE")
client_var = "github.com/kubescape/kubescape/v2/core/cautils.Client"
client_var = "github.com/kubescape/kubescape/v3/core/cautils.Client"
client_name = os.getenv("CLIENT")
# Create build directory
@@ -46,6 +52,7 @@ def main():
ks_file = os.path.join(build_dir, package_name)
hash_file = ks_file + ".sha256"
tar_file = ks_file + ".tar.gz"
if not os.path.isdir(build_dir):
os.makedirs(build_dir)
@@ -58,6 +65,9 @@ def main():
ldflags += " -X {}={}".format(client_var, client_name)
build_command = ["go", "build", "-buildmode=pie", "-tags=static,gitenabled", "-o", ks_file, "-ldflags" ,ldflags]
if CURRENT_PLATFORM == "Windows":
os.putenv("CGO_ENABLED", "0")
build_command = ["go", "build", "-o", ks_file, "-ldflags", ldflags]
print("Building kubescape and saving here: {}".format(ks_file))
print("Build command: {}".format(" ".join(build_command)))
@@ -73,6 +83,13 @@ def main():
print("kubescape hash: {}, file: {}".format(hash, hash_file))
kube_sha.write(sha256.hexdigest())
with tarfile.open(tar_file, 'w:gz') as archive:
name = "kubescape"
if CURRENT_PLATFORM == "Windows":
name += ".exe"
archive.add(ks_file, name)
archive.add("LICENSE", "LICENSE")
print("Build Done")

View File

@@ -1,51 +1,22 @@
FROM golang:1.19-alpine as builder
ARG image_version
ARG client
ENV RELEASE=$image_version
ENV CLIENT=$client
ENV GO111MODULE=
ENV CGO_ENABLED=1
# Install required python/pip
ENV PYTHONUNBUFFERED=1
RUN apk add --update --no-cache python3 gcc make git libc-dev binutils-gold cmake pkgconfig && ln -sf python3 /usr/bin/python
RUN python3 -m ensurepip
RUN pip3 install --no-cache --upgrade pip setuptools
FROM --platform=$BUILDPLATFORM golang:1.20-bullseye as builder
ENV GO111MODULE=on CGO_ENABLED=0
WORKDIR /work
ADD . .
ARG TARGETOS TARGETARCH
# install libgit2
RUN rm -rf git2go && make libgit2
RUN --mount=target=. \
--mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg \
cd httphandler && GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /out/ksserver .
# build kubescape server
WORKDIR /work/httphandler
RUN python build.py
RUN ls -ltr build/ubuntu-latest
FROM gcr.io/distroless/static-debian11:nonroot
# build kubescape cmd
WORKDIR /work
RUN python build.py
USER nonroot
WORKDIR /home/nonroot/
RUN /work/build/ubuntu-latest/kubescape download artifacts -o /work/artifacts
COPY --from=builder /out/ksserver /usr/bin/ksserver
FROM alpine:3.16.2
RUN addgroup -S ks && adduser -S ks -G ks
COPY --from=builder /work/artifacts/ /home/ks/.kubescape
RUN chown -R ks:ks /home/ks/.kubescape
USER ks
WORKDIR /home/ks
COPY --from=builder /work/httphandler/build/ubuntu-latest/kubescape /usr/bin/ksserver
COPY --from=builder /work/build/ubuntu-latest/kubescape /usr/bin/kubescape
ARG image_version client
ENV RELEASE=$image_version CLIENT=$client
ENTRYPOINT ["ksserver"]

View File

@@ -0,0 +1,3 @@
.git
git2go
kubescape*

View File

@@ -7,7 +7,13 @@
git clone https://github.com/kubescape/kubescape.git kubescape && cd "$_"
```
2. Build
2. Build kubescape CLI Docker image
```
make all
docker buildx build -t kubescape-cli -f build/kubescape-cli.Dockerfile --build-arg="ks_binary=kubescape" --load .
```
3. Build kubescape Docker image
```
docker buildx build -t kubescape -f build/Dockerfile --load .
```
docker build -t kubescape -f build/Dockerfile .
```

View File

@@ -0,0 +1,12 @@
FROM gcr.io/distroless/base-debian11:debug-nonroot
USER nonroot
WORKDIR /home/nonroot/
ARG image_version client ks_binary
ENV RELEASE=$image_version CLIENT=$client
COPY $ks_binary /usr/bin/kubescape
RUN ["kubescape", "download", "artifacts"]
ENTRYPOINT ["kubescape"]

View File

@@ -0,0 +1,2 @@
.git
git2go

View File

@@ -1,23 +1,23 @@
package completion
import (
"fmt"
"os"
"strings"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/spf13/cobra"
)
var completionCmdExamples = `
var completionCmdExamples = fmt.Sprintf(`
# Enable BASH shell autocompletion
$ source <(kubescape completion bash)
$ echo 'source <(kubescape completion bash)' >> ~/.bashrc
$ source <(%[1]s completion bash)
$ echo 'source <(%[1]s completion bash)' >> ~/.bashrc
# Enable ZSH shell autocompletion
$ source <(kubectl completion zsh)
$ echo 'source <(kubectl completion zsh)' >> "${fpath[1]}/_kubectl"
`
$ source <(%[1]s completion zsh)
$ echo 'source <(%[1]s completion zsh)' >> "${fpath[1]}/_%[1]s"
`, cautils.ExecName())
func GetCompletionCmd() *cobra.Command {
completionCmd := &cobra.Command{

View File

@@ -1,34 +1,31 @@
package config
import (
"github.com/kubescape/kubescape/v2/core/meta"
"fmt"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/meta"
"github.com/spf13/cobra"
)
var (
configExample = `
configExample = fmt.Sprintf(`
# View cached configurations
kubescape config view
%[1]s config view
# Delete cached configurations
kubescape config delete
%[1]s config delete
# Set cached configurations
kubescape config set --help
`
setConfigExample = `
%[1]s config set --help
`, cautils.ExecName())
setConfigExample = fmt.Sprintf(`
# Set account id
kubescape config set accountID <account id>
%[1]s config set accountID <account id>
# Set client id
kubescape config set clientID <client id>
# Set access key
kubescape config set secretKey <access key>
# Set cloudAPIURL
kubescape config set cloudAPIURL <cloud API URL>
`
# Set cloud report URL
%[1]s config set cloudReportURL <cloud Report URL>
`, cautils.ExecName())
)
func GetConfigCmd(ks meta.IKubescape) *cobra.Command {

View File

@@ -1,9 +1,11 @@
package config
import (
"context"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v2/core/meta"
v1 "github.com/kubescape/kubescape/v2/core/meta/datastructures/v1"
"github.com/kubescape/kubescape/v3/core/meta"
v1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
"github.com/spf13/cobra"
)
@@ -13,7 +15,7 @@ func getDeleteCmd(ks meta.IKubescape) *cobra.Command {
Short: "Delete cached configurations",
Long: ``,
Run: func(cmd *cobra.Command, args []string) {
if err := ks.DeleteCachedConfig(&v1.DeleteConfig{}); err != nil {
if err := ks.DeleteCachedConfig(context.TODO(), &v1.DeleteConfig{}); err != nil {
logger.L().Fatal(err.Error())
}
},

View File

@@ -5,8 +5,8 @@ import (
"strings"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v2/core/meta"
metav1 "github.com/kubescape/kubescape/v2/core/meta/datastructures/v1"
"github.com/kubescape/kubescape/v3/core/meta"
metav1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
"github.com/spf13/cobra"
)
@@ -33,13 +33,10 @@ func getSetCmd(ks meta.IKubescape) *cobra.Command {
}
var supportConfigSet = map[string]func(*metav1.SetConfig, string){
"accessKey": func(s *metav1.SetConfig, accessKey string) { s.AccessKey = accessKey },
"accountID": func(s *metav1.SetConfig, account string) { s.Account = account },
"clientID": func(s *metav1.SetConfig, clientID string) { s.ClientID = clientID },
"secretKey": func(s *metav1.SetConfig, secretKey string) { s.SecretKey = secretKey },
"cloudAPIURL": func(s *metav1.SetConfig, cloudAPIURL string) { s.CloudAPIURL = cloudAPIURL },
"cloudAuthURL": func(s *metav1.SetConfig, cloudAuthURL string) { s.CloudAuthURL = cloudAuthURL },
"cloudReportURL": func(s *metav1.SetConfig, cloudReportURL string) { s.CloudReportURL = cloudReportURL },
"cloudUIURL": func(s *metav1.SetConfig, cloudUIURL string) { s.CloudUIURL = cloudUIURL },
}
func stringKeysToSlice(m map[string]func(*metav1.SetConfig, string)) []string {

View File

@@ -4,8 +4,8 @@ import (
"os"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v2/core/meta"
v1 "github.com/kubescape/kubescape/v2/core/meta/datastructures/v1"
"github.com/kubescape/kubescape/v3/core/meta"
v1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
"github.com/spf13/cobra"
)

View File

@@ -1,34 +0,0 @@
package delete
import (
"github.com/kubescape/kubescape/v2/core/meta"
v1 "github.com/kubescape/kubescape/v2/core/meta/datastructures/v1"
"github.com/spf13/cobra"
)
var deleteExceptionsExamples = `
# Delete single exception
kubescape delete exceptions "exception name"
# Delete multiple exceptions
kubescape delete exceptions "first exception;second exception;third exception"
`
func GetDeleteCmd(ks meta.IKubescape) *cobra.Command {
var deleteInfo v1.Delete
var deleteCmd = &cobra.Command{
Use: "delete <command>",
Short: "Delete configurations in Kubescape SaaS version",
Long: ``,
Run: func(cmd *cobra.Command, args []string) {
},
}
deleteCmd.PersistentFlags().StringVarP(&deleteInfo.Credentials.Account, "account", "", "", "Kubescape SaaS account ID. Default will load account ID from cache")
deleteCmd.PersistentFlags().StringVarP(&deleteInfo.Credentials.ClientID, "client-id", "", "", "Kubescape SaaS client ID. Default will load client ID from cache, read more - https://hub.armosec.io/docs/authentication")
deleteCmd.PersistentFlags().StringVarP(&deleteInfo.Credentials.SecretKey, "secret-key", "", "", "Kubescape SaaS secret key. Default will load secret key from cache, read more - https://hub.armosec.io/docs/authentication")
deleteCmd.AddCommand(getExceptionsCmd(ks, &deleteInfo))
return deleteCmd
}

View File

@@ -1,46 +0,0 @@
package delete
import (
"fmt"
"strings"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v2/core/meta"
v1 "github.com/kubescape/kubescape/v2/core/meta/datastructures/v1"
"github.com/spf13/cobra"
)
func getExceptionsCmd(ks meta.IKubescape, deleteInfo *v1.Delete) *cobra.Command {
return &cobra.Command{
Use: "exceptions <exception name>",
Short: "Delete exceptions from Kubescape SaaS version. Run 'kubescape list exceptions' for all exceptions names",
Example: deleteExceptionsExamples,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return fmt.Errorf("missing exceptions names")
}
return nil
},
Run: func(cmd *cobra.Command, args []string) {
if err := flagValidationDelete(deleteInfo); err != nil {
logger.L().Fatal(err.Error())
}
exceptionsNames := strings.Split(args[0], ";")
if len(exceptionsNames) == 0 {
logger.L().Fatal("missing exceptions names")
}
if err := ks.DeleteExceptions(&v1.DeleteExceptions{Credentials: deleteInfo.Credentials, Exceptions: exceptionsNames}); err != nil {
logger.L().Fatal(err.Error())
}
},
}
}
// Check if the flag entered are valid
func flagValidationDelete(deleteInfo *v1.Delete) error {
// Validate the user's credentials
return deleteInfo.Credentials.Validate()
}

View File

@@ -1,47 +1,49 @@
package download
import (
"context"
"fmt"
"path/filepath"
"strings"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/kubescape/v2/core/core"
"github.com/kubescape/kubescape/v2/core/meta"
v1 "github.com/kubescape/kubescape/v2/core/meta/datastructures/v1"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/core"
"github.com/kubescape/kubescape/v3/core/meta"
v1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
"github.com/spf13/cobra"
"golang.org/x/exp/slices"
)
var (
downloadExample = `
downloadExample = fmt.Sprintf(`
# Download all artifacts and save them in the default path (~/.kubescape)
kubescape download artifacts
%[1]s download artifacts
# Download all artifacts and save them in /tmp path
kubescape download artifacts --output /tmp
%[1]s download artifacts --output /tmp
# Download the NSA framework. Run 'kubescape list frameworks' for all frameworks names
kubescape download framework nsa
# Download the NSA framework. Run '%[1]s list frameworks' for all frameworks names
%[1]s download framework nsa
# Download the "C-0001" control. Run 'kubescape list controls --id' for all controls ids
kubescape download control "C-0001"
# Download the "C-0001" control. Run '%[1]s list controls --id' for all controls ids
%[1]s download control "C-0001"
# Download the "C-0001" control. Run 'kubescape list controls --id' for all controls ids
kubescape download control C-0001
# Download the "C-0001" control. Run '%[1]s list controls --id' for all controls ids
%[1]s download control C-0001
# Download the configured exceptions
kubescape download exceptions
%[1]s download exceptions
# Download the configured controls-inputs
kubescape download controls-inputs
%[1]s download controls-inputs
# Download the attack tracks
kubescape download attack-tracks
`
%[1]s download attack-tracks
`, cautils.ExecName())
)
func GeDownloadCmd(ks meta.IKubescape) *cobra.Command {
func GetDownloadCmd(ks meta.IKubescape) *cobra.Command {
var downloadInfo = v1.DownloadInfo{}
downloadCmd := &cobra.Command{
@@ -54,7 +56,7 @@ func GeDownloadCmd(ks meta.IKubescape) *cobra.Command {
if len(args) < 1 {
return fmt.Errorf("policy type required, supported: %v", supported)
}
if cautils.StringInSlice(core.DownloadSupportCommands(), args[0]) == cautils.ValueNotFound {
if !slices.Contains(core.DownloadSupportCommands(), args[0]) {
return fmt.Errorf("invalid parameter '%s'. Supported parameters: %s", args[0], supported)
}
return nil
@@ -74,16 +76,17 @@ func GeDownloadCmd(ks meta.IKubescape) *cobra.Command {
downloadInfo.Identifier = args[1]
}
if err := ks.Download(&downloadInfo); err != nil {
if err := ks.Download(context.TODO(), &downloadInfo); err != nil {
logger.L().Fatal(err.Error())
}
return nil
},
}
downloadCmd.PersistentFlags().StringVarP(&downloadInfo.Credentials.Account, "account", "", "", "Kubescape SaaS account ID. Default will load account ID from cache")
downloadCmd.PersistentFlags().StringVarP(&downloadInfo.Credentials.ClientID, "client-id", "", "", "Kubescape SaaS client ID. Default will load client ID from cache, read more - https://hub.armosec.io/docs/authentication")
downloadCmd.PersistentFlags().StringVarP(&downloadInfo.Credentials.SecretKey, "secret-key", "", "", "Kubescape SaaS secret key. Default will load secret key from cache, read more - https://hub.armosec.io/docs/authentication")
downloadCmd.PersistentFlags().StringVarP(&downloadInfo.AccountID, "account", "", "", "Kubescape SaaS account ID. Default will load account ID from cache")
downloadCmd.PersistentFlags().StringVarP(&downloadInfo.AccessKey, "accessKey", "", "", "Kubescape SaaS access key. Default will load access key from cache")
downloadCmd.PersistentFlags().MarkDeprecated("client-id", "Client ID is no longer supported. Feel free to contact the Kubescape maintainers for more information.")
downloadCmd.PersistentFlags().MarkDeprecated("secret-key", "Secret Key is no longer supported. Feel free to contact the Kubescape maintainers for more information.")
downloadCmd.Flags().StringVarP(&downloadInfo.Path, "output", "o", "", "Output file. If not specified, will save in `~/.kubescape/<policy name>.json`")
return downloadCmd
@@ -93,5 +96,5 @@ func GeDownloadCmd(ks meta.IKubescape) *cobra.Command {
func flagValidationDownload(downloadInfo *v1.DownloadInfo) error {
// Validate the user's credentials
return downloadInfo.Credentials.Validate()
return cautils.ValidateAccountID(downloadInfo.AccountID)
}

View File

@@ -1,30 +1,33 @@
package fix
import (
"context"
"errors"
"fmt"
"github.com/kubescape/kubescape/v2/core/meta"
metav1 "github.com/kubescape/kubescape/v2/core/meta/datastructures/v1"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/meta"
metav1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
"github.com/spf13/cobra"
)
var fixCmdExamples = `
var fixCmdExamples = fmt.Sprintf(`
Fix command is for fixing kubernetes manifest files based on a scan command output.
Use with caution, this command will change your files in-place.
# Fix kubernetes YAML manifest files based on a scan command output (output.json)
1) kubescape scan --format json --format-version v2 --output output.json
2) kubescape fix output.json
1) %[1]s scan . --format json --output output.json
2) %[1]s fix output.json
`
`, cautils.ExecName())
func GetFixCmd(ks meta.IKubescape) *cobra.Command {
var fixInfo metav1.FixInfo
fixCmd := &cobra.Command{
Use: "fix <report output file>",
Short: "Fix misconfiguration in files",
Short: "Propose a fix for the misconfiguration found when scanning Kubernetes manifest files",
Long: ``,
Example: fixCmdExamples,
RunE: func(cmd *cobra.Command, args []string) error {
@@ -33,7 +36,7 @@ func GetFixCmd(ks meta.IKubescape) *cobra.Command {
}
fixInfo.ReportFile = args[0]
return ks.Fix(&fixInfo)
return ks.Fix(context.TODO(), &fixInfo)
},
}

View File

@@ -1,31 +1,33 @@
package list
import (
"context"
"fmt"
"strings"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/kubescape/v2/core/core"
"github.com/kubescape/kubescape/v2/core/meta"
v1 "github.com/kubescape/kubescape/v2/core/meta/datastructures/v1"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/core"
"github.com/kubescape/kubescape/v3/core/meta"
v1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
"github.com/spf13/cobra"
"golang.org/x/exp/slices"
)
var (
listExample = `
listExample = fmt.Sprintf(`
# List default supported frameworks names
kubescape list frameworks
%[1]s list frameworks
# List all supported frameworks names
kubescape list frameworks --account <account id>
%[1]s list frameworks --account <account id>
# List all supported controls names with ids
kubescape list controls
%[1]s list controls
Control documentation:
https://hub.armosec.io/docs/controls
`
`, cautils.ExecName())
)
func GetListCmd(ks meta.IKubescape) *cobra.Command {
@@ -42,7 +44,7 @@ func GetListCmd(ks meta.IKubescape) *cobra.Command {
if len(args) < 1 {
return fmt.Errorf("policy type requeued, supported: %s", supported)
}
if cautils.StringInSlice(core.ListSupportActions(), args[0]) == cautils.ValueNotFound {
if !slices.Contains(core.ListSupportActions(), args[0]) {
return fmt.Errorf("invalid parameter '%s'. Supported parameters: %s", args[0], supported)
}
return nil
@@ -55,17 +57,16 @@ func GetListCmd(ks meta.IKubescape) *cobra.Command {
listPolicies.Target = args[0]
if err := ks.List(&listPolicies); err != nil {
if err := ks.List(context.TODO(), &listPolicies); err != nil {
logger.L().Fatal(err.Error())
}
return nil
},
}
listCmd.PersistentFlags().StringVarP(&listPolicies.Credentials.Account, "account", "", "", "Kubescape SaaS account ID. Default will load account ID from cache")
listCmd.PersistentFlags().StringVarP(&listPolicies.Credentials.ClientID, "client-id", "", "", "Kubescape SaaS client ID. Default will load client ID from cache, read more - https://hub.armosec.io/docs/authentication")
listCmd.PersistentFlags().StringVarP(&listPolicies.Credentials.SecretKey, "secret-key", "", "", "Kubescape SaaS secret key. Default will load secret key from cache, read more - https://hub.armosec.io/docs/authentication")
listCmd.PersistentFlags().StringVarP(&listPolicies.AccountID, "account", "", "", "Kubescape SaaS account ID. Default will load account ID from cache")
listCmd.PersistentFlags().StringVarP(&listPolicies.AccessKey, "accessKey", "", "", "Kubescape SaaS access key. Default will load access key from cache")
listCmd.PersistentFlags().StringVar(&listPolicies.Format, "format", "pretty-print", "output format. supported: 'pretty-print'/'json'")
listCmd.PersistentFlags().MarkDeprecated("id", "Control ID's are included in list outpus")
listCmd.PersistentFlags().MarkDeprecated("id", "Control ID's are included in list outputs")
return listCmd
}
@@ -74,5 +75,5 @@ func GetListCmd(ks meta.IKubescape) *cobra.Command {
func flagValidationList(listPolicies *v1.ListPolicies) error {
// Validate the user's credentials
return listPolicies.Credentials.Validate()
return cautils.ValidateAccountID(listPolicies.AccountID)
}

View File

@@ -0,0 +1,56 @@
package operator
import (
"fmt"
"github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/core"
"github.com/kubescape/kubescape/v3/core/meta"
"github.com/spf13/cobra"
)
var operatorScanConfigExamples = fmt.Sprintf(`
# Run a configuration scan
%[1]s operator scan configurations
`, cautils.ExecName())
func getOperatorScanConfigCmd(ks meta.IKubescape, operatorInfo cautils.OperatorInfo) *cobra.Command {
configCmd := &cobra.Command{
Use: "configurations",
Short: "Trigger configuration scanning from the Kubescape-Operator microservice",
Long: ``,
Example: operatorScanConfigExamples,
Args: func(cmd *cobra.Command, args []string) error {
operatorInfo.Subcommands = append(operatorInfo.Subcommands, "config")
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
operatorAdapter, err := core.NewOperatorAdapter(operatorInfo.OperatorScanInfo)
if err != nil {
return err
}
logger.L().Start("Kubescape-Operator Triggering for configuration scanning")
_, err = operatorAdapter.OperatorScan()
if err != nil {
logger.L().StopError("Failed to triggering Kubescape-Operator for configuration scanning", helpers.Error(err))
return err
}
logger.L().StopSuccess("Triggered Kubescape-Operator for configuration scanning")
return nil
},
}
configScanInfo := &cautils.ConfigScanInfo{}
operatorInfo.OperatorScanInfo = configScanInfo
configCmd.PersistentFlags().StringSliceVar(&configScanInfo.IncludedNamespaces, "include-namespaces", nil, "scan specific namespaces. e.g: --include-namespaces ns-a,ns-b")
configCmd.PersistentFlags().StringSliceVar(&configScanInfo.ExcludedNamespaces, "exclude-namespaces", nil, "Namespaces to exclude from scanning. e.g: --exclude-namespaces ns-a,ns-b. Notice, when running with `exclude-namespace` kubescape does not scan cluster-scoped objects.")
configCmd.PersistentFlags().StringSliceVar(&configScanInfo.Frameworks, "frameworks", nil, "Load frameworks for configuration scanning")
configCmd.PersistentFlags().BoolVarP(&configScanInfo.HostScanner, "enable-host-scan", "", false, "Deploy Kubescape host-sensor daemonset in the scanned cluster. Deleting it right after we collecting the data. Required to collect valuable data from cluster nodes for certain controls. Yaml file: https://github.com/kubescape/kubescape/blob/master/core/pkg/hostsensorutils/hostsensor.yaml")
return configCmd
}

56
cmd/operator/operator.go Normal file
View File

@@ -0,0 +1,56 @@
package operator
import (
"errors"
"fmt"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/meta"
"github.com/spf13/cobra"
)
const (
scanSubCommand string = "scan"
)
var operatorExamples = fmt.Sprintf(`
# Trigger a configuration scan
%[1]s operator scan configurations
# Trigger a vulnerabilities scan
%[1]s operator scan vulnerabilities
`, cautils.ExecName())
func GetOperatorCmd(ks meta.IKubescape) *cobra.Command {
var operatorInfo cautils.OperatorInfo
operatorCmd := &cobra.Command{
Use: "operator",
Short: "The operator is used to communicate with the Kubescape-Operator within the cluster components.",
Long: ``,
Example: operatorExamples,
Args: func(cmd *cobra.Command, args []string) error {
operatorInfo.Subcommands = append(operatorInfo.Subcommands, "operator")
if len(args) < 2 {
return errors.New("For the operator sub-command, you need to provide at least one additional sub-command. Refer to the examples above.")
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) < 2 {
return errors.New("For the operator sub-command, you need to provide at least one additional sub-command. Refer to the examples above.")
}
if args[0] != scanSubCommand {
return errors.New(fmt.Sprintf("For the operator sub-command, only %s is supported. Refer to the examples above.", scanSubCommand))
}
return nil
},
}
operatorCmd.AddCommand(getOperatorScanCmd(ks, operatorInfo))
return operatorCmd
}

45
cmd/operator/scan.go Normal file
View File

@@ -0,0 +1,45 @@
package operator
import (
"errors"
"fmt"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/meta"
"github.com/spf13/cobra"
)
const (
vulnerabilitiesSubCommand string = "vulnerabilities"
configurationsSubCommand string = "configurations"
)
func getOperatorScanCmd(ks meta.IKubescape, operatorInfo cautils.OperatorInfo) *cobra.Command {
operatorCmd := &cobra.Command{
Use: "scan",
Short: "Scan your cluster using the Kubescape-operator within the cluster components",
Long: ``,
Example: operatorExamples,
Args: func(cmd *cobra.Command, args []string) error {
operatorInfo.Subcommands = append(operatorInfo.Subcommands, "scan")
if len(args) < 1 {
return errors.New("for operator scan sub command, you must pass at least 1 more sub commands, see above examples")
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return errors.New("for operator scan sub command, you must pass at least 1 more sub commands, see above examples")
}
if (args[0] != vulnerabilitiesSubCommand) && (args[0] != configurationsSubCommand) {
return errors.New(fmt.Sprintf("For the operator sub-command, only %s and %s are supported. Refer to the examples above.", vulnerabilitiesSubCommand, configurationsSubCommand))
}
return nil
},
}
operatorCmd.AddCommand(getOperatorScanConfigCmd(ks, operatorInfo))
operatorCmd.AddCommand(getOperatorScanVulnerabilitiesCmd(ks, operatorInfo))
return operatorCmd
}

View File

@@ -0,0 +1,56 @@
package operator
import (
"fmt"
"github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/k8s-interface/k8sinterface"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/core"
"github.com/kubescape/kubescape/v3/core/meta"
"github.com/spf13/cobra"
)
var operatorScanVulnerabilitiesExamples = fmt.Sprintf(`
# Trigger a vulnerabilities scan
%[1]s operator scan vulnerabilities
`, cautils.ExecName())
func getOperatorScanVulnerabilitiesCmd(ks meta.IKubescape, operatorInfo cautils.OperatorInfo) *cobra.Command {
configCmd := &cobra.Command{
Use: "vulnerabilities",
Short: "Vulnerabilities use for scan your cluster vulnerabilities using Kubescape operator in the in cluster components",
Long: ``,
Example: operatorScanVulnerabilitiesExamples,
Args: func(cmd *cobra.Command, args []string) error {
operatorInfo.Subcommands = append(operatorInfo.Subcommands, "vulnerabilities")
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
operatorAdapter, err := core.NewOperatorAdapter(operatorInfo.OperatorScanInfo)
if err != nil {
return err
}
logger.L().Start("Triggering the Kubescape-Operator for vulnerability scanning")
_, err = operatorAdapter.OperatorScan()
if err != nil {
logger.L().StopError("Failed to trigger the Kubescape-Operator for vulnerability scanning", helpers.Error(err))
return err
}
logger.L().StopSuccess("Triggered Kubescape-Operator for vulnerability scanning. View the scanning results once they are ready using the following command: \"kubectl get vulnerabilitysummaries\"")
return err
},
}
vulnerabilitiesScanInfo := &cautils.VulnerabilitiesScanInfo{
ClusterName: k8sinterface.GetContextName(),
}
operatorInfo.OperatorScanInfo = vulnerabilitiesScanInfo
configCmd.PersistentFlags().StringSliceVar(&vulnerabilitiesScanInfo.IncludeNamespaces, "include-namespaces", nil, "scan specific namespaces. e.g: --include-namespaces ns-a,ns-b")
return configCmd
}

141
cmd/patch/README.md Normal file
View File

@@ -0,0 +1,141 @@
# Patch Command
The patch command is used for patching container images with vulnerabilities.
It uses [copa](https://github.com/project-copacetic/copacetic) and [buildkit](https://github.com/moby/buildkit) under the hood for patching the container images, and [grype](https://github.com/anchore/grype) as the engine for scanning the images (at the moment).
## Usage
```bash
kubescape patch --image <image-name> [flags]
```
The patch command can be run in 2 ways:
1. **With sudo privileges**
You will need to start `buildkitd` if it is not already running
```bash
sudo buildkitd &
sudo kubescape patch --image <image-name>
```
2. **Without sudo privileges**
```bash
export BUILDKIT_VERSION=v0.11.4
export BUILDKIT_PORT=8888
docker run \
--detach \
--rm \
--privileged \
-p 127.0.0.1:$BUILDKIT_PORT:$BUILDKIT_PORT/tcp \
--name buildkitd \
--entrypoint buildkitd \
"moby/buildkit:$BUILDKIT_VERSION" \
--addr tcp://0.0.0.0:$BUILDKIT_PORT
kubescape patch \
-i <image-name> \
-a tcp://0.0.0.0:$BUILDKIT_PORT
```
### Flags
| Flag | Description | Required | Default |
| -------------- | ------------------------------------------------------ | -------- | ----------------------------------- |
| -i, --image | Image name to be patched (should be in canonical form) | Yes | |
| -a, --addr | Address of the buildkitd service | No | unix:///run/buildkit/buildkitd.sock |
| -t, --tag | Tag of the resultant patched image | No | image_name-patched |
| --timeout | Timeout for the patching process | No | 5m |
| -u, --username | Username for the image registry login | No | |
| -p, --password | Password for the image registry login | No | |
| -f, --format | Output file format. | No | |
| -o, --output | Output file. Print output to file and not stdout | No | |
| -v, --verbose | Display full report. Default to false | No | |
| -h, --help | help for patch | No | |
## Example
We will demonstrate how to use the patch command with an example of [nginx](https://www.nginx.com/) image.
### Pre-requisites
- [docker](https://docs.docker.com/desktop/install/linux-install/#generic-installation-steps) daemon must be installed and running.
- [buildkit](https://github.com/moby/buildkit) daemon must be installed
### Steps
1. Run `buildkitd` service:
```bash
sudo buildkitd
```
2. In a seperate terminal, run the `kubescape patch` command:
```bash
sudo kubescape patch --image docker.io/library/nginx:1.22
```
3. You will get an output like below:
```bash
✅ Successfully scanned image: docker.io/library/nginx:1.22
✅ Patched image successfully. Loaded image: nginx:1.22-patched
✅ Successfully re-scanned image: nginx:1.22-patched
| Severity | Vulnerability | Component | Version | Fixed In |
| -------- | -------------- | ------------- | ----------------------- | -------- |
| Critical | CVE-2023-23914 | curl | 7.74.0-1.3+deb11u7 | wont-fix |
| Critical | CVE-2019-8457 | libdb5.3 | 5.3.28+dfsg1-0.8 | wont-fix |
| High | CVE-2022-42916 | libcurl4 | 7.74.0-1.3+deb11u7 | wont-fix |
| High | CVE-2022-1304 | libext2fs2 | 1.46.2-2 | wont-fix |
| High | CVE-2022-42916 | curl | 7.74.0-1.3+deb11u7 | wont-fix |
| High | CVE-2022-1304 | e2fsprogs | 1.46.2-2 | wont-fix |
| High | CVE-2022-1304 | libcom-err2 | 1.46.2-2 | wont-fix |
| High | CVE-2023-27533 | curl | 7.74.0-1.3+deb11u7 | wont-fix |
| High | CVE-2023-27534 | libcurl4 | 7.74.0-1.3+deb11u7 | wont-fix |
| High | CVE-2023-27533 | libcurl4 | 7.74.0-1.3+deb11u7 | wont-fix |
| High | CVE-2022-43551 | libcurl4 | 7.74.0-1.3+deb11u7 | wont-fix |
| High | CVE-2022-3715 | bash | 5.1-2+deb11u1 | wont-fix |
| High | CVE-2023-27534 | curl | 7.74.0-1.3+deb11u7 | wont-fix |
| High | CVE-2022-43551 | curl | 7.74.0-1.3+deb11u7 | wont-fix |
| High | CVE-2021-33560 | libgcrypt20 | 1.8.7-6 | wont-fix |
| High | CVE-2023-2953 | libldap-2.4-2 | 2.4.57+dfsg-3+deb11u1 | wont-fix |
| High | CVE-2022-1304 | libss2 | 1.46.2-2 | wont-fix |
| High | CVE-2020-22218 | libssh2-1 | 1.9.0-2 | wont-fix |
| High | CVE-2023-29491 | libtinfo6 | 6.2+20201114-2+deb11u1 | wont-fix |
| High | CVE-2022-2309 | libxml2 | 2.9.10+dfsg-6.7+deb11u4 | wont-fix |
| High | CVE-2022-4899 | libzstd1 | 1.4.8+dfsg-2.1 | wont-fix |
| High | CVE-2022-1304 | logsave | 1.46.2-2 | wont-fix |
| High | CVE-2023-29491 | ncurses-base | 6.2+20201114-2+deb11u1 | wont-fix |
| High | CVE-2023-29491 | ncurses-bin | 6.2+20201114-2+deb11u1 | wont-fix |
| High | CVE-2023-31484 | perl-base | 5.32.1-4+deb11u2 | wont-fix |
| High | CVE-2020-16156 | perl-base | 5.32.1-4+deb11u2 | wont-fix |
Vulnerability summary - 161 vulnerabilities found:
Image: nginx:1.22-patched
* 3 Critical
* 24 High
* 31 Medium
* 103 Other
Most vulnerable components:
* curl (7.74.0-1.3+deb11u7) - 1 Critical, 4 High, 5 Medium, 1 Low, 3 Negligible
* libcurl4 (7.74.0-1.3+deb11u7) - 1 Critical, 4 High, 5 Medium, 1 Low, 3 Negligible
* libtiff5 (4.2.0-1+deb11u4) - 7 Medium, 10 Negligible, 2 Unknown
* libxml2 (2.9.10+dfsg-6.7+deb11u4) - 1 High, 2 Medium
* perl-base (5.32.1-4+deb11u2) - 2 High, 2 Negligible
What now?
─────────
* Run with '--verbose'/'-v' flag for detailed vulnerabilities view
* Install Kubescape in your cluster for continuous monitoring and a full vulnerability report: https://github.com/kubescape/helm-charts/tree/main/charts/kubescape-cloud-operator
```
## Limitations
- The patch command can only fix OS-level vulnerability. It cannot fix application-level vulnerabilities. This is a limitation of copa. The reason behind this is that application level vulnerabilities are best suited to be fixed by the developers of the application.
Hence, this is not really a limitation but a design decision.
- No support for windows containers given the dependency on buildkit.

144
cmd/patch/patch.go Normal file
View File

@@ -0,0 +1,144 @@
package patch
import (
"context"
"errors"
"fmt"
"strings"
"time"
ref "github.com/distribution/distribution/reference"
"github.com/docker/distribution/reference"
"github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v3/cmd/shared"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/meta"
metav1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
"github.com/kubescape/kubescape/v3/pkg/imagescan"
"github.com/spf13/cobra"
)
var patchCmdExamples = fmt.Sprintf(`
# Patch the nginx:1.22 image
1) sudo buildkitd # start buildkitd service, run in seperate terminal
2) sudo %[1]s patch --image docker.io/library/nginx:1.22 # patch the image
# The patch command can also be run without sudo privileges
# Documentation: https://github.com/kubescape/kubescape/tree/master/cmd/patch
`, cautils.ExecName())
func GetPatchCmd(ks meta.IKubescape) *cobra.Command {
var patchInfo metav1.PatchInfo
var scanInfo cautils.ScanInfo
patchCmd := &cobra.Command{
Use: "patch --image <image>:<tag> [flags]",
Short: "Patch container images with vulnerabilities ",
Long: `Patch command is for automatically patching images with vulnerabilities.`,
Example: patchCmdExamples,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) != 0 {
return fmt.Errorf("the command takes no arguments")
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
if err := shared.ValidateImageScanInfo(&scanInfo); err != nil {
return err
}
if err := validateImagePatchInfo(&patchInfo); err != nil {
return err
}
results, err := ks.Patch(context.Background(), &patchInfo, &scanInfo)
if err != nil {
return err
}
if imagescan.ExceedsSeverityThreshold(results, imagescan.ParseSeverity(scanInfo.FailThresholdSeverity)) {
shared.TerminateOnExceedingSeverity(&scanInfo, logger.L())
}
return nil
},
}
patchCmd.PersistentFlags().StringVarP(&patchInfo.Image, "image", "i", "", "Application image name and tag to patch")
patchCmd.PersistentFlags().StringVarP(&patchInfo.PatchedImageTag, "tag", "t", "", "Tag for the patched image. Defaults to '<image-tag>-patched' ")
patchCmd.PersistentFlags().StringVarP(&patchInfo.BuildkitAddress, "address", "a", "unix:///run/buildkit/buildkitd.sock", "Address of buildkitd service, defaults to local buildkitd.sock")
patchCmd.PersistentFlags().DurationVar(&patchInfo.Timeout, "timeout", 5*time.Minute, "Timeout for the operation, defaults to '5m'")
patchCmd.PersistentFlags().StringVarP(&patchInfo.Username, "username", "u", "", "Username for registry login")
patchCmd.PersistentFlags().StringVarP(&patchInfo.Password, "password", "p", "", "Password for registry login")
patchCmd.PersistentFlags().StringVarP(&scanInfo.Format, "format", "f", "", `Output file format. Supported formats: "pretty-printer", "json", "sarif"`)
patchCmd.PersistentFlags().StringVarP(&scanInfo.Output, "output", "o", "", "Output file. Print output to file and not stdout")
patchCmd.PersistentFlags().BoolVarP(&scanInfo.VerboseMode, "verbose", "v", false, "Display full report. Default to false")
patchCmd.PersistentFlags().StringVarP(&scanInfo.FailThresholdSeverity, "severity-threshold", "s", "", "Severity threshold is the severity of a vulnerability at which the command fails and returns exit code 1")
return patchCmd
}
// validateImagePatchInfo validates the image patch info for the `patch` command
func validateImagePatchInfo(patchInfo *metav1.PatchInfo) error {
if patchInfo.Image == "" {
return errors.New("image tag is required")
}
// Convert image to canonical format (required by copacetic for patching images)
patchInfoImage, err := cautils.NormalizeImageName(patchInfo.Image)
if err != nil {
return nil
}
// Parse the image full name to get image name and tag
named, err := ref.ParseNamed(patchInfoImage)
if err != nil {
return err
}
// If no tag or digest is provided, default to 'latest'
if ref.IsNameOnly(named) {
logger.L().Warning("Image name has no tag or digest, using latest as tag")
named = ref.TagNameOnly(named)
}
patchInfo.Image = named.String()
// If no patched image tag is provided, default to '<image-tag>-patched'
if patchInfo.PatchedImageTag == "" {
taggedName, ok := named.(ref.Tagged)
if !ok {
return errors.New("unexpected error while parsing image tag")
}
patchInfo.ImageTag = taggedName.Tag()
if patchInfo.ImageTag == "" {
logger.L().Warning("No tag provided, defaulting to 'patched'")
patchInfo.PatchedImageTag = "patched"
} else {
patchInfo.PatchedImageTag = fmt.Sprintf("%s-%s", patchInfo.ImageTag, "patched")
}
}
// Extract the "image" name from the canonical Image URL
// If it's an official docker image, we store just the "image-name". Else if a docker repo then we store as "repo/image". Else complete URL
ref, _ := reference.ParseNormalizedNamed(patchInfo.Image)
imageName := named.Name()
if strings.Contains(imageName, "docker.io/library/") {
imageName = reference.Path(ref)
imageName = imageName[strings.LastIndex(imageName, "/")+1:]
} else if strings.Contains(imageName, "docker.io/") {
imageName = reference.Path(ref)
}
patchInfo.ImageName = imageName
return nil
}

View File

@@ -6,39 +6,40 @@ import (
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/kubescape/v2/cmd/completion"
"github.com/kubescape/kubescape/v2/cmd/config"
"github.com/kubescape/kubescape/v2/cmd/delete"
"github.com/kubescape/kubescape/v2/cmd/download"
"github.com/kubescape/kubescape/v2/cmd/fix"
"github.com/kubescape/kubescape/v2/cmd/list"
"github.com/kubescape/kubescape/v2/cmd/scan"
"github.com/kubescape/kubescape/v2/cmd/submit"
"github.com/kubescape/kubescape/v2/cmd/update"
"github.com/kubescape/kubescape/v2/cmd/version"
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/kubescape/v2/core/cautils/getter"
"github.com/kubescape/kubescape/v2/core/core"
"github.com/kubescape/kubescape/v2/core/meta"
"github.com/kubescape/k8s-interface/k8sinterface"
"github.com/kubescape/kubescape/v3/cmd/completion"
"github.com/kubescape/kubescape/v3/cmd/config"
"github.com/kubescape/kubescape/v3/cmd/download"
"github.com/kubescape/kubescape/v3/cmd/fix"
"github.com/kubescape/kubescape/v3/cmd/list"
"github.com/kubescape/kubescape/v3/cmd/operator"
"github.com/kubescape/kubescape/v3/cmd/patch"
"github.com/kubescape/kubescape/v3/cmd/scan"
"github.com/kubescape/kubescape/v3/cmd/update"
"github.com/kubescape/kubescape/v3/cmd/version"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/cautils/getter"
"github.com/kubescape/kubescape/v3/core/core"
"github.com/kubescape/kubescape/v3/core/meta"
"github.com/spf13/cobra"
)
var rootInfo cautils.RootInfo
var ksExamples = `
# Scan command
kubescape scan
var ksExamples = fmt.Sprintf(`
# Scan a Kubernetes cluster or YAML files for image vulnerabilities and misconfigurations
%[1]s scan
# List supported frameworks
kubescape list frameworks
# List supported controls
%[1]s list controls
# Download artifacts (air-gapped environment support)
kubescape download artifacts
%[1]s download artifacts
# View cached configurations
kubescape config view
`
%[1]s config view
`, cautils.ExecName())
func NewDefaultKubescapeCommand() *cobra.Command {
ks := core.NewKubescape()
@@ -51,11 +52,29 @@ func getRootCmd(ks meta.IKubescape) *cobra.Command {
Use: "kubescape",
Short: "Kubescape is a tool for testing Kubernetes security posture. Docs: https://hub.armosec.io/docs",
Example: ksExamples,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
k8sinterface.SetClusterContextName(rootInfo.KubeContext)
initLogger()
initLoggerLevel()
initEnvironment()
initCacheDir()
},
}
rootCmd.PersistentFlags().StringVar(&rootInfo.KSCloudBEURLsDep, "environment", "", envFlagUsage)
rootCmd.PersistentFlags().StringVar(&rootInfo.KSCloudBEURLs, "env", "", envFlagUsage)
rootCmd.PersistentFlags().MarkDeprecated("environment", "use 'env' instead")
if cautils.IsKrewPlugin() {
// Invoked as a kubectl plugin.
// Cobra doesn't have a way to specify a two word command (i.e. "kubectl kubescape"), so set a custom usage template
// with kubectl in it. Cobra will use this template for the root and all child commands.
oldUsageTemplate := rootCmd.UsageTemplate()
newUsageTemplate := strings.NewReplacer("{{.UseLine}}", "kubectl {{.UseLine}}", "{{.CommandPath}}", "kubectl {{.CommandPath}}").Replace(oldUsageTemplate)
rootCmd.SetUsageTemplate(newUsageTemplate)
}
rootCmd.PersistentFlags().StringVar(&rootInfo.DiscoveryServerURL, "server", "", "Backend discovery server URL")
rootCmd.PersistentFlags().MarkDeprecated("environment", "'environment' is no longer supported, Use 'server' instead. Feel free to contact the Kubescape maintainers for more information.")
rootCmd.PersistentFlags().MarkDeprecated("env", "'env' is no longer supported, Use 'server' instead. Feel free to contact the Kubescape maintainers for more information.")
rootCmd.PersistentFlags().MarkHidden("environment")
rootCmd.PersistentFlags().MarkHidden("env")
@@ -64,22 +83,31 @@ 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)
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")
rootCmd.PersistentFlags().StringVarP(&rootInfo.KubeContext, "kube-context", "", "", "Kube context. Default will use the current-context")
// Supported commands
rootCmd.AddCommand(scan.GetScanCommand(ks))
rootCmd.AddCommand(download.GeDownloadCmd(ks))
rootCmd.AddCommand(delete.GetDeleteCmd(ks))
rootCmd.AddCommand(download.GetDownloadCmd(ks))
rootCmd.AddCommand(list.GetListCmd(ks))
rootCmd.AddCommand(submit.GetSubmitCmd(ks))
rootCmd.AddCommand(completion.GetCompletionCmd())
rootCmd.AddCommand(version.GetVersionCmd())
rootCmd.AddCommand(config.GetConfigCmd(ks))
rootCmd.AddCommand(update.GetUpdateCmd())
rootCmd.AddCommand(fix.GetFixCmd(ks))
rootCmd.AddCommand(patch.GetPatchCmd(ks))
rootCmd.AddCommand(operator.GetOperatorCmd(ks))
// deprecated commands
rootCmd.AddCommand(&cobra.Command{
Use: "submit",
Deprecated: "This command is deprecated. Contact Kubescape maintainers for more information.",
})
rootCmd.AddCommand(&cobra.Command{
Use: "delete",
Deprecated: "This command is deprecated. Contact Kubescape maintainers for more information.",
})
return rootCmd
}

View File

@@ -5,15 +5,19 @@ import (
"os"
"strings"
v1 "github.com/kubescape/backend/pkg/client/v1"
"github.com/kubescape/backend/pkg/servicediscovery"
sdClientV1 "github.com/kubescape/backend/pkg/servicediscovery/v1"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/kubescape/v2/core/cautils/getter"
"github.com/kubescape/go-logger/iconlogger"
"github.com/kubescape/go-logger/zaplogger"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/cautils/getter"
"github.com/mattn/go-isatty"
)
const envFlagUsage = "Send report results to specific URL. Format:<ReportReceiver>,<Backend>,<Frontend>.\n\t\tExample:report.armo.cloud,api.armo.cloud,portal.armo.cloud"
func initLogger() {
logger.DisableColor(rootInfo.DisableColor)
logger.EnableColor(rootInfo.EnableColor)
@@ -23,9 +27,9 @@ func initLogger() {
rootInfo.LoggerName = l
} else {
if isatty.IsTerminal(os.Stdout.Fd()) {
rootInfo.LoggerName = "pretty"
rootInfo.LoggerName = iconlogger.LoggerName
} else {
rootInfo.LoggerName = "zap"
rootInfo.LoggerName = zaplogger.LoggerName
}
}
}
@@ -56,35 +60,51 @@ func initCacheDir() {
logger.L().Debug("cache dir updated", helpers.String("path", getter.DefaultLocalStore))
}
func initEnvironment() {
if rootInfo.KSCloudBEURLs == "" {
rootInfo.KSCloudBEURLs = rootInfo.KSCloudBEURLsDep
if rootInfo.DiscoveryServerURL == "" {
return
}
urlSlices := strings.Split(rootInfo.KSCloudBEURLs, ",")
if len(urlSlices) != 1 && len(urlSlices) < 3 {
logger.L().Fatal("expected at least 3 URLs (report, api, frontend, auth)")
logger.L().Debug("fetching URLs from service discovery server", helpers.String("server", rootInfo.DiscoveryServerURL))
client, err := sdClientV1.NewServiceDiscoveryClientV1(rootInfo.DiscoveryServerURL)
if err != nil {
logger.L().Fatal("failed to create service discovery client", helpers.Error(err), helpers.String("server", rootInfo.DiscoveryServerURL))
return
}
switch len(urlSlices) {
case 1:
switch urlSlices[0] {
case "dev", "development":
getter.SetKSCloudAPIConnector(getter.NewKSCloudAPIDev())
case "stage", "staging":
getter.SetKSCloudAPIConnector(getter.NewKSCloudAPIStaging())
case "":
getter.SetKSCloudAPIConnector(getter.NewKSCloudAPIProd())
default:
logger.L().Fatal("--environment flag usage: " + envFlagUsage)
}
case 2:
logger.L().Fatal("--environment flag usage: " + envFlagUsage)
case 3, 4:
var ksAuthURL string
ksEventReceiverURL := urlSlices[0] // mandatory
ksBackendURL := urlSlices[1] // mandatory
ksFrontendURL := urlSlices[2] // mandatory
if len(urlSlices) >= 4 {
ksAuthURL = urlSlices[3]
}
getter.SetKSCloudAPIConnector(getter.NewKSCloudAPICustomized(ksEventReceiverURL, ksBackendURL, ksFrontendURL, ksAuthURL))
services, err := servicediscovery.GetServices(
client,
)
if err != nil {
logger.L().Fatal("failed to to get services from server", helpers.Error(err), helpers.String("server", rootInfo.DiscoveryServerURL))
return
}
logger.L().Debug("configuring service discovery URLs", helpers.String("cloudAPIURL", services.GetApiServerUrl()), helpers.String("cloudReportURL", services.GetReportReceiverHttpUrl()))
tenant := cautils.GetTenantConfig("", "", "", "", nil)
if services.GetApiServerUrl() != "" {
tenant.GetConfigObj().CloudAPIURL = services.GetApiServerUrl()
}
if services.GetReportReceiverHttpUrl() != "" {
tenant.GetConfigObj().CloudReportURL = services.GetReportReceiverHttpUrl()
}
if err = tenant.UpdateCachedConfig(); err != nil {
logger.L().Error("failed to update cached config", helpers.Error(err))
}
ksCloud, err := v1.NewKSCloudAPI(
services.GetApiServerUrl(),
services.GetReportReceiverHttpUrl(),
"",
"",
)
if err != nil {
logger.L().Fatal("failed to create KS Cloud client", helpers.Error(err))
return
}
getter.SetKSCloudAPIConnector(ksCloud)
}

View File

@@ -1,6 +1,7 @@
package scan
import (
"context"
"fmt"
"io"
"os"
@@ -10,36 +11,36 @@ import (
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/kubescape/v2/core/meta"
"github.com/kubescape/kubescape/v3/cmd/shared"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/meta"
"github.com/enescakir/emoji"
"github.com/spf13/cobra"
)
var (
controlExample = `
controlExample = fmt.Sprintf(`
# Scan the 'privileged container' control
kubescape scan control "privileged container"
%[1]s scan control "privileged container"
# Scan list of controls separated with a comma
kubescape scan control "privileged container","HostPath mount"
%[1]s scan control "privileged container","HostPath mount"
# Scan list of controls using the control ID separated with a comma
kubescape scan control C-0058,C-0057
%[1]s scan control C-0058,C-0057
Run 'kubescape list controls' for the list of supported controls
Run '%[1]s list controls' for the list of supported controls
Control documentation:
https://hub.armosec.io/docs/controls
`
`, cautils.ExecName())
)
// controlCmd represents the control command
func getControlCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Command {
return &cobra.Command{
Use: "control <control names list>/<control ids list>",
Short: "The controls you wish to use. Run 'kubescape list controls' for the list of supported controls",
Short: fmt.Sprintf("The controls you wish to use. Run '%[1]s list controls' for the list of supported controls", cautils.ExecName()),
Example: controlExample,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
@@ -67,7 +68,7 @@ func getControlCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comman
if len(args) == 0 {
scanInfo.ScanAll = true
} else { // expected control or list of control sepparated by ","
} else { // expected control or list of control separated by ","
// Read controls from input args
scanInfo.SetPolicyIdentifiers(strings.Split(args[0], ","), apisv1.KindControl)
@@ -91,24 +92,29 @@ func getControlCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comman
}
scanInfo.FrameworkScan = false
scanInfo.SetScanType(cautils.ScanTypeControl)
if err := validateControlScanInfo(scanInfo); err != nil {
return err
}
results, err := ks.Scan(scanInfo)
ctx := context.TODO()
results, err := ks.Scan(ctx, scanInfo)
if err != nil {
logger.L().Fatal(err.Error())
}
if err := results.HandleResults(); err != nil {
if err := results.HandleResults(ctx); err != nil {
logger.L().Fatal(err.Error())
}
if !scanInfo.VerboseMode {
cautils.SimpleDisplay(os.Stderr, "%s Run with '--verbose'/'-v' flag for detailed resources view\n\n", emoji.Detective)
logger.L().Info("Run with '--verbose'/'-v' flag for detailed resources view\n")
}
if results.GetRiskScore() > float32(scanInfo.FailThreshold) {
logger.L().Fatal("scan risk-score is above permitted threshold", helpers.String("risk-score", fmt.Sprintf("%.2f", results.GetRiskScore())), helpers.String("fail-threshold", fmt.Sprintf("%.2f", scanInfo.FailThreshold)))
}
if results.GetComplianceScore() < float32(scanInfo.ComplianceThreshold) {
logger.L().Fatal("scan compliance-score is below permitted threshold", helpers.String("compliance score", fmt.Sprintf("%.2f", results.GetComplianceScore())), helpers.String("compliance-threshold", fmt.Sprintf("%.2f", scanInfo.ComplianceThreshold)))
}
enforceSeverityThresholds(results.GetResults().SummaryDetails.GetResourcesSeverityCounters(), scanInfo, terminateOnExceedingSeverity)
return nil
@@ -124,7 +130,7 @@ func validateControlScanInfo(scanInfo *cautils.ScanInfo) error {
return fmt.Errorf("you can use `omit-raw-resources` or `submit`, but not both")
}
if err := validateSeverity(severity); severity != "" && err != nil {
if err := shared.ValidateSeverity(severity); severity != "" && err != nil {
return err
}
return nil

View File

@@ -1,6 +1,7 @@
package scan
import (
"context"
"errors"
"fmt"
"io"
@@ -10,43 +11,49 @@ import (
apisv1 "github.com/kubescape/opa-utils/httpserver/apis/v1"
reporthandlingapis "github.com/kubescape/opa-utils/reporthandling/apis"
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
"golang.org/x/exp/slices"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/kubescape/v2/core/meta"
"github.com/kubescape/kubescape/v3/cmd/shared"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/cautils/getter"
"github.com/kubescape/kubescape/v3/core/meta"
"github.com/spf13/cobra"
)
var (
frameworkExample = `
frameworkExample = fmt.Sprintf(`
# Scan all frameworks
kubescape scan framework all
%[1]s scan framework all
# Scan the NSA framework
kubescape scan framework nsa
%[1]s scan framework nsa
# Scan the NSA and MITRE framework
kubescape scan framework nsa,mitre
%[1]s scan framework nsa,mitre
# Scan all frameworks
kubescape scan framework all
%[1]s scan framework all
# Scan kubernetes YAML manifest files (single file or glob)
kubescape scan framework nsa .
%[1]s scan framework nsa .
Run 'kubescape list frameworks' for the list of supported frameworks
`
Run '%[1]s list frameworks' for the list of supported frameworks
`, cautils.ExecName())
ErrUnknownSeverity = errors.New("unknown severity")
ErrSecurityViewNotSupported = errors.New("security view is not supported for framework scan")
ErrBadThreshold = errors.New("bad argument: out of range threshold")
ErrKeepLocalOrSubmit = errors.New("you can use `keep-local` or `submit`, but not both")
ErrOmitRawResourcesOrSubmit = errors.New("you can use `omit-raw-resources` or `submit`, but not both")
)
func getFrameworkCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Command {
return &cobra.Command{
Use: "framework <framework names list> [`<glob pattern>`/`-`] [flags]",
Short: "The framework you wish to use. Run 'kubescape list frameworks' for the list of supported frameworks",
Short: fmt.Sprintf("The framework you wish to use. Run '%[1]s list frameworks' for the list of supported frameworks", cautils.ExecName()),
Example: frameworkExample,
Long: "Execute a scan on a running Kubernetes cluster or `yaml`/`json` files (use glob) or `-` for stdin",
Args: func(cmd *cobra.Command, args []string) error {
@@ -71,20 +78,25 @@ func getFrameworkCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comm
}
scanInfo.FrameworkScan = true
// We do not scan all frameworks by default when triggering scan from the CLI
scanInfo.ScanAll = false
var frameworks []string
if len(args) == 0 { // scan all frameworks
if len(args) == 0 {
scanInfo.ScanAll = true
} else {
// Read frameworks from input args
frameworks = strings.Split(args[0], ",")
if cautils.StringInSlice(frameworks, "all") != cautils.ValueNotFound {
if slices.Contains(frameworks, "all") {
scanInfo.ScanAll = true
frameworks = []string{}
frameworks = getter.NativeFrameworks
}
if len(args) > 1 {
if len(args[1:]) == 0 || args[1] != "-" {
scanInfo.InputPatterns = args[1:]
logger.L().Debug("List of input files", helpers.Interface("patterns", scanInfo.InputPatterns))
} else { // store stdin to file - do NOT move to separate function !!
tempFile, err := os.CreateTemp(".", "tmp-kubescape*.yaml")
if err != nil {
@@ -99,35 +111,42 @@ func getFrameworkCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comm
}
}
}
scanInfo.SetScanType(cautils.ScanTypeFramework)
scanInfo.FrameworkScan = true
scanInfo.SetPolicyIdentifiers(frameworks, apisv1.KindFramework)
results, err := ks.Scan(scanInfo)
ctx := context.TODO()
results, err := ks.Scan(ctx, scanInfo)
if err != nil {
logger.L().Fatal(err.Error())
}
if err = results.HandleResults(); err != nil {
if err = results.HandleResults(ctx); err != nil {
logger.L().Fatal(err.Error())
}
if !scanInfo.VerboseMode {
cautils.SimpleDisplay(os.Stderr, "Run with '--verbose'/'-v' flag for detailed resources view\n\n")
if !scanInfo.VerboseMode && scanInfo.ScanType == cautils.ScanTypeFramework {
logger.L().Info("Run with '--verbose'/'-v' flag for detailed resources view\n")
}
if results.GetRiskScore() > float32(scanInfo.FailThreshold) {
logger.L().Fatal("scan risk-score is above permitted threshold", helpers.String("risk-score", fmt.Sprintf("%.2f", results.GetRiskScore())), helpers.String("fail-threshold", fmt.Sprintf("%.2f", scanInfo.FailThreshold)))
}
if results.GetComplianceScore() < float32(scanInfo.ComplianceThreshold) {
logger.L().Fatal("scan compliance-score is below permitted threshold", helpers.String("compliance-score", fmt.Sprintf("%.2f", results.GetComplianceScore())), helpers.String("compliance-threshold", fmt.Sprintf("%.2f", scanInfo.ComplianceThreshold)))
}
enforceSeverityThresholds(results.GetData().Report.SummaryDetails.GetResourcesSeverityCounters(), scanInfo, terminateOnExceedingSeverity)
return nil
},
}
}
// countersExceedSeverityThreshold returns true if severity of failed controls exceed the set severity threshold, else returns false
func countersExceedSeverityThreshold(severityCounters reportsummary.ISeverityCounters, scanInfo *cautils.ScanInfo) (bool, error) {
targetSeverity := scanInfo.FailThresholdSeverity
if err := validateSeverity(targetSeverity); err != nil {
if err := shared.ValidateSeverity(targetSeverity); err != nil {
return false, err
}
@@ -161,14 +180,14 @@ func countersExceedSeverityThreshold(severityCounters reportsummary.ISeverityCou
}
// terminateOnExceedingSeverity terminates the application on exceeding severity
func terminateOnExceedingSeverity(scanInfo *cautils.ScanInfo, l logger.ILogger) {
func terminateOnExceedingSeverity(scanInfo *cautils.ScanInfo, l helpers.ILogger) {
l.Fatal("result exceeds severity threshold", helpers.String("set severity threshold", scanInfo.FailThresholdSeverity))
}
// enforceSeverityThresholds ensures that the scan results are below the defined severity threshold
//
// The function forces the application to terminate with an exit code 1 if at least one control failed control that exceeds the set severity threshold
func enforceSeverityThresholds(severityCounters reportsummary.ISeverityCounters, scanInfo *cautils.ScanInfo, onExceed func(*cautils.ScanInfo, logger.ILogger)) {
func enforceSeverityThresholds(severityCounters reportsummary.ISeverityCounters, scanInfo *cautils.ScanInfo, onExceed func(*cautils.ScanInfo, helpers.ILogger)) {
// If a severity threshold is not set, we dont need to enforce it
if scanInfo.FailThresholdSeverity == "" {
return
@@ -181,33 +200,29 @@ func enforceSeverityThresholds(severityCounters reportsummary.ISeverityCounters,
}
}
// validateSeverity returns an error if a given severity is not known, nil otherwise
func validateSeverity(severity string) error {
for _, val := range reporthandlingapis.GetSupportedSeverities() {
if strings.EqualFold(severity, val) {
return nil
}
}
return ErrUnknownSeverity
}
// validateFrameworkScanInfo validates the scan info struct for the `scan framework` command
func validateFrameworkScanInfo(scanInfo *cautils.ScanInfo) error {
if scanInfo.View == string(cautils.SecurityViewType) {
scanInfo.View = string(cautils.ResourceViewType)
}
if scanInfo.Submit && scanInfo.Local {
return fmt.Errorf("you can use `keep-local` or `submit`, but not both")
return ErrKeepLocalOrSubmit
}
if 100 < scanInfo.ComplianceThreshold || 0 > scanInfo.ComplianceThreshold {
return ErrBadThreshold
}
if 100 < scanInfo.FailThreshold || 0 > scanInfo.FailThreshold {
return fmt.Errorf("bad argument: out of range threshold")
return ErrBadThreshold
}
if scanInfo.Submit && scanInfo.OmitRawResources {
return fmt.Errorf("you can use `omit-raw-resources` or `submit`, but not both")
return ErrOmitRawResourcesOrSubmit
}
severity := scanInfo.FailThresholdSeverity
if err := validateSeverity(severity); severity != "" && err != nil {
if err := shared.ValidateSeverity(severity); severity != "" && err != nil {
return err
}
// Validate the user's credentials
return scanInfo.Credentials.Validate()
return cautils.ValidateAccountID(scanInfo.AccountID)
}

72
cmd/scan/image.go Normal file
View File

@@ -0,0 +1,72 @@
package scan
import (
"context"
"fmt"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v3/cmd/shared"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/meta"
metav1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
"github.com/kubescape/kubescape/v3/pkg/imagescan"
"github.com/spf13/cobra"
)
// TODO(vladklokun): document image scanning on the Kubescape Docs Hub?
var (
imageExample = fmt.Sprintf(`
Scan an image for vulnerabilities.
# Scan the 'nginx' image
%[1]s scan image "nginx"
# Scan the 'nginx' image and see the full report
%[1]s scan image "nginx" -v
`, cautils.ExecName())
)
// getImageCmd returns the scan image command
func getImageCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Command {
var imgCredentials shared.ImageCredentials
cmd := &cobra.Command{
Use: "image <image>:<tag> [flags]",
Short: "Scan an image for vulnerabilities",
Example: imageExample,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return fmt.Errorf("the command takes exactly one image name as an argument")
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
if err := shared.ValidateImageScanInfo(scanInfo); err != nil {
return err
}
imgScanInfo := &metav1.ImageScanInfo{
Image: args[0],
Username: imgCredentials.Username,
Password: imgCredentials.Password,
}
results, err := ks.ScanImage(context.Background(), imgScanInfo, scanInfo)
if err != nil {
return err
}
if imagescan.ExceedsSeverityThreshold(results, imagescan.ParseSeverity(scanInfo.FailThresholdSeverity)) {
shared.TerminateOnExceedingSeverity(scanInfo, logger.L())
}
return nil
},
}
cmd.PersistentFlags().StringVarP(&imgCredentials.Username, "username", "u", "", "Username for registry login")
cmd.PersistentFlags().StringVarP(&imgCredentials.Password, "password", "p", "", "Password for registry login")
return cmd
}

View File

@@ -1,34 +1,36 @@
package scan
import (
"context"
"flag"
"fmt"
"strings"
"github.com/kubescape/k8s-interface/k8sinterface"
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/kubescape/v2/core/meta"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/cautils/getter"
"github.com/kubescape/kubescape/v3/core/meta"
v1 "github.com/kubescape/opa-utils/httpserver/apis/v1"
"github.com/spf13/cobra"
)
var scanCmdExamples = `
var scanCmdExamples = fmt.Sprintf(`
Scan command is for scanning an existing cluster or kubernetes manifest files based on pre-defined frameworks
# Scan current cluster with all frameworks
kubescape scan --enable-host-scan --verbose
# Scan current cluster
%[1]s scan
# Scan kubernetes YAML manifest files
kubescape scan .
# Scan kubernetes manifest files
%[1]s scan .
# Scan and save the results in the JSON format
kubescape scan --format json --output results.json --format-version=v2
%[1]s scan --format json --output results.json
# Display all resources
kubescape scan --verbose
%[1]s scan --verbose
# Scan different clusters from the kubectl context
kubescape scan --kube-context <kubernetes context>
`
%[1]s scan --kube-context <kubernetes context>
`, cautils.ExecName())
func GetScanCommand(ks meta.IKubescape) *cobra.Command {
var scanInfo cautils.ScanInfo
@@ -36,46 +38,34 @@ func GetScanCommand(ks meta.IKubescape) *cobra.Command {
// scanCmd represents the scan command
scanCmd := &cobra.Command{
Use: "scan",
Short: "Scan the current running cluster or yaml files",
Short: "Scan a Kubernetes cluster or YAML files for image vulnerabilities and misconfigurations",
Long: `The action you want to perform`,
Example: scanCmdExamples,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
if args[0] != "framework" && args[0] != "control" {
scanInfo.ScanAll = true
return getFrameworkCmd(ks, &scanInfo).RunE(cmd, append([]string{"all"}, args...))
}
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
if scanInfo.View == string(cautils.SecurityViewType) {
setSecurityViewScanInfo(args, &scanInfo)
if len(args) == 0 {
scanInfo.ScanAll = true
return getFrameworkCmd(ks, &scanInfo).RunE(cmd, []string{"all"})
return securityScan(scanInfo, ks)
}
if len(args) == 0 || (args[0] != "framework" && args[0] != "control") {
return getFrameworkCmd(ks, &scanInfo).RunE(cmd, append([]string{strings.Join(getter.NativeFrameworks, ",")}, args...))
}
return nil
},
PreRun: func(cmd *cobra.Command, args []string) {
k8sinterface.SetClusterContextName(scanInfo.KubeContext)
},
PostRun: func(cmd *cobra.Command, args []string) {
// TODO - revert context
},
}
scanCmd.PersistentFlags().StringVarP(&scanInfo.Credentials.Account, "account", "", "", "Kubescape SaaS account ID. Default will load account ID from cache")
scanCmd.PersistentFlags().BoolVar(&scanInfo.CreateAccount, "create-account", false, "Create a Kubescape SaaS account ID account ID is not found in cache. After creating the account, the account ID will be saved in cache. In addition, the scanning results will be uploaded to the Kubescape SaaS")
scanCmd.PersistentFlags().StringVarP(&scanInfo.Credentials.ClientID, "client-id", "", "", "Kubescape SaaS client ID. Default will load client ID from cache, read more - https://hub.armosec.io/docs/authentication")
scanCmd.PersistentFlags().StringVarP(&scanInfo.Credentials.SecretKey, "secret-key", "", "", "Kubescape SaaS secret key. Default will load secret key from cache, read more - https://hub.armosec.io/docs/authentication")
scanCmd.PersistentFlags().StringVarP(&scanInfo.KubeContext, "kube-context", "", "", "Kube context. Default will use the current-context")
scanCmd.PersistentFlags().StringVarP(&scanInfo.AccountID, "account", "", "", "Kubescape SaaS account ID. Default will load account ID from cache")
scanCmd.PersistentFlags().StringVar(&scanInfo.ControlsInputs, "controls-config", "", "Path to an controls-config obj. If not set will download controls-config from ARMO management portal")
scanCmd.PersistentFlags().StringVar(&scanInfo.UseExceptions, "exceptions", "", "Path to an exceptions obj. If not set will download exceptions from ARMO management portal")
scanCmd.PersistentFlags().StringVar(&scanInfo.UseArtifactsFrom, "use-artifacts-from", "", "Load artifacts from local directory. If not used will download them")
scanCmd.PersistentFlags().StringVarP(&scanInfo.ExcludedNamespaces, "exclude-namespaces", "e", "", "Namespaces to exclude from scanning. Notice, when running with `exclude-namespace` kubescape does not scan cluster-scoped objects.")
scanCmd.PersistentFlags().StringVarP(&scanInfo.ExcludedNamespaces, "exclude-namespaces", "e", "", "Namespaces to exclude from scanning. e.g: --exclude-namespaces ns-a,ns-b. Notice, when running with `exclude-namespace` kubescape does not scan cluster-scoped objects.")
scanCmd.PersistentFlags().Float32VarP(&scanInfo.FailThreshold, "fail-threshold", "t", 100, "Failure threshold is the percent above which the command fails and returns exit code 1")
scanCmd.PersistentFlags().Float32VarP(&scanInfo.ComplianceThreshold, "compliance-threshold", "", 0, "Compliance threshold is the percent below which the command fails and returns exit code 1")
scanCmd.PersistentFlags().StringVar(&scanInfo.FailThresholdSeverity, "severity-threshold", "", "Severity threshold is the severity of failed controls at which the command fails and returns exit code 1")
scanCmd.PersistentFlags().StringVarP(&scanInfo.Format, "format", "f", "", `Output file format. Supported formats: "pretty-printer", "json", "junit", "prometheus", "pdf", "html", "sarif"`)
@@ -83,20 +73,25 @@ func GetScanCommand(ks meta.IKubescape) *cobra.Command {
scanCmd.PersistentFlags().BoolVarP(&scanInfo.Local, "keep-local", "", false, "If you do not want your Kubescape results reported to configured backend.")
scanCmd.PersistentFlags().StringVarP(&scanInfo.Output, "output", "o", "", "Output file. Print output to file and not stdout")
scanCmd.PersistentFlags().BoolVarP(&scanInfo.VerboseMode, "verbose", "v", false, "Display all of the input resources and not only failed resources")
scanCmd.PersistentFlags().StringVar(&scanInfo.View, "view", string(cautils.ResourceViewType), fmt.Sprintf("View results based on the %s/%s. default is --view=%s", cautils.ResourceViewType, cautils.ControlViewType, cautils.ResourceViewType))
scanCmd.PersistentFlags().StringVar(&scanInfo.View, "view", string(cautils.SecurityViewType), fmt.Sprintf("View results based on the %s/%s/%s. default is --view=%s", cautils.ResourceViewType, cautils.ControlViewType, cautils.SecurityViewType, cautils.SecurityViewType))
scanCmd.PersistentFlags().BoolVar(&scanInfo.UseDefault, "use-default", false, "Load local policy object from default path. If not used will download latest")
scanCmd.PersistentFlags().StringSliceVar(&scanInfo.UseFrom, "use-from", nil, "Load local policy object from specified path. If not used will download latest")
scanCmd.PersistentFlags().StringVar(&scanInfo.HostSensorYamlPath, "host-scan-yaml", "", "Override default host scanner DaemonSet. Use this flag cautiously")
scanCmd.PersistentFlags().StringVar(&scanInfo.FormatVersion, "format-version", "v1", "Output object can be different between versions, this is for maintaining backward and forward compatibility. Supported:'v1'/'v2'")
scanCmd.PersistentFlags().StringVar(&scanInfo.FormatVersion, "format-version", "v2", "Output object can be different between versions, this is for maintaining backward and forward compatibility. Supported:'v1'/'v2'")
scanCmd.PersistentFlags().StringVar(&scanInfo.CustomClusterName, "cluster-name", "", "Set the custom name of the cluster. Not same as the kube-context flag")
scanCmd.PersistentFlags().BoolVarP(&scanInfo.Submit, "submit", "", false, "Submit the scan results to Kubescape SaaS where you can see the results in a user-friendly UI, choose your preferred compliance framework, check risk results history and trends, manage exceptions, get remediation recommendations and much more. By default the results are not submitted")
scanCmd.PersistentFlags().BoolVarP(&scanInfo.OmitRawResources, "omit-raw-resources", "", false, "Omit raw resources from the output. By default the raw resources are included in the output")
scanCmd.PersistentFlags().BoolVarP(&scanInfo.PrintAttackTree, "print-attack-tree", "", false, "Print attack tree")
scanCmd.PersistentFlags().BoolVarP(&scanInfo.ScanImages, "scan-images", "", false, "Scan resources images")
scanCmd.PersistentFlags().MarkDeprecated("silent", "use '--logger' flag instead. Flag will be removed at 1.May.2022")
scanCmd.PersistentFlags().MarkDeprecated("fail-threshold", "use '--compliance-threshold' flag instead. Flag will be removed at 1.Dec.2023")
scanCmd.PersistentFlags().MarkDeprecated("client-id", "Client ID is no longer supported. Feel free to contact the Kubescape maintainers for more information.")
scanCmd.PersistentFlags().MarkDeprecated("create-account", "Create account is no longer supported. In case of a missing Account ID and a configured backend server, a new account id will be generated automatically by Kubescape. Feel free to contact the Kubescape maintainers for more information.")
scanCmd.PersistentFlags().MarkDeprecated("secret-key", "Secret Key is no longer supported. Feel free to contact the Kubescape maintainers for more information.")
// hidden flags
scanCmd.PersistentFlags().MarkHidden("host-scan-yaml") // this flag should be used very cautiously. We prefer users will not use it at all unless the DaemonSet can not run pods on the nodes
scanCmd.PersistentFlags().MarkHidden("omit-raw-resources")
scanCmd.PersistentFlags().MarkHidden("print-attack-tree")
@@ -106,9 +101,45 @@ func GetScanCommand(ks meta.IKubescape) *cobra.Command {
hostF := scanCmd.PersistentFlags().VarPF(&scanInfo.HostSensorEnabled, "enable-host-scan", "", "Deploy Kubescape host-sensor daemonset in the scanned cluster. Deleting it right after we collecting the data. Required to collect valuable data from cluster nodes for certain controls. Yaml file: https://github.com/kubescape/kubescape/blob/master/core/pkg/hostsensorutils/hostsensor.yaml")
hostF.NoOptDefVal = "true"
hostF.DefValue = "false, for no TTY in stdin"
scanCmd.PersistentFlags().MarkHidden("enable-host-scan")
scanCmd.PersistentFlags().MarkDeprecated("enable-host-scan", "To activate the host scanner capability, proceed with the installation of the kubescape operator chart found here: https://github.com/kubescape/helm-charts/tree/main/charts/kubescape-operator. The flag will be removed at 1.Dec.2023")
scanCmd.PersistentFlags().MarkHidden("host-scan-yaml") // this flag should be used very cautiously. We prefer users will not use it at all unless the DaemonSet can not run pods on the nodes
scanCmd.PersistentFlags().MarkDeprecated("host-scan-yaml", "To activate the host scanner capability, proceed with the installation of the kubescape operator chart found here: https://github.com/kubescape/helm-charts/tree/main/charts/kubescape-operator. The flag will be removed at 1.Dec.2023")
scanCmd.AddCommand(getControlCmd(ks, &scanInfo))
scanCmd.AddCommand(getFrameworkCmd(ks, &scanInfo))
scanCmd.AddCommand(getWorkloadCmd(ks, &scanInfo))
scanCmd.AddCommand(getImageCmd(ks, &scanInfo))
return scanCmd
}
func setSecurityViewScanInfo(args []string, scanInfo *cautils.ScanInfo) {
if len(args) > 0 {
scanInfo.SetScanType(cautils.ScanTypeRepo)
scanInfo.InputPatterns = args
} else {
scanInfo.SetScanType(cautils.ScanTypeCluster)
}
scanInfo.SetPolicyIdentifiers([]string{"clusterscan", "mitre", "nsa"}, v1.KindFramework)
}
func securityScan(scanInfo cautils.ScanInfo, ks meta.IKubescape) error {
ctx := context.TODO()
results, err := ks.Scan(ctx, &scanInfo)
if err != nil {
return err
}
if err = results.HandleResults(ctx); err != nil {
return err
}
enforceSeverityThresholds(results.GetData().Report.SummaryDetails.GetResourcesSeverityCounters(), &scanInfo, terminateOnExceedingSeverity)
return nil
}

View File

@@ -1,10 +1,13 @@
package scan
import (
logger "github.com/kubescape/go-logger"
"context"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/kubescape/v3/cmd/shared"
"github.com/kubescape/kubescape/v3/core/cautils"
v1 "github.com/kubescape/opa-utils/httpserver/apis/v1"
"github.com/kubescape/opa-utils/reporthandling/apis"
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
@@ -110,7 +113,7 @@ func TestExceedsSeverity(t *testing.T) {
ScanInfo: &cautils.ScanInfo{FailThresholdSeverity: "unknown"},
SeverityCounters: &reportsummary.SeverityCounters{LowSeverityCounter: 1},
Want: false,
Error: ErrUnknownSeverity,
Error: shared.ErrUnknownSeverity,
},
}
@@ -160,7 +163,7 @@ func Test_enforceSeverityThresholds(t *testing.T) {
want := tc.Want
got := false
onExceed := func(*cautils.ScanInfo, logger.ILogger) {
onExceed := func(*cautils.ScanInfo, helpers.ILogger) {
got = true
}
@@ -183,16 +186,20 @@ type spyLogger struct {
setItems []spyLogMessage
}
func (l *spyLogger) Error(msg string, details ...helpers.IDetails) {}
func (l *spyLogger) Success(msg string, details ...helpers.IDetails) {}
func (l *spyLogger) Warning(msg string, details ...helpers.IDetails) {}
func (l *spyLogger) Info(msg string, details ...helpers.IDetails) {}
func (l *spyLogger) Debug(msg string, details ...helpers.IDetails) {}
func (l *spyLogger) SetLevel(level string) error { return nil }
func (l *spyLogger) GetLevel() string { return "" }
func (l *spyLogger) SetWriter(w *os.File) {}
func (l *spyLogger) GetWriter() *os.File { return &os.File{} }
func (l *spyLogger) LoggerName() string { return "" }
func (l *spyLogger) Error(msg string, details ...helpers.IDetails) {}
func (l *spyLogger) Success(msg string, details ...helpers.IDetails) {}
func (l *spyLogger) Warning(msg string, details ...helpers.IDetails) {}
func (l *spyLogger) Info(msg string, details ...helpers.IDetails) {}
func (l *spyLogger) Debug(msg string, details ...helpers.IDetails) {}
func (l *spyLogger) SetLevel(level string) error { return nil }
func (l *spyLogger) GetLevel() string { return "" }
func (l *spyLogger) SetWriter(w *os.File) {}
func (l *spyLogger) GetWriter() *os.File { return &os.File{} }
func (l *spyLogger) LoggerName() string { return "" }
func (l *spyLogger) Ctx(_ context.Context) helpers.ILogger { return l }
func (l *spyLogger) Start(msg string, details ...helpers.IDetails) {}
func (l *spyLogger) StopSuccess(msg string, details ...helpers.IDetails) {}
func (l *spyLogger) StopError(msg string, details ...helpers.IDetails) {}
func (l *spyLogger) Fatal(msg string, details ...helpers.IDetails) {
firstDetail := details[0]
@@ -252,3 +259,106 @@ func Test_terminateOnExceedingSeverity(t *testing.T) {
)
}
}
func TestSetSecurityViewScanInfo(t *testing.T) {
tests := []struct {
name string
args []string
want *cautils.ScanInfo
}{
{
name: "no args",
args: []string{},
want: &cautils.ScanInfo{
InputPatterns: []string{},
ScanType: cautils.ScanTypeCluster,
PolicyIdentifier: []cautils.PolicyIdentifier{
{
Kind: v1.KindFramework,
Identifier: "clusterscan",
},
{
Kind: v1.KindFramework,
Identifier: "mitre",
},
{
Kind: v1.KindFramework,
Identifier: "nsa",
},
},
},
},
{
name: "with args",
args: []string{
"file.yaml",
"file2.yaml",
},
want: &cautils.ScanInfo{
ScanType: cautils.ScanTypeRepo,
InputPatterns: []string{
"file.yaml",
"file2.yaml",
},
PolicyIdentifier: []cautils.PolicyIdentifier{
{
Kind: v1.KindFramework,
Identifier: "clusterscan",
},
{
Kind: v1.KindFramework,
Identifier: "mitre",
},
{
Kind: v1.KindFramework,
Identifier: "nsa",
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := &cautils.ScanInfo{
View: string(cautils.SecurityViewType),
}
setSecurityViewScanInfo(tt.args, got)
if len(tt.want.InputPatterns) != len(got.InputPatterns) {
t.Errorf("in test: %s, got: %v, want: %v", tt.name, got.InputPatterns, tt.want.InputPatterns)
}
if tt.want.ScanType != got.ScanType {
t.Errorf("in test: %s, got: %v, want: %v", tt.name, got.ScanType, tt.want.ScanType)
}
for i := range tt.want.InputPatterns {
found := false
for j := range tt.want.InputPatterns[i] {
if tt.want.InputPatterns[i][j] == got.InputPatterns[i][j] {
found = true
break
}
}
if !found {
t.Errorf("in test: %s, got: %v, want: %v", tt.name, got.InputPatterns, tt.want.InputPatterns)
}
}
for i := range tt.want.PolicyIdentifier {
found := false
for j := range got.PolicyIdentifier {
if tt.want.PolicyIdentifier[i].Kind == got.PolicyIdentifier[j].Kind && tt.want.PolicyIdentifier[i].Identifier == got.PolicyIdentifier[j].Identifier {
found = true
break
}
}
if !found {
t.Errorf("in test: %s, got: %v, want: %v", tt.name, got.PolicyIdentifier, tt.want.PolicyIdentifier)
}
}
})
}
}

View File

@@ -3,7 +3,8 @@ package scan
import (
"testing"
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/kubescape/v3/cmd/shared"
"github.com/kubescape/kubescape/v3/core/cautils"
)
// Test_validateControlScanInfo tests how scan info is validated for the `scan control` command
@@ -26,7 +27,7 @@ func Test_validateControlScanInfo(t *testing.T) {
{
"Unknown severity should be invalid for scan info",
&cautils.ScanInfo{FailThresholdSeverity: "Unknown"},
ErrUnknownSeverity,
shared.ErrUnknownSeverity,
},
}
@@ -66,7 +67,17 @@ func Test_validateFrameworkScanInfo(t *testing.T) {
{
"Unknown severity should be invalid for scan info",
&cautils.ScanInfo{FailThresholdSeverity: "Unknown"},
ErrUnknownSeverity,
shared.ErrUnknownSeverity,
},
{
"Security view should be invalid for scan info",
&cautils.ScanInfo{View: string(cautils.SecurityViewType)},
nil,
},
{
"Empty view should be valid for scan info",
&cautils.ScanInfo{},
nil,
},
}
@@ -86,27 +97,22 @@ func Test_validateFrameworkScanInfo(t *testing.T) {
}
}
func Test_validateSeverity(t *testing.T) {
func Test_validateWorkloadIdentifier(t *testing.T) {
testCases := []struct {
Description string
Input string
Want error
}{
{"low should be a valid severity", "low", nil},
{"Low should be a valid severity", "Low", nil},
{"medium should be a valid severity", "medium", nil},
{"Medium should be a valid severity", "Medium", nil},
{"high should be a valid severity", "high", nil},
{"Critical should be a valid severity", "Critical", nil},
{"critical should be a valid severity", "critical", nil},
{"Unknown should be an invalid severity", "Unknown", ErrUnknownSeverity},
{"valid workload identifier should be valid", "deployment/test", nil},
{"invalid workload identifier missing kind", "deployment", ErrInvalidWorkloadIdentifier},
{"invalid workload identifier with namespace", "ns/deployment/name", ErrInvalidWorkloadIdentifier},
}
for _, testCase := range testCases {
t.Run(testCase.Description, func(t *testing.T) {
input := testCase.Input
want := testCase.Want
got := validateSeverity(input)
got := validateWorkloadIdentifier(input)
if got != want {
t.Errorf("got: %v, want: %v", got, want)

124
cmd/scan/workload.go Normal file
View File

@@ -0,0 +1,124 @@
package scan
import (
"context"
"errors"
"fmt"
"strings"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/meta"
v1 "github.com/kubescape/opa-utils/httpserver/apis/v1"
"github.com/kubescape/opa-utils/objectsenvelopes"
"github.com/spf13/cobra"
)
var (
workloadExample = fmt.Sprintf(`
Scan a workload for misconfigurations and image vulnerabilities.
# Scan an workload
%[1]s scan workload <kind>/<name>
# Scan an workload in a specific namespace
%[1]s scan workload <kind>/<name> --namespace <namespace>
# Scan an workload from a file path
%[1]s scan workload <kind>/<name> --file-path <file path>
# Scan an workload from a helm-chart template
%[1]s scan workload <kind>/<name> --chart-path <chart path> --file-path <file path>
`, cautils.ExecName())
ErrInvalidWorkloadIdentifier = errors.New("invalid workload identifier")
)
var namespace string
// controlCmd represents the control command
func getWorkloadCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Command {
workloadCmd := &cobra.Command{
Use: "workload <kind>/<name> [`<glob pattern>`/`-`] [flags]",
Short: "Scan a workload for misconfigurations and image vulnerabilities",
Example: workloadExample,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return fmt.Errorf("usage: <kind>/<name> [`<glob pattern>`/`-`] [flags]")
}
if scanInfo.ChartPath != "" && scanInfo.FilePath == "" {
return fmt.Errorf("usage: --chart-path <chart path> --file-path <file path>")
}
return validateWorkloadIdentifier(args[0])
},
RunE: func(cmd *cobra.Command, args []string) error {
kind, name, err := parseWorkloadIdentifierString(args[0])
if err != nil {
return fmt.Errorf("invalid input: %s", err.Error())
}
setWorkloadScanInfo(scanInfo, kind, name)
// todo: add api version if provided
ctx := context.TODO()
results, err := ks.Scan(ctx, scanInfo)
if err != nil {
logger.L().Fatal(err.Error())
}
if err = results.HandleResults(ctx); err != nil {
logger.L().Fatal(err.Error())
}
return nil
},
}
workloadCmd.PersistentFlags().StringVarP(&namespace, "namespace", "n", "", "Namespace of the workload. Default will be empty.")
workloadCmd.PersistentFlags().StringVar(&scanInfo.FilePath, "file-path", "", "Path to the workload file.")
workloadCmd.PersistentFlags().StringVar(&scanInfo.ChartPath, "chart-path", "", "Path to the helm chart the workload is part of. Must be used with --file-path.")
return workloadCmd
}
func setWorkloadScanInfo(scanInfo *cautils.ScanInfo, kind string, name string) {
scanInfo.SetScanType(cautils.ScanTypeWorkload)
scanInfo.ScanImages = true
scanInfo.ScanObject = &objectsenvelopes.ScanObject{}
scanInfo.ScanObject.SetNamespace(namespace)
scanInfo.ScanObject.SetKind(kind)
scanInfo.ScanObject.SetName(name)
scanInfo.SetPolicyIdentifiers([]string{"workloadscan"}, v1.KindFramework)
if scanInfo.FilePath != "" {
scanInfo.InputPatterns = []string{scanInfo.FilePath}
}
}
func validateWorkloadIdentifier(workloadIdentifier string) error {
// workloadIdentifier is in the form of kind/name
x := strings.Split(workloadIdentifier, "/")
if len(x) != 2 || x[0] == "" || x[1] == "" {
return ErrInvalidWorkloadIdentifier
}
return nil
}
func parseWorkloadIdentifierString(workloadIdentifier string) (kind, name string, err error) {
// workloadIdentifier is in the form of namespace/kind/name
// example: default/Deployment/nginx-deployment
x := strings.Split(workloadIdentifier, "/")
if len(x) != 2 {
return "", "", ErrInvalidWorkloadIdentifier
}
return x[0], x[1], nil
}

69
cmd/scan/workload_test.go Normal file
View File

@@ -0,0 +1,69 @@
package scan
import (
"testing"
"github.com/kubescape/kubescape/v3/core/cautils"
v1 "github.com/kubescape/opa-utils/httpserver/apis/v1"
"github.com/kubescape/opa-utils/objectsenvelopes"
)
func TestSetWorkloadScanInfo(t *testing.T) {
test := []struct {
Description string
kind string
name string
want *cautils.ScanInfo
}{
{
Description: "Set workload scan info",
kind: "Deployment",
name: "test",
want: &cautils.ScanInfo{
PolicyIdentifier: []cautils.PolicyIdentifier{
{
Identifier: "workloadscan",
Kind: v1.KindFramework,
},
},
ScanType: cautils.ScanTypeWorkload,
ScanObject: &objectsenvelopes.ScanObject{
Kind: "Deployment",
Metadata: objectsenvelopes.ScanObjectMetadata{
Name: "test",
},
},
},
},
}
for _, tc := range test {
t.Run(
tc.Description,
func(t *testing.T) {
scanInfo := &cautils.ScanInfo{}
setWorkloadScanInfo(scanInfo, tc.kind, tc.name)
if scanInfo.ScanType != tc.want.ScanType {
t.Errorf("got: %v, want: %v", scanInfo.ScanType, tc.want.ScanType)
}
if scanInfo.ScanObject.Kind != tc.want.ScanObject.Kind {
t.Errorf("got: %v, want: %v", scanInfo.ScanObject.Kind, tc.want.ScanObject.Kind)
}
if scanInfo.ScanObject.Metadata.Name != tc.want.ScanObject.Metadata.Name {
t.Errorf("got: %v, want: %v", scanInfo.ScanObject.Metadata.Name, tc.want.ScanObject.Metadata.Name)
}
if len(scanInfo.PolicyIdentifier) != 1 {
t.Errorf("got: %v, want: %v", len(scanInfo.PolicyIdentifier), 1)
}
if scanInfo.PolicyIdentifier[0].Identifier != tc.want.PolicyIdentifier[0].Identifier {
t.Errorf("got: %v, want: %v", scanInfo.PolicyIdentifier[0].Identifier, tc.want.PolicyIdentifier[0].Identifier)
}
},
)
}
}

18
cmd/shared/image_scan.go Normal file
View File

@@ -0,0 +1,18 @@
package shared
import "github.com/kubescape/kubescape/v3/core/cautils"
type ImageCredentials struct {
Username string
Password string
}
// ValidateImageScanInfo validates the ScanInfo struct for image scanning commands
func ValidateImageScanInfo(scanInfo *cautils.ScanInfo) error {
severity := scanInfo.FailThresholdSeverity
if err := ValidateSeverity(severity); severity != "" && err != nil {
return err
}
return nil
}

28
cmd/shared/scan.go Normal file
View File

@@ -0,0 +1,28 @@
package shared
import (
"fmt"
"strings"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/kubescape/v3/core/cautils"
reporthandlingapis "github.com/kubescape/opa-utils/reporthandling/apis"
)
var ErrUnknownSeverity = fmt.Errorf("unknown severity. Supported severities are: %s", strings.Join(reporthandlingapis.GetSupportedSeverities(), ", "))
// ValidateSeverity returns an error if a given severity is not known, nil otherwise
func ValidateSeverity(severity string) error {
for _, val := range reporthandlingapis.GetSupportedSeverities() {
if strings.EqualFold(severity, val) {
return nil
}
}
return ErrUnknownSeverity
}
// TerminateOnExceedingSeverity terminates the program if the result exceeds the severity threshold
func TerminateOnExceedingSeverity(scanInfo *cautils.ScanInfo, l helpers.ILogger) {
l.Fatal("result exceeds severity threshold", helpers.String("Set severity threshold", scanInfo.FailThresholdSeverity))
}

124
cmd/shared/scan_test.go Normal file
View File

@@ -0,0 +1,124 @@
package shared
import (
"context"
"os"
"reflect"
"testing"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/opa-utils/reporthandling/apis"
)
type spyLogMessage struct {
Message string
Details map[string]string
}
type spyLogger struct {
setItems []spyLogMessage
}
func (l *spyLogger) Error(msg string, details ...helpers.IDetails) {}
func (l *spyLogger) Success(msg string, details ...helpers.IDetails) {}
func (l *spyLogger) Warning(msg string, details ...helpers.IDetails) {}
func (l *spyLogger) Info(msg string, details ...helpers.IDetails) {}
func (l *spyLogger) Debug(msg string, details ...helpers.IDetails) {}
func (l *spyLogger) SetLevel(level string) error { return nil }
func (l *spyLogger) GetLevel() string { return "" }
func (l *spyLogger) SetWriter(w *os.File) {}
func (l *spyLogger) GetWriter() *os.File { return &os.File{} }
func (l *spyLogger) LoggerName() string { return "" }
func (l *spyLogger) Ctx(_ context.Context) helpers.ILogger { return l }
func (l *spyLogger) Start(msg string, details ...helpers.IDetails) {}
func (l *spyLogger) StopSuccess(msg string, details ...helpers.IDetails) {}
func (l *spyLogger) StopError(msg string, details ...helpers.IDetails) {}
func (l *spyLogger) Fatal(msg string, details ...helpers.IDetails) {
firstDetail := details[0]
detailsMap := map[string]string{firstDetail.Key(): firstDetail.Value().(string)}
newMsg := spyLogMessage{msg, detailsMap}
l.setItems = append(l.setItems, newMsg)
}
func (l *spyLogger) GetSpiedItems() []spyLogMessage {
return l.setItems
}
func TestTerminateOnExceedingSeverity(t *testing.T) {
expectedMessage := "result exceeds severity threshold"
expectedKey := "Set severity threshold"
testCases := []struct {
Description string
ExpectedMessage string
ExpectedKey string
ExpectedValue string
Logger *spyLogger
}{
{
"Should log the Critical threshold that was set in scan info",
expectedMessage,
expectedKey,
apis.SeverityCriticalString,
&spyLogger{},
},
{
"Should log the High threshold that was set in scan info",
expectedMessage,
expectedKey,
apis.SeverityHighString,
&spyLogger{},
},
}
for _, tc := range testCases {
t.Run(
tc.Description,
func(t *testing.T) {
want := []spyLogMessage{
{tc.ExpectedMessage, map[string]string{tc.ExpectedKey: tc.ExpectedValue}},
}
scanInfo := &cautils.ScanInfo{FailThresholdSeverity: tc.ExpectedValue}
TerminateOnExceedingSeverity(scanInfo, tc.Logger)
got := tc.Logger.GetSpiedItems()
if !reflect.DeepEqual(got, want) {
t.Errorf("got: %v, want: %v", got, want)
}
},
)
}
}
func TestValidateSeverity(t *testing.T) {
testCases := []struct {
Description string
Input string
Want error
}{
{"low should be a valid severity", "low", nil},
{"Low should be a valid severity", "Low", nil},
{"medium should be a valid severity", "medium", nil},
{"Medium should be a valid severity", "Medium", nil},
{"high should be a valid severity", "high", nil},
{"Critical should be a valid severity", "Critical", nil},
{"critical should be a valid severity", "critical", nil},
{"Unknown should be an invalid severity", "Unknown", ErrUnknownSeverity},
}
for _, testCase := range testCases {
t.Run(testCase.Description, func(t *testing.T) {
input := testCase.Input
want := testCase.Want
got := ValidateSeverity(input)
if got != want {
t.Errorf("got: %v, want: %v", got, want)
}
})
}
}

View File

@@ -1,34 +0,0 @@
package submit
import (
"fmt"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v2/core/meta"
metav1 "github.com/kubescape/kubescape/v2/core/meta/datastructures/v1"
"github.com/spf13/cobra"
)
func getExceptionsCmd(ks meta.IKubescape, submitInfo *metav1.Submit) *cobra.Command {
return &cobra.Command{
Use: "exceptions <full path to exceptions file>",
Short: "Submit exceptions to the Kubescape SaaS version",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return fmt.Errorf("missing full path to exceptions file")
}
return nil
},
Run: func(cmd *cobra.Command, args []string) {
if err := flagValidationSubmit(submitInfo); err != nil {
logger.L().Fatal(err.Error())
}
if err := ks.SubmitExceptions(&submitInfo.Credentials, args[0]); err != nil {
logger.L().Fatal(err.Error())
}
},
}
}

View File

@@ -1,97 +0,0 @@
package submit
import (
"fmt"
"github.com/google/uuid"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/k8s-interface/k8sinterface"
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/kubescape/v2/core/cautils/getter"
"github.com/kubescape/kubescape/v2/core/meta"
"github.com/kubescape/kubescape/v2/core/meta/cliinterfaces"
v1 "github.com/kubescape/kubescape/v2/core/meta/datastructures/v1"
reporterv2 "github.com/kubescape/kubescape/v2/core/pkg/resultshandling/reporter/v2"
"github.com/kubescape/rbac-utils/rbacscanner"
"github.com/spf13/cobra"
)
var (
rbacExamples = `
# Submit cluster's Role-Based Access Control(RBAC)
kubescape submit rbac
# Submit cluster's Role-Based Access Control(RBAC) with account ID
kubescape submit rbac --account <account-id>
`
)
// getRBACCmd represents the RBAC command
func getRBACCmd(ks meta.IKubescape, submitInfo *v1.Submit) *cobra.Command {
return &cobra.Command{
Use: "rbac",
Deprecated: "This command is deprecated and will not be supported after 1/Jan/2023. Please use the 'scan' command instead.",
Example: rbacExamples,
Short: "Submit cluster's Role-Based Access Control(RBAC)",
Long: ``,
RunE: func(cmd *cobra.Command, args []string) error {
if err := flagValidationSubmit(submitInfo); err != nil {
return err
}
k8s := k8sinterface.NewKubernetesApi()
// get config
clusterConfig := getTenantConfig(&submitInfo.Credentials, "", "", k8s)
if err := clusterConfig.SetTenant(); err != nil {
logger.L().Error("failed setting account ID", helpers.Error(err))
}
if clusterConfig.GetAccountID() == "" {
return fmt.Errorf("account ID is not set, run 'kubescape submit rbac --account <account-id>'")
}
// list RBAC
rbacObjects := cautils.NewRBACObjects(rbacscanner.NewRbacScannerFromK8sAPI(k8s, clusterConfig.GetAccountID(), clusterConfig.GetContextName()))
// submit resources
r := reporterv2.NewReportEventReceiver(clusterConfig.GetConfigObj(), uuid.NewString(), reporterv2.SubmitContextRBAC)
submitInterfaces := cliinterfaces.SubmitInterfaces{
ClusterConfig: clusterConfig,
SubmitObjects: rbacObjects,
Reporter: r,
}
if err := ks.Submit(submitInterfaces); err != nil {
logger.L().Fatal(err.Error())
}
return nil
},
}
}
// getKubernetesApi
func getKubernetesApi() *k8sinterface.KubernetesApi {
if !k8sinterface.IsConnectedToCluster() {
return nil
}
return k8sinterface.NewKubernetesApi()
}
func getTenantConfig(credentials *cautils.Credentials, clusterName string, customClusterName string, k8s *k8sinterface.KubernetesApi) cautils.ITenantConfig {
if !k8sinterface.IsConnectedToCluster() || k8s == nil {
return cautils.NewLocalConfig(getter.GetKSCloudAPIConnector(), credentials, clusterName, customClusterName)
}
return cautils.NewClusterConfig(k8s, getter.GetKSCloudAPIConnector(), credentials, clusterName, customClusterName)
}
// Check if the flag entered are valid
func flagValidationSubmit(submitInfo *v1.Submit) error {
// Validate the user's credentials
return submitInfo.Credentials.Validate()
}

View File

@@ -1,104 +0,0 @@
package submit
import (
"encoding/json"
"fmt"
"os"
"github.com/google/uuid"
reporthandlingv2 "github.com/kubescape/opa-utils/reporthandling/v2"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/k8s-interface/workloadinterface"
"github.com/kubescape/kubescape/v2/core/meta"
"github.com/kubescape/kubescape/v2/core/meta/cliinterfaces"
v1 "github.com/kubescape/kubescape/v2/core/meta/datastructures/v1"
reporterv2 "github.com/kubescape/kubescape/v2/core/pkg/resultshandling/reporter/v2"
"github.com/spf13/cobra"
)
var formatVersion string
type ResultsObject struct {
filePath string
customerGUID string
clusterName string
}
func NewResultsObject(customerGUID, clusterName, filePath string) *ResultsObject {
return &ResultsObject{
filePath: filePath,
customerGUID: customerGUID,
clusterName: clusterName,
}
}
func (resultsObject *ResultsObject) SetResourcesReport() (*reporthandlingv2.PostureReport, error) {
// load framework results from json file
report, err := loadResultsFromFile(resultsObject.filePath)
if err != nil {
return nil, err
}
return report, nil
}
func (resultsObject *ResultsObject) ListAllResources() (map[string]workloadinterface.IMetadata, error) {
return map[string]workloadinterface.IMetadata{}, nil
}
func getResultsCmd(ks meta.IKubescape, submitInfo *v1.Submit) *cobra.Command {
var resultsCmd = &cobra.Command{
Use: "results <json file>\nExample:\n$ kubescape submit results path/to/results.json --format-version v2",
Short: "Submit a pre scanned results file. The file must be in json format",
Long: ``,
RunE: func(cmd *cobra.Command, args []string) error {
if err := flagValidationSubmit(submitInfo); err != nil {
return err
}
if len(args) == 0 {
return fmt.Errorf("missing results file")
}
k8s := getKubernetesApi()
// get config
clusterConfig := getTenantConfig(&submitInfo.Credentials, "", "", k8s)
if err := clusterConfig.SetTenant(); err != nil {
logger.L().Error("failed setting account ID", helpers.Error(err))
}
resultsObjects := NewResultsObject(clusterConfig.GetAccountID(), clusterConfig.GetContextName(), args[0])
r := reporterv2.NewReportEventReceiver(clusterConfig.GetConfigObj(), uuid.NewString(), reporterv2.SubmitContextScan)
submitInterfaces := cliinterfaces.SubmitInterfaces{
ClusterConfig: clusterConfig,
SubmitObjects: resultsObjects,
Reporter: r,
}
if err := ks.Submit(submitInterfaces); err != nil {
logger.L().Fatal(err.Error())
}
return nil
},
}
resultsCmd.PersistentFlags().StringVar(&formatVersion, "format-version", "v1", "Output object can be differnet between versions, this is for maintaining backward and forward compatibility. Supported:'v1'/'v2'")
return resultsCmd
}
func loadResultsFromFile(filePath string) (*reporthandlingv2.PostureReport, error) {
report := &reporthandlingv2.PostureReport{}
f, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}
if err = json.Unmarshal(f, report); err != nil {
return report, fmt.Errorf("failed to unmarshal results file: %s, make sure you run kubescape with '--format=json --format-version=v2'", err.Error())
}
return report, nil
}

View File

@@ -1,37 +0,0 @@
package submit
import (
"github.com/kubescape/kubescape/v2/core/meta"
metav1 "github.com/kubescape/kubescape/v2/core/meta/datastructures/v1"
"github.com/spf13/cobra"
)
var submitCmdExamples = `
# Submit Kubescape scan results file
kubescape submit results
# Submit exceptions file to Kubescape SaaS
kubescape submit exceptions
`
func GetSubmitCmd(ks meta.IKubescape) *cobra.Command {
var submitInfo metav1.Submit
submitCmd := &cobra.Command{
Use: "submit <command>",
Short: "Submit an object to the Kubescape SaaS version",
Long: ``,
Example: submitCmdExamples,
Run: func(cmd *cobra.Command, args []string) {
},
}
submitCmd.PersistentFlags().StringVarP(&submitInfo.Credentials.Account, "account", "", "", "Kubescape SaaS account ID. Default will load account ID from cache")
submitCmd.PersistentFlags().StringVarP(&submitInfo.Credentials.ClientID, "client-id", "", "", "Kubescape SaaS client ID. Default will load client ID from cache, read more - https://hub.armosec.io/docs/authentication")
submitCmd.PersistentFlags().StringVarP(&submitInfo.Credentials.SecretKey, "secret-key", "", "", "Kubescape SaaS secret key. Default will load secret key from cache, read more - https://hub.armosec.io/docs/authentication")
submitCmd.AddCommand(getExceptionsCmd(ks, &submitInfo))
submitCmd.AddCommand(getResultsCmd(ks, &submitInfo))
submitCmd.AddCommand(getRBACCmd(ks, &submitInfo))
return submitCmd
}

View File

@@ -5,52 +5,36 @@ package update
// kubescape update
import (
"os/exec"
"runtime"
"fmt"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/spf13/cobra"
)
const (
installationLink string = "https://github.com/kubescape/kubescape/blob/master/docs/installation.md"
)
var updateCmdExamples = fmt.Sprintf(`
# Update to the latest kubescape release
%[1]s update
`, cautils.ExecName())
func GetUpdateCmd() *cobra.Command {
updateCmd := &cobra.Command{
Use: "update",
Short: "Update your version",
Long: ``,
Use: "update",
Short: "Update to latest release version",
Long: ``,
Example: updateCmdExamples,
RunE: func(_ *cobra.Command, args []string) error {
//Checking the user's version of kubescape to the latest release
if cautils.BuildNumber == cautils.LatestReleaseVersion {
//your version == latest version
logger.L().Info(("You are in the latest version"))
logger.L().Info(("Nothing to update, you are running the latest version"), helpers.String("Version", cautils.BuildNumber))
} else {
const OSTYPE string = runtime.GOOS
var ShellToUse string
switch OSTYPE {
case "windows":
cautils.StartSpinner()
//run the installation command for windows
ShellToUse = "powershell"
_, err := exec.Command(ShellToUse, "-c", "iwr -useb https://raw.githubusercontent.com/kubescape/kubescape/master/install.ps1 | iex").Output()
if err != nil {
logger.L().Fatal(err.Error())
}
cautils.StopSpinner()
default:
ShellToUse = "bash"
cautils.StartSpinner()
//run the installation command for linux and macOS
_, err := exec.Command(ShellToUse, "-c", "curl -s https://raw.githubusercontent.com/kubescape/kubescape/master/install.sh | /bin/bash").Output()
if err != nil {
logger.L().Fatal(err.Error())
}
cautils.StopSpinner()
}
fmt.Printf("Please refer to our installation docs in the following link: %s\n", installationLink)
}
return nil
},

View File

@@ -1,10 +1,12 @@
package version
import (
"context"
"fmt"
"os"
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/spf13/cobra"
)
@@ -14,13 +16,14 @@ func GetVersionCmd() *cobra.Command {
Short: "Get current version",
Long: ``,
RunE: func(cmd *cobra.Command, args []string) error {
v := cautils.NewIVersionCheckHandler()
v.CheckLatestVersion(cautils.NewVersionCheckRequest(cautils.BuildNumber, "", "", "version"))
ctx := context.TODO()
v := cautils.NewIVersionCheckHandler(ctx)
v.CheckLatestVersion(ctx, cautils.NewVersionCheckRequest(cautils.BuildNumber, "", "", "version"))
fmt.Fprintf(os.Stdout,
"Your current version is: %s [git enabled in build: %t]\n",
"Your current version is: %s\n",
cautils.BuildNumber,
isGitEnabled(),
)
logger.L().Debug(fmt.Sprintf("git enabled in build: %t", isGitEnabled()))
return nil
},
}

View File

@@ -3,21 +3,40 @@ package cautils
import (
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/google/uuid"
v1 "github.com/kubescape/backend/pkg/client/v1"
"github.com/kubescape/backend/pkg/servicediscovery"
servicediscoveryv1 "github.com/kubescape/backend/pkg/servicediscovery/v1"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/k8s-interface/k8sinterface"
"github.com/kubescape/kubescape/v2/core/cautils/getter"
"github.com/kubescape/kubescape/v3/core/cautils/getter"
corev1 "k8s.io/api/core/v1"
)
const configFileName = "config"
const (
configFileName string = "config"
kubescapeNamespace string = "kubescape"
kubescapeConfigMapName string = "kubescape-config" // deprecated - for backward compatibility
kubescapeCloudConfigMapName string = "ks-cloud-config" // deprecated - for backward compatibility
cloudConfigMapLabelSelector string = "kubescape.io/infra=config"
credsLabelSelectors string = "kubescape.io/infra=credentials" //nolint:gosec
// env vars
defaultConfigMapNamespaceEnvVar string = "KS_DEFAULT_CONFIGMAP_NAMESPACE"
accountIdEnvVar string = "KS_ACCOUNT_ID"
accessKeyEnvVar string = "KS_ACCESS_KEY"
cloudApiUrlEnvVar string = "KS_CLOUD_API_URL"
cloudReportUrlEnvVar string = "KS_CLOUD_REPORT_URL"
)
func ConfigFileFullPath() string { return getter.GetDefaultPath(configFileName + ".json") }
@@ -26,17 +45,11 @@ func ConfigFileFullPath() string { return getter.GetDefaultPath(configFileName +
// ======================================================================================
type ConfigObj struct {
AccountID string `json:"accountID,omitempty"`
ClientID string `json:"clientID,omitempty"`
SecretKey string `json:"secretKey,omitempty"`
CustomerGUID string `json:"customerGUID,omitempty"` // Deprecated
Token string `json:"invitationParam,omitempty"`
CustomerAdminEMail string `json:"adminMail,omitempty"`
ClusterName string `json:"clusterName,omitempty"`
CloudReportURL string `json:"cloudReportURL,omitempty"`
CloudAPIURL string `json:"cloudAPIURL,omitempty"`
CloudUIURL string `json:"cloudUIURL,omitempty"`
CloudAuthURL string `json:"cloudAuthURL,omitempty"`
AccountID string `json:"accountID,omitempty"`
ClusterName string `json:"clusterName,omitempty"`
CloudReportURL string `json:"cloudReportURL,omitempty"`
CloudAPIURL string `json:"cloudAPIURL,omitempty"`
AccessKey string `json:"accessKey,omitempty"`
}
// Config - convert ConfigObj to config file
@@ -44,17 +57,11 @@ func (co *ConfigObj) Config() []byte {
// remove cluster name before saving to file
clusterName := co.ClusterName
customerAdminEMail := co.CustomerAdminEMail
token := co.Token
co.ClusterName = ""
co.Token = ""
co.CustomerAdminEMail = ""
b, err := json.MarshalIndent(co, "", " ")
co.ClusterName = clusterName
co.CustomerAdminEMail = customerAdminEMail
co.Token = token
if err == nil {
return b
@@ -63,55 +70,62 @@ func (co *ConfigObj) Config() []byte {
return []byte{}
}
func (co *ConfigObj) updateEmptyFields(inCO *ConfigObj) error {
if inCO.AccountID != "" {
co.AccountID = inCO.AccountID
}
if inCO.CloudAPIURL != "" {
co.CloudAPIURL = inCO.CloudAPIURL
}
if inCO.CloudReportURL != "" {
co.CloudReportURL = inCO.CloudReportURL
}
if inCO.ClusterName != "" {
co.ClusterName = inCO.ClusterName
}
return nil
}
// ======================================================================================
// =============================== interface ============================================
// ======================================================================================
type ITenantConfig interface {
// set
SetTenant() error
UpdateCachedConfig() error
DeleteCachedConfig() error
DeleteCachedConfig(ctx context.Context) error
GenerateAccountID() (string, error)
DeleteCredentials() error
// getters
GetContextName() string
GetAccountID() string
GetTenantEmail() string
GetToken() string
GetClientID() string
GetSecretKey() string
GetAccessKey() string
GetConfigObj() *ConfigObj
GetCloudReportURL() string
GetCloudAPIURL() string
GetCloudUIURL() string
GetCloudAuthURL() string
// GetBackendAPI() getter.IBackend
// GenerateURL()
IsConfigFound() bool
}
// ======================================================================================
// ============================ Local Config ============================================
// ======================================================================================
// Config when scanning YAML files or URL but not a Kubernetes cluster
var _ ITenantConfig = &LocalConfig{}
type LocalConfig struct {
backendAPI getter.IBackend
configObj *ConfigObj
configObj *ConfigObj
}
func NewLocalConfig(
backendAPI getter.IBackend, credentials *Credentials, clusterName string, customClusterName string) *LocalConfig {
func NewLocalConfig(accountID, accessKey, clusterName, customClusterName string) *LocalConfig {
lc := &LocalConfig{
backendAPI: backendAPI,
configObj: &ConfigObj{},
configObj: &ConfigObj{},
}
// get from configMap
if existsConfigFile() { // get from file
loadConfigFromFile(lc.configObj)
}
updateCredentials(lc.configObj, credentials)
updateCredentials(lc.configObj, accountID, accessKey)
updateCloudURLs(lc.configObj)
// If a custom cluster name is provided then set that name, else use the cluster's original name
@@ -121,87 +135,42 @@ func NewLocalConfig(
lc.configObj.ClusterName = AdoptClusterName(clusterName) // override config clusterName
}
lc.backendAPI.SetAccountID(lc.configObj.AccountID)
lc.backendAPI.SetClientID(lc.configObj.ClientID)
lc.backendAPI.SetSecretKey(lc.configObj.SecretKey)
if lc.configObj.CloudAPIURL != "" {
lc.backendAPI.SetCloudAPIURL(lc.configObj.CloudAPIURL)
} else {
lc.configObj.CloudAPIURL = lc.backendAPI.GetCloudAPIURL()
}
if lc.configObj.CloudAuthURL != "" {
lc.backendAPI.SetCloudAuthURL(lc.configObj.CloudAuthURL)
} else {
lc.configObj.CloudAuthURL = lc.backendAPI.GetCloudAuthURL()
}
if lc.configObj.CloudReportURL != "" {
lc.backendAPI.SetCloudReportURL(lc.configObj.CloudReportURL)
} else {
lc.configObj.CloudReportURL = lc.backendAPI.GetCloudReportURL()
}
if lc.configObj.CloudUIURL != "" {
lc.backendAPI.SetCloudUIURL(lc.configObj.CloudUIURL)
} else {
lc.configObj.CloudUIURL = lc.backendAPI.GetCloudUIURL()
}
logger.L().Debug("Kubescape Cloud URLs", helpers.String("api", lc.backendAPI.GetCloudAPIURL()), helpers.String("auth", lc.backendAPI.GetCloudAuthURL()), helpers.String("report", lc.backendAPI.GetCloudReportURL()), helpers.String("UI", lc.backendAPI.GetCloudUIURL()))
initializeCloudAPI(lc)
return lc
}
func (lc *LocalConfig) GetConfigObj() *ConfigObj { return lc.configObj }
func (lc *LocalConfig) GetTenantEmail() string { return lc.configObj.CustomerAdminEMail }
func (lc *LocalConfig) GetAccountID() string { return lc.configObj.AccountID }
func (lc *LocalConfig) GetClientID() string { return lc.configObj.ClientID }
func (lc *LocalConfig) GetSecretKey() string { return lc.configObj.SecretKey }
func (lc *LocalConfig) GetContextName() string { return lc.configObj.ClusterName }
func (lc *LocalConfig) GetToken() string { return lc.configObj.Token }
func (lc *LocalConfig) GetCloudReportURL() string { return lc.configObj.CloudReportURL }
func (lc *LocalConfig) GetCloudAPIURL() string { return lc.configObj.CloudAPIURL }
func (lc *LocalConfig) GetCloudUIURL() string { return lc.configObj.CloudUIURL }
func (lc *LocalConfig) GetCloudAuthURL() string { return lc.configObj.CloudAuthURL }
func (lc *LocalConfig) IsConfigFound() bool { return existsConfigFile() }
func (lc *LocalConfig) SetTenant() error {
// Kubescape Cloud tenant GUID
if err := getTenantConfigFromBE(lc.backendAPI, lc.configObj); err != nil {
return err
}
lc.UpdateCachedConfig()
return nil
func (lc *LocalConfig) GetAccessKey() string { return lc.configObj.AccessKey }
func (lc *LocalConfig) GenerateAccountID() (string, error) {
lc.configObj.AccountID = uuid.NewString()
err := lc.UpdateCachedConfig()
return lc.configObj.AccountID, err
}
func (lc *LocalConfig) DeleteCredentials() error {
lc.configObj.AccessKey = ""
lc.configObj.AccountID = ""
return lc.UpdateCachedConfig()
}
func (lc *LocalConfig) UpdateCachedConfig() error {
logger.L().Debug("updating cached config", helpers.Interface("configObj", lc.configObj))
return updateConfigFile(lc.configObj)
}
func (lc *LocalConfig) DeleteCachedConfig() error {
func (lc *LocalConfig) DeleteCachedConfig(ctx context.Context) error {
if err := DeleteConfigFile(); err != nil {
logger.L().Warning(err.Error())
logger.L().Ctx(ctx).Warning(err.Error())
}
return nil
}
func getTenantConfigFromBE(backendAPI getter.IBackend, configObj *ConfigObj) error {
// get from Kubescape Cloud API
tenantResponse, err := backendAPI.GetTenant()
if err == nil && tenantResponse != nil {
if tenantResponse.AdminMail != "" { // registered tenant
configObj.CustomerAdminEMail = tenantResponse.AdminMail
} else { // new tenant
configObj.Token = tenantResponse.Token
configObj.AccountID = tenantResponse.TenantID
}
} else {
if err != nil && !strings.Contains(err.Error(), "already exists") {
return err
}
}
return nil
}
// ======================================================================================
// ========================== Cluster Config ============================================
// ======================================================================================
@@ -214,40 +183,37 @@ KS_DEFAULT_CONFIGMAP_NAME // name of configmap, if not set default is 'kubescap
KS_DEFAULT_CONFIGMAP_NAMESPACE // configmap namespace, if not set default is 'default'
KS_ACCOUNT_ID
KS_CLIENT_ID
KS_SECRET_KEY
TODO - support:
KS_CACHE // path to cached files
*/
var _ ITenantConfig = &ClusterConfig{}
type ClusterConfig struct {
backendAPI getter.IBackend
k8s *k8sinterface.KubernetesApi
configObj *ConfigObj
configMapName string
configMapNamespace string
}
func NewClusterConfig(k8s *k8sinterface.KubernetesApi, backendAPI getter.IBackend, credentials *Credentials, clusterName string, customClusterName string) *ClusterConfig {
// var configObj *ConfigObj
func NewClusterConfig(k8s *k8sinterface.KubernetesApi, accountID, accessKey, clusterName, customClusterName string) *ClusterConfig {
c := &ClusterConfig{
k8s: k8s,
backendAPI: backendAPI,
configObj: &ConfigObj{},
configMapName: getConfigMapName(),
configMapNamespace: getConfigMapNamespace(),
configMapNamespace: GetConfigMapNamespace(),
}
// first, load from configMap
if c.existsConfigMap() {
c.loadConfigFromConfigMap()
}
// second, load from file
// first, load from file
if existsConfigFile() { // get from file
loadConfigFromFile(c.configObj)
}
updateCredentials(c.configObj, credentials)
// second, load urls from config map
c.updateConfigEmptyFieldsFromKubescapeConfigMap()
// third, credentials from secret
c.updateConfigEmptyFieldsFromCredentialsSecret()
updateCredentials(c.configObj, accountID, accessKey)
updateCloudURLs(c.configObj)
// If a custom cluster name is provided then set that name, else use the cluster's original name
@@ -262,80 +228,25 @@ func NewClusterConfig(k8s *k8sinterface.KubernetesApi, backendAPI getter.IBacken
} else { // override the cluster name if it has unwanted characters
c.configObj.ClusterName = AdoptClusterName(c.configObj.ClusterName)
}
c.backendAPI.SetAccountID(c.configObj.AccountID)
c.backendAPI.SetClientID(c.configObj.ClientID)
c.backendAPI.SetSecretKey(c.configObj.SecretKey)
if c.configObj.CloudAPIURL != "" {
c.backendAPI.SetCloudAPIURL(c.configObj.CloudAPIURL)
} else {
c.configObj.CloudAPIURL = c.backendAPI.GetCloudAPIURL()
}
if c.configObj.CloudAuthURL != "" {
c.backendAPI.SetCloudAuthURL(c.configObj.CloudAuthURL)
} else {
c.configObj.CloudAuthURL = c.backendAPI.GetCloudAuthURL()
}
if c.configObj.CloudReportURL != "" {
c.backendAPI.SetCloudReportURL(c.configObj.CloudReportURL)
} else {
c.configObj.CloudReportURL = c.backendAPI.GetCloudReportURL()
}
if c.configObj.CloudUIURL != "" {
c.backendAPI.SetCloudUIURL(c.configObj.CloudUIURL)
} else {
c.configObj.CloudUIURL = c.backendAPI.GetCloudUIURL()
}
logger.L().Debug("Kubescape Cloud URLs", helpers.String("api", c.backendAPI.GetCloudAPIURL()), helpers.String("auth", c.backendAPI.GetCloudAuthURL()), helpers.String("report", c.backendAPI.GetCloudReportURL()), helpers.String("UI", c.backendAPI.GetCloudUIURL()))
initializeCloudAPI(c)
return c
}
func (c *ClusterConfig) GetConfigObj() *ConfigObj { return c.configObj }
func (c *ClusterConfig) GetDefaultNS() string { return c.configMapNamespace }
func (c *ClusterConfig) GetAccountID() string { return c.configObj.AccountID }
func (c *ClusterConfig) GetClientID() string { return c.configObj.ClientID }
func (c *ClusterConfig) GetSecretKey() string { return c.configObj.SecretKey }
func (c *ClusterConfig) GetTenantEmail() string { return c.configObj.CustomerAdminEMail }
func (c *ClusterConfig) GetToken() string { return c.configObj.Token }
func (c *ClusterConfig) GetCloudReportURL() string { return c.configObj.CloudReportURL }
func (c *ClusterConfig) GetCloudAPIURL() string { return c.configObj.CloudAPIURL }
func (c *ClusterConfig) GetCloudUIURL() string { return c.configObj.CloudUIURL }
func (c *ClusterConfig) GetCloudAuthURL() string { return c.configObj.CloudAuthURL }
func (c *ClusterConfig) IsConfigFound() bool { return existsConfigFile() || c.existsConfigMap() }
func (c *ClusterConfig) SetTenant() error {
// ARMO tenant GUID
if err := getTenantConfigFromBE(c.backendAPI, c.configObj); err != nil {
return err
}
c.UpdateCachedConfig()
return nil
}
func (c *ClusterConfig) GetAccessKey() string { return c.configObj.AccessKey }
func (c *ClusterConfig) UpdateCachedConfig() error {
// update/create config
if c.existsConfigMap() {
if err := c.updateConfigMap(); err != nil {
return err
}
} else {
if err := c.createConfigMap(); err != nil {
return err
}
}
logger.L().Debug("updating cached config", helpers.Interface("configObj", c.configObj))
return updateConfigFile(c.configObj)
}
func (c *ClusterConfig) DeleteCachedConfig() error {
if err := c.deleteConfigMap(); err != nil {
logger.L().Warning(err.Error())
}
func (c *ClusterConfig) DeleteCachedConfig(ctx context.Context) error {
if err := DeleteConfigFile(); err != nil {
logger.L().Warning(err.Error())
logger.L().Ctx(ctx).Warning(err.Error())
}
return nil
}
@@ -350,13 +261,81 @@ func (c *ClusterConfig) ToMapString() map[string]interface{} {
}
return m
}
func (c *ClusterConfig) loadConfigFromConfigMap() error {
configMap, err := c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).Get(context.Background(), c.configMapName, metav1.GetOptions{})
func (c *ClusterConfig) updateConfigEmptyFieldsFromKubescapeConfigMap() error {
configMaps, err := c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).List(context.Background(), metav1.ListOptions{
LabelSelector: cloudConfigMapLabelSelector,
})
if err != nil {
return err
}
var ksConfigMap *corev1.ConfigMap
var urlsConfigMap *corev1.ConfigMap
if len(configMaps.Items) == 0 {
// try to find configmaps by name (for backward compatibility)
ksConfigMap, _ = c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).Get(context.Background(), kubescapeConfigMapName, metav1.GetOptions{})
urlsConfigMap, _ = c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).Get(context.Background(), kubescapeCloudConfigMapName, metav1.GetOptions{})
} else {
// use the first configmap with the label
ksConfigMap = &configMaps.Items[0]
urlsConfigMap = &configMaps.Items[0]
}
if ksConfigMap != nil {
if jsonConf, ok := ksConfigMap.Data["clusterData"]; ok {
tempCO := ConfigObj{}
if err = json.Unmarshal([]byte(jsonConf), &tempCO); err != nil {
return err
}
c.configObj.updateEmptyFields(&tempCO)
}
}
if urlsConfigMap != nil {
if jsonConf, ok := urlsConfigMap.Data["services"]; ok {
services, err := servicediscovery.GetServices(
servicediscoveryv1.NewServiceDiscoveryStreamV1([]byte(jsonConf)),
)
if err != nil {
return err
}
if services.GetApiServerUrl() != "" {
c.configObj.CloudAPIURL = services.GetApiServerUrl()
}
if services.GetReportReceiverHttpUrl() != "" {
c.configObj.CloudReportURL = services.GetReportReceiverHttpUrl()
}
}
}
return err
}
func (c *ClusterConfig) updateConfigEmptyFieldsFromCredentialsSecret() error {
secrets, err := c.k8s.KubernetesClient.CoreV1().Secrets(c.configMapNamespace).List(context.Background(),
metav1.ListOptions{LabelSelector: credsLabelSelectors})
if err != nil {
return err
}
return loadConfigFromData(c.configObj, configMap.Data)
if len(secrets.Items) == 0 {
return nil
}
if jsonConf, ok := secrets.Items[0].Data["account"]; ok {
if account := string(jsonConf); account != "" {
c.configObj.AccountID = account
}
}
if jsonConf, ok := secrets.Items[0].Data["accessKey"]; ok {
if accessKey := string(jsonConf); accessKey != "" {
c.configObj.AccessKey = accessKey
}
}
return nil
}
func loadConfigFromData(co *ConfigObj, data map[string]string) error {
@@ -370,107 +349,32 @@ func loadConfigFromData(co *ConfigObj, data map[string]string) error {
return e
}
func (c *ClusterConfig) existsConfigMap() bool {
_, err := c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).Get(context.Background(), c.configMapName, metav1.GetOptions{})
// TODO - check if has customerGUID
return err == nil
}
func (c *ClusterConfig) GetValueByKeyFromConfigMap(key string) (string, error) {
configMap, err := c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).Get(context.Background(), c.configMapName, metav1.GetOptions{})
if err != nil {
return "", err
}
if val, ok := configMap.Data[key]; ok {
return val, nil
} else {
return "", fmt.Errorf("value does not exist")
}
}
func GetValueFromConfigJson(key string) (string, error) {
data, err := os.ReadFile(ConfigFileFullPath())
if err != nil {
return "", err
}
var obj map[string]interface{}
if err := json.Unmarshal(data, &obj); err != nil {
return "", err
}
if val, ok := obj[key]; ok {
return fmt.Sprint(val), nil
} else {
return "", fmt.Errorf("value does not exist")
}
}
func (c *ClusterConfig) SetKeyValueInConfigmap(key string, value string) error {
configMap, err := c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).Get(context.Background(), c.configMapName, metav1.GetOptions{})
if err != nil {
configMap = &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: c.configMapName,
},
}
}
if len(configMap.Data) == 0 {
configMap.Data = make(map[string]string)
}
configMap.Data[key] = value
if err != nil {
_, err = c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).Create(context.Background(), configMap, metav1.CreateOptions{})
} else {
_, err = c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).Update(context.Background(), configMap, metav1.UpdateOptions{})
}
return err
}
func existsConfigFile() bool {
_, err := os.ReadFile(ConfigFileFullPath())
return err == nil
}
func (c *ClusterConfig) createConfigMap() error {
if c.k8s == nil {
return nil
}
configMap := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: c.configMapName,
},
}
c.updateConfigData(configMap)
_, err := c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).Create(context.Background(), configMap, metav1.CreateOptions{})
return err
}
func (c *ClusterConfig) updateConfigMap() error {
if c.k8s == nil {
return nil
}
configMap, err := c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).Get(context.Background(), c.configMapName, metav1.GetOptions{})
if err != nil {
func updateConfigFile(configObj *ConfigObj) error {
fullPath := ConfigFileFullPath()
dir := filepath.Dir(fullPath)
if err := os.MkdirAll(dir, 0755); err != nil {
return err
}
c.updateConfigData(configMap)
_, err = c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).Update(context.Background(), configMap, metav1.UpdateOptions{})
return err
return os.WriteFile(fullPath, configObj.Config(), 0664) //nolint:gosec
}
func updateConfigFile(configObj *ConfigObj) error {
return os.WriteFile(ConfigFileFullPath(), configObj.Config(), 0664) //nolint:gosec
func (c *ClusterConfig) GenerateAccountID() (string, error) {
c.configObj.AccountID = uuid.NewString()
err := c.UpdateCachedConfig()
return c.configObj.AccountID, err
}
func (c *ClusterConfig) DeleteCredentials() error {
c.configObj.AccountID = ""
c.configObj.AccessKey = ""
return c.UpdateCachedConfig()
}
func (c *ClusterConfig) updateConfigData(configMap *corev1.ConfigMap) {
@@ -500,35 +404,9 @@ func readConfig(dat []byte, configObj *ConfigObj) error {
if err := json.Unmarshal(dat, configObj); err != nil {
return err
}
if configObj.AccountID == "" {
configObj.AccountID = configObj.CustomerGUID
}
configObj.CustomerGUID = ""
return nil
}
// Check if the customer is submitted
func (clusterConfig *ClusterConfig) IsSubmitted() bool {
return clusterConfig.existsConfigMap() || existsConfigFile()
}
// Check if the customer is registered
func (clusterConfig *ClusterConfig) IsRegistered() bool {
// get from armoBE
tenantResponse, err := clusterConfig.backendAPI.GetTenant()
if err == nil && tenantResponse != nil {
if tenantResponse.AdminMail != "" { // this customer already belongs to some user
return true
}
}
return false
}
func (clusterConfig *ClusterConfig) deleteConfigMap() error {
return clusterConfig.k8s.KubernetesClient.CoreV1().ConfigMaps(clusterConfig.configMapNamespace).Delete(context.Background(), clusterConfig.configMapName, metav1.DeleteOptions{})
}
func DeleteConfigFile() error {
return os.Remove(ConfigFileFullPath())
}
@@ -541,66 +419,42 @@ func AdoptClusterName(clusterName string) string {
return re.ReplaceAllString(clusterName, "-")
}
func getConfigMapName() string {
if n := os.Getenv("KS_DEFAULT_CONFIGMAP_NAME"); n != "" {
// GetConfigMapNamespace returns the namespace of the cluster config, which is the same for all in-cluster components
func GetConfigMapNamespace() string {
if n := os.Getenv(defaultConfigMapNamespaceEnvVar); n != "" {
return n
}
return "kubescape"
return kubescapeNamespace
}
func getConfigMapNamespace() string {
if n := os.Getenv("KS_DEFAULT_CONFIGMAP_NAMESPACE"); n != "" {
return n
}
return "default"
}
func getAccountFromEnv(credentials *Credentials) {
// load from env
if accountID := os.Getenv("KS_ACCOUNT_ID"); credentials.Account == "" && accountID != "" {
credentials.Account = accountID
}
if clientID := os.Getenv("KS_CLIENT_ID"); credentials.ClientID == "" && clientID != "" {
credentials.ClientID = clientID
}
if secretKey := os.Getenv("KS_SECRET_KEY"); credentials.SecretKey == "" && secretKey != "" {
credentials.SecretKey = secretKey
}
}
func updateCredentials(configObj *ConfigObj, credentials *Credentials) {
if credentials == nil {
credentials = &Credentials{}
}
getAccountFromEnv(credentials)
if credentials.Account != "" {
configObj.AccountID = credentials.Account // override config Account
}
if credentials.ClientID != "" {
configObj.ClientID = credentials.ClientID // override config ClientID
}
if credentials.SecretKey != "" {
configObj.SecretKey = credentials.SecretKey // override config SecretKey
func updateCredentials(configObj *ConfigObj, accountID, accessKey string) {
if accessKey != "" {
configObj.AccessKey = accessKey
}
if envAccessKey := os.Getenv(accessKeyEnvVar); envAccessKey != "" {
configObj.AccessKey = envAccessKey
}
if accountID != "" {
configObj.AccountID = accountID
}
if envAccountID := os.Getenv(accountIdEnvVar); envAccountID != "" {
configObj.AccountID = envAccountID
}
}
func getCloudURLsFromEnv(cloudURLs *CloudURLs) {
// load from env
if cloudAPIURL := os.Getenv("KS_CLOUD_API_URL"); cloudAPIURL != "" {
if cloudAPIURL := os.Getenv(cloudApiUrlEnvVar); cloudAPIURL != "" {
logger.L().Debug("cloud API URL updated from env var", helpers.Interface(cloudApiUrlEnvVar, cloudAPIURL))
cloudURLs.CloudAPIURL = cloudAPIURL
}
if cloudAuthURL := os.Getenv("KS_CLOUD_AUTH_URL"); cloudAuthURL != "" {
cloudURLs.CloudAuthURL = cloudAuthURL
}
if cloudReportURL := os.Getenv("KS_CLOUD_REPORT_URL"); cloudReportURL != "" {
if cloudReportURL := os.Getenv(cloudReportUrlEnvVar); cloudReportURL != "" {
logger.L().Debug("cloud Report URL updated from env var", helpers.Interface(cloudReportUrlEnvVar, cloudReportURL))
cloudURLs.CloudReportURL = cloudReportURL
}
if cloudUIURL := os.Getenv("KS_CLOUD_UI_URL"); cloudUIURL != "" {
cloudURLs.CloudUIURL = cloudUIURL
}
}
func updateCloudURLs(configObj *ConfigObj) {
@@ -611,14 +465,60 @@ func updateCloudURLs(configObj *ConfigObj) {
if cloudURLs.CloudAPIURL != "" {
configObj.CloudAPIURL = cloudURLs.CloudAPIURL // override config CloudAPIURL
}
if cloudURLs.CloudAuthURL != "" {
configObj.CloudAuthURL = cloudURLs.CloudAuthURL // override config CloudAuthURL
}
if cloudURLs.CloudReportURL != "" {
configObj.CloudReportURL = cloudURLs.CloudReportURL // override config CloudReportURL
}
if cloudURLs.CloudUIURL != "" {
configObj.CloudUIURL = cloudURLs.CloudUIURL // override config CloudUIURL
}
}
func initializeCloudAPI(c ITenantConfig) *v1.KSCloudAPI {
if ksCloud := getter.GetKSCloudAPIConnector(); ksCloud != nil {
logger.L().Debug("KS Cloud API already initialized")
if val := c.GetCloudAPIURL(); val != "" && val != ksCloud.GetCloudAPIURL() {
logger.L().Debug("updating KS Cloud API from config", helpers.String("old", ksCloud.GetCloudAPIURL()), helpers.String("new", val))
ksCloud.SetCloudAPIURL(val)
}
if val := c.GetCloudReportURL(); val != "" && val != ksCloud.GetCloudReportURL() {
logger.L().Debug("updating KS Cloud Report from config", helpers.String("old", ksCloud.GetCloudReportURL()), helpers.String("new", val))
ksCloud.SetCloudReportURL(val)
}
if val := c.GetAccountID(); val != "" && val != ksCloud.GetAccountID() {
logger.L().Debug("updating Account ID from config", helpers.String("old", ksCloud.GetAccountID()), helpers.String("new", val))
ksCloud.SetAccountID(val)
}
if val := c.GetAccessKey(); val != "" && val != ksCloud.GetAccessKey() {
logger.L().Debug("updating Access Key from config", helpers.Int("old (len)", len(ksCloud.GetAccessKey())), helpers.Int("new (len)", len(val)))
ksCloud.SetAccessKey(val)
}
getter.SetKSCloudAPIConnector(ksCloud)
} else {
logger.L().Debug("initializing KS Cloud API from config", helpers.String("accountID", c.GetAccountID()), helpers.String("cloudAPIURL", c.GetCloudAPIURL()), helpers.String("cloudReportURL", c.GetCloudReportURL()))
cloud, err := v1.NewKSCloudAPI(
c.GetCloudAPIURL(),
c.GetCloudReportURL(),
c.GetAccountID(),
c.GetAccessKey())
if err != nil {
logger.L().Fatal("failed to create KS Cloud client", helpers.Error(err))
}
getter.SetKSCloudAPIConnector(cloud)
}
return getter.GetKSCloudAPIConnector()
}
func GetTenantConfig(accountID, accessKey, clusterName, customClusterName string, k8s *k8sinterface.KubernetesApi) ITenantConfig {
if !k8sinterface.IsConnectedToCluster() || k8s == nil {
return NewLocalConfig(accountID, accessKey, clusterName, customClusterName)
}
return NewClusterConfig(k8s, accountID, accessKey, clusterName, customClusterName)
}
// firstNonEmpty returns the first non-empty string
func firstNonEmpty(s1, s2 string) string {
if s1 != "" {
return s1
}
return s2
}

View File

@@ -5,35 +5,28 @@ import (
"os"
"testing"
"github.com/kubescape/kubescape/v3/core/cautils/getter"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
)
func mockConfigObj() *ConfigObj {
return &ConfigObj{
AccountID: "aaa",
ClientID: "bbb",
SecretKey: "ccc",
ClusterName: "ddd",
CustomerAdminEMail: "ab@cd",
Token: "eee",
CloudReportURL: "report.armo.cloud",
CloudAPIURL: "api.armosec.io",
CloudUIURL: "cloud.armosec.io",
CloudAuthURL: "auth.armosec.io",
AccountID: "aaa",
ClusterName: "ddd",
CloudReportURL: "report.domain.com",
CloudAPIURL: "api.domain.com",
}
}
func mockLocalConfig() *LocalConfig {
return &LocalConfig{
backendAPI: nil,
configObj: mockConfigObj(),
configObj: mockConfigObj(),
}
}
func mockClusterConfig() *ClusterConfig {
return &ClusterConfig{
backendAPI: nil,
configObj: mockConfigObj(),
configObj: mockConfigObj(),
}
}
func TestConfig(t *testing.T) {
@@ -42,15 +35,9 @@ func TestConfig(t *testing.T) {
assert.NoError(t, json.Unmarshal(co.Config(), &cop))
assert.Equal(t, co.AccountID, cop.AccountID)
assert.Equal(t, co.ClientID, cop.ClientID)
assert.Equal(t, co.SecretKey, cop.SecretKey)
assert.Equal(t, co.CloudReportURL, cop.CloudReportURL)
assert.Equal(t, co.CloudAPIURL, cop.CloudAPIURL)
assert.Equal(t, co.CloudUIURL, cop.CloudUIURL)
assert.Equal(t, co.CloudAuthURL, cop.CloudAuthURL)
assert.Equal(t, "", cop.ClusterName) // Not copied to bytes
assert.Equal(t, "", cop.CustomerAdminEMail) // Not copied to bytes
assert.Equal(t, "", cop.Token) // Not copied to bytes
assert.Equal(t, "", cop.ClusterName) // Not copied to bytes
}
@@ -64,27 +51,15 @@ func TestITenantConfig(t *testing.T) {
// test LocalConfig methods
assert.Equal(t, co.AccountID, lc.GetAccountID())
assert.Equal(t, co.ClientID, lc.GetClientID())
assert.Equal(t, co.SecretKey, lc.GetSecretKey())
assert.Equal(t, co.ClusterName, lc.GetContextName())
assert.Equal(t, co.CustomerAdminEMail, lc.GetTenantEmail())
assert.Equal(t, co.Token, lc.GetToken())
assert.Equal(t, co.CloudReportURL, lc.GetCloudReportURL())
assert.Equal(t, co.CloudAPIURL, lc.GetCloudAPIURL())
assert.Equal(t, co.CloudUIURL, lc.GetCloudUIURL())
assert.Equal(t, co.CloudAuthURL, lc.GetCloudAuthURL())
// test ClusterConfig methods
assert.Equal(t, co.AccountID, c.GetAccountID())
assert.Equal(t, co.ClientID, c.GetClientID())
assert.Equal(t, co.SecretKey, c.GetSecretKey())
assert.Equal(t, co.ClusterName, c.GetContextName())
assert.Equal(t, co.CustomerAdminEMail, c.GetTenantEmail())
assert.Equal(t, co.Token, c.GetToken())
assert.Equal(t, co.CloudReportURL, c.GetCloudReportURL())
assert.Equal(t, co.CloudAPIURL, c.GetCloudAPIURL())
assert.Equal(t, co.CloudUIURL, c.GetCloudUIURL())
assert.Equal(t, co.CloudAuthURL, c.GetCloudAuthURL())
}
func TestUpdateConfigData(t *testing.T) {
@@ -95,12 +70,8 @@ func TestUpdateConfigData(t *testing.T) {
c.updateConfigData(configMap)
assert.Equal(t, c.GetAccountID(), configMap.Data["accountID"])
assert.Equal(t, c.GetClientID(), configMap.Data["clientID"])
assert.Equal(t, c.GetSecretKey(), configMap.Data["secretKey"])
assert.Equal(t, c.GetCloudReportURL(), configMap.Data["cloudReportURL"])
assert.Equal(t, c.GetCloudAPIURL(), configMap.Data["cloudAPIURL"])
assert.Equal(t, c.GetCloudUIURL(), configMap.Data["cloudUIURL"])
assert.Equal(t, c.GetCloudAuthURL(), configMap.Data["cloudAuthURL"])
}
func TestReadConfig(t *testing.T) {
@@ -113,15 +84,9 @@ func TestReadConfig(t *testing.T) {
readConfig(b, co)
assert.Equal(t, com.AccountID, co.AccountID)
assert.Equal(t, com.ClientID, co.ClientID)
assert.Equal(t, com.SecretKey, co.SecretKey)
assert.Equal(t, com.ClusterName, co.ClusterName)
assert.Equal(t, com.CustomerAdminEMail, co.CustomerAdminEMail)
assert.Equal(t, com.Token, co.Token)
assert.Equal(t, com.CloudReportURL, co.CloudReportURL)
assert.Equal(t, com.CloudAPIURL, co.CloudAPIURL)
assert.Equal(t, com.CloudUIURL, co.CloudUIURL)
assert.Equal(t, com.CloudAuthURL, co.CloudAuthURL)
}
func TestLoadConfigFromData(t *testing.T) {
@@ -140,15 +105,9 @@ func TestLoadConfigFromData(t *testing.T) {
loadConfigFromData(c.configObj, configMap.Data)
assert.Equal(t, c.GetAccountID(), co.AccountID)
assert.Equal(t, c.GetClientID(), co.ClientID)
assert.Equal(t, c.GetSecretKey(), co.SecretKey)
assert.Equal(t, c.GetContextName(), co.ClusterName)
assert.Equal(t, c.GetTenantEmail(), co.CustomerAdminEMail)
assert.Equal(t, c.GetToken(), co.Token)
assert.Equal(t, c.GetCloudReportURL(), co.CloudReportURL)
assert.Equal(t, c.GetCloudAPIURL(), co.CloudAPIURL)
assert.Equal(t, c.GetCloudUIURL(), co.CloudUIURL)
assert.Equal(t, c.GetCloudAuthURL(), co.CloudAuthURL)
}
// use case: all data is in config.json
@@ -166,12 +125,8 @@ func TestLoadConfigFromData(t *testing.T) {
loadConfigFromData(c.configObj, configMap.Data)
assert.Equal(t, c.GetAccountID(), co.AccountID)
assert.Equal(t, c.GetClientID(), co.ClientID)
assert.Equal(t, c.GetSecretKey(), co.SecretKey)
assert.Equal(t, c.GetCloudReportURL(), co.CloudReportURL)
assert.Equal(t, c.GetCloudAPIURL(), co.CloudAPIURL)
assert.Equal(t, c.GetCloudUIURL(), co.CloudUIURL)
assert.Equal(t, c.GetCloudAuthURL(), co.CloudAuthURL)
}
// use case: some data is in config.json
@@ -182,21 +137,15 @@ func TestLoadConfigFromData(t *testing.T) {
}
// add to map
configMap.Data["clientID"] = c.configObj.ClientID
configMap.Data["secretKey"] = c.configObj.SecretKey
configMap.Data["cloudReportURL"] = c.configObj.CloudReportURL
// delete the content
c.configObj.ClientID = ""
c.configObj.SecretKey = ""
c.configObj.CloudReportURL = ""
configMap.Data["config.json"] = string(c.GetConfigObj().Config())
loadConfigFromData(c.configObj, configMap.Data)
assert.NotEmpty(t, c.GetAccountID())
assert.NotEmpty(t, c.GetClientID())
assert.NotEmpty(t, c.GetSecretKey())
assert.NotEmpty(t, c.GetCloudReportURL())
}
@@ -211,19 +160,11 @@ func TestLoadConfigFromData(t *testing.T) {
// add to map
configMap.Data["accountID"] = mockConfigObj().AccountID
configMap.Data["clientID"] = c.configObj.ClientID
configMap.Data["secretKey"] = c.configObj.SecretKey
// delete the content
c.configObj.ClientID = ""
c.configObj.SecretKey = ""
configMap.Data["config.json"] = string(c.GetConfigObj().Config())
loadConfigFromData(c.configObj, configMap.Data)
assert.Equal(t, mockConfigObj().AccountID, c.GetAccountID())
assert.NotEmpty(t, c.GetClientID())
assert.NotEmpty(t, c.GetSecretKey())
}
}
@@ -268,3 +209,149 @@ func TestUpdateCloudURLs(t *testing.T) {
updateCloudURLs(co)
assert.Equal(t, co.CloudAPIURL, mockCloudAPIURL)
}
func Test_initializeCloudAPI(t *testing.T) {
type args struct {
c ITenantConfig
}
tests := []struct {
name string
args args
}{
{
name: "test",
args: args{
c: mockClusterConfig(),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
initializeCloudAPI(tt.args.c)
cloud := getter.GetKSCloudAPIConnector()
assert.Equal(t, "https://api.domain.com", cloud.GetCloudAPIURL())
assert.Equal(t, "https://report.domain.com", cloud.GetCloudReportURL())
assert.Equal(t, tt.args.c.GetAccountID(), cloud.GetAccountID())
})
}
}
func TestGetConfigMapNamespace(t *testing.T) {
tests := []struct {
name string
env string
want string
}{
{
name: "no env",
want: kubescapeNamespace,
},
{
name: "default ns",
env: kubescapeNamespace,
want: kubescapeNamespace,
},
{
name: "custom ns",
env: "my-ns",
want: "my-ns",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.env != "" {
_ = os.Setenv("KS_DEFAULT_CONFIGMAP_NAMESPACE", tt.env)
}
assert.Equalf(t, tt.want, GetConfigMapNamespace(), "GetConfigMapNamespace()")
})
}
}
const (
anyString string = "anyString"
shouldNotUpdate string = "shouldNotUpdate"
shouldUpdate string = "shouldUpdate"
)
func checkIsUpdateCorrectly(t *testing.T, beforeField string, afterField string) {
switch beforeField {
case anyString:
assert.Equal(t, anyString, afterField)
case "":
assert.Equal(t, shouldUpdate, afterField)
}
}
func TestUpdateEmptyFields(t *testing.T) {
tests := []struct {
inCo *ConfigObj
outCo *ConfigObj
}{
{
outCo: &ConfigObj{
AccountID: "",
ClusterName: "",
CloudReportURL: "",
CloudAPIURL: "",
},
inCo: &ConfigObj{
AccountID: shouldUpdate,
ClusterName: shouldUpdate,
CloudReportURL: shouldUpdate,
CloudAPIURL: shouldUpdate,
},
},
{
outCo: &ConfigObj{
AccountID: anyString,
ClusterName: "",
CloudReportURL: "",
CloudAPIURL: "",
},
inCo: &ConfigObj{
AccountID: shouldNotUpdate,
ClusterName: shouldUpdate,
CloudReportURL: shouldUpdate,
CloudAPIURL: shouldUpdate,
},
},
{
outCo: &ConfigObj{
AccountID: "",
ClusterName: anyString,
CloudReportURL: anyString,
CloudAPIURL: anyString,
},
inCo: &ConfigObj{
AccountID: shouldUpdate,
ClusterName: shouldNotUpdate,
CloudReportURL: shouldNotUpdate,
CloudAPIURL: shouldNotUpdate,
},
},
{
outCo: &ConfigObj{
AccountID: anyString,
ClusterName: anyString,
CloudReportURL: "",
CloudAPIURL: anyString,
},
inCo: &ConfigObj{
AccountID: shouldNotUpdate,
ClusterName: shouldNotUpdate,
CloudReportURL: shouldUpdate,
CloudAPIURL: shouldNotUpdate,
},
},
}
for i := range tests {
beforeChangesOutCO := tests[i].outCo
tests[i].outCo.updateEmptyFields(tests[i].inCo)
checkIsUpdateCorrectly(t, beforeChangesOutCO.AccountID, tests[i].outCo.AccountID)
checkIsUpdateCorrectly(t, beforeChangesOutCO.CloudAPIURL, tests[i].outCo.CloudAPIURL)
checkIsUpdateCorrectly(t, beforeChangesOutCO.CloudReportURL, tests[i].outCo.CloudReportURL)
checkIsUpdateCorrectly(t, beforeChangesOutCO.ClusterName, tests[i].outCo.ClusterName)
}
}

View File

@@ -1,6 +1,10 @@
package cautils
import (
"context"
"sort"
"github.com/anchore/grype/grype/presenter/models"
"github.com/armosec/armoapi-go/armotypes"
"github.com/kubescape/k8s-interface/workloadinterface"
"github.com/kubescape/opa-utils/reporthandling"
@@ -13,12 +17,30 @@ import (
// K8SResources map[<api group>/<api version>/<resource>][]<resourceID>
type K8SResources map[string][]string
type KSResources map[string][]string
type ExternalResources map[string][]string
type ImageScanData struct {
PresenterConfig *models.PresenterConfig
Image string
}
type ScanTypes string
const (
TopWorkloadsNumber = 3
ScanTypeCluster ScanTypes = "cluster"
ScanTypeRepo ScanTypes = "repo"
ScanTypeImage ScanTypes = "image"
ScanTypeWorkload ScanTypes = "workload"
ScanTypeFramework ScanTypes = "framework"
ScanTypeControl ScanTypes = "control"
)
type OPASessionObj struct {
K8SResources *K8SResources // input k8s objects
ArmoResource *KSResources // input ARMO objects
K8SResources K8SResources // input k8s objects
ExternalResources ExternalResources // input non-k8s objects (external resources)
AllPolicies *Policies // list of all frameworks
ExcludedRules map[string]bool // rules to exclude map[rule name>]X
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>
@@ -34,9 +56,11 @@ type OPASessionObj struct {
Policies []reporthandling.Framework // list of frameworks to scan
Exceptions []armotypes.PostureExceptionPolicy // list of exceptions to apply on scan results
OmitRawResources bool // omit raw resources from output
SingleResourceScan workloadinterface.IWorkload // single resource scan
TopWorkloadsByScore []reporthandling.IResource
}
func NewOPASessionObj(frameworks []reporthandling.Framework, k8sResources *K8SResources, scanInfo *ScanInfo) *OPASessionObj {
func NewOPASessionObj(ctx context.Context, frameworks []reporthandling.Framework, k8sResources K8SResources, scanInfo *ScanInfo) *OPASessionObj {
return &OPASessionObj{
Report: &reporthandlingv2.PostureReport{},
Policies: frameworks,
@@ -48,11 +72,50 @@ func NewOPASessionObj(frameworks []reporthandling.Framework, k8sResources *K8SRe
ResourceToControlsMap: make(map[string][]string),
ResourceSource: make(map[string]reporthandling.Source),
SessionID: scanInfo.ScanID,
Metadata: scanInfoToScanMetadata(scanInfo),
Metadata: scanInfoToScanMetadata(ctx, scanInfo),
OmitRawResources: scanInfo.OmitRawResources,
}
}
// SetTopWorkloads sets the top workloads by score
func (sessionObj *OPASessionObj) SetTopWorkloads() {
count := 0
topWorkloadsSorted := make([]prioritization.PrioritizedResource, 0)
// create list in order to sort
for _, wl := range sessionObj.ResourcesPrioritized {
topWorkloadsSorted = append(topWorkloadsSorted, wl)
}
// sort by score. If scores are equal, sort by resource ID
sort.Slice(topWorkloadsSorted, func(i, j int) bool {
if topWorkloadsSorted[i].Score == topWorkloadsSorted[j].Score {
return topWorkloadsSorted[i].ResourceID < topWorkloadsSorted[j].ResourceID
}
return topWorkloadsSorted[i].Score > topWorkloadsSorted[j].Score
})
if sessionObj.Report == nil {
sessionObj.Report = &reporthandlingv2.PostureReport{}
}
// set top workloads according to number of top workloads
for i := 0; i < TopWorkloadsNumber; i++ {
if i >= len(topWorkloadsSorted) {
break
}
source := sessionObj.ResourceSource[topWorkloadsSorted[i].ResourceID]
wlObj := &reporthandling.Resource{
IMetadata: sessionObj.AllResources[topWorkloadsSorted[i].ResourceID],
Source: &source,
}
sessionObj.TopWorkloadsByScore = append(sessionObj.TopWorkloadsByScore, wlObj)
count++
}
}
func (sessionObj *OPASessionObj) SetMapNamespaceToNumberOfResources(mapNamespaceToNumberOfResources map[string]int) {
if sessionObj.Metadata.ContextMetadata.ClusterContextMetadata == nil {
sessionObj.Metadata.ContextMetadata.ClusterContextMetadata = &reporthandlingv2.ClusterMetadata{}

View File

@@ -5,6 +5,7 @@ import (
"github.com/armosec/utils-go/boolutils"
"github.com/kubescape/opa-utils/reporthandling"
"github.com/kubescape/opa-utils/reporthandling/apis"
)
func NewPolicies() *Policies {
@@ -14,22 +15,41 @@ func NewPolicies() *Policies {
}
}
func (policies *Policies) Set(frameworks []reporthandling.Framework, version string) {
func (policies *Policies) Set(frameworks []reporthandling.Framework, version string, excludedRules map[string]bool, scanningScope reporthandling.ScanningScopeType) {
for i := range frameworks {
if !isFrameworkFitToScanScope(frameworks[i], scanningScope) {
continue
}
if frameworks[i].Name != "" && len(frameworks[i].Controls) > 0 {
policies.Frameworks = append(policies.Frameworks, frameworks[i].Name)
}
for j := range frameworks[i].Controls {
compatibleRules := []reporthandling.PolicyRule{}
for r := range frameworks[i].Controls[j].Rules {
if !ruleWithKSOpaDependency(frameworks[i].Controls[j].Rules[r].Attributes) && isRuleKubescapeVersionCompatible(frameworks[i].Controls[j].Rules[r].Attributes, version) {
if excludedRules != nil {
ruleName := frameworks[i].Controls[j].Rules[r].Name
if _, exclude := excludedRules[ruleName]; exclude {
continue
}
}
if !ruleWithKSOpaDependency(frameworks[i].Controls[j].Rules[r].Attributes) && isRuleKubescapeVersionCompatible(frameworks[i].Controls[j].Rules[r].Attributes, version) && isControlFitToScanScope(frameworks[i].Controls[j], scanningScope) {
compatibleRules = append(compatibleRules, frameworks[i].Controls[j].Rules[r])
}
}
if len(compatibleRules) > 0 {
frameworks[i].Controls[j].Rules = compatibleRules
policies.Controls[frameworks[i].Controls[j].ControlID] = frameworks[i].Controls[j]
} else { // if the control type is manual review, add it to the list of controls
actionRequiredStr := frameworks[i].Controls[j].GetActionRequiredAttribute()
if actionRequiredStr == "" {
continue
}
if actionRequiredStr == string(apis.SubStatusManualReview) {
policies.Controls[frameworks[i].Controls[j].ControlID] = frameworks[i].Controls[j]
}
}
}
}
@@ -66,3 +86,55 @@ func isRuleKubescapeVersionCompatible(attributes map[string]interface{}, version
}
return true
}
func isScanningScopeMatchToControlScope(scanScope reporthandling.ScanningScopeType, controlScope reporthandling.ScanningScopeType) bool {
switch controlScope {
case reporthandling.ScopeFile:
return reporthandling.ScopeFile == scanScope
case reporthandling.ScopeCluster:
return reporthandling.ScopeCluster == scanScope || reporthandling.ScopeCloud == scanScope || reporthandling.ScopeCloudAKS == scanScope || reporthandling.ScopeCloudEKS == scanScope || reporthandling.ScopeCloudGKE == scanScope
case reporthandling.ScopeCloud:
return reporthandling.ScopeCloud == scanScope || reporthandling.ScopeCloudAKS == scanScope || reporthandling.ScopeCloudEKS == scanScope || reporthandling.ScopeCloudGKE == scanScope
case reporthandling.ScopeCloudAKS:
return reporthandling.ScopeCloudAKS == scanScope
case reporthandling.ScopeCloudEKS:
return reporthandling.ScopeCloudEKS == scanScope
case reporthandling.ScopeCloudGKE:
return reporthandling.ScopeCloudGKE == scanScope
default:
return true
}
}
func isControlFitToScanScope(control reporthandling.Control, scanScopeMatches reporthandling.ScanningScopeType) bool {
// for backward compatibility - case: kubescape with scope(new one) and regolibrary without scope(old one)
if control.ScanningScope == nil {
return true
}
if len(control.ScanningScope.Matches) == 0 {
return true
}
for i := range control.ScanningScope.Matches {
if isScanningScopeMatchToControlScope(scanScopeMatches, control.ScanningScope.Matches[i]) {
return true
}
}
return false
}
func isFrameworkFitToScanScope(framework reporthandling.Framework, scanScopeMatches reporthandling.ScanningScopeType) bool {
// for backward compatibility - case: kubescape with scope(new one) and regolibrary without scope(old one)
if framework.ScanningScope == nil {
return true
}
if len(framework.ScanningScope.Matches) == 0 {
return true
}
for i := range framework.ScanningScope.Matches {
if isScanningScopeMatchToControlScope(scanScopeMatches, framework.ScanningScope.Matches[i]) {
return true
}
}
return false
}

View File

@@ -0,0 +1,241 @@
package cautils
import (
"fmt"
"testing"
"github.com/armosec/armoapi-go/armotypes"
"github.com/kubescape/opa-utils/reporthandling"
"github.com/stretchr/testify/assert"
)
func TestIsScanningScopeMatchToControlScope(t *testing.T) {
tests := []struct {
scanScope reporthandling.ScanningScopeType
controlScope reporthandling.ScanningScopeType
expected bool
}{
{
scanScope: reporthandling.ScopeFile,
controlScope: reporthandling.ScopeFile,
expected: true,
},
{
scanScope: ScopeCluster,
controlScope: ScopeCluster,
expected: true,
},
{
scanScope: reporthandling.ScopeCloud,
controlScope: reporthandling.ScopeCloud,
expected: true,
},
{
scanScope: reporthandling.ScopeCloudAKS,
controlScope: reporthandling.ScopeCloudAKS,
expected: true,
},
{
scanScope: reporthandling.ScopeCloudEKS,
controlScope: reporthandling.ScopeCloudEKS,
expected: true,
},
{
scanScope: reporthandling.ScopeCloudGKE,
controlScope: reporthandling.ScopeCloudGKE,
expected: true,
},
{
scanScope: ScopeCluster,
controlScope: reporthandling.ScopeCloud,
expected: false,
},
{
scanScope: reporthandling.ScopeCloud,
controlScope: ScopeCluster,
expected: true,
},
{
scanScope: reporthandling.ScopeCloudAKS,
controlScope: ScopeCluster,
expected: true,
},
{
scanScope: reporthandling.ScopeCloudEKS,
controlScope: ScopeCluster,
expected: true,
},
{
scanScope: reporthandling.ScopeCloudGKE,
controlScope: ScopeCluster,
expected: true,
},
{
scanScope: reporthandling.ScopeCloud,
controlScope: reporthandling.ScopeCloudAKS,
expected: false,
},
{
scanScope: reporthandling.ScopeCloudAKS,
controlScope: reporthandling.ScopeCloud,
expected: true,
},
{
scanScope: reporthandling.ScopeCloudEKS,
controlScope: reporthandling.ScopeCloud,
expected: true,
},
{
scanScope: reporthandling.ScopeCloudGKE,
controlScope: reporthandling.ScopeCloud,
expected: true,
},
{
scanScope: ScopeCluster,
controlScope: reporthandling.ScopeCloudAKS,
expected: false,
},
{
scanScope: ScopeCluster,
controlScope: reporthandling.ScopeCloudEKS,
expected: false,
},
{
scanScope: ScopeCluster,
controlScope: reporthandling.ScopeCloudGKE,
expected: false,
},
{
scanScope: reporthandling.ScopeFile,
controlScope: ScopeCluster,
expected: false,
},
{
scanScope: reporthandling.ScopeFile,
controlScope: reporthandling.ScopeCloud,
expected: false,
},
{
scanScope: reporthandling.ScopeFile,
controlScope: reporthandling.ScopeCloudAKS,
expected: false,
},
{
scanScope: reporthandling.ScopeFile,
controlScope: reporthandling.ScopeCloudEKS,
expected: false,
},
{
scanScope: reporthandling.ScopeFile,
controlScope: reporthandling.ScopeCloudGKE,
expected: false,
},
{
scanScope: reporthandling.ScopeCloud,
controlScope: reporthandling.ScopeCloudEKS,
expected: false,
},
{
scanScope: reporthandling.ScopeCloud,
controlScope: reporthandling.ScopeCloudGKE,
expected: false,
},
{
scanScope: reporthandling.ScopeCloudAKS,
controlScope: reporthandling.ScopeCloudEKS,
expected: false,
},
{
scanScope: reporthandling.ScopeCloudAKS,
controlScope: reporthandling.ScopeCloudGKE,
expected: false,
},
{
scanScope: reporthandling.ScopeCloudEKS,
controlScope: reporthandling.ScopeCloudAKS,
expected: false,
},
{
scanScope: reporthandling.ScopeCloudEKS,
controlScope: reporthandling.ScopeCloudGKE,
expected: false,
},
{
scanScope: reporthandling.ScopeCloudGKE,
controlScope: reporthandling.ScopeCloudAKS,
expected: false,
},
{
scanScope: reporthandling.ScopeCloudGKE,
controlScope: reporthandling.ScopeCloudEKS,
expected: false,
},
}
for _, test := range tests {
result := isScanningScopeMatchToControlScope(test.scanScope, test.controlScope)
assert.Equal(t, test.expected, result, fmt.Sprintf("scanScope: %v, controlScope: %v", test.scanScope, test.controlScope))
}
}
func TestIsFrameworkFitToScanScope(t *testing.T) {
tests := []struct {
name string
framework reporthandling.Framework
scanScopeMatch reporthandling.ScanningScopeType
want bool
}{
{
name: "Framework with nil ScanningScope should return true",
framework: reporthandling.Framework{
PortalBase: armotypes.PortalBase{
Name: "test-framework",
},
},
scanScopeMatch: reporthandling.ScopeFile,
want: true,
},
{
name: "Framework with empty ScanningScope.Matches should return true",
framework: reporthandling.Framework{
PortalBase: armotypes.PortalBase{
Name: "test-framework",
}, ScanningScope: &reporthandling.ScanningScope{},
},
scanScopeMatch: reporthandling.ScopeFile,
want: true,
},
{
name: "Framework with matching ScanningScope.Matches should return true",
framework: reporthandling.Framework{
PortalBase: armotypes.PortalBase{
Name: "test-framework",
}, ScanningScope: &reporthandling.ScanningScope{
Matches: []reporthandling.ScanningScopeType{reporthandling.ScopeFile},
},
},
scanScopeMatch: reporthandling.ScopeFile,
want: true,
},
{
name: "Framework with non-matching ScanningScope.Matches should return false",
framework: reporthandling.Framework{
PortalBase: armotypes.PortalBase{
Name: "test-framework",
}, ScanningScope: &reporthandling.ScanningScope{
Matches: []reporthandling.ScanningScopeType{reporthandling.ScopeCluster},
},
},
scanScopeMatch: reporthandling.ScopeFile,
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := isFrameworkFitToScanScope(tt.framework, tt.scanScopeMatch); got != tt.want {
t.Errorf("isFrameworkFitToScanScope() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -1,26 +1,62 @@
package cautils
import (
"fmt"
"io"
"os"
"time"
spinnerpkg "github.com/briandowns/spinner"
"github.com/fatih/color"
"github.com/jwalton/gchalk"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/mattn/go-isatty"
"github.com/schollz/progressbar/v3"
)
var FailureDisplay = color.New(color.Bold, color.FgHiRed).FprintfFunc()
var WarningDisplay = color.New(color.Bold, color.FgHiYellow).FprintfFunc()
var FailureTextDisplay = color.New(color.Faint, color.FgHiRed).FprintfFunc()
var InfoDisplay = color.New(color.Bold, color.FgCyan).FprintfFunc()
var InfoTextDisplay = color.New(color.Bold, color.FgHiYellow).FprintfFunc()
var SimpleDisplay = color.New().FprintfFunc()
var SuccessDisplay = color.New(color.Bold, color.FgHiGreen).FprintfFunc()
var DescriptionDisplay = color.New(color.Faint, color.FgWhite).FprintfFunc()
func FailureDisplay(w io.Writer, format string, a ...interface{}) {
fmt.Fprintf(w, gchalk.WithBrightRed().Bold(format), a...)
}
func WarningDisplay(w io.Writer, format string, a ...interface{}) {
fmt.Fprintf(w, gchalk.WithBrightYellow().Bold(format), a...)
}
func FailureTextDisplay(w io.Writer, format string, a ...interface{}) {
fmt.Fprintf(w, gchalk.WithBrightRed().Dim(format), a...)
}
func InfoDisplay(w io.Writer, format string, a ...interface{}) {
fmt.Fprintf(w, gchalk.WithCyan().Bold(format), a...)
}
func InfoTextDisplay(w io.Writer, format string, a ...interface{}) {
fmt.Fprintf(w, gchalk.WithBrightYellow().Bold(format), a...)
}
func SimpleDisplay(w io.Writer, format string, a ...interface{}) {
fmt.Fprintf(w, gchalk.White(format), a...)
}
func SuccessDisplay(w io.Writer, format string, a ...interface{}) {
fmt.Fprintf(w, gchalk.WithBlue().Bold(format), a...)
}
func DescriptionDisplay(w io.Writer, format string, a ...interface{}) {
fmt.Fprintf(w, gchalk.WithWhite().Dim(format), a...)
}
func BoldDisplay(w io.Writer, format string, a ...interface{}) {
fmt.Fprintf(w, gchalk.Bold(format), a...)
}
var spinner *spinnerpkg.Spinner
func StartSpinner() {
if helpers.ToLevel(logger.L().GetLevel()) >= helpers.WarningLevel {
return
}
if spinner != nil {
if !spinner.Active() {
spinner.Start()
@@ -39,3 +75,28 @@ func StopSpinner() {
}
spinner.Stop()
}
type ProgressHandler struct {
pb *progressbar.ProgressBar
title string
}
func NewProgressHandler(title string) *ProgressHandler {
return &ProgressHandler{title: title}
}
func (p *ProgressHandler) Start(allSteps int) {
if !isatty.IsTerminal(os.Stderr.Fd()) || helpers.ToLevel(logger.L().GetLevel()) >= helpers.WarningLevel {
p.pb = progressbar.DefaultSilent(int64(allSteps), p.title)
return
}
p.pb = progressbar.Default(int64(allSteps), p.title)
}
func (p *ProgressHandler) ProgressJob(step int, message string) {
p.pb.Add(step)
p.pb.Describe(message)
}
func (p *ProgressHandler) Stop() {
}

View File

@@ -0,0 +1,32 @@
package cautils
import (
"testing"
"github.com/kubescape/go-logger"
)
func TestStartSpinner(t *testing.T) {
tests := []struct {
name string
loggerLevel string
enabled bool
}{
{
name: "TestStartSpinner - disabled",
loggerLevel: "warning",
enabled: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
logger.L().SetLevel(tt.loggerLevel)
StartSpinner()
if !tt.enabled {
if spinner != nil {
t.Errorf("spinner should be nil")
}
}
})
}
}

View File

@@ -1,7 +0,0 @@
package cautils
// Kubescape Cloud environment vars
var (
CustomerGUID = ""
ClusterName = ""
)

View File

@@ -2,6 +2,7 @@ package cautils
import (
"bytes"
"context"
"encoding/json"
"fmt"
"os"
@@ -10,6 +11,7 @@ import (
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/k8s-interface/workloadinterface"
"golang.org/x/exp/slices"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/opa-utils/objectsenvelopes"
@@ -30,8 +32,13 @@ const (
JSON_FILE_FORMAT FileFormat = "json"
)
type Chart struct {
Name string
Path string
}
// LoadResourcesFromHelmCharts scans a given path (recursively) for helm charts, renders the templates and returns a map of workloads and a map of chart names
func LoadResourcesFromHelmCharts(basePath string) (map[string][]workloadinterface.IMetadata, map[string]string) {
func LoadResourcesFromHelmCharts(ctx context.Context, basePath string) (map[string][]workloadinterface.IMetadata, map[string]Chart) {
directories, _ := listDirs(basePath)
helmDirectories := make([]string, 0)
for _, dir := range directories {
@@ -41,29 +48,32 @@ func LoadResourcesFromHelmCharts(basePath string) (map[string][]workloadinterfac
}
sourceToWorkloads := map[string][]workloadinterface.IMetadata{}
sourceToChartName := map[string]string{}
sourceToChart := make(map[string]Chart, 0)
for _, helmDir := range helmDirectories {
chart, err := NewHelmChart(helmDir)
if err == nil {
wls, errs := chart.GetWorkloadsWithDefaultValues()
if len(errs) > 0 {
logger.L().Error(fmt.Sprintf("Rendering of Helm chart template '%s', failed: %v", chart.GetName(), errs))
logger.L().Ctx(ctx).Warning(fmt.Sprintf("Rendering of Helm chart template '%s', failed: %v", chart.GetName(), errs))
continue
}
chartName := chart.GetName()
for k, v := range wls {
sourceToWorkloads[k] = v
sourceToChartName[k] = chartName
sourceToChart[k] = Chart{
Name: chartName,
Path: helmDir,
}
}
}
}
return sourceToWorkloads, sourceToChartName
return sourceToWorkloads, sourceToChart
}
// If the contents at given path is a Kustomize Directory, LoadResourcesFromKustomizeDirectory will
// generate yaml files using "Kustomize" & renders a map of workloads from those yaml files
func LoadResourcesFromKustomizeDirectory(basePath string) (map[string][]workloadinterface.IMetadata, string) {
func LoadResourcesFromKustomizeDirectory(ctx context.Context, basePath string) (map[string][]workloadinterface.IMetadata, string) {
isKustomizeDirectory := IsKustomizeDirectory(basePath)
isKustomizeFile := IsKustomizeFile(basePath)
if ok := isKustomizeDirectory || isKustomizeFile; !ok {
@@ -87,7 +97,7 @@ func LoadResourcesFromKustomizeDirectory(basePath string) (map[string][]workload
kustomizeDirectoryName := GetKustomizeDirectoryName(newBasePath)
if len(errs) > 0 {
logger.L().Error(fmt.Sprintf("Rendering yaml from Kustomize failed: %v", errs))
logger.L().Ctx(ctx).Warning(fmt.Sprintf("Rendering yaml from Kustomize failed: %v", errs))
}
for k, v := range wls {
@@ -96,18 +106,19 @@ func LoadResourcesFromKustomizeDirectory(basePath string) (map[string][]workload
return sourceToWorkloads, kustomizeDirectoryName
}
func LoadResourcesFromFiles(input, rootPath string) map[string][]workloadinterface.IMetadata {
func LoadResourcesFromFiles(ctx context.Context, input, rootPath string) map[string][]workloadinterface.IMetadata {
files, errs := listFiles(input)
if len(errs) > 0 {
logger.L().Error(fmt.Sprintf("%v", errs))
logger.L().Ctx(ctx).Warning(fmt.Sprintf("%v", errs))
}
if len(files) == 0 {
logger.L().Ctx(ctx).Error("no files found to scan", helpers.String("input", input))
return nil
}
workloads, errs := loadFiles(rootPath, files)
if len(errs) > 0 {
logger.L().Error(fmt.Sprintf("%v", errs))
logger.L().Ctx(ctx).Warning(fmt.Sprintf("%v", errs))
}
return workloads
@@ -282,11 +293,11 @@ func convertYamlToJson(i interface{}) interface{} {
}
func IsYaml(filePath string) bool {
return StringInSlice(YAML_PREFIX, strings.ReplaceAll(filepath.Ext(filePath), ".", "")) != ValueNotFound
return slices.Contains(YAML_PREFIX, strings.ReplaceAll(filepath.Ext(filePath), ".", ""))
}
func IsJson(filePath string) bool {
return StringInSlice(JSON_PREFIX, strings.ReplaceAll(filepath.Ext(filePath), ".", "")) != ValueNotFound
return slices.Contains(JSON_PREFIX, strings.ReplaceAll(filepath.Ext(filePath), ".", ""))
}
func glob(root, pattern string, onlyDirectories bool) ([]string, error) {

View File

@@ -1,6 +1,7 @@
package cautils
import (
"context"
"os"
"path/filepath"
"strings"
@@ -30,7 +31,7 @@ func TestListFiles(t *testing.T) {
}
func TestLoadResourcesFromFiles(t *testing.T) {
workloads := LoadResourcesFromFiles(onlineBoutiquePath(), "")
workloads := LoadResourcesFromFiles(context.TODO(), onlineBoutiquePath(), "")
assert.Equal(t, 12, len(workloads))
for i, w := range workloads {
@@ -44,7 +45,7 @@ func TestLoadResourcesFromFiles(t *testing.T) {
}
func TestLoadResourcesFromHelmCharts(t *testing.T) {
sourceToWorkloads, sourceToChartName := LoadResourcesFromHelmCharts(helmChartPath())
sourceToWorkloads, sourceToChartName := LoadResourcesFromHelmCharts(context.TODO(), helmChartPath())
assert.Equal(t, 6, len(sourceToWorkloads))
for file, workloads := range sourceToWorkloads {
@@ -52,7 +53,8 @@ func TestLoadResourcesFromHelmCharts(t *testing.T) {
w := workloads[0]
assert.True(t, localworkload.IsTypeLocalWorkload(w.GetObject()), "Expected localworkload as object type")
assert.Equal(t, "kubescape", sourceToChartName[file])
assert.Equal(t, "kubescape", sourceToChartName[file].Name)
assert.Equal(t, helmChartPath(), sourceToChartName[file].Path)
switch filepath.Base(file) {
case "serviceaccount.yaml":

View File

@@ -1,24 +1,4 @@
package getter
type FeLoginData struct {
Secret string `json:"secret"`
ClientId string `json:"clientId"`
}
type FeLoginResponse struct {
Token string `json:"accessToken"`
RefreshToken string `json:"refreshToken"`
Expires string `json:"expires"`
ExpiresIn int32 `json:"expiresIn"`
}
type KSCloudSelectCustomer struct {
SelectedCustomerGuid string `json:"selectedCustomer"`
}
type TenantResponse struct {
TenantID string `json:"tenantId"`
Token string `json:"token"`
Expires string `json:"expires"`
AdminMail string `json:"adminMail,omitempty"`
}
// NativeFrameworks identifies all pre-built, native frameworks.
var NativeFrameworks = []string{"allcontrols", "nsa", "mitre"}

View File

@@ -0,0 +1,8 @@
// Package getter provides functionality to retrieve policy objects.
//
// It comes with 3 implementations:
//
// * KSCloudAPI is a client for the KS Cloud SaaS API
// * LoadPolicy exposes policy objects stored in a local repository
// * DownloadReleasedPolicy downloads policy objects from the policy library released on github: https://github.com/kubescape/regolibrary
package getter

View File

@@ -5,14 +5,22 @@ import (
"strings"
"github.com/armosec/armoapi-go/armotypes"
"github.com/kubescape/opa-utils/gitregostore"
"github.com/kubescape/opa-utils/reporthandling"
"github.com/kubescape/opa-utils/reporthandling/attacktrack/v1alpha1"
"github.com/kubescape/regolibrary/gitregostore"
)
// =======================================================================================================================
// ======================================== DownloadReleasedPolicy =======================================================
// =======================================================================================================================
var (
_ IPolicyGetter = &DownloadReleasedPolicy{}
_ IExceptionsGetter = &DownloadReleasedPolicy{}
_ IAttackTracksGetter = &DownloadReleasedPolicy{}
_ IControlsInputsGetter = &DownloadReleasedPolicy{}
)
// Use gitregostore to get policies from github release
type DownloadReleasedPolicy struct {
@@ -71,12 +79,12 @@ func (drp *DownloadReleasedPolicy) ListControls() ([]string, error) {
}
var controlsFrameworksList [][]string
for _, control := range controls {
controlsFrameworksList = append(controlsFrameworksList, control.FrameworkNames)
controlsFrameworksList = append(controlsFrameworksList, drp.gs.GetOpaFrameworkListByControlID(control.ControlID))
}
controlsNamesWithIDsandFrameworksList := make([]string, len(controlsIDsList))
// by design all slices have the same lengt
for i := range controlsIDsList {
controlsNamesWithIDsandFrameworksList[i] = fmt.Sprintf("%v|%v|%v", controlsIDsList[i], controlsNamesList[i], strings.Join(controlsFrameworksList[i], ","))
controlsNamesWithIDsandFrameworksList[i] = fmt.Sprintf("%v|%v|%v", controlsIDsList[i], controlsNamesList[i], strings.Join(controlsFrameworksList[i], ", "))
}
return controlsNamesWithIDsandFrameworksList, nil
}
@@ -105,19 +113,6 @@ func (drp *DownloadReleasedPolicy) SetRegoObjects() error {
return drp.gs.SetRegoObjects()
}
func isNativeFramework(framework string) bool {
return contains(NativeFrameworks, framework)
}
func contains(s []string, str string) bool {
for _, v := range s {
if strings.EqualFold(v, str) {
return true
}
}
return false
}
func (drp *DownloadReleasedPolicy) GetExceptions(clusterName string) ([]armotypes.PostureExceptionPolicy, error) {
exceptions, err := drp.gs.GetSystemPostureExceptionPolicies()
if err != nil {

View File

@@ -0,0 +1,172 @@
package getter
import (
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
"testing"
jsoniter "github.com/json-iterator/go"
"github.com/kubescape/kubescape/v3/internal/testutils"
"github.com/stretchr/testify/require"
)
func min(a, b int64) int64 {
if a < b {
return a
}
return b
}
func TestReleasedPolicy(t *testing.T) {
t.Parallel()
p := NewDownloadReleasedPolicy()
t.Run("should initialize objects", func(t *testing.T) {
t.Parallel()
// acquire from github or from local fixture
hydrateReleasedPolicyFromMock(t, p)
require.NoError(t, p.SetRegoObjects())
t.Run("with ListControls", func(t *testing.T) {
t.Parallel()
controlIDs, err := p.ListControls()
require.NoError(t, err)
require.NotEmpty(t, controlIDs)
sampleSize := int(min(int64(len(controlIDs)), 10))
for _, toPin := range controlIDs[:sampleSize] {
// Example of a returned "ID": `C-0154|Ensure_that_the_--client-cert-auth_argument_is_set_to_true|`
controlString := toPin
parts := strings.Split(controlString, "|")
controlID := parts[0]
t.Run(fmt.Sprintf("with GetControl(%q)", controlID), func(t *testing.T) {
t.Parallel()
ctrl, err := p.GetControl(controlID)
require.NoError(t, err)
require.NotEmpty(t, ctrl)
require.Equal(t, controlID, ctrl.ControlID)
})
}
t.Run("with unknown GetControl()", func(t *testing.T) {
t.Parallel()
ctrl, err := p.GetControl("zork")
require.Error(t, err)
require.Nil(t, ctrl)
})
})
t.Run("with GetFrameworks", func(t *testing.T) {
t.Parallel()
frameworks, err := p.GetFrameworks()
require.NoError(t, err)
require.NotEmpty(t, frameworks)
for _, toPin := range frameworks {
framework := toPin
require.NotEmpty(t, framework)
require.NotEmpty(t, framework.Name)
t.Run(fmt.Sprintf("with GetFramework(%q)", framework.Name), func(t *testing.T) {
t.Parallel()
fw, err := p.GetFramework(framework.Name)
require.NoError(t, err)
require.NotNil(t, fw)
require.EqualValues(t, framework, *fw)
})
}
t.Run("with unknown GetFramework()", func(t *testing.T) {
t.Parallel()
ctrl, err := p.GetFramework("zork")
require.Error(t, err)
require.Nil(t, ctrl)
})
t.Run("with ListFrameworks", func(t *testing.T) {
t.Parallel()
frameworkIDs, err := p.ListFrameworks()
require.NoError(t, err)
require.NotEmpty(t, frameworkIDs)
require.Len(t, frameworkIDs, len(frameworks))
})
})
t.Run("with GetControlsInput", func(t *testing.T) {
t.Parallel()
controlInputs, err := p.GetControlsInputs("") // NOTE: cluster name currently unused
require.NoError(t, err)
require.NotEmpty(t, controlInputs)
})
t.Run("with GetAttackTracks", func(t *testing.T) {
t.Parallel()
attackTracks, err := p.GetAttackTracks()
require.NoError(t, err)
require.NotEmpty(t, attackTracks)
})
t.Run("with GetExceptions", func(t *testing.T) {
t.Parallel()
exceptions, err := p.GetExceptions("") // NOTE: cluster name currently unused
require.NoError(t, err)
require.NotEmpty(t, exceptions)
})
})
}
func hydrateReleasedPolicyFromMock(t testing.TB, p *DownloadReleasedPolicy) {
regoFile := testRegoFile("policy")
if _, err := os.Stat(regoFile); errors.Is(err, fs.ErrNotExist) {
// retrieve fixture from latest released policy from github.
//
// NOTE: to update the mock, just delete the testdata/policy.json file and run the tests again.
t.Logf("updating fixture file %q from github", regoFile)
require.NoError(t, p.SetRegoObjects())
require.NotNil(t, p.gs)
require.NoError(t,
SaveInFile(p.gs, regoFile),
)
return
}
// we have a mock fixture: load this rather than calling github
t.Logf("populating rego policy from fixture file %q", regoFile)
buf, err := os.ReadFile(regoFile)
require.NoError(t, err)
require.NoError(t,
jsoniter.Unmarshal(buf, p.gs),
)
}
func testRegoFile(framework string) string {
return filepath.Join(testutils.CurrentDir(), "testdata", fmt.Sprintf("%s.json", framework))
}

View File

@@ -1,42 +0,0 @@
package getter
import (
"context"
"os"
containeranalysis "cloud.google.com/go/containeranalysis/apiv1"
)
type GCPCloudAPI struct {
credentialsPath string
context context.Context
client *containeranalysis.Client
projectID string
credentialsCheck bool
}
func GetGlobalGCPCloudAPIConnector() *GCPCloudAPI {
if os.Getenv("KS_GCP_CREDENTIALS_PATH") == "" || os.Getenv("KS_GCP_PROJECT_ID") == "" {
return &GCPCloudAPI{
credentialsCheck: false,
}
} else {
return &GCPCloudAPI{
context: context.Background(),
credentialsPath: os.Getenv("KS_GCP_CREDENTIALS_PATH"),
projectID: os.Getenv("KS_GCP_PROJECT_ID"),
credentialsCheck: true,
}
}
}
func (api *GCPCloudAPI) SetClient(client *containeranalysis.Client) {
api.client = client
}
func (api *GCPCloudAPI) GetCredentialsPath() string { return api.credentialsPath }
func (api *GCPCloudAPI) GetClient() *containeranalysis.Client { return api.client }
func (api *GCPCloudAPI) GetProjectID() string { return api.projectID }
func (api *GCPCloudAPI) GetCredentialsCheck() bool { return api.credentialsCheck }
func (api *GCPCloudAPI) GetContext() context.Context { return api.context }

View File

@@ -1,47 +0,0 @@
package getter
import (
"github.com/armosec/armoapi-go/armotypes"
"github.com/kubescape/opa-utils/reporthandling"
"github.com/kubescape/opa-utils/reporthandling/attacktrack/v1alpha1"
)
type IPolicyGetter interface {
GetFramework(name string) (*reporthandling.Framework, error)
GetFrameworks() ([]reporthandling.Framework, error)
GetControl(ID string) (*reporthandling.Control, error)
ListFrameworks() ([]string, error)
ListControls() ([]string, error)
}
type IExceptionsGetter interface {
GetExceptions(clusterName string) ([]armotypes.PostureExceptionPolicy, error)
}
type IBackend interface {
GetAccountID() string
GetClientID() string
GetSecretKey() string
GetCloudReportURL() string
GetCloudAPIURL() string
GetCloudUIURL() string
GetCloudAuthURL() string
SetAccountID(accountID string)
SetClientID(clientID string)
SetSecretKey(secretKey string)
SetCloudReportURL(cloudReportURL string)
SetCloudAPIURL(cloudAPIURL string)
SetCloudUIURL(cloudUIURL string)
SetCloudAuthURL(cloudAuthURL string)
GetTenant() (*TenantResponse, error)
}
type IControlsInputsGetter interface {
GetControlsInputs(clusterName string) (map[string][]string, error)
}
type IAttackTracksGetter interface {
GetAttackTracks() ([]v1alpha1.AttackTrack, error)
}

View File

@@ -6,24 +6,27 @@ import (
"io"
"net/http"
"os"
"path"
"path/filepath"
"strings"
)
// GetDefaultPath returns a location under the local dot files for kubescape.
//
// This is typically located under $HOME/.kubescape
func GetDefaultPath(name string) string {
return filepath.Join(DefaultLocalStore, name)
}
func SaveInFile(policy interface{}, pathStr string) error {
encodedData, err := json.MarshalIndent(policy, "", " ")
// SaveInFile serializes any object as a JSON file.
func SaveInFile(object interface{}, targetFile string) error {
encodedData, err := json.MarshalIndent(object, "", " ")
if err != nil {
return err
}
err = os.WriteFile(pathStr, encodedData, 0644) //nolint:gosec
err = os.WriteFile(targetFile, encodedData, 0644) //nolint:gosec
if err != nil {
if os.IsNotExist(err) {
pathDir := path.Dir(pathStr)
pathDir := filepath.Dir(targetFile)
// pathDir could contain subdirectories
if erm := os.MkdirAll(pathDir, 0755); erm != nil {
return erm
@@ -32,7 +35,7 @@ func SaveInFile(policy interface{}, pathStr string) error {
return err
}
err = os.WriteFile(pathStr, encodedData, 0644) //nolint:gosec
err = os.WriteFile(targetFile, encodedData, 0644) //nolint:gosec
if err != nil {
return err
}
@@ -40,6 +43,9 @@ func SaveInFile(policy interface{}, pathStr string) error {
return nil
}
// HttpDelete provides a low-level capability to send a HTTP DELETE request and serialize the response as a string.
//
// Deprecated: use methods of the KSCloudAPI client instead.
func HttpDelete(httpClient *http.Client, fullURL string, headers map[string]string) (string, error) {
req, err := http.NewRequest("DELETE", fullURL, nil)
@@ -59,8 +65,10 @@ func HttpDelete(httpClient *http.Client, fullURL string, headers map[string]stri
return respStr, nil
}
// HttpGetter provides a low-level capability to send a HTTP GET request and serialize the response as a string.
//
// Deprecated: use methods of the KSCloudAPI client instead.
func HttpGetter(httpClient *http.Client, fullURL string, headers map[string]string) (string, error) {
req, err := http.NewRequest("GET", fullURL, nil)
if err != nil {
return "", err
@@ -78,8 +86,10 @@ func HttpGetter(httpClient *http.Client, fullURL string, headers map[string]stri
return respStr, nil
}
// HttpPost provides a low-level capability to send a HTTP POST request and serialize the response as a string.
//
// Deprecated: use methods of the KSCloudAPI client instead.
func HttpPost(httpClient *http.Client, fullURL string, headers map[string]string, body []byte) (string, error) {
req, err := http.NewRequest("POST", fullURL, bytes.NewReader(body))
if err != nil {
return "", err
@@ -104,7 +114,7 @@ func setHeaders(req *http.Request, headers map[string]string) {
}
}
// HTTPRespToString parses the body as string and checks the HTTP status code, it closes the body reader at the end
// httpRespToString parses the body as string and checks the HTTP status code, it closes the body reader at the end
func httpRespToString(resp *http.Response) (string, error) {
if resp == nil || resp.Body == nil {
return "", nil
@@ -114,6 +124,7 @@ func httpRespToString(resp *http.Response) (string, error) {
if resp.ContentLength > 0 {
strBuilder.Grow(int(resp.ContentLength))
}
_, err := io.Copy(&strBuilder, resp.Body)
respStr := strBuilder.String()
if err != nil {

View File

@@ -0,0 +1,98 @@
package getter
import (
"net/http"
"os"
"path/filepath"
"testing"
beClient "github.com/kubescape/backend/pkg/client/v1"
"github.com/stretchr/testify/require"
)
func TestGetDefaultPath(t *testing.T) {
t.Parallel()
const name = "mine"
pth := GetDefaultPath(name)
require.Equal(t, name, filepath.Base(pth))
require.Equal(t, ".kubescape", filepath.Base(filepath.Dir(pth)))
}
func TestSaveInFile(t *testing.T) {
t.Parallel()
dir, err := os.MkdirTemp(".", "test")
require.NoError(t, err)
defer func() {
_ = os.RemoveAll(dir)
}()
policy := map[string]interface{}{
"key": "value",
"number": 1.00,
}
t.Run("should save data as JSON (target folder exists)", func(t *testing.T) {
target := filepath.Join(dir, "target.json")
require.NoError(t, SaveInFile(policy, target))
buf, err := os.ReadFile(target)
require.NoError(t, err)
var retrieved interface{}
require.NoError(t, json.Unmarshal(buf, &retrieved))
require.EqualValues(t, policy, retrieved)
})
t.Run("should save data as JSON (new target folder)", func(t *testing.T) {
target := filepath.Join(dir, "subdir", "target.json")
require.NoError(t, SaveInFile(policy, target))
buf, err := os.ReadFile(target)
require.NoError(t, err)
var retrieved interface{}
require.NoError(t, json.Unmarshal(buf, &retrieved))
require.EqualValues(t, policy, retrieved)
})
t.Run("should error", func(t *testing.T) {
badPolicy := map[string]interface{}{
"key": "value",
"number": 1.00,
"err": func() {},
}
target := filepath.Join(dir, "error.json")
require.Error(t, SaveInFile(badPolicy, target))
})
}
func TestHttpMethods(t *testing.T) {
client := http.DefaultClient
hdrs := map[string]string{"key": "value"}
srv := beClient.MockAPIServer(t)
t.Cleanup(srv.Close)
t.Run("HttpGetter should GET", func(t *testing.T) {
resp, err := HttpGetter(client, srv.URL(pathTestGet), hdrs)
require.NoError(t, err)
require.EqualValues(t, "body-get", resp)
})
t.Run("HttpPost should POST", func(t *testing.T) {
body := []byte("body-post")
resp, err := HttpPost(client, srv.URL(pathTestPost), hdrs, body)
require.NoError(t, err)
require.EqualValues(t, string(body), resp)
})
t.Run("HttpDelete should DELETE", func(t *testing.T) {
resp, err := HttpDelete(client, srv.URL(pathTestDelete), hdrs)
require.NoError(t, err)
require.EqualValues(t, "body-delete", resp)
})
}

View File

@@ -0,0 +1,34 @@
package getter
import (
"github.com/armosec/armoapi-go/armotypes"
"github.com/kubescape/opa-utils/reporthandling"
"github.com/kubescape/opa-utils/reporthandling/attacktrack/v1alpha1"
)
type (
// IPolicyGetter knows how to retrieve policies, i.e. frameworks and their controls.
IPolicyGetter interface {
GetFramework(name string) (*reporthandling.Framework, error)
GetFrameworks() ([]reporthandling.Framework, error)
GetControl(ID string) (*reporthandling.Control, error)
ListFrameworks() ([]string, error)
ListControls() ([]string, error)
}
// IExceptionsGetter knows how to retrieve exceptions.
IExceptionsGetter interface {
GetExceptions(clusterName string) ([]armotypes.PostureExceptionPolicy, error)
}
// IControlsInputsGetter knows how to retrieve controls inputs.
IControlsInputsGetter interface {
GetControlsInputs(clusterName string) (map[string][]string, error)
}
// IAttackTracksGetter knows how to retrieve attack tracks.
IAttackTracksGetter interface {
GetAttackTracks() ([]v1alpha1.AttackTrack, error)
}
)

View File

@@ -1,16 +1,13 @@
package getter
import (
"io"
"strings"
stdjson "encoding/json"
jsoniter "github.com/json-iterator/go"
)
var (
json jsoniter.API
)
var json jsoniter.API
func init() {
// NOTE(fredbi): attention, this configuration rounds floats down to 6 digits
@@ -18,9 +15,24 @@ func init() {
json = jsoniter.ConfigFastest
}
// JSONDecoder returns JSON decoder for given string
func JSONDecoder(origin string) *stdjson.Decoder {
dec := stdjson.NewDecoder(strings.NewReader(origin))
// JSONDecoder provides a low-level utility that returns a JSON decoder for given string.
//
// Deprecated: use higher level methods from the KSCloudAPI client instead.
func JSONDecoder(origin string) *jsoniter.Decoder {
dec := jsoniter.NewDecoder(strings.NewReader(origin))
dec.UseNumber()
return dec
}
func decode[T any](rdr io.Reader) (T, error) {
var receiver T
dec := newDecoder(rdr)
err := dec.Decode(&receiver)
return receiver, err
}
func newDecoder(rdr io.Reader) *jsoniter.Decoder {
return json.NewDecoder(rdr)
}

View File

@@ -1,379 +1,49 @@
package getter
import (
"bytes"
"fmt"
"io"
"net/http"
"strings"
"time"
"github.com/armosec/armoapi-go/armotypes"
"github.com/kubescape/opa-utils/reporthandling"
"github.com/kubescape/opa-utils/reporthandling/attacktrack/v1alpha1"
v1 "github.com/kubescape/backend/pkg/client/v1"
"github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
)
var (
ksCloudERURL = "report.armo.cloud"
ksCloudBEURL = "api.armosec.io"
ksCloudFEURL = "cloud.armosec.io"
ksCloudAUTHURL = "auth.armosec.io"
// globalKSCloudAPIConnector is a static global instance of the KS Cloud client,
// to be initialized with SetKSCloudAPIConnector.
globalKSCloudAPIConnector *v1.KSCloudAPI
ksCloudStageERURL = "report-ks.eustage2.cyberarmorsoft.com"
ksCloudStageBEURL = "api-stage.armosec.io"
ksCloudStageFEURL = "armoui-stage.armosec.io"
ksCloudStageAUTHURL = "eggauth-stage.armosec.io"
ksCloudDevERURL = "report.eudev3.cyberarmorsoft.com"
ksCloudDevBEURL = "api-dev.armosec.io"
ksCloudDevFEURL = "cloud-dev.armosec.io"
ksCloudDevAUTHURL = "eggauth-dev.armosec.io"
_ IPolicyGetter = &v1.KSCloudAPI{}
_ IExceptionsGetter = &v1.KSCloudAPI{}
_ IAttackTracksGetter = &v1.KSCloudAPI{}
_ IControlsInputsGetter = &v1.KSCloudAPI{}
)
// KSCloudAPI allows accessing the API of the Kubescape Cloud offering
type KSCloudAPI struct {
httpClient *http.Client
cloudAPIURL string
cloudAuthURL string
cloudReportURL string
cloudUIURL string
accountID string
clientID string
secretKey string
authCookie string
feToken FeLoginResponse
loggedIn bool
}
var globalKSCloudAPIConnector *KSCloudAPI
func SetKSCloudAPIConnector(ksCloudAPI *KSCloudAPI) {
// SetKSCloudAPIConnector registers a global instance of the KS Cloud client.
//
// NOTE: cannot be used concurrently.
func SetKSCloudAPIConnector(ksCloudAPI *v1.KSCloudAPI) {
if ksCloudAPI != nil {
logger.L().Debug("setting global KS Cloud API connector",
helpers.String("accountID", ksCloudAPI.GetAccountID()),
helpers.String("cloudAPIURL", ksCloudAPI.GetCloudAPIURL()),
helpers.String("cloudReportURL", ksCloudAPI.GetCloudReportURL()))
} else {
logger.L().Debug("setting global KS Cloud API connector (nil)")
}
globalKSCloudAPIConnector = ksCloudAPI
}
func GetKSCloudAPIConnector() *KSCloudAPI {
// GetKSCloudAPIConnector returns a shallow clone of the KS Cloud client registered for this package.
//
// NOTE: cannot be used concurrently with SetKSCloudAPIConnector.
func GetKSCloudAPIConnector() *v1.KSCloudAPI {
if globalKSCloudAPIConnector == nil {
SetKSCloudAPIConnector(NewKSCloudAPIProd())
SetKSCloudAPIConnector(v1.NewEmptyKSCloudAPI())
}
return globalKSCloudAPIConnector
}
func NewKSCloudAPIDev() *KSCloudAPI {
apiObj := newKSCloudAPI()
apiObj.cloudAPIURL = ksCloudDevBEURL
apiObj.cloudAuthURL = ksCloudDevAUTHURL
apiObj.cloudReportURL = ksCloudDevERURL
apiObj.cloudUIURL = ksCloudDevFEURL
return apiObj
}
func NewKSCloudAPIProd() *KSCloudAPI {
apiObj := newKSCloudAPI()
apiObj.cloudAPIURL = ksCloudBEURL
apiObj.cloudReportURL = ksCloudERURL
apiObj.cloudUIURL = ksCloudFEURL
apiObj.cloudAuthURL = ksCloudAUTHURL
return apiObj
}
func NewKSCloudAPIStaging() *KSCloudAPI {
apiObj := newKSCloudAPI()
apiObj.cloudAPIURL = ksCloudStageBEURL
apiObj.cloudReportURL = ksCloudStageERURL
apiObj.cloudUIURL = ksCloudStageFEURL
apiObj.cloudAuthURL = ksCloudStageAUTHURL
return apiObj
}
func NewKSCloudAPICustomized(ksCloudERURL, ksCloudBEURL, ksCloudFEURL, ksCloudAUTHURL string) *KSCloudAPI {
apiObj := newKSCloudAPI()
apiObj.cloudReportURL = ksCloudERURL
apiObj.cloudAPIURL = ksCloudBEURL
apiObj.cloudUIURL = ksCloudFEURL
apiObj.cloudAuthURL = ksCloudAUTHURL
return apiObj
}
func newKSCloudAPI() *KSCloudAPI {
return &KSCloudAPI{
httpClient: &http.Client{Timeout: time.Duration(61) * time.Second},
loggedIn: false,
}
}
func (api *KSCloudAPI) Post(fullURL string, headers map[string]string, body []byte) (string, error) {
if headers == nil {
headers = make(map[string]string)
}
api.appendAuthHeaders(headers)
return HttpPost(api.httpClient, fullURL, headers, body)
}
func (api *KSCloudAPI) Delete(fullURL string, headers map[string]string) (string, error) {
if headers == nil {
headers = make(map[string]string)
}
api.appendAuthHeaders(headers)
return HttpDelete(api.httpClient, fullURL, headers)
}
func (api *KSCloudAPI) Get(fullURL string, headers map[string]string) (string, error) {
if headers == nil {
headers = make(map[string]string)
}
api.appendAuthHeaders(headers)
return HttpGetter(api.httpClient, fullURL, headers)
}
func (api *KSCloudAPI) GetAccountID() string { return api.accountID }
func (api *KSCloudAPI) IsLoggedIn() bool { return api.loggedIn }
func (api *KSCloudAPI) GetClientID() string { return api.clientID }
func (api *KSCloudAPI) GetSecretKey() string { return api.secretKey }
func (api *KSCloudAPI) GetCloudReportURL() string { return api.cloudReportURL }
func (api *KSCloudAPI) GetCloudAPIURL() string { return api.cloudAPIURL }
func (api *KSCloudAPI) GetCloudUIURL() string { return api.cloudUIURL }
func (api *KSCloudAPI) GetCloudAuthURL() string { return api.cloudAuthURL }
func (api *KSCloudAPI) SetAccountID(accountID string) { api.accountID = accountID }
func (api *KSCloudAPI) SetClientID(clientID string) { api.clientID = clientID }
func (api *KSCloudAPI) SetSecretKey(secretKey string) { api.secretKey = secretKey }
func (api *KSCloudAPI) SetCloudReportURL(cloudReportURL string) { api.cloudReportURL = cloudReportURL }
func (api *KSCloudAPI) SetCloudAPIURL(cloudAPIURL string) { api.cloudAPIURL = cloudAPIURL }
func (api *KSCloudAPI) SetCloudUIURL(cloudUIURL string) { api.cloudUIURL = cloudUIURL }
func (api *KSCloudAPI) SetCloudAuthURL(cloudAuthURL string) { api.cloudAuthURL = cloudAuthURL }
func (api *KSCloudAPI) GetAttackTracks() ([]v1alpha1.AttackTrack, error) {
respStr, err := api.Get(api.getAttackTracksURL(), nil)
if err != nil {
return nil, nil
}
attackTracks := []v1alpha1.AttackTrack{}
if err = JSONDecoder(respStr).Decode(&attackTracks); err != nil {
return nil, err
}
return attackTracks, err
}
func (api *KSCloudAPI) GetFramework(name string) (*reporthandling.Framework, error) {
respStr, err := api.Get(api.getFrameworkURL(name), nil)
if err != nil {
return nil, nil
}
framework := &reporthandling.Framework{}
if err = JSONDecoder(respStr).Decode(framework); err != nil {
return nil, err
}
return framework, err
}
func (api *KSCloudAPI) GetFrameworks() ([]reporthandling.Framework, error) {
respStr, err := api.Get(api.getListFrameworkURL(), nil)
if err != nil {
return nil, nil
}
frameworks := []reporthandling.Framework{}
if err = JSONDecoder(respStr).Decode(&frameworks); err != nil {
return nil, err
}
return frameworks, err
}
func (api *KSCloudAPI) GetControl(ID string) (*reporthandling.Control, error) {
return nil, fmt.Errorf("control api is not public")
}
func (api *KSCloudAPI) GetExceptions(clusterName string) ([]armotypes.PostureExceptionPolicy, error) {
exceptions := []armotypes.PostureExceptionPolicy{}
respStr, err := api.Get(api.getExceptionsURL(clusterName), nil)
if err != nil {
return nil, err
}
if err = JSONDecoder(respStr).Decode(&exceptions); err != nil {
return nil, err
}
return exceptions, nil
}
func (api *KSCloudAPI) GetTenant() (*TenantResponse, error) {
url := api.getAccountURL()
if api.accountID != "" {
url = fmt.Sprintf("%s?customerGUID=%s", url, api.accountID)
}
respStr, err := api.Get(url, nil)
if err != nil {
return nil, err
}
tenant := &TenantResponse{}
if err = JSONDecoder(respStr).Decode(tenant); err != nil {
return nil, err
}
if tenant.TenantID != "" {
api.accountID = tenant.TenantID
}
return tenant, nil
}
// ControlsInputs // map[<control name>][<input arguments>]
func (api *KSCloudAPI) GetAccountConfig(clusterName string) (*armotypes.CustomerConfig, error) {
accountConfig := &armotypes.CustomerConfig{}
if api.accountID == "" {
return accountConfig, nil
}
respStr, err := api.Get(api.getAccountConfig(clusterName), nil)
if err != nil {
return nil, err
}
if err = JSONDecoder(respStr).Decode(&accountConfig); err != nil {
// try with default scope
respStr, err = api.Get(api.getAccountConfigDefault(clusterName), nil)
if err != nil {
return nil, err
}
if err = JSONDecoder(respStr).Decode(&accountConfig); err != nil {
return nil, err
}
}
return accountConfig, nil
}
// ControlsInputs // map[<control name>][<input arguments>]
func (api *KSCloudAPI) GetControlsInputs(clusterName string) (map[string][]string, error) {
accountConfig, err := api.GetAccountConfig(clusterName)
if err == nil {
return accountConfig.Settings.PostureControlInputs, nil
}
return nil, err
}
func (api *KSCloudAPI) ListCustomFrameworks() ([]string, error) {
respStr, err := api.Get(api.getListFrameworkURL(), nil)
if err != nil {
return nil, err
}
frs := []reporthandling.Framework{}
if err = json.Unmarshal([]byte(respStr), &frs); err != nil {
return nil, err
}
frameworkList := []string{}
for _, fr := range frs {
if !isNativeFramework(fr.Name) {
frameworkList = append(frameworkList, fr.Name)
}
}
return frameworkList, nil
}
func (api *KSCloudAPI) ListFrameworks() ([]string, error) {
respStr, err := api.Get(api.getListFrameworkURL(), nil)
if err != nil {
return nil, err
}
frs := []reporthandling.Framework{}
if err = json.Unmarshal([]byte(respStr), &frs); err != nil {
return nil, err
}
frameworkList := []string{}
for _, fr := range frs {
if isNativeFramework(fr.Name) {
frameworkList = append(frameworkList, strings.ToLower(fr.Name))
} else {
frameworkList = append(frameworkList, fr.Name)
}
}
return frameworkList, nil
}
func (api *KSCloudAPI) ListControls() ([]string, error) {
return nil, fmt.Errorf("control api is not public")
}
func (api *KSCloudAPI) PostExceptions(exceptions []armotypes.PostureExceptionPolicy) error {
for i := range exceptions {
ex, err := json.Marshal(exceptions[i])
if err != nil {
return err
}
_, err = api.Post(api.exceptionsURL(""), map[string]string{"Content-Type": "application/json"}, ex)
if err != nil {
return err
}
}
return nil
}
func (api *KSCloudAPI) DeleteException(exceptionName string) error {
_, err := api.Delete(api.exceptionsURL(exceptionName), nil)
if err != nil {
return err
}
return nil
}
func (api *KSCloudAPI) Login() error {
if api.accountID == "" {
return fmt.Errorf("failed to login, missing accountID")
}
if api.clientID == "" {
return fmt.Errorf("failed to login, missing clientID")
}
if api.secretKey == "" {
return fmt.Errorf("failed to login, missing secretKey")
}
// init URLs
feLoginData := FeLoginData{ClientId: api.clientID, Secret: api.secretKey}
body, _ := json.Marshal(feLoginData)
resp, err := http.Post(api.getApiToken(), "application/json", bytes.NewBuffer(body))
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("error authenticating: %d", resp.StatusCode)
}
responseBody, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
var feLoginResponse FeLoginResponse
if err = json.Unmarshal(responseBody, &feLoginResponse); err != nil {
return err
}
api.feToken = feLoginResponse
/* Now we have JWT */
api.authCookie, err = api.getAuthCookie()
if err != nil {
return err
}
api.loggedIn = true
return nil
// we return a shallow clone that may be freely modified by the caller.
client := *globalKSCloudAPIConnector
options := *globalKSCloudAPIConnector.KsCloudOptions
client.KsCloudOptions = &options
return &client
}

View File

@@ -0,0 +1,49 @@
package getter
import (
"os"
"sync"
"testing"
v1 "github.com/kubescape/backend/pkg/client/v1"
"github.com/stretchr/testify/require"
)
const (
// extra mock API routes
pathTestPost = "/test-post"
pathTestDelete = "/test-delete"
pathTestGet = "/test-get"
)
var (
globalMx sync.Mutex // a mutex to avoid data races on package globals while testing
testOptions = []v1.KSCloudOption{
v1.WithTrace(os.Getenv("DEBUG_TEST") != ""),
}
)
func TestGlobalKSCloudAPIConnector(t *testing.T) {
t.Parallel()
globalMx.Lock()
defer globalMx.Unlock()
globalKSCloudAPIConnector = nil
t.Run("uninitialized global connector should yield an empty KS client", func(t *testing.T) {
empty := v1.NewEmptyKSCloudAPI()
require.EqualValues(t, empty, GetKSCloudAPIConnector())
})
t.Run("initialized global connector should yield the same pointer", func(t *testing.T) {
ksCloud, _ := v1.NewKSCloudAPI("test-123", "test-456", "account", "token")
SetKSCloudAPIConnector(ksCloud)
client := GetKSCloudAPIConnector()
require.Equal(t, ksCloud, client)
require.Equal(t, client, GetKSCloudAPIConnector())
})
}

View File

@@ -1,186 +0,0 @@
package getter
import (
"bytes"
"fmt"
"net/http"
"net/url"
"strings"
)
var NativeFrameworks = []string{"nsa", "mitre", "armobest", "devopsbest"}
func (api *KSCloudAPI) getFrameworkURL(frameworkName string) string {
u := url.URL{}
u.Scheme, u.Host = parseHost(api.GetCloudAPIURL())
u.Path = "api/v1/armoFrameworks"
q := u.Query()
q.Add("customerGUID", api.getCustomerGUIDFallBack())
if isNativeFramework(frameworkName) {
q.Add("frameworkName", strings.ToUpper(frameworkName))
} else {
// For customer framework has to be the way it was added
q.Add("frameworkName", frameworkName)
}
u.RawQuery = q.Encode()
return u.String()
}
func (api *KSCloudAPI) getAttackTracksURL() string {
u := url.URL{}
u.Scheme, u.Host = parseHost(api.GetCloudAPIURL())
u.Path = "api/v1/attackTracks"
q := u.Query()
q.Add("customerGUID", api.getCustomerGUIDFallBack())
u.RawQuery = q.Encode()
return u.String()
}
func (api *KSCloudAPI) getListFrameworkURL() string {
u := url.URL{}
u.Scheme, u.Host = parseHost(api.GetCloudAPIURL())
u.Path = "api/v1/armoFrameworks"
q := u.Query()
q.Add("customerGUID", api.getCustomerGUIDFallBack())
u.RawQuery = q.Encode()
return u.String()
}
func (api *KSCloudAPI) getExceptionsURL(clusterName string) string {
u := url.URL{}
u.Scheme, u.Host = parseHost(api.GetCloudAPIURL())
u.Path = "api/v1/armoPostureExceptions"
q := u.Query()
q.Add("customerGUID", api.getCustomerGUIDFallBack())
// if clusterName != "" { // TODO - fix customer name support in Armo BE
// q.Add("clusterName", clusterName)
// }
u.RawQuery = q.Encode()
return u.String()
}
func (api *KSCloudAPI) exceptionsURL(exceptionsPolicyName string) string {
u := url.URL{}
u.Scheme, u.Host = parseHost(api.GetCloudAPIURL())
u.Path = "api/v1/postureExceptionPolicy"
q := u.Query()
q.Add("customerGUID", api.getCustomerGUIDFallBack())
if exceptionsPolicyName != "" { // for delete
q.Add("policyName", exceptionsPolicyName)
}
u.RawQuery = q.Encode()
return u.String()
}
func (api *KSCloudAPI) getAccountConfigDefault(clusterName string) string {
config := api.getAccountConfig(clusterName)
url := config + "&scope=customer"
return url
}
func (api *KSCloudAPI) getAccountConfig(clusterName string) string {
u := url.URL{}
u.Scheme, u.Host = parseHost(api.GetCloudAPIURL())
u.Path = "api/v1/armoCustomerConfiguration"
q := u.Query()
q.Add("customerGUID", api.getCustomerGUIDFallBack())
if clusterName != "" { // TODO - fix customer name support in Armo BE
q.Add("clusterName", clusterName)
}
u.RawQuery = q.Encode()
return u.String()
}
func (api *KSCloudAPI) getAccountURL() string {
u := url.URL{}
u.Scheme, u.Host = parseHost(api.GetCloudAPIURL())
u.Path = "api/v1/createTenant"
return u.String()
}
func (api *KSCloudAPI) getApiToken() string {
u := url.URL{}
u.Scheme, u.Host = parseHost(api.GetCloudAuthURL())
u.Path = "identity/resources/auth/v1/api-token"
return u.String()
}
func (api *KSCloudAPI) getOpenidCustomers() string {
u := url.URL{}
u.Scheme, u.Host = parseHost(api.GetCloudAPIURL())
u.Path = "api/v1/openid_customers"
return u.String()
}
func (api *KSCloudAPI) getAuthCookie() (string, error) {
selectCustomer := KSCloudSelectCustomer{SelectedCustomerGuid: api.accountID}
requestBody, _ := json.Marshal(selectCustomer)
client := &http.Client{}
httpRequest, err := http.NewRequest(http.MethodPost, api.getOpenidCustomers(), bytes.NewBuffer(requestBody))
if err != nil {
return "", err
}
httpRequest.Header.Set("Content-Type", "application/json")
httpRequest.Header.Set("Authorization", fmt.Sprintf("Bearer %s", api.feToken.Token))
httpResponse, err := client.Do(httpRequest)
if err != nil {
return "", err
}
defer httpResponse.Body.Close()
if httpResponse.StatusCode != http.StatusOK {
return "", fmt.Errorf("failed to get cookie from %s: status %d", api.getOpenidCustomers(), httpResponse.StatusCode)
}
cookies := httpResponse.Header.Get("set-cookie")
if len(cookies) == 0 {
return "", fmt.Errorf("no cookie field in response from %s", api.getOpenidCustomers())
}
authCookie := ""
for _, cookie := range strings.Split(cookies, ";") {
kv := strings.Split(cookie, "=")
if kv[0] == "auth" {
authCookie = kv[1]
}
}
if len(authCookie) == 0 {
return "", fmt.Errorf("no auth cookie field in response from %s", api.getOpenidCustomers())
}
return authCookie, nil
}
func (api *KSCloudAPI) appendAuthHeaders(headers map[string]string) {
if api.feToken.Token != "" {
headers["Authorization"] = fmt.Sprintf("Bearer %s", api.feToken.Token)
}
if api.authCookie != "" {
headers["Cookie"] = fmt.Sprintf("auth=%s", api.authCookie)
}
}
func (api *KSCloudAPI) getCustomerGUIDFallBack() string {
if api.accountID != "" {
return api.accountID
}
return "11111111-1111-1111-1111-111111111111"
}
func parseHost(host string) (string, string) {
if strings.HasPrefix(host, "http://") {
return "http", strings.Replace(host, "http://", "", 1)
}
// default scheme
return "https", strings.Replace(host, "https://", "", 1)
}

Some files were not shown because too many files have changed in this diff Show More