Compare commits

...
136 Commits
Author SHA1 Message Date
Andy Suderman 4de082b443 docs: update documentation from template (#1140) 2025-08-01 13:24:25 -06:00
dependabot[bot]andlnx01 264dc51f4c Bump sigs.k8s.io/yaml from 1.4.0 to 1.5.0 (#1127)
---
updated-dependencies:
- dependency-name: sigs.k8s.io/yaml
  dependency-version: 1.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-25 11:23:39 -03:00
jdesouza 45b1f6a1a5 Bumped libs (#1139) 2025-07-25 10:18:03 -03:00
Vitor Rodrigo Vezaniandjdesouza 38e540e0cf Remove flags from audit command and remove auth command (#1138)
* update libs

* Remove unused authentication code and dependencies from the Polaris project, streamlining the audit process by eliminating the upload insights feature and related flags.

* remove insights reporter

* remove lingering libs

* update docs

* INS-1251: Polaris: upgrade github.com/qri-io/jsonschema to v0.2.1 (#1135)

* Bump lins

* Code refactoring

* Fixign issues

* Fixing issues

* Fixing issues

* Fixing issues

* [WIP]

* [WIP]

* [WIP]

* Trying to fix tests

* Trying to fix tests

* Fixing issues

* Fixing issues

* Fixing issues

* Fixing issues

* Fixing issues

* Fixing issues

* Revert go mod

* Revert go mod

* Revert go mod

* Revert go mod

* Fixing issues

* Fixing issue

* Code refactoring

* Updating json schema version

* Updating json schema version

* fix go mod

* fix go sum

---------

Co-authored-by: jdesouza <james@fairwinds.com>
2025-07-24 16:48:23 -03:00
jdesouza 2b17c31957 INS-1251: Polaris: upgrade github.com/qri-io/jsonschema to v0.2.1 (#1135)
* Bump lins

* Code refactoring

* Fixign issues

* Fixing issues

* Fixing issues

* Fixing issues

* [WIP]

* [WIP]

* [WIP]

* Trying to fix tests

* Trying to fix tests

* Fixing issues

* Fixing issues

* Fixing issues

* Fixing issues

* Fixing issues

* Fixing issues

* Revert go mod

* Revert go mod

* Revert go mod

* Revert go mod

* Fixing issues

* Fixing issue

* Code refactoring

* Updating json schema version

* Updating json schema version
2025-07-24 13:46:37 -03:00
jdesouza 813d9c0a2a INS-1097: Fix CVE-2025-22874 for polaris (#1122)
* Bumping polaris libs

* Fixing lint

* Fixed vuln

* Fixed vuln

* Fixed vuln

* Fixed vuln
2025-06-17 08:58:10 -03:00
jdesouza d7d30ac611 INS-933 - pullPolicyNotAlways is crashing webhook mutations (#1115)
* Debugging

* Debugging

* Trying to fix

* Revert

* Debugging

* Debugging

* Debugging

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue
2025-04-21 17:07:12 -03:00
dependabot[bot]andlnx01 8fe7a94260 Bump golang.org/x/net from 0.33.0 to 0.36.0 (#1108)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.33.0 to 0.36.0.
- [Commits](https://github.com/golang/net/compare/v0.33.0...v0.36.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-16 13:26:47 -03:00
dependabot[bot]andlnx01 f29571e8bb Bump k8s.io/client-go from 0.32.0 to 0.32.2 (#1103)
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.32.0 to 0.32.2.
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.32.0...v0.32.2)

---
updated-dependencies:
- dependency-name: k8s.io/client-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-16 13:21:50 -03:00
dependabot[bot]andlnx01 a74714b5e5 Bump k8s.io/apimachinery from 0.32.0 to 0.32.2 (#1102)
Bumps [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) from 0.32.0 to 0.32.2.
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.32.0...v0.32.2)

---
updated-dependencies:
- dependency-name: k8s.io/apimachinery
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-16 13:16:16 -03:00
dependabot[bot]andlnx01 ba04b7e330 Bump sigs.k8s.io/controller-runtime from 0.19.3 to 0.20.2 (#1101)
Bumps [sigs.k8s.io/controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) from 0.19.3 to 0.20.2.
- [Release notes](https://github.com/kubernetes-sigs/controller-runtime/releases)
- [Changelog](https://github.com/kubernetes-sigs/controller-runtime/blob/main/RELEASE.md)
- [Commits](https://github.com/kubernetes-sigs/controller-runtime/compare/v0.19.3...v0.20.2)

---
updated-dependencies:
- dependency-name: sigs.k8s.io/controller-runtime
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-16 12:42:36 -03:00
youM d70591b1b8 fixed pdbMinAvailableGreaterThanHPAMinReplicas and added validation for pdbMinAvailableEqualToHPAMinReplicas. (#1073)
* rename pdbMinAvailableGreaterThanHPAMinReplicas to pdbMinAvailableGreaterThanOrEqualToHPAMinReplicas

* modify doc

* Revert "modify doc"

This reverts commit faffffc298cde23a99c5e19528123f249d92d314.

* Revert "rename pdbMinAvailableGreaterThanHPAMinReplicas to pdbMinAvailableGreaterThanOrEqualToHPAMinReplicas"

This reverts commit b93f283acc279b90c7e7a9d8dbbe53b2f8ab9a31.

* fix test

* fix impl
2025-04-14 11:36:32 -03:00
jdesouza 80e6f7214e INSIGHTS-593 Fix Polaris vulerabilities (#1094) 2025-01-02 13:01:37 -03:00
Vitor Rodrigo Vezani 1d20a16cb3 update supporting libs and bump alpine to 3.21 (#1093)
* bump alpine

* bump libs
2024-12-19 09:20:30 -07:00
dependabot[bot]andlnx01 37edbc7159 Bump k8s.io/client-go from 0.31.2 to 0.31.3 (#1084)
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.31.2 to 0.31.3.
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.31.2...v0.31.3)

---
updated-dependencies:
- dependency-name: k8s.io/client-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-05 06:17:16 -07:00
dependabot[bot]andlnx01 d451480acf Bump k8s.io/api from 0.31.2 to 0.31.3 (#1083)
Bumps [k8s.io/api](https://github.com/kubernetes/api) from 0.31.2 to 0.31.3.
- [Commits](https://github.com/kubernetes/api/compare/v0.31.2...v0.31.3)

---
updated-dependencies:
- dependency-name: k8s.io/api
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-05 08:16:46 -05:00
705e6e4016 Bump sigs.k8s.io/controller-runtime from 0.19.1 to 0.19.2 (#1086)
Bumps [sigs.k8s.io/controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) from 0.19.1 to 0.19.2.
- [Release notes](https://github.com/kubernetes-sigs/controller-runtime/releases)
- [Changelog](https://github.com/kubernetes-sigs/controller-runtime/blob/main/RELEASE.md)
- [Commits](https://github.com/kubernetes-sigs/controller-runtime/compare/v0.19.1...v0.19.2)

---
updated-dependencies:
- dependency-name: sigs.k8s.io/controller-runtime
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Vitor Rodrigo Vezani <vitor.vezani@fairwinds.com>
2024-12-05 10:12:36 -03:00
dependabot[bot]andlnx01 2d9aa54e68 Bump k8s.io/apimachinery from 0.31.2 to 0.31.3 (#1087)
Bumps [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) from 0.31.2 to 0.31.3.
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.31.2...v0.31.3)

---
updated-dependencies:
- dependency-name: k8s.io/apimachinery
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-05 10:09:26 -03:00
jdesouzaandAndy Suderman 4dd3a81bbd INSIGHTS-475 Add 3 new checks to polaris (#1082)
* INSIGHTS-448 Add Two Polaris Checks

* Added another chec

* Added another chec

* Added another chec

* Added another chec

* Added another chec

* Added another chec

* Fixing issue

* Fixing issue

* Added another validation

* Added some tests cases

* Added some tests cases

* Update pkg/config/checks/hostProcess.yaml

* Update pkg/validator/pod_test.go

---------

Co-authored-by: Andy Suderman <andy@fairwinds.com>
2024-11-13 08:24:37 -03:00
dependabot[bot]andlnx01 4b87bafbb9 Bump k8s.io/client-go from 0.31.1 to 0.31.2 (#1078)
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.31.1 to 0.31.2.
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.31.1...v0.31.2)

---
updated-dependencies:
- dependency-name: k8s.io/client-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-08 11:48:05 -03:00
dependabot[bot]andlnx01 62effa36b6 Bump sigs.k8s.io/controller-runtime from 0.19.0 to 0.19.1 (#1079)
Bumps [sigs.k8s.io/controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) from 0.19.0 to 0.19.1.
- [Release notes](https://github.com/kubernetes-sigs/controller-runtime/releases)
- [Changelog](https://github.com/kubernetes-sigs/controller-runtime/blob/main/RELEASE.md)
- [Commits](https://github.com/kubernetes-sigs/controller-runtime/compare/v0.19.0...v0.19.1)

---
updated-dependencies:
- dependency-name: sigs.k8s.io/controller-runtime
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-08 11:43:26 -03:00
dependabot[bot]andlnx01 913988e44c Bump github.com/fatih/color from 1.17.0 to 1.18.0 (#1081)
Bumps [github.com/fatih/color](https://github.com/fatih/color) from 1.17.0 to 1.18.0.
- [Release notes](https://github.com/fatih/color/releases)
- [Commits](https://github.com/fatih/color/compare/v1.17.0...v1.18.0)

---
updated-dependencies:
- dependency-name: github.com/fatih/color
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-08 10:41:00 -03:00
dependabot[bot]andlnx01 f281cd1e33 Bump k8s.io/api from 0.31.1 to 0.31.2 (#1077)
Bumps [k8s.io/api](https://github.com/kubernetes/api) from 0.31.1 to 0.31.2.
- [Commits](https://github.com/kubernetes/api/compare/v0.31.1...v0.31.2)

---
updated-dependencies:
- dependency-name: k8s.io/api
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-08 10:35:50 -03:00
Vitor Rodrigo VezaniandAndy Suderman 073847559a Add --merge-config flag to support merging with default configuration (#1075)
* add config merge support

* fix indentation

* Update cmd/polaris/root.go

Co-authored-by: Andy Suderman <andy@fairwinds.com>

---------

Co-authored-by: Andy Suderman <andy@fairwinds.com>
2024-10-22 15:31:18 -03:00
Grégoire MartiniandVitor Vezani 9b5438d864 Fix: rolebindingRolePodExecAttach check (#1070)
* Fix: rolebindingRolePodExecAttach check

Fix the case of a RoleBinding that points to a ClusterRole.
In that case, we ignore the RoleBinding since it will be evaluated by the rolebindingClusterRolePodExecAttach check.

* add tests for role-binding that uses a cluster-role binding

---------

Co-authored-by: Vitor Vezani <vitor.vezani@fairwinds.com>
2024-10-02 10:43:24 -06:00
jdesouza be349a885d Updated Go to 1.22.7 to fix vulnerabilities (#1069)
* Bumped to to 1.24 to fix vulnerability

* Bumped to to 1.22.7 to fix vulnerability

* Bumped to to 1.22.7 to fix vulnerability

* Bumped to to 1.22.7 to fix vulnerability

* Fixing issues

* Fixing issues

* Fixing issues

* Fixing issues

* Fixing issues

* Fixing issues

* Fixing issues
2024-09-25 12:17:50 -03:00
Terraform User 08f2afe6c9 Managed by Terraform 2024-09-20 16:57:29 +00:00
Terraform User 9f681b3ed4 Managed by Terraform 2024-09-20 16:57:22 +00:00
Terraform User 74cbaefc58 Managed by Terraform 2024-09-20 16:55:05 +00:00
Terraform User bd8d4cc08b Managed by Terraform 2024-09-20 16:49:26 +00:00
Terraform User e66ef8b948 Managed by Terraform 2024-09-20 16:45:48 +00:00
Terraform User 7930ede331 Managed by Terraform 2024-09-20 16:45:42 +00:00
Terraform User 1625b755ac Managed by Terraform 2024-09-20 16:45:26 +00:00
Terraform User 08a7863167 Managed by Terraform 2024-09-20 16:43:50 +00:00
jdesouza 8d5247e501 INSIGHTS-358 Bump polaris libs (#1068)
* Bumped libs

* Bumped libs

* Fixed issues

* Fixed issues

* Fixed issues

* Fixed issues

* Fixed issues

* Fixed issues

* Fixed issues

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issue

* Fixing issues

* Fixing issues

* Fixing issues

* Fixing issues

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix releaser

* Trying to fix

* Trying to fix

* Trying to fix

* Trying to fix

* Trying to fix

* Trying to fix

* Trying to fix
2024-09-18 17:07:50 -03:00
Terraform User d30865cefb Managed by Terraform 2024-09-09 19:47:56 +00:00
jdesouza cb7c10d288 INSIGHTS-8 Polaris: Harden admission against rogue pods (#1064)
* INSIGHTS-8 Polaris: Harden admission against rogue pods

* INSIGHTS-8 Polaris: Harden admission against rogue pods

* INSIGHTS-8 Polaris: Harden admission against rogue pods

* Adding validation

* Adding validation

* Fixing owners
2024-09-09 11:00:06 -03:00
Andy Suderman bdfcb8fbb8 docs: update documentation from template (#1063) 2024-07-18 10:44:35 -06:00
Vitor Rodrigo Vezani 1c1e990454 fix pdbMinAvailableGreaterThanHPAMinReplicas check when minAvailable is not present (#1062) 2024-07-18 13:26:30 -03:00
Vitor Rodrigo VezaniandAndy Suderman 952b6aed65 INSIGHTS-157 - PDB <> HPA check (#1057)
* fix typo

* fix failure message

* fix changelog

* fix missingPodDisruptionBudget validation

* add tests for pdbMinAvailableLessThenHPAMaxReplicas

* add simple success test

* fix typo

* lowercasing warnings

* WIP implement pdbMinAvailableLessThanHPAMaxReplicas

* change check name

* rename testes

* fix check message

* change check name

* minor fixes

* improving tests

* improve tests

* fix check name

* Update docs/checks/reliability.md

Co-authored-by: Andy Suderman <andy@fairwinds.com>

* fix/add tests

* fixes from PR

* fix error message

---------

Co-authored-by: Andy Suderman <andy@fairwinds.com>
2024-07-08 14:47:54 -03:00
Terraform User 875a8ffd40 Managed by Terraform 2024-07-01 17:24:36 +00:00
Vitor Rodrigo Vezani 61e0d34e8b INSIGHTS-156 - Fix typo and improve failure message (#1055)
* fix typo

* fix failure message

* fix changelog

* fix missingPodDisruptionBudget validation

* Update failure.empty-labels.yaml

* Update failure.no-metadata.yaml

* INSIGHTS-159 - use go templating instead of custom function validation (#1056)

* use go templating instead of custom function validation

* fix changelog
2024-06-27 17:10:21 -03:00
Vitor Rodrigo Vezani 8b236c2fa2 INSIGHTS-159 - use go templating instead of custom function validation (#1056)
* use go templating instead of custom function validation

* fix changelog
2024-06-27 17:01:59 -03:00
Vitor Rodrigo Vezani f504de33cf fix changelog for release (#1054) 2024-06-26 17:59:42 -03:00
Vitor Rodrigo Vezani 2d33bf2565 INSIGHTS-90 - implement HPA minAvailable and HPA maxAvailable checks (#1053)
* implement minAvailable and maxAvailable checks

* fix tests

* update hpaMaxAvailability check
2024-06-26 17:31:35 -03:00
Vitor Rodrigo Vezani 9824be2c26 fix typo for minAvailable and maxAvailable (#1050) 2024-06-03 16:53:13 -03:00
Vitor Rodrigo Vezani a81bd29674 Fix comments handling in addOrReplaceValue function (#1039) 2024-03-15 11:43:35 -03:00
Vitor Rodrigo Vezani ac638e01ba FWI-5820 - remove packr in favor of go:embed (#1035)
* move dashboard to embed

* use embed in favor of packr

* fix references

* Fix error creating router in dashboard.go

* create default config

* remove examples/config.yaml
2024-03-12 16:11:07 -03:00
Vitor Rodrigo Vezani 4a0713c754 FWI-5804 - expose issue fixer and mutations in the library (#1032)
* Add local path replacement for Polaris module

* expose fix.Execute

* Remove local module replacement in go.mod

* Fix error handling and return error instead of exiting the program
2024-03-08 13:23:33 -03:00
Takumi Sue 48fc87a663 Fix trying to list cluster-level resources (#1004)
when namespace specified

close #984
2024-03-05 10:19:02 -05:00
dependabot[bot]andlnx01 1ee4df0c81 Bump github.com/spf13/cobra from 1.7.0 to 1.8.0 (#1024)
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.7.0 to 1.8.0.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.7.0...v1.8.0)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-05 10:17:09 -05:00
b73aabc42e Bump k8s.io/client-go from 0.27.3 to 0.29.0 (#1021)
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.27.3 to 0.29.0.
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.27.3...v0.29.0)

---
updated-dependencies:
- dependency-name: k8s.io/client-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Robert Brennan <accounts@rbren.io>
2024-03-05 10:16:47 -05:00
Robert Brennan e60793a022 fix missing PDB check (#1027) 2024-02-13 13:13:11 -05:00
John Slivka c8394bf9d7 fix: conditional expressions should be at very top of additionalSchemaStrings (#1025) 2024-01-03 14:17:04 -06:00
Robert Brennan 0b765df04d Update alpine to 3.19 (#1022) 2023-12-18 11:16:47 -05:00
John Slivka 3e96c582f0 FWI-5385 Add quiet flag to polaris audit CLI command to suppress 'upload to Insights' prompt (#1017)
* add quiet flag to polaris audit CLI command to suppress 'upload to Insights' prompt
* add docs for polaris audit --quiet option
* add additional detail about polaris audit --quiet flag
2023-12-06 15:44:53 -06:00
Terraform User 391b802d4d Managed by Terraform 2023-11-02 15:47:51 -04:00
jdesouza f295dd0fb5 Using controller-utils to get workloads (#1012)
* Using controller-utils to get workloads

* Code cleanup
2023-11-01 15:59:46 -03:00
Robert Brennan 97687761a7 Fix numerical resource ranges (#991)
* fix numerical resource numbers

* add resource range tests
2023-09-05 11:15:45 -06:00
Robert BrennanandAndrew Suderman c856874564 Update topologySpreadConstraint.yaml (#971)
* Update topologySpreadConstraint.yaml

* Update topologySpreadConstraint.yaml

* fix test

* add passing test

---------

Co-authored-by: Andrew Suderman <andy@fairwinds.com>
2023-08-28 08:49:08 -06:00
Takumi Sue 09525d01a1 Add helm-skip-tests flag (#986)
* Add helm-skip-tests flag

close #985

* Update cli doc
2023-08-25 08:39:27 -06:00
Vitor Rodrigo Vezani 10e82cf0ae update CLI documentation (#967) 2023-08-03 10:21:49 -04:00
dependabot[bot]andlnx01 a5144c45b2 Bump k8s.io/apimachinery from 0.27.3 to 0.27.4 (#977)
Bumps [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) from 0.27.3 to 0.27.4.
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.27.3...v0.27.4)

---
updated-dependencies:
- dependency-name: k8s.io/apimachinery
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-24 15:47:59 -04:00
Takumi Sue 9be34236cb feat: handle multiple values files (#974) 2023-07-24 14:26:58 -04:00
Andrew Suderman e7eb079921 change kubernetes.io/ label from name to instance (#973)
* Fix #972 change label from name to instance

* Fix tests

* more references

* fix check

* Fix example config
2023-07-13 11:33:15 -06:00
Robert Brennan d55cd4bdf8 Add insights prompt (#968)
* add insights prompt

* switch to stderr

* adjust message

* adjust message
2023-06-29 12:07:26 -04:00
75997f0e93 Bump github.com/AlecAivazis/survey/v2 from 2.3.6 to 2.3.7 (#961)
Bumps [github.com/AlecAivazis/survey/v2](https://github.com/AlecAivazis/survey) from 2.3.6 to 2.3.7.
- [Release notes](https://github.com/AlecAivazis/survey/releases)
- [Commits](https://github.com/AlecAivazis/survey/compare/v2.3.6...v2.3.7)

---
updated-dependencies:
- dependency-name: github.com/AlecAivazis/survey/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Grace Gude <44000341+mggude@users.noreply.github.com>
2023-06-29 09:22:11 -06:00
John Slivka b0d86cdcd2 Add option to filter audit results by severity level (#969) 2023-06-28 08:38:47 -05:00
5595de4ef9 Bump k8s.io/client-go from 0.27.2 to 0.27.3 (#960)
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.27.2 to 0.27.3.
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.27.2...v0.27.3)

---
updated-dependencies:
- dependency-name: k8s.io/client-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Grace Gude <44000341+mggude@users.noreply.github.com>
2023-06-27 11:46:13 -04:00
Robert Brennan 4ca4c8f0f5 Fix nil pointer issue with webhook (#966)
* update

* update go mod

* tidy

* revert go mod

* fix port

* move pod test case

* downgrade controller-runtime

* revert updates

* fix nil pointer

* add logs

* fix var

* remove test requirement

* fix decoder

* fix mutate

* fix test case

* fix logs

* fmt

* fix owned pods in mutate

* fix test

* add logs

* add mutations to tests

* convert to json for patch

* fix up tests

* remove nil check

* fix logs

* add logs

* add env vars to webhook tests
2023-06-22 13:22:19 -04:00
Vitor Rodrigo Vezani 4b1d6635e0 add test for required fields on builtin checks (#965) 2023-06-21 12:25:44 -04:00
Vitor Rodrigo Vezani 0a26f3f578 FWI-4307 - fix checks category (#964)
* fix checks category

* add changelog
2023-06-21 12:08:49 -04:00
Robert Brennan 85a439653d fix cert dir arg (#958) 2023-06-14 10:51:21 -04:00
dependabot[bot]andlnx01 ba63e6691a Bump github.com/sirupsen/logrus from 1.9.2 to 1.9.3 (#957)
Bumps [github.com/sirupsen/logrus](https://github.com/sirupsen/logrus) from 1.9.2 to 1.9.3.
- [Release notes](https://github.com/sirupsen/logrus/releases)
- [Changelog](https://github.com/sirupsen/logrus/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sirupsen/logrus/compare/v1.9.2...v1.9.3)

---
updated-dependencies:
- dependency-name: github.com/sirupsen/logrus
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-12 15:43:59 -06:00
Vitor Rodrigo Vezani 07747d76f2 tweak net listener to localhost - removing unwanted popup (#955) 2023-06-09 16:01:59 -03:00
Vitor Rodrigo Vezani b876d301c8 redirect user to cluster action-items instead of cluster overview (#956) 2023-06-09 15:55:13 -03:00
Robert BrennanandAndrew Suderman 8bfed75498 Minor fixes for NSA checks (#952)
* fix rbac checks

* fix sensitive env var check

* add test case

* fix service account check

* fix comment

---------

Co-authored-by: Andrew Suderman <andy@fairwinds.com>
2023-06-09 12:35:36 -06:00
Vitor Rodrigo Vezani 52a5aa8f74 improve cluster-name flag description (#954) 2023-06-09 08:41:52 -06:00
8e3cf1ddd9 FWI-4190 - Upload polaris results to Fairwinds Insights support (#948)
* add login flow

* add logout functionality

* improve code

* implement token and status print

* implement status command

* add user to login

* improve server port management

* improve login flow

* fix login flow

* make insights URL for login configurable

* remove comments

* fix logrus directive usage

* add upload-insights command

* remove unnecessary usage of pointer

* error when using upload-insights and audit-path simultaneously

* upload-insights support

* set priority to reports

* adds report verification

* fix logging to meet expected results

* renaming variable name

* improve results printing

* improve variable naming

* remove TODO

* Update checks severities (#950)

* change all ignore checks to warning

* promoting checks initially warning that should be danger.

* fixing docs and examples

* adds changelog

* fix changelog version

* improve general error message

* update workloads to be able grab its version

* print URL on stdout on browser error

* use os.WriteFile instead of low-level API

* renaming fn params

* add insights client

* validating token on auth status

* minor fix

* only query for re-auth if token is still valid

* update some dependencies in go and CI (#951)

* update some dependencies

* update testing requirements

* Fix cert-manager

* lots of deprecated versions

* attempts

* review suggestions

* avoid nil pointer

* fix fixtures

* fix test

---------

Co-authored-by: Robert Brennan <contact@rbren.io>

* update changelog

---------

Co-authored-by: Andrew Suderman <andy@fairwinds.com>
Co-authored-by: Robert Brennan <contact@rbren.io>
2023-06-06 13:51:42 -03:00
Andrew SudermanandRobert Brennan f1bbe9236b update some dependencies in go and CI (#951)
* update some dependencies

* update testing requirements

* Fix cert-manager

* lots of deprecated versions

* attempts

* review suggestions

* avoid nil pointer

* fix fixtures

* fix test

---------

Co-authored-by: Robert Brennan <contact@rbren.io>
2023-06-06 12:01:20 -04:00
Vitor Rodrigo Vezani 65c5ff59ca Update checks severities (#950)
* change all ignore checks to warning

* promoting checks initially warning that should be danger.

* fixing docs and examples

* adds changelog

* fix changelog version
2023-05-31 17:41:18 -03:00
Andrew Suderman 166b39b695 move to latest alpine (#944) 2023-05-16 16:24:13 -06:00
StevieandRobert Brennan ef4ea66d49 Update checks documentation (#936)
* Update docs with new checks; make sure both config-full has all config.yml checks

* Update doc on mutating webhooks

---------

Co-authored-by: Robert Brennan <accounts@rbren.io>
2023-05-16 16:31:43 -04:00
Terraform User b472f34266 Managed by Terraform 2023-04-06 06:54:22 -06:00
Robert Brennan 1ddd2d985a Update documentation from template (#935) 2023-03-31 10:43:46 -04:00
Robert Brennan 727c6fa2c3 Update documentation from template (#934) 2023-03-31 10:24:11 -04:00
Robert Brennan f531103fa0 Update documentation from template (#926) 2023-03-14 11:25:31 -06:00
Pål-Magnus Slåtto d909dfd00b chore(ci): Upgrade Github CI/CD to non-deprecated actions (#933) 2023-03-13 10:29:02 -04:00
fsl 6abfbb3570 Update package-lock.json (#923)
Signed-off-by: fengshunli <1171313930@qq.com>
2023-02-21 09:24:09 -05:00
fsl b75db7fc5b Bump golang.org/x/net from 0.6.0 to 0.7.0 (#922)
Signed-off-by: fengshunli <1171313930@qq.com>
2023-02-21 08:50:39 -05:00
fsl 501744a65f Skip https certificate verification (#920)
Signed-off-by: fengshunli <1171313930@qq.com>
2023-02-17 15:10:28 -05:00
Andrew Suderman 9a678b46e2 update alpine (#918) 2023-02-09 12:13:23 -07:00
Robert Brennan 80c433478b update go modules (#917)
* update go modules

* revert jsonschema

* fix quay token

* remove insights
2023-02-09 11:20:51 -05:00
Joseph Richardson 498ccf2215 Fix #908 by generating release name (#909) 2023-02-03 12:31:32 -05:00
Robert Brennan bf065f9b54 Update dangerousCapabilities.yaml (#866) 2023-01-05 10:24:21 -07:00
StevieandAndrew Suderman 2d28ea551a sc/rd 71 add plg link (#896)
* Add persistentpostrun to root cmd and postrun to version cmd

* Change PLG link

* Add PLG link to dashboard

* <strong> the link

Co-authored-by: Andrew Suderman <andy@suderman.dev>
2023-01-05 09:33:45 -05:00
Robert BrennanandAndrew Suderman 71b0e00288 Update documentation from template (#899)
Co-authored-by: Andrew Suderman <andy@suderman.dev>
2023-01-04 14:17:54 -07:00
Andrew Suderman a1b63ac417 Fix #547 - add a check for topologySpreadConstraint (#879) 2023-01-04 14:05:23 -07:00
Robert Brennan 8af4363672 update dependencies (#898) 2023-01-04 10:10:09 -05:00
dependabot[bot]andlnx01 c2d1b1cc4a Bump alpine from 3.16 to 3.17 (#885)
Bumps alpine from 3.16 to 3.17.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-13 08:50:35 -05:00
dependabot[bot]andlnx01 81755e32ec Bump github.com/spf13/cobra from 1.6.0 to 1.6.1 (#870)
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.6.0 to 1.6.1.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.6.0...v1.6.1)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-17 14:56:41 -07:00
531322c6b3 Bump github.com/stretchr/testify from 1.8.0 to 1.8.1 (#869)
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.8.0 to 1.8.1.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.8.0...v1.8.1)

---
updated-dependencies:
- dependency-name: github.com/stretchr/testify
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Andrew Suderman <andrew@sudermanjr.com>
2022-11-17 13:36:02 -07:00
Terraform User e3f3254fe6 Managed by Terraform 2022-11-17 10:55:07 -07:00
Eng Zer JunandAndrew Suderman 8bc1a4bcde refactor: move from io/ioutil to io and os packages (#858)
The io/ioutil package has been deprecated as of Go 1.16 [1]. This commit
replaces the existing io/ioutil functions with their new definitions in
io and os packages.

[1]: https://golang.org/doc/go1.16#ioutil
Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>

Co-authored-by: Andrew Suderman <andrew@sudermanjr.com>
2022-11-16 16:28:09 -05:00
ivanfetch-fw 467d06f4db FWI-2719: Enable new RBAC / sensitive content / Pod exec checks, add hasPrefix and hasSuffix functions to the GO template, exempt system: name prefixes for RBAC checks, sensitive content checks ignore valueFrom, (#832)
* Enable these checks in the default configuration file, which may produce many new results:
  * automountServiceAccountToken
  * linuxHardening
  * sensitiveConfigmapContent and sensitiveContainerEnvVar
  * clusterrolebindingClusterAdmin, rolebindingClusterAdminClusterRole, and rolebindingClusterAdminRole
  * clusterrolePodExecAttach, rolePodExecAttach, clusterrolebindingPodExecAttach, rolebindingClusterRolePodExecAttach, and  rolebindingRolePodExecAttach
* Ignore the `missingNetworkPolicy` and `automountServiceAccountToken` checks by default
* `hasPrefix` and `hasSuffix` functions are now available in the go template
* Fix the `sensitiveContainerEnvVar` check to ignore sensitive environment
variable names when those variables use `valueFrom` to reference an
external resource.
* Add the `*ClusterAdmin` checks to `examples/config-full.yaml`.
* Exempt the prefix `system:` instead of individual entries for RBAC checks (#871)
2022-11-14 15:05:02 -07:00
Terraform User 4091355e18 Managed by Terraform 2022-10-31 11:23:56 -06:00
Robert Brennan 6ef87be59b update dependencies (#867)
* update packages

* fix jsonschema
2022-10-19 08:28:36 -04:00
dependabot[bot]andlnx01 587396a5c9 Bump k8s.io/api from 0.25.0 to 0.25.3 (#862)
Bumps [k8s.io/api](https://github.com/kubernetes/api) from 0.25.0 to 0.25.3.
- [Release notes](https://github.com/kubernetes/api/releases)
- [Commits](https://github.com/kubernetes/api/compare/v0.25.0...v0.25.3)

---
updated-dependencies:
- dependency-name: k8s.io/api
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-17 16:17:16 -04:00
ivanfetch-fw 45be5cbbef FWI-2912: Add logging to improve debugging of JSON Schema (#859)
* Add debug logging for JSON Schema validation and Go templating

* Fix `--help` to display the full Polaris usage

* add valid log possible levels to `--log-level` flag help
2022-10-05 11:22:42 -06:00
ivanfetch-fw b3d842a1ba Fix CI tag filters and re-enable docs (#852)
* Re-enable build/push of documentation

* Define tag filters for all jobs in the workflow

* Fix 7e099521
2022-10-03 10:45:50 -06:00
ivanfetch-fw 29102deadf Build docker images using goreleaser and support arm64 (#845)
* Use goreleaser to build and push docker images

* Update CircleCI config to install goreleaser dependencies

* Update goreleaser.sh to create a temporary tag when CIRCLE_TAG is not set

* Update Dockerfile for goreleaser

* Update goreleaser.sh to trap errors and cleanup temporary git branch, for local runs

* Update goreleaser.sh to envsubst specific variables, to not break the `sign` section using signature and artifact variables

* Fix goreleaser.sh logic to only release when CIRCLE_TAG is set
2022-09-22 11:00:02 -06:00
Robert Brennan 68e27571fd fix packr (#851) 2022-09-22 11:53:42 -04:00
Robert Brennan 681ed3e272 fix goreleaser version 2022-09-22 11:41:40 -04:00
Robert Brennan f6f85c765b update goreleaser (#850) 2022-09-22 11:38:30 -04:00
Robert Brennan b6c6bbe893 update docs (#846) 2022-09-22 11:18:44 -04:00
Robert Brennan 8e7100acaf Add debug info to kube resources, better caching strategy (#840)
* add debug info

* remove extra build step

* try and fix memory usage

* fix pointers

* add more debug logs

* fix up caching for replicasets

* fix import

* replace info with debug

* add logs

* dont cache jobs

* gofmt

* fix import
2022-09-16 10:07:20 -04:00
Robert Brennan 42d2b3368b update deps (#841)
* update deps

* update go

* update to go 1.19

* fix cimg

* fix work dir

* fix golint

* revert jsonschema

* fix packr2
2022-09-15 15:32:43 -04:00
4d96993a18 [FWI-2357] Let Polaris modify YAML without losing comments/formatting (#821)
* added fix command implementation

* use node api

* fix tests

* added hostport mutate rule

* update mutating server

* fix array reference and add back leading slash

* added test and refactor findNodes

* more tests

* added more test and fix issue with arrays

* rename findNode function and ensure we capture exceptions

* rename findNode function

* append array value at the end and for single item remove brackets

* append array value at the end and for single item remove brackets

* create array if it does not exists

* fix tests

* handle some exceptions

* fix tests

* fix string format

* guard for PodResult

* fix flag name

* fix privilegeEscalation check

* fix up mutations for local files

* fix pod parsing

* fix object values

* remove logspam

* fix import

* update some comments for health probes

* add an option to not apply any mutations\, and just adjust yaml formatting

* add preliminary support for helm

* logspam

* change up comment strategy

* fix object comments

* format

* fix tests

* add comments

* fix key updates

* fix mutation tests

* tidy

* refactor test

* add test

* add test

* add test for object comments

Co-authored-by: Robert Brennan <accounts@rbren.io>
Co-authored-by: Robert Brennan <contact@rbren.io>
2022-09-15 12:38:22 -04:00
Robert BrennanandAndrew Suderman 1486e3090f Add warning message for multi-schema checks in admission (#839)
* make cert dir option

* log message for multi-resource checks in admission

* Update pkg/validator/schema.go

Co-authored-by: Andrew Suderman <andrew@sudermanjr.com>
2022-09-14 09:01:27 -06:00
a2eaa210f6 Update README.md (#833)
* Update README.md

Updates to the header and opening paragraphs.

* Update README.md

* Update README.md

Co-authored-by: Andrew Suderman <andrew@sudermanjr.com>
Co-authored-by: Robert Brennan <accounts@rbren.io>
2022-09-14 09:13:17 -04:00
Robert Brennan e8e642b010 update dependencies (#836)
* update dependencies

* revert

* update x/net
2022-09-13 12:15:37 -04:00
Terraform User 1b50b85157 Managed by Terraform 2022-09-13 08:31:02 -06:00
Terraform User 5f7bbd981b Managed by Terraform 2022-09-07 11:05:01 -06:00
Terraform User 3cf4a88b93 Managed by Terraform 2022-09-07 11:02:30 -06:00
Terraform User 5a2a72b582 Managed by Terraform 2022-09-07 11:02:28 -06:00
Igor BeliakovandRobert Brennan 01dd7b7b68 Omit empty results, make pretty output less verbose (#767)
* Pretty output: remove 2 leading line breaks and 1 trailing after container results

Signed-off-by: Igor Beliakov <demtis.register@gmail.com>

* validator: don't add empty results in ApplyAllSchemaChecksToAllResources

Signed-off-by: Igor Beliakov <demtis.register@gmail.com>

* Fix MockPod() fixture:
- Since now result is considered non-empty only if Kind and Name are set, needed to adjust MockPod() to make it contain Name.

Signed-off-by: Igor Beliakov <demtis.register@gmail.com>

Co-authored-by: Robert Brennan <accounts@rbren.io>
2022-08-25 10:34:06 -04:00
Robert Brennan 6b64369698 Update changelog.md (#825)
* Update changelog.md

* Update changelog.md
2022-08-24 12:38:15 -04:00
9448686168 Bump k8s.io/client-go from 0.24.3 to 0.24.4 (#828)
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.24.3 to 0.24.4.
- [Release notes](https://github.com/kubernetes/client-go/releases)
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.24.3...v0.24.4)

---
updated-dependencies:
- dependency-name: k8s.io/client-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Barnabas Makonda <6409210+makoscafee@users.noreply.github.com>
2022-08-24 12:50:18 +03:00
ivanfetch-fw 01d7a8ac00 FWI-2547: Add checks for RBAC allowing execing or attaching to a Pod (#820)
* Add `rolePodExecAttach` and `clusterrolePodExecAttach` checks

* Add schema tests

* Add clusterrolebindingPodExecAttach, rolebindingRolePodExecAttach, and rolebindingClusterRolePodExecAttach checks + schema-tests

* Add the new checks to the full example config

* Update checks' success/failure messages and add some helpful comments

* Update binding-related check messaging RE: roleRef pointing to a nonexistent resource, and add tests for this case

* Update rolebindingClusterRolePodExecAttach and rolebindingRolePodExecAttach to pass if a binding roleRef is a different kind, and schema tests to include a namespace

* Add additional schema tests, remove "ignore default ClusterRole|Role bindings" code from checks that actually have no default bindings
2022-08-23 12:09:44 -06:00
ivanfetch-fw 742b21c6a2 FWI-2582: Add clusterrolebindingClusterAdmin, rolebindingClusterAdminRole, and rolebindingClusterAdminClusterRole checks + schema tests (#823)
* Add `clusterrolebindingClusterAdmin`, `rolebindingClusterAdminRole`, and `rolebindingClusterAdminClusterRole` checks + schema tests

* Update `rolebindingClusterAdminClusterRole` check to explicitly match the `cluster-admin` default ClusterRole, fix `...all_verbs` schema test, add schema checks for unrelated permissions
2022-08-22 09:50:58 -06:00
Robert Brennan b90f091bb6 fix polaris cves (#824) 2022-08-22 09:44:44 -04:00
ivanfetch-fw e3a6cb3774 Fix namespace checking when validating additional schemas which are not namespaced (#822) 2022-08-18 18:34:32 -06:00
dependabot[bot]andlnx01 7addced32c Bump github.com/sirupsen/logrus from 1.8.1 to 1.9.0 (#815)
Bumps [github.com/sirupsen/logrus](https://github.com/sirupsen/logrus) from 1.8.1 to 1.9.0.
- [Release notes](https://github.com/sirupsen/logrus/releases)
- [Changelog](https://github.com/sirupsen/logrus/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sirupsen/logrus/compare/v1.8.1...v1.9.0)

---
updated-dependencies:
- dependency-name: github.com/sirupsen/logrus
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-18 16:53:49 -04:00
dependabot[bot]andlnx01 7e77350428 Bump sigs.k8s.io/controller-runtime from 0.12.1 to 0.12.3 (#814)
Bumps [sigs.k8s.io/controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) from 0.12.1 to 0.12.3.
- [Release notes](https://github.com/kubernetes-sigs/controller-runtime/releases)
- [Changelog](https://github.com/kubernetes-sigs/controller-runtime/blob/master/RELEASE.md)
- [Commits](https://github.com/kubernetes-sigs/controller-runtime/compare/v0.12.1...v0.12.3)

---
updated-dependencies:
- dependency-name: sigs.k8s.io/controller-runtime
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-18 16:53:39 -04:00
af0d548a07 Bump k8s.io/apimachinery from 0.24.1 to 0.24.3 (#807)
Bumps [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) from 0.24.1 to 0.24.3.
- [Release notes](https://github.com/kubernetes/apimachinery/releases)
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.24.1...v0.24.3)

---
updated-dependencies:
- dependency-name: k8s.io/apimachinery
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Barnabas Makonda <6409210+makoscafee@users.noreply.github.com>
Co-authored-by: Robert Brennan <accounts@rbren.io>
2022-08-18 16:45:12 -04:00
3efa3b40c9 Bump k8s.io/client-go from 0.24.1 to 0.24.3 (#806)
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.24.1 to 0.24.3.
- [Release notes](https://github.com/kubernetes/client-go/releases)
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.24.1...v0.24.3)

---
updated-dependencies:
- dependency-name: k8s.io/client-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Robert Brennan <accounts@rbren.io>
2022-08-18 16:45:03 -04:00
334 changed files with 14663 additions and 16615 deletions
+41 -120
View File
@@ -1,7 +1,7 @@
version: 2.1
orbs:
rok8s: fairwinds/rok8s-scripts@11
rok8s: fairwinds/rok8s-scripts@12
oss-docs: fairwinds/oss-docs@0
executors:
@@ -9,6 +9,17 @@ executors:
machine:
enabled: true
commands:
install_goreleaser_dependencies:
description: Installs dependencies for CI scripts
steps:
- run: apk update
# gettext provides envsubst
- run: apk add gettext
# Register other docker platforms, to build arm64.
# This shouldn't be needed, why TBD.
- run: docker run --privileged --rm tonistiigi/binfmt --install all
references:
set_environment_variables: &set_environment_variables
run:
@@ -33,20 +44,20 @@ references:
sudo apt-get install -yqq jq git
echo "Installing KIND"
curl -sLO https://github.com/kubernetes-sigs/kind/releases/download/v0.14.0/kind-linux-amd64
curl -sLO https://github.com/kubernetes-sigs/kind/releases/download/v0.19.0/kind-linux-amd64
chmod 0755 kind-linux-amd64
sudo mv kind-linux-amd64 /usr/local/bin/kind
kind version
echo "Installing Kubectl"
curl -sLO https://storage.googleapis.com/kubernetes-release/release/v1.21.12/bin/linux/amd64/kubectl
curl -sLO https://storage.googleapis.com/kubernetes-release/release/v1.25.10/bin/linux/amd64/kubectl
chmod 0755 kubectl
sudo mv kubectl /usr/local/bin/
kubectl version --client
echo "Creating Kubernetes Cluster with Kind"
kind create cluster --wait=90s --image kindest/node:v1.21.12
kind create cluster --wait=90s --image kindest/node:v1.25.9@sha256:c08d6c52820aa42e533b70bce0c2901183326d86dcdcbedecc9343681db45161
docker ps -a
kubectl version
@@ -57,18 +68,17 @@ references:
./get_helm.sh
echo "Installing cert-manager"
kubectl create namespace cert-manager
helm repo add jetstack https://charts.jetstack.io
helm repo update
echo "Helm install"
helm install cert-manager jetstack/cert-manager --namespace cert-manager --version 0.16.1 --set "installCRDs=true" --wait
helm install cert-manager jetstack/cert-manager --namespace cert-manager --version v1.12.1 --set "installCRDs=true" --wait --create-namespace
echo "Install cert-manager successful"
test_binary_dashboard: &test_binary_dashboard
run:
name: Test Dashboard
command: |
go run main.go dashboard --port 3000 --audit-path ./examples &
go run main.go dashboard --port 3000 --audit-path ./pkg/config/examples &
sleep 30
curl -f http://localhost:3000 > /dev/null
curl -f http://localhost:3000/health > /dev/null
@@ -87,170 +97,81 @@ references:
echo "Skipping Kubernetes tests for forked PR"
fi
docker_build: &docker_build
run:
name: Docker login and build
command: |
docker-pull -f .circleci/build.config
docker-build -f .circleci/build.config
docker_build_and_push: &docker_build_and_push
run:
name: Docker login, build, and push
command: |
docker-pull -f .circleci/build.config
docker-build -f .circleci/build.config
docker login quay.io -u="${fairwinds_quay_user}" -p="${fairwinds_quay_token}"
docker-push -f .circleci/build.config
enable_experimental_features: &enable_experimental_docker_features
run:
name: enable experimental features
command: |
set -ex
apk --update add openssh
ssh remote-docker \<<EOF
sudo bash -c 'echo "{\"experimental\": true}" > /etc/docker/daemon.json'
sudo systemctl restart docker
EOF
install_vault_alpine: &install_vault_alpine
run:
name: install hashicorp vault
command: |
apk --update add curl yq
cd /tmp
curl -LO https://releases.hashicorp.com/vault/1.9.3/vault_1.9.3_linux_amd64.zip
unzip vault_1.9.3_linux_amd64.zip
curl -LO https://releases.hashicorp.com/vault/1.13.2/vault_1.13.2_linux_amd64.zip
sha256sum vault_1.13.2_linux_amd64.zip | grep f7930279de8381de7c532164b4a4408895d9606c0d24e2e9d2f9acb5dfe99b3c
unzip vault_1.13.2_linux_amd64.zip
mv vault /usr/bin/vault
jobs:
build:
docker:
- image: quay.io/reactiveops/ci-images:v11.0-stretch
steps:
- checkout
- setup_remote_docker
- *set_environment_variables
- *docker_build
push:
docker:
- image: quay.io/reactiveops/ci-images:v11.0-stretch
steps:
- checkout
- setup_remote_docker
- *set_environment_variables
- *docker_build_and_push
test_k8s:
working_directory: ~/polaris
resource_class: medium
executor: vm
steps:
- checkout
- *set_environment_variables
- *install_k8s
- *test_k8s
test:
working_directory: /go/src/github.com/fairwindsops/polaris/
docker:
- image: circleci/golang:1.17
- image: cimg/go:1.24.4
steps:
- checkout
- *set_environment_variables
- run: go get -u golang.org/x/lint/golint
- run: go list ./... | grep -v vendor | xargs golint -set_exit_status
- run: go list ./... | grep -v vendor | xargs go vet
- run: go vet ./...
- run: go test ./... -coverprofile=coverage.txt -covermode=count
- *test_binary_dashboard
insights:
docker:
- image: quay.io/reactiveops/ci-images:v11.0-stretch
steps:
- checkout
- setup_remote_docker
- run:
name: Insights CI
command: curl -L https://insights.fairwinds.com/v0/insights-ci.sh | bash
release_binary:
build_and_push:
working_directory: /go/src/github.com/fairwindsops/polaris/
resource_class: large
shell: /bin/bash
docker:
- image: goreleaser/goreleaser:v1.3.0
# The goreleaser image tag determins the version of Go.
# Manually check goreleaser images for their version of Go.
# Ref: https://hub.docker.com/r/goreleaser/goreleaser/tags
- image: goreleaser/goreleaser:v2.10.2
steps:
- checkout
- setup_remote_docker:
version: 20.10.6
- *enable_experimental_docker_features
- setup_remote_docker
- *install_vault_alpine
- rok8s/get_vault_env:
vault_path: repo/global/env
- rok8s/get_vault_env:
vault_path: repo/polaris/env
- *set_environment_variables
- run: go get -u github.com/gobuffalo/packr/v2/packr2
- run: git checkout -- . # FIXME: the go get makes the directory dirty
- run: packr2
- run: echo 'export GORELEASER_CURRENT_TAG="${CIRCLE_TAG}"' >> $BASH_ENV
- run: goreleaser
- run: docker login quay.io -u="${FAIRWINDS_QUAY_USER}" -p="${FAIRWINDS_QUAY_TOKEN}"
- install_goreleaser_dependencies
- run: scripts/goreleaser.sh
release_images:
working_directory: /go/src/github.com/fairwindsops/polaris/
docker:
- image: quay.io/reactiveops/ci-images:v11.0-stretch
steps:
- checkout
- setup_remote_docker
- *set_environment_variables
- *docker_build_and_push
workflows:
version: 2
build:
jobs:
- test
- build:
requires:
- test
- push:
context: org-global
requires:
- build
filters:
branches:
ignore: /pull\/[0-9]+/
- insights:
requires:
- push
filters:
branches:
ignore: /pull\/[0-9]+/
- test_k8s:
requires:
- push
filters:
branches:
ignore: /pull\/[0-9]+/
release:
jobs:
- release_binary:
- test:
filters:
tags:
only: /.*/
- build_and_push:
context: org-global
filters:
branches:
ignore: /.*/
ignore: /pull\/[0-9]+/
tags:
ignore: /^testing-.*/
- release_images:
- test_k8s:
requires:
- release_binary
context: org-global
- build_and_push
filters:
branches:
ignore: /.*/
ignore: /pull\/[0-9]+/
tags:
ignore: /^testing-.*/
- oss-docs/publish-docs:
+1 -1
View File
@@ -2,7 +2,7 @@
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
labels: [triage, enhancement]
assignees: ''
---
+1 -1
View File
@@ -2,7 +2,7 @@
name: Other
about: For misc. tasks like research or continued conversation
title: ''
labels: ''
labels: [triage]
assignees: ''
---
+1 -1
View File
@@ -1,6 +1,6 @@
# The action uses an own Dockerfile on purpose because the root Dockerfile takes way too long to build for an action
FROM alpine:3.10
FROM alpine:3.22
RUN apk add --no-cache \
bash \
+1 -1
View File
@@ -17,4 +17,4 @@ mkdir polaris
tar -xzf $TARGET_FILE -C polaris
rm $TARGET_FILE
echo "polaris" >> $GITHUB_PATH
echo "::set-output name=version::$INPUT_VERSION"
echo "version=$INPUT_VERSION" >> $GITHUB_OUTPUT
+1
View File
@@ -1,3 +1,4 @@
This PR fixes #
## Checklist
+2 -2
View File
@@ -7,7 +7,7 @@ jobs:
build-int:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Setup polaris
uses: ./.github/actions/setup-polaris
with:
@@ -18,7 +18,7 @@ jobs:
build-ext:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Setup polaris
uses: fairwindsops/polaris/.github/actions/setup-polaris@master
with:
+5 -2
View File
@@ -1,4 +1,7 @@
# Binaries for programs and plugins
# goreleaser is run via a wrapper that creates .goreleaser.yml from .goreleaser.yml.envsubst
.goreleaser.yml
# dist
# # Binaries for programs and plugins
.go-version
*.exe
*.exe~
@@ -20,7 +23,6 @@ Tiltfile
main
.DS_Store
*-packr.go
dist
.vscode
@@ -28,3 +30,4 @@ dist
node_modules
/dist
docs/README.md
-51
View File
@@ -1,51 +0,0 @@
checksum:
name_template: 'checksums.txt'
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
builds:
- id: polaris
ldflags:
- -X main.Version={{.Version}} -X main.Commit={{.Commit}} -s -w
env:
- CGO_ENABLED=0
- GO111MODULE=on
goos:
- linux
- darwin
- windows
goarch:
- amd64
- arm
- arm64
goarm:
- 6
- 7
archives:
- id: polaris
builds: ["polaris"]
name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}"
signs:
- cmd: cosign
args: ["sign-blob", "--key=hashivault://cosign", "-output-signature=${signature}", "${artifact}"]
artifacts: checksum
release:
prerelease: auto
footer: |
You can verify the signature of the checksums.txt file using [cosign](https://github.com/sigstore/cosign).
```
cosign verify-blob checksums.txt --signature=checksums.txt.sig --key https://artifacts.fairwinds.com/cosign.pub
```
brews:
- name: polaris
tap:
owner: FairwindsOps
name: homebrew-tap
folder: Formula
description: Open Source Best Practices for Kubernetes
test: |
system "#{bin}/polaris version"
+114
View File
@@ -0,0 +1,114 @@
version: 2
checksum:
name_template: 'checksums.txt'
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
env:
- GOBIN={{ .Env.TMPDIR }}/go-bin
before:
hooks:
- go mod download
builds:
- id: polaris
ldflags:
- -X main.Version={{.Version}} -X main.Commit={{.Commit}} -s -w
env:
- CGO_ENABLED=0
- GO111MODULE=on
goos:
- linux
- darwin
- windows
goarch:
- amd64
- arm
- arm64
goarm:
- 6
- 7
archives:
- id: polaris
builds: ["polaris"]
name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}"
signs:
- cmd: cosign
args: ["sign-blob", "--key=hashivault://cosign", "-output-signature=${signature}", "${artifact}"]
artifacts: checksum
release:
# This is replaced using `envsubst`, depending on the git branch.
disable: ${skip_release}
prerelease: auto
footer: |
You can verify the signature of the checksums.txt file using [cosign](https://github.com/sigstore/cosign).
```
cosign verify-blob checksums.txt --signature=checksums.txt.sig --key https://artifacts.fairwinds.com/cosign.pub
```
brews:
- name: polaris
# This is replaced using `envsubst`, depending on the git branch.
skip_upload: ${skip_release}
repository:
owner: FairwindsOps
name: homebrew-tap
directory: Formula
description: Open Source Best Practices for Kubernetes
url_template: "https://github.com/FairwindsOps/polaris/releases/download/{{ .Tag }}/{{ .ArtifactName }}"
test: |
system "#{bin}/polaris version"
dockers:
# There are multiple images to match the `--platform` docker build flag with
# combinations of `GOOS`, `GOARCH`, and `GOARM`
- image_templates:
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-amd64"
use: buildx
build_flag_templates:
- "--platform=linux/amd64"
- image_templates:
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-arm64"
use: buildx
goarch: arm64
goos: linux
build_flag_templates:
- "--platform=linux/arm64"
docker_manifests:
# Create DOcker manifests that make multiple architectures available within a tag,
# and provide partial-version tags like 2, and 2.2.
- name_template: quay.io/fairwinds/polaris:{{ .FullCommit }}
image_templates:
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-amd64"
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-arm64"
- name_template: quay.io/fairwinds/polaris:{{ .Env.feature_docker_tag }}
# This is replaced using `envsubst`, depending on the git branch.
skip_push: ${skip_feature_docker_tags}
image_templates:
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-amd64"
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-arm64"
- name_template: quay.io/fairwinds/polaris:latest
# This is replaced using `envsubst`, depending on the git branch.
skip_push: ${skip_release}
image_templates:
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-amd64"
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-arm64"
- name_template: quay.io/fairwinds/polaris:{{ .Tag }}
# This is replaced using `envsubst`, depending on the git branch.
skip_push: ${skip_release}
image_templates:
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-amd64"
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-arm64"
- name_template: quay.io/fairwinds/polaris:{{ .Major }}
# This is replaced using `envsubst`, depending on the git branch.
skip_push: ${skip_release}
image_templates:
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-amd64"
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-arm64"
- name_template: quay.io/fairwinds/polaris:{{ .Major }}.{{ .Minor }}
# This is replaced using `envsubst`, depending on the git branch.
skip_push: ${skip_release}
image_templates:
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-amd64"
- "quay.io/fairwinds/polaris:{{ .FullCommit }}-arm64"
+1 -1
View File
@@ -1,2 +1,2 @@
## DO NOT EDIT - Managed by Terraform
* @rbren @makoscafee
* @sudermanjr @jdesouza @vitorvezani
+11 -17
View File
@@ -1,27 +1,21 @@
FROM golang:1.17 AS build-env
WORKDIR /go/src/github.com/fairwindsops/polaris/
FROM alpine:3.22
ENV GO111MODULE=on
ENV GOPROXY=https://proxy.golang.org
ENV CGO_ENABLED=0
ENV GOOS=linux
ENV GOARCH=amd64
LABEL org.opencontainers.image.authors="FairwindsOps, Inc." \
org.opencontainers.image.vendor="FairwindsOps, Inc." \
org.opencontainers.image.title="polaris" \
org.opencontainers.image.description="Polaris is a cli tool to help discover deprecated apiVersions in Kubernetes" \
org.opencontainers.image.documentation="https://polaris.docs.fairwinds.com/" \
org.opencontainers.image.source="https://github.com/FairwindsOps/polaris" \
org.opencontainers.image.url="https://github.com/FairwindsOps/polaris" \
org.opencontainers.image.licenses="Apache License 2.0"
COPY go.mod .
COPY go.sum .
RUN go mod download
RUN go get -u github.com/gobuffalo/packr/v2/packr2
COPY . .
RUN packr2 build -a -o polaris *.go
FROM alpine:3.16.1
WORKDIR /usr/local/bin
RUN apk -U upgrade
RUN apk --no-cache add ca-certificates
RUN addgroup -S polaris && adduser -u 1200 -S polaris -G polaris
USER 1200
COPY --from=build-env /go/src/github.com/fairwindsops/polaris/polaris .
COPY polaris .
WORKDIR /opt/app
+7 -20
View File
@@ -1,7 +1,7 @@
<div align="center" class="no-border">
<img src="https://polaris.docs.fairwinds.com/img/polaris-logo.png" alt="Polaris Logo">
<br>
<h3>Best Practices for Kubernetes Workload Configuration</h3>
<h3>Polaris is an open source policy engine for Kubernetes</h3>
<a href="https://github.com/FairwindsOps/polaris/releases">
<img src="https://img.shields.io/github/v/release/FairwindsOps/polaris">
</a>
@@ -16,15 +16,12 @@
</a>
</div>
Fairwinds' Polaris keeps your clusters sailing smoothly. It runs a variety of checks to ensure that
Kubernetes pods and controllers are configured using best practices, helping you avoid
problems in the future.
Polaris is an open source policy engine for Kubernetes that validates and remediates resource configuration. It includes 30+ built in configuration policies, as well as the ability to build custom policies with JSON Schema. When run on the command line or as a mutating webhook, Polaris can automatically remediate issues based on policy criteria.
Polaris can be run in three different modes:
* As a [dashboard](https://polaris.docs.fairwinds.com/dashboard), so you can audit what's running inside your cluster.
* As an [admission controller](https://polaris.docs.fairwinds.com/admission-controller), so you can automatically reject workloads that don't adhere to your organization's policies.
* As a [command-line tool](https://polaris.docs.fairwinds.com/infrastructure-as-code), so you can test local YAML files, e.g. as part of a CI/CD process.
* As a [dashboard](https://polaris.docs.fairwinds.com/dashboard) - Validate Kubernetes resources against policy-as-code.
* As an [admission controller](https://polaris.docs.fairwinds.com/admission-controller) - Automatically reject or modify workloads that don't adhere to your organization's policies.
* As a [command-line tool](https://polaris.docs.fairwinds.com/infrastructure-as-code) - Incorporate policy-as-code into the CI/CD process to test local YAML files.
<p align="center">
<img src="https://polaris.docs.fairwinds.com/img/architecture.svg" alt="Polaris Architecture" width="550"/>
</p>
@@ -37,13 +34,7 @@ Check out the [documentation at docs.fairwinds.com](https://polaris.docs.fairwin
The goal of the Fairwinds Community is to exchange ideas, influence the open source roadmap,
and network with fellow Kubernetes users.
[Chat with us on Slack](https://join.slack.com/t/fairwindscommunity/shared_invite/zt-e3c6vj4l-3lIH6dvKqzWII5fSSFDi1g)
or
[join the user group](https://www.fairwinds.com/open-source-software-user-group) to get involved!
<a href="https://www.fairwinds.com/t-shirt-offer?utm_source=polaris&utm_medium=polaris&utm_campaign=polaris-tshirt">
<img src="https://www.fairwinds.com/hubfs/Doc_Banners/Fairwinds_OSS_User_Group_740x125_v6.png" alt="Love Fairwinds Open Source? Share your business email and job title and we'll send you a free Fairwinds t-shirt!" />
</a>
[Chat with us on Slack](https://join.slack.com/t/fairwindscommunity/shared_invite/zt-2na8gtwb4-DGQ4qgmQbczQyB2NlFlYQQ)
## Other Projects from Fairwinds
@@ -58,9 +49,5 @@ Or [check out the full list](https://www.fairwinds.com/open-source-software?utm_
If you're interested in running Polaris in multiple clusters,
tracking the results over time, integrating with Slack, Datadog, and Jira,
or unlocking other functionality, check out
[Fairwinds Insights](https://www.fairwinds.com/polaris-user-insights-demo?utm_source=polaris&utm_medium=polaris&utm_campaign=polaris),
[Fairwinds Insights](https://fairwinds.com/insights),
a platform for auditing and enforcing policy in Kubernetes clusters.
<a href="https://www.fairwinds.com/polaris-user-insights-demo?utm_source=polaris&utm_medium=ad&utm_campaign=polarisad">
<img src="https://www.fairwinds.com/hubfs/Doc_Banners/Fairwinds_Polaris_Ad.png" alt="Fairwinds Insights" />
</a>
-17
View File
@@ -1,17 +0,0 @@
successMessage: Label app.kubernetes.io/name matches metadata.name
failureMessage: Label app.kubernetes.io/name must match metadata.name
target: Controller
schema:
'$schema': http://json-schema.org/draft-07/schema
type: object
properties:
metadata:
type: object
required: ["labels"]
properties:
labels:
type: object
required: ["app.kubernetes.io/name"]
properties:
app.kubernetes.io/name:
const: "{{ .metadata.name }}"
-43
View File
@@ -1,43 +0,0 @@
successMessage: The container does not set potentially sensitive environment variables
failureMessage: The container sets potentially sensitive environment variables
category: Security
target: Container
schemaString: |
'$schema': http://json-schema.org/draft-07/schema
type: object
properties:
env:
type: array
items:
type: object
required: ["name"]
properties:
name:
type: string
'$comment': These environment variable names will be disallowed.
allOf:
- not:
pattern: '(?i)^AWS_SECRET_ACCESS_KEY$'
- not:
pattern: '(?i)^GOOGLE_APPLICATION_CREDENTIALS$'
- not:
pattern: '(?i)^AZURE_.+KEY$'
- not:
pattern: '(?i)^OCI_CLI_KEY_CONTENT$'
- not:
pattern: '(?i)password'
- not:
pattern: '(?i)token'
- not:
pattern: '(?i)bearer'
- not:
pattern: '(?i)secret'
'$comment': This allows variable names not excluded above.
- pattern: '(?i).*'
value:
type: string
'$comment': These environment variable values will be disallowed.
allOf:
- not:
'$comment': THis matches variations like begin private key, begin rsa private key ...
pattern: '(?i)\s*-BEGIN\s+.*PRIVATE KEY-\s*'
+44 -18
View File
@@ -17,9 +17,10 @@ package cmd
import (
"bytes"
"context"
"crypto/tls"
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/http"
"os"
"os/exec"
@@ -42,9 +43,12 @@ var (
resourceToAudit string
useColor bool
helmChart string
helmValues string
helmValues []string
helmSkipTests bool
checks []string
auditNamespace string
severityLevel string
skipSslValidation bool
)
func init() {
@@ -60,9 +64,12 @@ func init() {
auditCmd.PersistentFlags().StringVar(&displayName, "display-name", "", "An optional identifier for the audit.")
auditCmd.PersistentFlags().StringVar(&resourceToAudit, "resource", "", "Audit a specific resource, in the format namespace/kind/version/name, e.g. nginx-ingress/Deployment.apps/v1/default-backend.")
auditCmd.PersistentFlags().StringVar(&helmChart, "helm-chart", "", "Will fill out Helm template")
auditCmd.PersistentFlags().StringVar(&helmValues, "helm-values", "", "Optional flag to add helm values")
auditCmd.PersistentFlags().StringSliceVar(&helmValues, "helm-values", []string{}, "Optional flag to add helm values")
auditCmd.PersistentFlags().BoolVar(&helmSkipTests, "helm-skip-tests", false, "Corresponds to --skip-tests of helm template")
auditCmd.PersistentFlags().StringSliceVar(&checks, "checks", []string{}, "Optional flag to specify specific checks to check")
auditCmd.PersistentFlags().StringVar(&auditNamespace, "namespace", "", "Namespace to audit. Only applies to in-cluster audits")
auditCmd.PersistentFlags().StringVar(&severityLevel, "severity", "", "Severity level used to filter results. Behaves like log levels. 'danger' is the least verbose (warning, danger)")
auditCmd.PersistentFlags().BoolVar(&skipSslValidation, "skip-ssl-validation", false, "Skip https certificate verification")
}
var auditCmd = &cobra.Command{
@@ -95,26 +102,27 @@ var auditCmd = &cobra.Command{
}
if helmChart != "" {
var err error
auditPath, err = ProcessHelmTemplates(helmChart, helmValues)
auditPath, err = ProcessHelmTemplates(helmChart, helmValues, helmSkipTests)
if err != nil {
logrus.Infof("Couldn't process helm chart: %v", err)
logrus.Errorf("Couldn't process helm chart: %v", err)
os.Exit(1)
}
}
k, err := kube.CreateResourceProvider(context.TODO(), auditPath, resourceToAudit, config)
ctx := context.TODO()
k, err := kube.CreateResourceProvider(ctx, auditPath, resourceToAudit, config)
if err != nil {
logrus.Errorf("Error fetching Kubernetes resources %v", err)
os.Exit(1)
}
auditData, err := validator.RunAudit(config, k)
auditData, err := validator.RunAudit(context.Background(), config, k)
if err != nil {
logrus.Errorf("Error while running audit on resources: %v", err)
os.Exit(1)
}
outputAudit(auditData, auditOutputFile, auditOutputURL, auditOutputFormat, useColor, onlyShowFailedTests)
outputAudit(auditData, auditOutputFile, auditOutputURL, auditOutputFormat, useColor, onlyShowFailedTests, severityLevel)
summary := auditData.GetSummary()
score := summary.GetScore()
@@ -129,7 +137,7 @@ var auditCmd = &cobra.Command{
}
// ProcessHelmTemplates turns helm into yaml to be processed by Polaris or the other tools.
func ProcessHelmTemplates(helmChart, helmValues string) (string, error) {
func ProcessHelmTemplates(helmChart string, helmValues []string, helmSkipTests bool) (string, error) {
cmd := exec.Command("helm", "dependency", "update", helmChart)
output, err := cmd.CombinedOutput()
if err != nil {
@@ -137,18 +145,22 @@ func ProcessHelmTemplates(helmChart, helmValues string) (string, error) {
return "", err
}
dir, err := ioutil.TempDir("", "*")
dir, err := os.MkdirTemp("", "*")
if err != nil {
return "", err
}
params := []string{
"template", helmChart,
helmChart,
"--generate-name",
"--output-dir",
dir,
}
if helmValues != "" {
params = append(params, "--values", helmValues)
for _, v := range helmValues {
params = append(params, "--values", v)
}
if helmSkipTests {
params = append(params, "--skip-tests")
}
cmd = exec.Command("helm", params...)
@@ -161,10 +173,20 @@ func ProcessHelmTemplates(helmChart, helmValues string) (string, error) {
return dir, nil
}
func outputAudit(auditData validator.AuditData, outputFile, outputURL, outputFormat string, useColor bool, onlyShowFailedTests bool) {
func outputAudit(auditData validator.AuditData, outputFile, outputURL, outputFormat string, useColor bool, onlyShowFailedTests bool, severityLevel string) {
if onlyShowFailedTests {
auditData = auditData.RemoveSuccessfulResults()
}
if severityLevel != "" {
switch severityLevel {
case "danger":
auditData = auditData.FilterResultsBySeverityLevel(cfg.SeverityDanger)
case "warning":
auditData = auditData.FilterResultsBySeverityLevel(cfg.SeverityWarning)
}
}
var outputBytes []byte
var err error
if outputFormat == "score" {
@@ -202,9 +224,13 @@ func outputAudit(auditData validator.AuditData, outputFile, outputURL, outputFor
} else {
req.Header.Set("Content-Type", "text/plain")
}
client := &http.Client{}
resp, err := client.Do(req)
client := &http.Client{}
if skipSslValidation {
transport := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
client = &http.Client{Transport: transport}
}
resp, err := client.Do(req)
if err != nil {
logrus.Errorf("Error making request for output: %v", err)
os.Exit(1)
@@ -212,7 +238,7 @@ func outputAudit(auditData validator.AuditData, outputFile, outputURL, outputFor
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
logrus.Errorf("Error reading response: %v", err)
@@ -223,7 +249,7 @@ func outputAudit(auditData validator.AuditData, outputFile, outputURL, outputFor
}
if outputFile != "" {
err := ioutil.WriteFile(outputFile, []byte(outputBytes), 0644)
err := os.WriteFile(outputFile, outputBytes, 0644)
if err != nil {
logrus.Errorf("Error writing output to file: %v", err)
os.Exit(1)
+6 -1
View File
@@ -15,6 +15,7 @@
package cmd
import (
"context"
"fmt"
"net/http"
@@ -54,7 +55,11 @@ var dashboardCmd = &cobra.Command{
auditData := validator.ReadAuditFromFile(loadAuditFile)
auditDataPtr = &auditData
}
router := dashboard.GetRouter(config, auditPath, serverPort, basePath, auditDataPtr)
router, err := dashboard.GetRouter(context.Background(), config, auditPath, serverPort, basePath, auditDataPtr)
if err != nil {
logrus.Fatalf("error creating router: %v", err)
}
router.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("OK"))
})
+9 -131
View File
@@ -15,33 +15,25 @@
package cmd
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/fairwindsops/polaris/pkg/kube"
"github.com/fairwindsops/polaris/pkg/mutation"
"github.com/fairwindsops/polaris/pkg/validator"
"github.com/fairwindsops/polaris/pkg/fix"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
yamlV3 "gopkg.in/yaml.v3"
"sigs.k8s.io/yaml"
)
var (
filesPath string
checksToFix []string
fixAll bool
isTemplate bool
)
func init() {
rootCmd.AddCommand(fixCommand)
fixCommand.PersistentFlags().StringVar(&filesPath, "files-path", "", "mutate and fix one or more YAML files in a specified folder")
fixCommand.PersistentFlags().BoolVar(&isTemplate, "template", false, "set to true when modifyng a YAML template, like a Helm chart (experimental)")
fixCommand.PersistentFlags().StringSliceVar(&checksToFix, "checks", []string{}, "Optional flag to specify specific checks to fix eg. checks=hostIPCSet,hostPIDSet and checks=all applies fix to all defined checks mutations")
}
@@ -52,128 +44,14 @@ var fixCommand = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
logrus.Debug("Setting up controller manager")
if filesPath == "" {
logrus.Error("Please specify a file-path flag")
cmd.Help()
os.Exit(1)
}
var yamlFiles []string
fileInfo, err := os.Stat(filesPath)
err := fix.Execute(context.Background(), config, filesPath, isTemplate, checksToFix...)
if err != nil {
logrus.Error(err)
os.Exit(1)
}
if fileInfo.IsDir() {
baseDir := filesPath
if !strings.HasSuffix(filesPath, "/") {
baseDir = baseDir + "/"
}
yamlFiles, err = getYamlFiles(baseDir)
if err != nil {
logrus.Error(err)
if errors.Is(err, fix.ErrFilesPathRequired) {
logrus.Error("Please specify a files-path flag")
cmd.Help()
os.Exit(1)
}
} else {
yamlFiles = append(yamlFiles, filesPath)
logrus.Fatal(err)
}
var contentStr string
isFirstResource := true
if len(checksToFix) > 0 {
if len(checksToFix) == 1 && checksToFix[0] == "all" {
allchecks := []string{}
for key := range config.Checks {
allchecks = append(allchecks, key)
}
config.Mutations = allchecks
} else {
config.Mutations = checksToFix
}
}
for _, fullFilePath := range yamlFiles {
yamlFile, err := ioutil.ReadFile(fullFilePath)
if err != nil {
logrus.Fatalf("Error reading file with file path %s: %v", fullFilePath, err)
}
dec := yamlV3.NewDecoder(bytes.NewReader(yamlFile))
for {
data := map[string]interface{}{}
err := dec.Decode(&data)
// check it was parsed
if data == nil {
continue
}
// break the loop in case of EOF
if errors.Is(err, io.EOF) {
break
}
if err != nil {
logrus.Fatalf("Error decoding data for file with file path %s: %v", fullFilePath, err)
}
yamlContent, err := yamlV3.Marshal(data)
if err != nil {
logrus.Fatalf("Error marshalling %s: %v", fullFilePath, err)
}
kubeResources := kube.CreateResourceProviderFromYaml(string(yamlContent))
results, err := validator.ApplyAllSchemaChecksToResourceProvider(&config, kubeResources)
if err != nil {
logrus.Fatalf("Error applying schema check to the resources %s: %v", fullFilePath, err)
}
comments, allMutations := mutation.GetMutationsAndCommentsFromResults(results)
updatedYamlContent := string(yamlContent)
if len(allMutations) > 0 {
for _, resources := range kubeResources.Resources {
key := fmt.Sprintf("%s/%s/%s", resources[0].Kind, resources[0].Resource.GetName(), resources[0].Resource.GetNamespace())
mutations := allMutations[key]
mutated, err := mutation.ApplyAllSchemaMutations(&config, kubeResources, resources[0], mutations)
if err != nil {
logrus.Errorf("Error applying schema mutations to the resources: %v", err)
os.Exit(1)
}
mutatedYamlContent, err := yaml.JSONToYAML(mutated.OriginalObjectJSON)
if err != nil {
logrus.Errorf("Error converting JSON to Yaml : %v", err)
os.Exit(1)
}
updatedYamlContent = mutation.UpdateMutatedContentWithComments(string(mutatedYamlContent), comments)
}
}
if isFirstResource {
contentStr = updatedYamlContent
isFirstResource = false
} else {
contentStr += "\n"
contentStr += "---"
contentStr += "\n"
contentStr += updatedYamlContent
}
}
if contentStr != "" {
err = ioutil.WriteFile(fullFilePath, []byte(contentStr), 0644)
if err != nil {
logrus.Fatalf("Error writing output to file: %v", err)
}
}
}
},
}
func getYamlFiles(rootpath string) ([]string, error) {
var list []string
err := filepath.Walk(rootpath, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
}
if filepath.Ext(path) == ".yaml" || filepath.Ext(path) == ".yml" {
list = append(list, path)
}
return nil
})
return list, err
}
+23 -12
View File
@@ -15,21 +15,27 @@
package cmd
import (
"flag"
"os"
"strings"
conf "github.com/fairwindsops/polaris/pkg/config"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
var configPath string
var disallowExemptions, disallowConfigExemptions, disallowAnnotationExemptions, fixChecks bool
var logLevel string
var auditPath string
var displayName string
var kubeContext string
var (
mergeConfig bool
configPath string
disallowExemptions bool
disallowConfigExemptions bool
disallowAnnotationExemptions bool
fixChecks bool
logLevel string
auditPath string
displayName string
kubeContext string
insightsHost string
)
var (
version string
@@ -37,14 +43,14 @@ var (
func init() {
// Flags
rootCmd.PersistentFlags().BoolVarP(&mergeConfig, "merge-config", "m", false, "If true, custom configuration will be merged with default configuration instead of replacing it.")
rootCmd.PersistentFlags().StringVarP(&configPath, "config", "c", "", "Location of Polaris configuration file.")
rootCmd.PersistentFlags().StringVarP(&kubeContext, "context", "x", "", "Set the kube context.")
rootCmd.PersistentFlags().BoolVarP(&disallowExemptions, "disallow-exemptions", "", false, "Disallow any configured exemption.")
rootCmd.PersistentFlags().BoolVarP(&disallowConfigExemptions, "disallow-config-exemptions", "", false, "Disallow exemptions set within the configuration file.")
rootCmd.PersistentFlags().BoolVarP(&disallowAnnotationExemptions, "disallow-annotation-exemptions", "", false, "Disallow any exemption defined as a controller annotation.")
rootCmd.PersistentFlags().StringVarP(&logLevel, "log-level", "", logrus.InfoLevel.String(), "Logrus log level.")
flag.Parse()
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
rootCmd.PersistentFlags().StringVarP(&logLevel, "log-level", "", logrus.InfoLevel.String(), "Logrus log level to be output (trace, debug, info, warning, error, fatal, panic).")
rootCmd.PersistentFlags().StringVar(&insightsHost, "insights-host", "https://insights.fairwinds.com", "Fairwinds Insights host URL")
}
var config conf.Configuration
@@ -61,7 +67,7 @@ var rootCmd = &cobra.Command{
logrus.SetLevel(parsedLevel)
}
config, err = conf.ParseFile(configPath)
config, err = conf.MergeConfigAndParseFile(configPath, mergeConfig)
if err != nil {
logrus.Errorf("Error parsing config at %s: %v", configPath, err)
os.Exit(1)
@@ -80,6 +86,11 @@ var rootCmd = &cobra.Command{
}
os.Exit(1)
},
PersistentPostRun: func(cmd *cobra.Command, args []string) {
if !strings.HasPrefix(cmd.Use, "audit") {
os.Stderr.WriteString("\n\nWant more? Automate Polaris for free with Fairwinds Insights!\n🚀 https://fairwinds.com/insights-signup/polaris 🚀 \n")
}
},
}
// Execute the stuff
+3
View File
@@ -31,4 +31,7 @@ var versionCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Polaris version:" + version)
},
PersistentPostRunE: func(cmd *cobra.Command, args []string) error {
return nil
},
}
+13 -10
View File
@@ -15,8 +15,8 @@
package cmd
import (
"context"
"os"
"time"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -25,12 +25,14 @@ import (
k8sConfig "sigs.k8s.io/controller-runtime/pkg/client/config"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/manager/signals"
"sigs.k8s.io/controller-runtime/pkg/webhook"
)
var webhookPort int
var disableWebhookConfigInstaller bool
var enableMutations bool
var enableValidations bool
var certDir string
func init() {
rootCmd.AddCommand(webhookCmd)
@@ -38,6 +40,7 @@ func init() {
webhookCmd.PersistentFlags().BoolVar(&disableWebhookConfigInstaller, "disable-webhook-config-installer", false, "Disable the installer in the webhook server, so it won't install webhook configuration resources during bootstrapping.")
webhookCmd.PersistentFlags().BoolVar(&enableValidations, "validate", true, "Enable the validating webhook to reject workloads with issues")
webhookCmd.PersistentFlags().BoolVar(&enableMutations, "mutate", false, "Enable the mutating webhook to modify workloads with issues")
webhookCmd.PersistentFlags().StringVar(&certDir, "cert-dir", "/opt/cert", "Directory in which tls certificate is located")
}
var webhookCmd = &cobra.Command{
@@ -48,22 +51,22 @@ var webhookCmd = &cobra.Command{
logrus.Debug("Setting up controller manager")
mgr, err := manager.New(k8sConfig.GetConfigOrDie(), manager.Options{
CertDir: "/opt/cert",
Port: webhookPort,
WebhookServer: webhook.NewServer(webhook.Options{
CertDir: certDir,
Port: webhookPort,
CertName: "tls.crt",
KeyName: "tls.key",
}),
})
if err != nil {
logrus.Errorf("Unable to set up overall controller manager: %v", err)
os.Exit(1)
}
_, err = os.Stat("/opt/cert/tls.crt")
_, err = os.Stat(certDir + "/tls.crt")
if os.IsNotExist(err) {
time.Sleep(time.Second * 10)
panic("Cert does not exist")
}
server := mgr.GetWebhookServer()
server.CertName = "tls.crt"
server.KeyName = "tls.key"
if !enableMutations && !enableValidations {
logrus.Errorf("One of --mutate or --validate must be set to true")
@@ -71,10 +74,10 @@ var webhookCmd = &cobra.Command{
}
if enableValidations {
fwebhook.NewValidateWebhook(mgr, fwebhook.Validator{Config: config, Client: mgr.GetClient()})
fwebhook.NewValidateWebhook(mgr, config)
}
if enableMutations {
fwebhook.NewMutateWebhook(mgr, fwebhook.Mutator{Config: config, Client: mgr.GetClient()})
fwebhook.NewMutateWebhook(context.Background(), mgr, config)
}
logrus.Infof("Polaris webhook server listening on port %d", webhookPort)
if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
+10 -6
View File
@@ -11,6 +11,16 @@ var sf14gv = 32793;
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(sf14g, s);
})();
(function() {
var gtag = document.createElement('script');
gtag.src = "https://www.googletagmanager.com/gtag/js?id=G-ZR5M5SRYKY";
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(gtag, s);
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-ZR5M5SRYKY');
})();
!function(f,b,e,v,n,t,s)
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
@@ -21,9 +31,3 @@ s.parentNode.insertBefore(t,s)}(window,document,'script',
'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', '521127644762074');
fbq('track', 'PageView');
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-TM95WXQ');
+23 -2
View File
@@ -53,9 +53,30 @@ This means Polaris will remediate the issue it finds, rather than rejecting
the deployment.
To enable the mutating webhook, add `--set webhook.mutate=true` to your
Helm instlallation command.
Helm installation command.
By default, the only mutation enabled is `pullPolicyNotAlways`. If you'd like to
The following default checks currently have mutation support enabled:
* `hostPIDSet`
* `hostNetworkSet`
* `hostIPCSet`
* `priorityClassNotSet`
* `hostPortSet`
* `pullPolicyNotAlways`
* `deploymentMissingReplicas`
* `dangerousCapabilities`
* `cpuLimitsMissing`
* `memoryLimitsMissing`
* `livenessProbeMissing`
* `memoryRequestsMissing`
* `cpuRequestsMissing`
* `runAsPrivileged`
* `readinessProbeMissing`
* `privilegeEscalationAllowed`
* `notReadOnlyRootFilesystem`
* `insecureCapabilities`
* `runAsRootAllowed`
If you'd like to
enable other mutations, you can set the `webhook.mutations` flag.
+100 -1
View File
@@ -5,6 +5,105 @@ meta:
content: "Fairwinds Polaris | Changelog"
---
## 9.1.1
* Fix `hpaMinAvailability` failure message
* Fix `missingPodDisruptionBudget` typo
* Rewrite `hpaMaxAvailability` check to use go-template
## 9.1.0
* Add HPA `minAvailable` and HPA `maxAvailable` checks
* Fix typo for PDB `minAvailable`
## 9.0.1
* Fix comments handling in `addOrReplaceValue` function
## 9.0.0
* Expose issue fixer and mutations in the library
* Remove `packr` in favor of `go:embed`
## 8.5.6
* Fix trying to list cluster-level resources
## 8.5.5
* Fix missing PDB check
## 8.5.4
* Fix conditional expressions should be at very top of `additionalSchemaStrings`
* Update alpine to 3.19
## 8.5.3
* Add quiet flag to polaris audit CLI command to suppress 'upload to Insights' prompt
## 8.5.2
* Switch to `controller-utils` package to get workloads
## 8.5.1
* Update `topologySpreadConstraint` check
## 8.5.0
* Add helm-skip-tests flag
* Update CLI docs
* Handle multiple helm-values files
## 8.4.0
* Change kubernetes.io/ label from name to instance
## 8.3.0
* Add option to filter audit results by severity level
* Add insights prompt
## 8.2.4
* Fix nil pointer issue with webhook
## 8.2.3
* Add category for `metadataAndNameMismatched`.
* Fix category for `priorityClassNotSet`.
## 8.2.2
* Fix webhook server cert dir argument
## 8.2.1
* Fix on Insights integration
## 8.2.0
* Minor fixes for NSA checks
## 8.1.0
* Add `insights-host` global flag to configure Fairwinds Insights host (defaults to `https://insights.fairwinds.com`).
* Add new `auth` sub-commands be able to authenticate on Polaris using Fairwinds Insights credentials
- `login` - login using Fairwinds Insights credentials via the web interface or provide a token
- `logout` - logout from Fairwinds Insights
- `status` - show relevant information regarding login state
- `token` - prints the token from local storage
* Add new `audit` flags to be able to upload Workloads and Polaris results to Fairwinds Insights
- `upload-insights` - indicates that the results should be uploaded to Fairwinds Insights. (defaults to `false`)
- `cluster-name` - cluster name that the results belongs to. Creates the cluster if it does not exist. (required if `upload-insights` is used)
## 8.0.0
* Change default severity from `ignore` to `warning` for `priorityClassNotSet`, `metadataAndNameMismatched`, `missingPodDisruptionBudget`, `automountServiceAccountToken`, `missingNetworkPolicy` checks.
* Change default severity from `warning` to `danger` for `sensitiveContainerEnvVar`, `sensitiveConfigmapContent`, `clusterrolePodExecAttach`, `rolePodExecAttach`, `clusterrolebindingPodExecAttach`, `rolebindingClusterRolePodExecAttach`, `rolebindingRolePodExecAttach`,`clusterrolebindingClusterAdmin`,`rolebindingClusterAdminClusterRole`,`rolebindingClusterAdminRole` checks.
## 7.4.0
* Skip https certificate verification (#920)
## 7.3.0
* Add a check for `topologySpreadConstraint` (#879)
## 7.2.0
* Enable new RBAC / sensitive content / Pod exec checks, add `hasPrefix` and `hasSuffix` functions to the GO template, exempt `system:` name prefixes for RBAC checks, sensitive content checks ignore `valueFrom`, (#832)
## 7.1.0
* Let Polaris modify YAML without losing comments/formatting (#821)
* Add checks for RBAC allowing exec or attaching to a Pod (#820)
* Add `clusterrolebindingClusterAdmin`, `rolebindingClusterAdminRole`, and `rolebindingClusterAdminClusterRole` checks + schema tests (#823)
## 7.0.2
* Fixes for pretty CLI output
* Some new checks (disabled by default)
* Some additional features in templating engine
## 7.0.1
* Documentation updates
@@ -152,7 +251,7 @@ JSON schema (see changes to `./checks/multipleReplicasForDeployment.yaml`)
* Docker image now includes the default config
### Breaking Changes
* Breaking changes in both input and output formats. See [Examples](https://github.com/FairwindsOps/polaris/tree/master/examples) for examples of the new formats.
* Breaking changes in both input and output formats. See [Examples](https://github.com/FairwindsOps/polaris/tree/master/pkg/config/examples) for examples of the new formats.
* removed config-level configuration for checks like max/min memory settings
* changed severity `error` to `danger`
* Breaking changes to the CLI
+39 -2
View File
@@ -14,22 +14,58 @@ key | default | description
`livenessProbeMissing` | `warning` | Fails when a liveness probe is not configured for a pod.
`tagNotSpecified` | `danger` | Fails when an image tag is either not specified or `latest`.
`pullPolicyNotAlways` | `warning` | Fails when an image pull policy is not `always`.
`priorityClassNotSet` | `ignore` | Fails when a priorityClassName is not set for a pod.
`priorityClassNotSet` | `warning` | Fails when a priorityClassName is not set for a pod.
`deploymentMissingReplicas` | `warning` | Fails when there is only one replica for a deployment.
`missingPodDisruptionBudget` | `ignore`
`missingPodDisruptionBudget` | `warning` | Fails when PDB is missing.
`metadataAndInstanceMismatched` | `warning` | Fails when label `app.kubernetes.io/instance` and `metadata.name` mismatch
`topologySpreadConstraint` | `warning` | Fails when there is no topology spread constraint on the pod
`hpaMaxAvailability` | `warning` | Fails when `maxAvailable` lesser or equal than `minAvailable` (if defined) for a HorizontalPodAutoscaler
`hpaMinAvailability` | `warning` | Fails when `minAvailable` (if defined) lesser or equal to one for a HorizontalPodAutoscaler
`pdbMinAvailableGreaterThanHPAMinReplicas` | `warning` | Fails when PDB `minAvailable` is greater than HPA `minReplicas`
## Background
### Liveness and Readiness Probes
Readiness and liveness probes can help maintain the health of applications running inside Kubernetes. By default, Kubernetes only knows whether or not a process is running, not if it's healthy. Properly configured readiness and liveness probes will also be able to ensure the health of an application.
Readiness probes are designed to ensure that an application has reached a "ready" state. In many cases there is a period of time between when a webserver process starts and when it is ready to receive traffic. A readiness probe can ensure the traffic is not sent to a pod until it is actually ready to receive traffic.
Liveness probes are designed to ensure that an application stays in a healthy state. When a liveness probe fails, the pod will be restarted.
### Image Pull Policy
Docker's `latest` tag is applied by default to images where a tag hasn't been specified. Not specifying a specific version of an image can lead to a wide variety of problems. The underlying image could include unexpected breaking changes that break your application whenever the latest image is pulled. Reusing the same tag for multiple versions of an image can lead to different nodes in the same cluster having different versions of an image, even if the tag is identical.
Related to that, relying on cached versions of a Docker image can become a security vulnerability. By default, an image will be pulled if it isn't already cached on the node attempting to run it. This can result in variations in images that are running per node, or potentially provide a way to gain access to an image without having direct access to the ImagePullSecret. With that in mind, it's often better to ensure the a pod has `pullPolicy: Always` specified, so images are always pulled directly from their source.
### Topology Spread Constraints
By default, the Kubernetes scheduler uses a bin-packing algorithm to fit as many pods as possible into a cluster. The scheduler prefers a more evenly distributed general node load to app replicas precisely spread across nodes. Therefore, by default, multi-replica is not guaranteed to be spread across multiple availability zones. Kubernetes provides topologySpreadConstraint configuration in order to better ensure pod spread across multiple AZs and/or Hosts.
Example of a topologySpreadConstraint spreading across zones:
```
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-basic-demo
spec:
selector:
matchLabels:
app.kubernetes.io/name: basic-demo
app.kubernetes.io/instance: demo
template:
metadata:
labels:
app.kubernetes.io/name: basic-demo
app.kubernetes.io/instance: demo
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: "topology.kubernetes.io/zone"
whenUnsatisfiable: ScheduleAnyway
```
## Further Reading
- [What's Wrong With The Docker :latest Tag?](https://vsupalov.com/docker-latest-tag/)
@@ -37,3 +73,4 @@ Related to that, relying on cached versions of a Docker image can become a secur
- [Kubernetes Docs: Configure Liveness and Readiness Probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/)
- [Utilizing Kubernetes Liveness and Readiness Probes to Automatically Recover From Failure](https://medium.com/spire-labs/utilizing-kubernetes-liveness-and-readiness-probes-to-automatically-recover-from-failure-2fe0314f2b2e)
- [Kubernetes Liveness and Readiness Probes: How to Avoid Shooting Yourself in the Foot](https://blog.colinbreck.com/kubernetes-liveness-and-readiness-probes-how-to-avoid-shooting-yourself-in-the-foot/)
- [Topology Spread Constraints](https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/)
+15 -2
View File
@@ -11,17 +11,30 @@ for privilege escalation.
key | default | description
----|---------|------------
`automountServiceAccountToken` | `warning` | Fails when `automountServiceAccountToken` is automounted.
`hostIPCSet` | `danger` | Fails when `hostIPC` attribute is configured.
`hostPIDSet` | `danger` | Fails when `hostPID` attribute is configured.
`linuxHardening` | `danger` | Fails when neither `AppArmor`, `Seccomp`, `SELinux`, or dropping Linux Capabilities is in use.
`notReadOnlyRootFilesystem` | `warning` | Fails when `securityContext.readOnlyRootFilesystem` is not true.
`privilegeEscalationAllowed` | `danger` | Fails when `securityContext.allowPrivilegeEscalation` is true.
`runAsRootAllowed` | `warning` | Fails when `securityContext.runAsNonRoot` is not true.
`runAsPrivileged` | `danger` | Fails when `securityContext.privileged` is true.
`insecureCapabilities` | `warning` | Fails when `securityContext.capabilities` includes one of the capabilities [listed here](https://github.com/FairwindsOps/polaris/tree/master/checks/insecureCapabilities.yaml)
`dangerousCapabilities` | `danger` | Fails when `securityContext.capabilities` includes one of the capabilities [listed here](https://github.com/FairwindsOps/polaris/tree/master/checks/dangerousCapabilities.yaml)
`insecureCapabilities` | `warning` | Fails when `securityContext.capabilities` includes one of the capabilities [listed here](https://github.com/FairwindsOps/polaris/tree/master/pkg/config/checks/insecureCapabilities.yaml)
`dangerousCapabilities` | `danger` | Fails when `securityContext.capabilities` includes one of the capabilities [listed here](https://github.com/FairwindsOps/polaris/tree/master/pkg/config/checks/dangerousCapabilities.yaml)
`hostNetworkSet` | `warning` | Fails when `hostNetwork` attribute is configured.
`hostPortSet` | `warning` | Fails when `hostPort` attribute is configured.
`tlsSettingsMissing` | `warning` | Fails when an Ingress lacks TLS settings.
`sensitiveContainerEnvVar` | `danger` | Fails when the container sets potentially sensitive environment variables.
`sensitiveConfigmapContent` | `danger` | Fails when potentially sensitive content is detected in the ConfigMap keys or values.
`missingNetworkPolicy` | `warning`
`clusterrolePodExecAttach` | `danger` | Fails when the ClusterRole allows Pods/exec or pods/attach.
`rolePodExecAttach` | `danger` | Fails when the Role allows Pods/exec or pods/attach.
`clusterrolebindingPodExecAttach` | `danger` | Fails when the ClusterRoleBinding references a ClusterRole that allows Pods/exec, allows pods/attach, or that does not exist.
`rolebindingRolePodExecAttach` | `danger` | Fails when the RoleBinding references a Role that allows Pods/exec, allows pods/attach, or that does not exist.
`rolebindingClusterRolePodExecAttach` | `danger` | Fails when the RoleBinding references a ClusterRole that allows Pods/exec, allows pods/attach, or that does not exist.
`clusterrolebindingClusterAdmin` | `danger` | Fails when the ClusterRoleBinding references the default cluster-admin ClusterRole or one with wildcard permissions.
`rolebindingClusterAdminClusterRole` | `danger` | Fails when the RoleBinding references the default cluster-admin ClusterRole or one with wildcard permissions.
`rolebindingClusterAdminRole` | `danger` | Fails when the RoleBinding references a Role with wildcard permissions.
## Background
+16 -3
View File
@@ -11,12 +11,14 @@ audit
Runs a one-time audit.
dashboard
Runs the webserver for Polaris dashboard.
fix
Fix Infrastructure as code files.
help
Prints help, if you give it a command then it will print help for that command. Same as -h
version
Prints the version of Polaris
webhook
Runs the webhook webserver
Runs the webhook webserver.
# global flags
-c, --config string Location of Polaris configuration file.
@@ -25,6 +27,7 @@ webhook
--disallow-config-exemptions Disallow exemptions set within the configuration file.
--disallow-annotation-exemptions Disallow any exemption defined as a controller annotation.
--kubeconfig string Paths to a kubeconfig. Only required if out-of-cluster.
--insights-host string Fairwinds Insights host URL. (default "https://insights.fairwinds.com")
--log-level string Logrus log level. (default "info")
# dashboard flags
@@ -38,12 +41,13 @@ webhook
# audit flags
--audit-path string If specified, audits one or more YAML files instead of a cluster.
--checks stringArray Optional flag to specify specific checks to check
--checks strings Optional flag to specify specific checks to check
--color Whether to use color in pretty format. (default true)
--display-name string An optional identifier for the audit.
-f, --format string Output format for results - json, yaml, pretty, or score. (default "json")
--helm-chart string Will fill out Helm template
--helm-values string Optional flag to add helm values
--helm-skip-tests bool Corresponds to --skip-tests of helm template
-h, --help help for audit
--namespace string Namespace to audit. Only applies to in-cluster audits
--only-show-failed-tests If specified, audit output will only show failed tests.
@@ -52,10 +56,19 @@ webhook
--resource string Audit a specific resource, in the format namespace/kind/version/name, e.g. nginx-ingress/Deployment.apps/v1/default-backend.
--set-exit-code-below-score int Set an exit code of 4 when the score is below this threshold (1-100).
--set-exit-code-on-danger Set an exit code of 3 when the audit contains danger-level issues.
--severity string Severity level used to filter results. Behaves like log levels. 'danger' is the least verbose (warning, danger)
--skip-ssl-validation Skip https certificate verification
# fix flags
--checks strings Optional flag to specify specific checks to fix eg. checks=hostIPCSet,hostPIDSet and checks=all applies fix to all defined checks mutations
--files-path string mutate and fix one or more YAML files in a specified folder
-h, --help help for fix
--template set to true when modifyng a YAML template, like a Helm chart (experimental)
# webhook flags
--disable-webhook-config-installer disable the installer in the webhook server, so it won't install webhook configuration resources during bootstrapping.
-h, --help help for webhook
-p, --port int Port for the dashboard webserver. (default 9876)
```
```
+1 -2
View File
@@ -49,8 +49,7 @@ kind create cluster --wait=90s --image kindest/node:v1.15.11 --name polaris-test
docker build -t quay.io/fairwinds/polaris:debug . # or use your own registry
docker push quay.io/fairwinds/polaris:debug
helm repo add jetstack https://charts.jetstack.io
kubectl create ns cert-manager
helm install cert-manager jetstack/cert-manager --namespace cert-manager --version 0.16.1 --set "installCRDs=true" --wait
helm install cert-manager jetstack/cert-manager --namespace cert-manager --version v1.12.1 --set "installCRDs=true" --wait
POLARIS_IMAGE=quay.io/fairwinds/polaris:debug ./test/webhook_test.sh
```
to avoid the final cleanup for debugging purposes, you can run
+1 -1
View File
@@ -5,7 +5,7 @@ meta:
---
# Configuration
The default Polaris configuration can be [seen here](https://github.com/FairwindsOps/polaris/blob/master/examples/config.yaml).
The default Polaris configuration can be [seen here](https://github.com/FairwindsOps/polaris/blob/master/pkg/config/default.yaml).
You can customize the configuration to do things like:
* Turn checks [on and off](checks.md)
+18 -6
View File
@@ -7,7 +7,7 @@ meta:
If you'd like to create your own checks, you can use [JSON Schema](https://json-schema.org/).
This is how built-in Polaris checks are defined as well - you can see all the built-in checks
in the [checks folder](https://github.com/FairwindsOps/polaris/tree/master/checks) for examples.
in the [checks folder](https://github.com/FairwindsOps/polaris/tree/master/pkg/config/checks) for examples.
If you write a check that could be useful for others, feel free to open a PR to add it in!
@@ -25,7 +25,7 @@ customChecks:
category: Security
target: Container
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
properties:
image:
@@ -73,7 +73,7 @@ customChecks:
category: Resources
target: Container
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
required:
- resources
@@ -120,7 +120,7 @@ successMessage: Label app.kubernetes.io/name matches metadata.name
failureMessage: Label app.kubernetes.io/name must match metadata.name
target: Controller
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
properties:
metadata:
@@ -167,6 +167,18 @@ schemaString: |
{{ end }}
```
### Additional Go Template Functions
These functions are also available in the GO template.
* [hasPrefix](https://pkg.go.dev/strings#HasPrefix) - for example, `hasPrefix "string" "prefix"`
* [hasSuffix](https://pkg.go.dev/strings#HasSuffix) - for example, `hasSuffix "string" "suffix"`
For example, the `hasPrefix` function can be used in a template to determine whether a resource name starts with `system:`
```
{{ if hasPrefix .metadata.name "system:" }}
```
## Multi-Resource Checks
You can write checks that span multiple resources. This is helpful for ensuring e.g.
that every Deployment has a PDB or an HPA associated with it.
@@ -181,7 +193,7 @@ controllers:
include:
- Deployment
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
properties:
metadata:
@@ -221,7 +233,7 @@ customChecks:
foo:
jsonSchema: |
{
"$schema": "http://json-schema.org/draft-07/schema",
"$schema": "https://json-schema.org/draft/2019-09/schema",
"type": "object"
}
```
+6592 -14123
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -8,9 +8,9 @@
},
"description": "A repository with a Vuepress template for Fairwinds projects",
"devDependencies": {
"vuepress": "^1.4.0",
"vuepress": "^1.9.7",
"vuepress-plugin-clean-urls": "^1.1.1",
"vuepress-plugin-redirect": "^1.2.3"
"vuepress-plugin-redirect": "^1.2.5"
},
"directories": {
"doc": "docs"
+60 -76
View File
@@ -1,93 +1,77 @@
module github.com/fairwindsops/polaris
go 1.17
go 1.24.4
require (
github.com/evanphx/json-patch/v5 v5.6.0
github.com/fatih/color v1.13.0
github.com/gobuffalo/packr/v2 v2.8.3
github.com/gorilla/mux v1.8.0
github.com/qri-io/jsonschema v0.1.1
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.5.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.0
github.com/thoas/go-funk v0.9.2
golang.org/x/text v0.3.7 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
github.com/fairwindsops/controller-utils v0.3.4
github.com/fatih/color v1.18.0
github.com/gorilla/mux v1.8.1
github.com/pkg/errors v0.9.1
github.com/qri-io/jsonpointer v0.1.1
github.com/qri-io/jsonschema v0.2.1
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.9.1
github.com/stretchr/testify v1.10.0
github.com/thoas/go-funk v0.9.3
gomodules.xyz/jsonpatch/v2 v2.5.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.24.3
k8s.io/apimachinery v0.24.3
k8s.io/client-go v0.24.1
sigs.k8s.io/controller-runtime v0.12.1
sigs.k8s.io/yaml v1.3.0
k8s.io/api v0.33.3
k8s.io/apimachinery v0.33.3
k8s.io/client-go v0.33.1
sigs.k8s.io/controller-runtime v0.21.0
sigs.k8s.io/yaml v1.6.0
)
require gomodules.xyz/jsonpatch/v2 v2.2.0
require (
cloud.google.com/go/compute v1.6.1 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.27 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.20 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emicklei/go-restful/v3 v3.8.0 // indirect
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.20.0 // indirect
github.com/go-openapi/swag v0.21.1 // indirect
github.com/gobuffalo/logger v1.0.6 // indirect
github.com/gobuffalo/packd v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
github.com/evanphx/json-patch v5.9.0+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.21.1 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/swag v0.23.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.4.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/gnostic v0.6.9 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/google/gnostic-models v0.6.9 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/karrick/godirwalk v1.17.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/markbates/errx v1.1.0 // indirect
github.com/markbates/oncer v1.0.0 // indirect
github.com/markbates/safe v1.0.1 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/mailru/easyjson v0.9.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.12.2 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.34.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/qri-io/jsonpointer v0.1.1 // indirect
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
golang.org/x/net v0.0.0-20220607020251-c690dde0001d // indirect
golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401 // indirect
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.22.0 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.64.0 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
github.com/samber/lo v1.51.0 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sys v0.34.0 // indirect
golang.org/x/term v0.33.0 // indirect
golang.org/x/text v0.26.0 // indirect
golang.org/x/time v0.12.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
k8s.io/component-base v0.24.1 // indirect
k8s.io/klog/v2 v2.60.1 // indirect
k8s.io/kube-openapi v0.0.0-20220603121420-31174f50af60 // indirect
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
k8s.io/apiextensions-apiserver v0.33.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20250610211856-8b98d1ed966a // indirect
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
)
+158 -1120
View File
File diff suppressed because it is too large Load Diff
+26 -7
View File
@@ -15,14 +15,13 @@
package config
import (
"github.com/gobuffalo/packr/v2"
"embed"
"fmt"
"github.com/sirupsen/logrus"
)
var (
// BuiltInChecks contains the checks that come pre-installed w/ Polaris
BuiltInChecks = map[string]SchemaCheck{}
schemaBox = (*packr.Box)(nil)
// We explicitly set the order to avoid thrash in the
// tests as we migrate toward JSON schema
checkOrder = []string{
@@ -30,10 +29,14 @@ var (
"deploymentMissingReplicas",
// Pod checks
"hostIPCSet",
"hostPathSet",
"hostProcess",
"hostPIDSet",
"hostNetworkSet",
"automountServiceAccountToken",
"topologySpreadConstraint",
// Container checks
"procMount",
"memoryLimitsMissing",
"memoryRequestsMissing",
"cpuLimitsMissing",
@@ -55,17 +58,33 @@ var (
// Other checks
"tlsSettingsMissing",
"pdbDisruptionsIsZero",
"metadataAndNameMismatched",
"metadataAndInstanceMismatched",
"missingPodDisruptionBudget",
"missingNetworkPolicy",
"sensitiveConfigmapContent",
"clusterrolePodExecAttach",
"rolePodExecAttach",
"clusterrolebindingPodExecAttach",
"rolebindingClusterRolePodExecAttach",
"rolebindingRolePodExecAttach",
"clusterrolebindingClusterAdmin",
"rolebindingClusterAdminClusterRole",
"rolebindingClusterAdminRole",
"hpaMaxAvailability",
"hpaMinAvailability",
"pdbMinAvailableGreaterThanHPAMinReplicas",
}
// BuiltInChecks contains the checks that come pre-installed w/ Polaris
BuiltInChecks = map[string]SchemaCheck{}
//go:embed all:checks
checksFS embed.FS
)
func init() {
schemaBox = packr.New("Schemas", "../../checks")
for _, checkID := range checkOrder {
contents, err := schemaBox.Find(checkID + ".yaml")
contents, err := checksFS.ReadFile(fmt.Sprintf("checks/%s.yaml", checkID))
if err != nil {
panic(err)
}
@@ -3,9 +3,8 @@ failureMessage: The ServiceAccount will be automounted
category: Security
target: PodSpec
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
required: ["serviceAccountName"]
properties:
serviceAccountName:
type: string
@@ -15,12 +14,11 @@ schema:
const: true
additionalSchemaStrings:
ServiceAccount: |
{{ if not (eq .Polaris.PodSpec.automountServiceAccountToken false) }}
type: object
required:
- metadata
{{ if not (eq .Polaris.PodSpec.automountServiceAccountToken false) }}
- automountServiceAccountToken
{{ end }}
properties:
metadata:
type: object
@@ -34,3 +32,4 @@ additionalSchemaStrings:
type: boolean
const: false
{{ end }}
{{ end }}
@@ -0,0 +1,54 @@
successMessage: The ClusterRole does not allow pods/exec or pods/attach
failureMessage: The ClusterRole allows Pods/exec or pods/attach
category: Security
target: rbac.authorization.k8s.io/ClusterRole
schemaString: |
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
required: ["metadata", "rules"]
anyOf:
# Do not alert on default ClusterRoles.
- properties:
metadata:
required: ["name"]
properties:
name:
type: string
anyOf:
- const: 'admin'
- const: "cluster-admin"
- const: "edit"
- pattern: '^system:'
- const: "gce:podsecuritypolicy:calico-sa"
- properties:
rules:
type: array
items:
type: object
not:
required: ["apiGroups", "resources", "verbs"]
properties:
apiGroups:
type: array
contains:
type: string
anyOf:
- const: ""
- const: '*'
resources:
type: array
contains:
type: string
anyOf:
- const: '*'
- const: "pods/exec"
- const: "pods/attach"
verbs:
type: array
contains:
type: string
anyOf:
- const: '*'
# An exec is also possible by `get`ing a web socket.
- const: 'get'
- const: 'create'
@@ -0,0 +1,90 @@
successMessage: The ClusterRoleBinding does not reference the default cluster-admin ClusterRole or one with wildcard permissions
failureMessage: The ClusterRoleBinding references the default cluster-admin ClusterRole or one with wildcard permissions
category: Security
target: rbac.authorization.k8s.io/ClusterRoleBinding
schemaString: |
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
anyOf:
# Do not alert on default ClusterRoleBindings.
- required: ["metadata"]
properties:
metadata:
type: object
required: ["name"]
properties:
name:
type: string
anyOf:
- const: "cluster-admin"
- pattern: '^system:'
- const: "gce:podsecuritypolicy:calico-sa"
- required: ["roleRef"]
properties:
roleRef:
required: ["apiGroup", "kind", "name"]
properties:
apiGroup:
type: string
const: "rbac.authorization.k8s.io"
kind:
type: string
const: "ClusterRole"
name:
type: string
minLength: 1
not:
const: "cluster-admin"
additionalSchemaStrings:
rbac.authorization.k8s.io/ClusterRole: |
{{ if (ne .roleRef.name "view") }}
{{ if and (ne .metadata.name "cluster-admin") (not (hasPrefix .metadata.name "system:")) (ne .metadata.name "gce:podsecuritypolicy:calico-sa") }}
# Do not alert on default ClusterRoleBindings.
type: object
required: ["metadata", "rules"]
allOf:
- properties:
metadata:
required: ["name"]
properties:
name:
type: string
const: "{{ .roleRef.name }}"
- properties:
rules:
type: array
items:
type: object
not:
required: ["apiGroups", "resources", "verbs"]
properties:
apiGroups:
type: array
contains:
type: string
const: "*"
resources:
type: array
contains:
type: string
const: '*'
verbs:
type: array
uniqueItems: true
oneOf:
- contains:
type: string
const: '*'
- minItems: 7
items:
type: string
enum:
- "get"
- "list"
- "watch"
- "create"
- "update"
- "patch"
- "delete"
{{ end }}
{{ end }}
@@ -0,0 +1,84 @@
successMessage: The ClusterRoleBinding does not reference a ClusterRole allowing pods/exec or pods/attach
failureMessage: The ClusterRoleBinding references a ClusterRole that allows Pods/exec, allows pods/attach, or that does not exist
category: Security
target: rbac.authorization.k8s.io/ClusterRoleBinding
schemaString: |
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
anyOf:
# Do not alert on default ClusterRoleBindings.
- required: ["metadata"]
properties:
metadata:
type: object
required: ["name"]
properties:
name:
type: string
anyOf:
- const: "cluster-admin"
- pattern: '^system:'
- const: "gce:podsecuritypolicy:calico-sa"
- required: ["roleRef"]
properties:
roleRef:
required: ["apiGroup", "kind", "name"]
properties:
apiGroup:
type: string
const: "rbac.authorization.k8s.io"
kind:
type: string
const: "ClusterRole"
name:
type: string
minLength: 1
additionalSchemaStrings:
rbac.authorization.k8s.io/ClusterRole: |
type: object
# Do not alert on default ClusterRoleBindings.
{{ if (ne .roleRef.name "view") }}
{{ if and (ne .metadata.name "cluster-admin") (not (hasPrefix .metadata.name "system:")) (ne .metadata.name "gce:podsecuritypolicy:calico-sa") }}
required: ["metadata", "rules"]
allOf:
- properties:
metadata:
required: ["name"]
properties:
name:
type: string
const: "{{ .roleRef.name }}"
- properties:
rules:
type: array
items:
type: object
not:
required: ["apiGroups", "resources", "verbs"]
properties:
apiGroups:
type: array
contains:
type: string
anyOf:
- const: ""
- const: '*'
resources:
type: array
contains:
type: string
anyOf:
- const: '*'
- const: "pods/exec"
- const: "pods/attach"
verbs:
type: array
contains:
type: string
anyOf:
- const: '*'
# An exec is also possible by `get`ing a web socket.
- const: 'get'
- const: 'create'
{{ end }}
{{ end }}
@@ -6,7 +6,7 @@ containers:
exclude:
- initContainer
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
required:
- resources
@@ -29,6 +29,4 @@ mutations:
- op: add
path: /resources/limits/cpu
value: 100m
comments:
- find: "cpu: 100m"
comment: "TODO: Set this to the maximum amount of CPU you want your workload to use"
@@ -6,7 +6,7 @@ containers:
exclude:
- initContainer
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
required:
- resources
@@ -29,6 +29,4 @@ mutations:
- op: add
path: /resources/requests/cpu
value: 100m
comments:
- find: "cpu: 100m"
comment: "TODO: Set this to the amount of CPU you want to reserve for your workload"
@@ -3,7 +3,7 @@ failureMessage: Container should not have dangerous capabilities
category: Security
target: Container
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
properties:
securityContext:
@@ -28,4 +28,4 @@ schema:
mutations:
- op: remove
path: /securityContext/capabilities
path: /securityContext/capabilities/add
@@ -6,7 +6,7 @@ controllers:
include:
- Deployment
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
required:
- spec
@@ -3,7 +3,7 @@ failureMessage: Host IPC should not be configured
category: Security
target: PodSpec
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
properties:
hostIPC:
@@ -3,7 +3,7 @@ failureMessage: Host network should not be configured
category: Security
target: PodSpec
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
properties:
hostNetwork:
@@ -3,7 +3,7 @@ failureMessage: Host PID should not be configured
category: Security
target: PodSpec
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
properties:
hostPID:
+16
View File
@@ -0,0 +1,16 @@
successMessage: HostPath volumes are not configured
failureMessage: HostPath volumes must be forbidden
category: Security
target: PodSpec
schema:
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
properties:
volumes:
type: array
items:
type: object
properties:
hostPath:
type: string
const: ''
@@ -3,7 +3,7 @@ failureMessage: Host port should not be configured
category: Security
target: Container
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
required:
properties:
@@ -12,4 +12,7 @@ schema:
items:
properties:
hostPort:
const: 0
const: 0
mutations:
- op: remove
path: /ports/*/hostPort
+31
View File
@@ -0,0 +1,31 @@
successMessage: Privileged access to the host check is valid
failureMessage: Privileged access to the host is disallowed
category: Security
target: PodSpec
schema:
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
properties:
containers:
type: array
items:
type: object
properties:
securityContext:
type: object
properties:
windowsOptions:
type: object
properties:
hostProcess:
type: boolean
const: false
securityContext:
type: object
properties:
windowsOptions:
type: object
properties:
hostProcess:
type: boolean
const: false
+35
View File
@@ -0,0 +1,35 @@
successMessage: HPA has a valid max and min replica configuration
failureMessage: HPA maxReplicas and minReplicas should be different
category: Reliability
target: autoscaling/HorizontalPodAutoscaler
schemaString: |
"$schema": https://json-schema.org/draft/2019-09/schema#
type: object
properties:
spec:
type: object
properties:
minReplicas:
type: integer
minimum: 1
maxReplicas:
type: integer
minimum: 1
required:
- maxReplicas
{{- if .spec.minReplicas }}
if:
properties:
minReplicas:
type: integer
maxReplicas:
type: integer
then:
properties:
maxReplicas:
exclusiveMinimum: {{ .spec.minReplicas }}
else:
properties:
maxReplicas:
minimum: 1
{{- end }}
+14
View File
@@ -0,0 +1,14 @@
successMessage: HPA has a valid min replica configuration
failureMessage: HPA minReplicas should be 2 or more
category: Reliability
target: autoscaling/HorizontalPodAutoscaler
schema:
"$schema": https://json-schema.org/draft/2019-09/schema#
type: object
properties:
spec:
type: object
properties:
minReplicas:
type: integer
minimum: 2
@@ -3,7 +3,7 @@ failureMessage: Container should not have insecure capabilities
category: Security
target: Container
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
required:
- securityContext
@@ -55,8 +55,6 @@ schema:
- contains:
pattern: '^(?i)AUDIT_WRITE$'
mutations:
- op: remove
path: /securityContext/capabilities
- op: add
- op: replace
path: /securityContext/capabilities
value: {"drop": ["ALL"]}
@@ -3,8 +3,8 @@ FailureMessage: Use one of AppArmor, Seccomp, SELinux, or dropping Linux Capabil
category: Security
target: Container
schemaString: |
'$schema': http://json-schema.org/draft-07/schema
definitions:
'$schema': https://json-schema.org/draft/2019-09/schema
$defs:
podOrContainerSeccompProfile:
type: object
{{ $podSeccompProfileType := .Polaris.PodSpec.securityContext.seccompProfile.type }}
@@ -83,7 +83,7 @@ schemaString: |
type: object
{{ else }}
anyOf:
- $ref: "#/definitions/podOrContainerSeccompProfile"
- $ref: "#/definitions/podOrContainerSELinuxOptions"
- $ref: "#/definitions/containerDropCapabilities"
- $ref: "#/$defs/podOrContainerSeccompProfile"
- $ref: "#/$defs/podOrContainerSELinuxOptions"
- $ref: "#/$defs/containerDropCapabilities"
{{ end}}
@@ -10,7 +10,7 @@ containers:
- initContainer
target: Container
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
required:
- livenessProbe
@@ -23,6 +23,4 @@ mutations:
- op: add
path: /livenessProbe
value: {"exec": { "command": [ "cat", "/tmp/healthy" ] }, "initialDelaySeconds": 5, "periodSeconds": 5 }
comments:
- find: "livenessProbe:"
comment: "TODO: Change livenessProbe setting to reflect your health endpoints"
comment: "TODO: Change the livenessProbe setting to reflect your application's health"
@@ -6,7 +6,7 @@ containers:
exclude:
- initContainer
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
required:
- resources
@@ -29,6 +29,4 @@ mutations:
- op: add
path: /resources/limits/memory
value: "512Mi"
comments:
- find: "memory: 512Mi"
comment: "TODO: Set this to the maximum amount of memory you want your workload to use"
@@ -6,7 +6,7 @@ containers:
exclude:
- initContainer
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
required:
- resources
@@ -29,6 +29,4 @@ mutations:
- op: add
path: /resources/requests/memory
value: "512Mi"
comments:
- find: "memory: 512Mi"
comment: "TODO: Set this to the amount of Memory you want to reserve for your workload"
@@ -0,0 +1,18 @@
successMessage: Label app.kubernetes.io/instance matches metadata.name
failureMessage: Label app.kubernetes.io/instance must match metadata.name
category: Reliability
target: Controller
schema:
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
properties:
metadata:
type: object
required: ["labels"]
properties:
labels:
type: object
required: ["app.kubernetes.io/instance"]
properties:
app.kubernetes.io/instance:
const: "{{ .metadata.name }}"
@@ -3,7 +3,7 @@ failureMessage: A NetworkPolicy should match pod labels and contain applied egre
category: Security
target: PodTemplate
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
properties:
metadata:
@@ -4,17 +4,27 @@ category: Reliability
target: Controller
controllers:
include:
- Deployment
- Deployment
schema:
'$schema': http://json-schema.org/draft-07/schema
"$schema": https://json-schema.org/draft/2019-09/schema#
type: object
required: [spec]
properties:
metadata:
spec:
type: object
required: [template]
properties:
labels:
template:
type: object
minProperties: 1
required: [metadata]
properties:
metadata:
type: object
required: [labels]
properties:
labels:
type: object
minProperties: 1
additionalSchemaStrings:
policy/PodDisruptionBudget: |
type: object
@@ -30,7 +40,7 @@ additionalSchemaStrings:
matchLabels:
type: object
anyOf:
{{ range $key, $value := .metadata.labels }}
{{ range $key, $value := .spec.template.metadata.labels }}
- properties:
"{{ $key }}":
type: string
@@ -4,8 +4,8 @@ category: Security
target: Container
schemaTarget: PodSpec
schema:
'$schema': http://json-schema.org/draft-07/schema
definitions:
'$schema': https://json-schema.org/draft/2019-09/schema
$defs:
goodSecurityContext:
type: object
anyOf:
@@ -25,13 +25,13 @@ schema:
- securityContext
properties:
securityContext:
$ref: "#/definitions/goodSecurityContext"
$ref: "#/$defs/goodSecurityContext"
containers:
type: array
items:
properties:
securityContext:
$ref: "#/definitions/notBadSecurityContext"
$ref: "#/$defs/notBadSecurityContext"
- properties:
containers:
type: array
@@ -40,7 +40,7 @@ schema:
- securityContext
properties:
securityContext:
$ref: "#/definitions/goodSecurityContext"
$ref: "#/$defs/goodSecurityContext"
mutations:
- op: add
path: /securityContext/readOnlyRootFilesystem
@@ -3,7 +3,7 @@ failureMessage: Voluntary evictions are not possible
category: Reliability
target: policy/PodDisruptionBudget
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
required:
- spec
@@ -0,0 +1,7 @@
successMessage: PDB and HPA are correctly configured
failureMessage: PDB minAvailable is greater than HPA minReplicas
category: Reliability
target: Controller
controllers:
include:
- Deployment
@@ -1,9 +1,9 @@
successMessage: Priority class has been set
failureMessage: Priority class should be set
category: Security
category: Reliability
target: PodSpec
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
required:
- priorityClassName
@@ -4,8 +4,8 @@ category: Security
target: Container
schemaTarget: PodSpec
schema:
'$schema': http://json-schema.org/draft-07/schema
definitions:
'$schema': https://json-schema.org/draft/2019-09/schema
$defs:
goodSecurityContext:
type: object
anyOf:
@@ -25,13 +25,13 @@ schema:
- securityContext
properties:
securityContext:
$ref: "#/definitions/goodSecurityContext"
$ref: "#/$defs/goodSecurityContext"
containers:
type: array
items:
properties:
securityContext:
$ref: "#/definitions/notBadSecurityContext"
$ref: "#/$defs/notBadSecurityContext"
- properties:
containers:
type: array
@@ -40,4 +40,9 @@ schema:
- securityContext
properties:
securityContext:
$ref: "#/definitions/goodSecurityContext"
$ref: "#/$defs/goodSecurityContext"
mutations:
- op: add
path: /securityContext/allowPrivilegeEscalation
value: false
+19
View File
@@ -0,0 +1,19 @@
successMessage: The default /proc masks are set up to reduce attack surface, and should be required
failureMessage: Proc mount must not be changed from the default
category: Security
target: PodSpec
schema:
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
properties:
containers:
type: array
items:
type: object
properties:
securityContext:
type: object
properties:
procMount:
type: string
const: Default
@@ -3,7 +3,7 @@ failureMessage: Image pull policy should be "Always"
category: Reliability
target: Container
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
required:
- imagePullPolicy
properties:
@@ -10,7 +10,7 @@ containers:
- initContainer
target: Container
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
required:
- readinessProbe
@@ -23,6 +23,4 @@ mutations:
- op: add
path: /readinessProbe
value: {"exec": { "command": [ "cat", "/tmp/healthy" ] }, "initialDelaySeconds": 5, "periodSeconds": 5 }
comments:
- find: "readinessProbe:"
comment: "TODO: Change livenessProbe setting to reflect your health endpoints"
comment: "TODO: Change the readinessProbe setting to reflect your application's readiness to serve traffic"
+56
View File
@@ -0,0 +1,56 @@
successMessage: The Role does not allow pods/exec or pods/attach
failureMessage: The Role allows Pods/exec or pods/attach
category: Security
target: rbac.authorization.k8s.io/Role
schemaString: |
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
required: ["metadata", "rules"]
anyOf:
# Do not alert on default Roles.
- properties:
metadata:
required: ["name"]
properties:
name:
type: string
anyOf:
- pattern: '^system:'
- const: "gce:podsecuritypolicy:calico-sa"
- properties:
metadata:
required: ["name"]
properties:
name:
type: string
rules:
type: array
items:
type: object
not:
required: ["apiGroups", "resources", "verbs"]
properties:
apiGroups:
type: array
contains:
type: string
anyOf:
- const: ""
- const: '*'
resources:
type: array
contains:
type: string
anyOf:
- const: '*'
- const: "pods/exec"
- const: "pods/attach"
verbs:
type: array
contains:
type: string
anyOf:
- const: '*'
# An exec is also possible by `get`ing a web socket.
- const: 'get'
- const: 'create'
@@ -0,0 +1,98 @@
successMessage: The RoleBinding does not reference the default cluster-admin ClusterRole or one with wildcard permissions
failureMessage: The RoleBinding references the default cluster-admin ClusterRole or one with wildcard permissions
category: Security
target: rbac.authorization.k8s.io/RoleBinding
schemaString: |
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
anyOf:
# Pass RoleBindings that point to a Role.
- required: ["roleRef"]
properties:
roleRef:
required: ["kind"]
properties:
kind:
type: string
const: "Role"
# Do not alert on default ClusterRoleBindings.
- required: ["metadata"]
properties:
metadata:
type: object
required: ["name"]
properties:
name:
type: string
anyOf:
- pattern: '^system:'
- const: "gce:podsecuritypolicy:calico-sa"
- required: ["roleRef"]
properties:
roleRef:
required: ["apiGroup", "kind", "name"]
properties:
apiGroup:
type: string
const: "rbac.authorization.k8s.io"
kind:
type: string
const: "ClusterRole"
name:
type: string
minLength: 1
not:
const: "cluster-admin"
additionalSchemaStrings:
rbac.authorization.k8s.io/ClusterRole: |
{{ if eq .roleRef.kind "ClusterRole" }}
{{ if and (not (hasPrefix .metadata.name "system:")) (ne .metadata.name "gce:podsecuritypolicy:calico-sa") }}
# This schema is validated for all roleBindings, regardless of their roleRef.
type: object
required: ["metadata", "rules"]
allOf:
- properties:
metadata:
required: ["name"]
properties:
name:
type: string
const: "{{ .roleRef.name }}"
- properties:
rules:
type: array
items:
type: object
not:
required: ["apiGroups", "resources", "verbs"]
properties:
apiGroups:
type: array
contains:
type: string
const: "*"
resources:
type: array
contains:
type: string
const: '*'
verbs:
type: array
uniqueItems: true
oneOf:
- contains:
type: string
const: '*'
- minItems: 7
items:
type: string
enum:
- "get"
- "list"
- "watch"
- "create"
- "update"
- "patch"
- "delete"
{{ end }}
{{ end }}
@@ -0,0 +1,96 @@
successMessage: The RoleBinding does not reference a Role with wildcard permissions
failureMessage: The RoleBinding references a Role with wildcard permissions
category: Security
target: rbac.authorization.k8s.io/RoleBinding
schemaString: |
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
anyOf:
# Pass RoleBindings that point to a ClusterRole.
- required: ["roleRef"]
properties:
roleRef:
required: ["kind"]
properties:
kind:
type: string
const: "ClusterRole"
# Do not alert on default RoleBindings.
- required: ["metadata"]
properties:
metadata:
type: object
required: ["name"]
properties:
name:
type: string
anyOf:
- pattern: '^system:'
- const: "gce:podsecuritypolicy:calico-sa"
- required: ["roleRef"]
properties:
roleRef:
required: ["apiGroup", "kind", "name"]
properties:
apiGroup:
type: string
const: "rbac.authorization.k8s.io"
kind:
type: string
const: "Role"
name:
type: string
minLength: 1
additionalSchemaStrings:
rbac.authorization.k8s.io/Role: |
type: object
# This schema is validated for all roleBindings, regardless of their roleRef.
{{ if eq .roleRef.kind "Role" }}
{{ if and (not (hasPrefix .metadata.name "system:")) (ne .metadata.name "gce:podsecuritypolicy:calico-sa") }}
required: ["metadata", "rules"]
allOf:
- properties:
metadata:
required: ["name"]
properties:
name:
type: string
const: "{{ .roleRef.name }}"
- properties:
rules:
type: array
items:
type: object
not:
required: ["apiGroups", "resources", "verbs"]
properties:
apiGroups:
type: array
contains:
type: string
const: "*"
resources:
type: array
contains:
type: string
const: '*'
verbs:
type: array
uniqueItems: true
oneOf:
- contains:
type: string
const: '*'
- minItems: 7
items:
type: string
enum:
- "get"
- "list"
- "watch"
- "create"
- "update"
- "patch"
- "delete"
{{ end }}
{{ end }}
@@ -0,0 +1,92 @@
successMessage: The RoleBinding does not reference a ClusterRole allowing pods/exec or pods/attach
failureMessage: The RoleBinding references a ClusterRole that allows Pods/exec, allows pods/attach, or that does not exist
category: Security
target: rbac.authorization.k8s.io/RoleBinding
schemaString: |
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
anyOf:
# Pass RoleBindings that point to a Role.
- required: ["roleRef"]
properties:
roleRef:
required: ["kind"]
properties:
kind:
type: string
const: "Role"
# Do not alert on default RoleBindings.
- required: ["metadata"]
properties:
metadata:
type: object
required: ["name"]
properties:
name:
type: string
anyOf:
- pattern: '^system:'
- const: "gce:podsecuritypolicy:calico-sa"
- required: ["roleRef"]
properties:
roleRef:
required: ["apiGroup", "kind", "name"]
properties:
apiGroup:
type: string
const: "rbac.authorization.k8s.io"
kind:
type: string
const: "ClusterRole"
name:
type: string
minLength: 1
additionalSchemaStrings:
rbac.authorization.k8s.io/ClusterRole: |
{{ if eq .roleRef.kind "ClusterRole" }}
{{ if and (not (hasPrefix .metadata.name "system:")) (ne .metadata.name "gce:podsecuritypolicy:calico-sa") }}
# This schema is validated for all roleBindings, regardless of their roleRef.
type: object
required: ["metadata", "rules"]
allOf:
- properties:
metadata:
required: ["name"]
properties:
name:
type: string
const: "{{ .roleRef.name }}"
- properties:
rules:
type: array
items:
type: object
not:
required: ["apiGroups", "resources", "verbs"]
properties:
apiGroups:
type: array
contains:
type: string
anyOf:
- const: ""
- const: '*'
resources:
type: array
contains:
type: string
anyOf:
- const: '*'
- const: "pods/exec"
- const: "pods/attach"
verbs:
type: array
contains:
type: string
anyOf:
- const: '*'
# An exec is also possible by `get`ing a web socket.
- const: 'get'
- const: 'create'
{{ end }}
{{ end }}
@@ -0,0 +1,95 @@
successMessage: The RoleBinding does not reference a Role allowing Pod exec or attach
failureMessage: The RoleBinding references a Role that allows Pods/exec, allows pods/attach, or that does not exist
category: Security
target: rbac.authorization.k8s.io/RoleBinding
schemaString: |
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
anyOf:
# Pass RoleBindings that point to a ClusterRole.
- required: ["roleRef"]
properties:
roleRef:
required: ["apiGroup", "kind", "name"]
properties:
apiGroup:
type: string
const: "rbac.authorization.k8s.io"
kind:
type: string
const: "ClusterRole"
# Do not alert on default RoleBindings.
- required: ["metadata"]
properties:
metadata:
type: object
required: ["name"]
properties:
name:
type: string
anyOf:
- pattern: '^system:'
- const: "gce:podsecuritypolicy:calico-sa"
- required: ["roleRef"]
properties:
roleRef:
required: ["apiGroup", "kind", "name"]
properties:
apiGroup:
type: string
const: "rbac.authorization.k8s.io"
kind:
type: string
const: "Role"
name:
type: string
minLength: 1
additionalSchemaStrings:
rbac.authorization.k8s.io/Role: |
{{ if eq .roleRef.kind "Role" }}
{{ if and (not (hasPrefix .metadata.name "system:")) (ne .metadata.name "gce:podsecuritypolicy:calico-sa") }}
# This schema is validated for all roleBindings, regardless of their roleRef.
type: object
required: ["metadata", "rules"]
allOf:
- properties:
metadata:
required: ["name"]
properties:
name:
type: string
const: "{{ .roleRef.name }}"
- properties:
rules:
type: array
items:
type: object
not:
required: ["apiGroups", "resources", "verbs"]
properties:
apiGroups:
type: array
contains:
type: string
anyOf:
- const: ""
- const: '*'
resources:
type: array
contains:
type: string
anyOf:
- const: '*'
- const: "pods/exec"
- const: "pods/attach"
verbs:
type: array
contains:
type: string
anyOf:
- const: '*'
# An exec is also possible by `get`ing a web socket.
- const: 'get'
- const: 'create'
{{ end }}
{{ end }}
@@ -4,8 +4,8 @@ category: Security
target: Container
schemaTarget: PodSpec
schema:
'$schema': http://json-schema.org/draft-07/schema
definitions:
'$schema': https://json-schema.org/draft/2019-09/schema
$defs:
notBadSecurityContext:
type: object
properties:
@@ -15,13 +15,13 @@ schema:
type: object
properties:
securityContext:
$ref: "#/definitions/notBadSecurityContext"
$ref: "#/$defs/notBadSecurityContext"
containers:
type: array
items:
properties:
securityContext:
$ref: "#/definitions/notBadSecurityContext"
$ref: "#/$defs/notBadSecurityContext"
mutations:
- op: add
path: /securityContext/privileged
@@ -4,8 +4,8 @@ category: Security
target: Container
schemaTarget: PodSpec
schema:
'$schema': http://json-schema.org/draft-07/schema
definitions:
'$schema': https://json-schema.org/draft/2019-09/schema
$defs:
goodSecurityContext:
type: object
anyOf:
@@ -33,13 +33,13 @@ schema:
- securityContext
properties:
securityContext:
$ref: "#/definitions/goodSecurityContext"
$ref: "#/$defs/goodSecurityContext"
containers:
type: array
items:
properties:
securityContext:
$ref: "#/definitions/notBadSecurityContext"
$ref: "#/$defs/notBadSecurityContext"
# non-root specified at container level
- properties:
containers:
@@ -49,7 +49,7 @@ schema:
- securityContext
properties:
securityContext:
$ref: "#/definitions/goodSecurityContext"
$ref: "#/$defs/goodSecurityContext"
mutations:
- op: add
path: /securityContext/runAsNonRoot
@@ -3,7 +3,7 @@ failureMessage: Potentially sensitive content is detected in the ConfigMap keys
category: Security
target: /ConfigMap
schemaString: |
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
required: ["metadata"]
properties:
@@ -0,0 +1,52 @@
successMessage: The container does not set potentially sensitive environment variables
failureMessage: The container sets potentially sensitive environment variables
category: Security
target: Container
schemaString: |
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
properties:
env:
type: array
items:
type: object
anyOf:
- not:
required: ["value"]
- required: ["name", "value"]
properties:
name:
type: string
'$comment': These environment variable names will be disallowed.
allOf:
- not:
pattern: '(?i)^AWS_SECRET_ACCESS_KEY$'
- not:
pattern: '(?i)^GOOGLE_APPLICATION_CREDENTIALS$'
- not:
pattern: '(?i)^AZURE_.+KEY$'
- not:
pattern: '(?i)^OCI_CLI_KEY_CONTENT$'
- not:
pattern: '(?i)password'
- not:
pattern: '(?i)token'
- not:
pattern: '(?i)bearer'
- not:
pattern: '(?i)secret'
'$comment': This allows variable names not excluded above.
- pattern: '(?i).*'
value:
type: string
'$comment': These environment variable values will be disallowed.
allOf:
- not:
'$comment': THis matches variations like begin private key, begin rsa private key ...
pattern: '(?i)\s*-BEGIN\s+.*PRIVATE KEY-\s*'
- required: ["name", "valueFrom"]
properties:
name:
type: string
valueFrom:
type: object
@@ -3,7 +3,7 @@ failureMessage: Image tag should be specified
category: Reliability
target: Container
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
required:
- image
allOf:
@@ -3,7 +3,7 @@ failureMessage: Ingress does not have TLS configured
category: Security
target: networking.k8s.io/Ingress
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
required:
- spec
@@ -0,0 +1,17 @@
successMessage: Pod has a valid topology spread constraint
failureMessage: Pod should be configured with a valid topology spread constraint
category: Reliability
target: PodSpec
controllers:
exclude:
- Job
- CronJob
schema:
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
required:
- topologySpreadConstraints
properties:
topologySpreadConstraints:
type: array
minItems: 1
+16
View File
@@ -0,0 +1,16 @@
package config
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestRequiredFieldsOnBuiltInChecks(t *testing.T) {
for _, v := range BuiltInChecks {
assert.NotEmpty(t, v.SuccessMessage)
assert.NotEmpty(t, v.FailureMessage)
assert.NotEmpty(t, v.Category)
assert.NotEmpty(t, v.Target)
}
}
+44 -27
View File
@@ -16,14 +16,14 @@ package config
import (
"bytes"
_ "embed"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"strings"
"github.com/gobuffalo/packr/v2"
"k8s.io/apimachinery/pkg/util/yaml"
)
@@ -49,38 +49,55 @@ type Exemption struct {
Namespace string `json:"namespace"`
}
var configBox = (*packr.Box)(nil)
//go:embed default.yaml
var defaultConfig []byte
func getConfigBox() *packr.Box {
if configBox == (*packr.Box)(nil) {
configBox = packr.New("Config", "../../examples")
}
return configBox
}
// ParseFile parses config from a file.
func ParseFile(path string) (Configuration, error) {
var rawBytes []byte
var err error
if path == "" {
rawBytes, err = getConfigBox().Find("config.yaml")
} else if strings.HasPrefix(path, "https://") || strings.HasPrefix(path, "http://") {
// path is a url
response, err2 := http.Get(path)
if err2 != nil {
return Configuration{}, err2
}
rawBytes, err = ioutil.ReadAll(response.Body)
} else {
// path is local
rawBytes, err = ioutil.ReadFile(path)
}
// MergeConfigAndParseFile parses config from a file.
func MergeConfigAndParseFile(customConfigPath string, mergeConfig bool) (Configuration, error) {
rawBytes, err := mergeConfigFile(customConfigPath, mergeConfig)
if err != nil {
return Configuration{}, err
}
return Parse(rawBytes)
}
func mergeConfigFile(customConfigPath string, mergeConfig bool) ([]byte, error) {
if customConfigPath == "" {
return defaultConfig, nil
}
var customConfigContent []byte
var err error
if strings.HasPrefix(customConfigPath, "https://") || strings.HasPrefix(customConfigPath, "http://") {
// path is a url
response, err := http.Get(customConfigPath)
if err != nil {
return nil, err
}
customConfigContent, err = io.ReadAll(response.Body)
if err != nil {
return nil, err
}
} else {
// path is local
customConfigContent, err = os.ReadFile(customConfigPath)
if err != nil {
return nil, err
}
}
if mergeConfig {
mergedConfig, err := mergeYaml(defaultConfig, customConfigContent)
if err != nil {
return nil, err
}
return mergedConfig, nil
}
return customConfigContent, nil
}
// Parse parses config from a byte array.
func Parse(rawBytes []byte) (Configuration, error) {
reader := bytes.NewReader(rawBytes)
+9 -9
View File
@@ -52,7 +52,7 @@ customChecks:
category: Security
target: Container
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
required:
- securityContext
@@ -69,7 +69,7 @@ customChecks:
target: Container
jsonSchema: >
{
"$schema": "http://json-schema.org/draft-07/schema",
"$schema": "https://json-schema.org/draft/2019-09/schema",
"type": "object",
"required": ["securityContext"]
}
@@ -83,7 +83,7 @@ customChecks:
category: Security
target: Container
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
required:
- securityContext
@@ -125,7 +125,7 @@ func TestConfigFromURL(t *testing.T) {
}()
time.Sleep(time.Second)
parsedConf, err = ParseFile("http://localhost:8081/exampleURL")
parsedConf, err = MergeConfigAndParseFile("http://localhost:8081/exampleURL", false)
assert.NoError(t, err, "Expected no error when parsing YAML from URL")
if err := srv.Shutdown(context.TODO()); err != nil {
panic(err)
@@ -136,7 +136,7 @@ func TestConfigFromURL(t *testing.T) {
func TestConfigNoServerError(t *testing.T) {
var err error
_, err = ParseFile("http://localhost:8081/exampleURL")
_, err = MergeConfigAndParseFile("http://localhost:8081/exampleURL", false)
assert.Error(t, err)
assert.Regexp(t, regexp.MustCompile("connection refused"), err.Error())
}
@@ -155,22 +155,22 @@ func TestConfigWithCustomChecks(t *testing.T) {
assert.NoError(t, err, "Expected no error when parsing YAML config")
assert.Equal(t, 1, len(parsedConf.CustomChecks))
check, err := parsedConf.CustomChecks["foo"].TemplateForResource(map[string]interface{}{})
isValid, _, err := check.CheckObject(valid)
isValid, _, err := check.CheckObject(context.TODO(), valid)
assert.NoError(t, err)
assert.Equal(t, true, isValid)
isValid, _, err = check.CheckObject(invalid)
isValid, _, err = check.CheckObject(context.TODO(), invalid)
assert.NoError(t, err)
assert.Equal(t, false, isValid)
parsedConf, err = Parse([]byte(confCustomChecksWithJSONSchema))
assert.NoError(t, err, "Expected no error when parsing YAML config")
assert.Equal(t, 1, len(parsedConf.CustomChecks))
isValid, problems, err := parsedConf.CustomChecks["foo"].CheckObject(valid)
isValid, problems, err := parsedConf.CustomChecks["foo"].CheckObject(context.TODO(), valid)
assert.NoError(t, err)
if !assert.Equal(t, true, isValid) {
fmt.Println(problems[0].PropertyPath, problems[0].InvalidValue, problems[0].Message)
}
isValid, _, err = check.CheckObject(invalid)
isValid, _, err = check.CheckObject(context.TODO(), invalid)
assert.NoError(t, err)
assert.Equal(t, false, isValid)
}
@@ -1,25 +1,36 @@
checks:
# reliability
deploymentMissingReplicas: warning
priorityClassNotSet: ignore
priorityClassNotSet: warning
tagNotSpecified: danger
pullPolicyNotAlways: warning
readinessProbeMissing: warning
livenessProbeMissing: warning
metadataAndNameMismatched: ignore
metadataAndInstanceMismatched: warning
pdbDisruptionsIsZero: warning
missingPodDisruptionBudget: ignore
missingPodDisruptionBudget: warning
topologySpreadConstraint: warning
hpaMaxAvailability: warning
hpaMinAvailability: warning
pdbMinAvailableGreaterThanHPAMinReplicas: warning
# efficiency
cpuRequestsMissing: warning
cpuLimitsMissing: warning
memoryRequestsMissing: warning
memoryLimitsMissing: warning
# security
automountServiceAccountToken: warning
hostIPCSet: danger
hostPathSet: warning
hostProcess: warning
hostPIDSet: danger
linuxHardening: warning
missingNetworkPolicy: warning
notReadOnlyRootFilesystem: warning
privilegeEscalationAllowed: danger
procMount: warning
runAsRootAllowed: danger
runAsPrivileged: danger
dangerousCapabilities: danger
@@ -27,11 +38,61 @@ checks:
hostNetworkSet: danger
hostPortSet: warning
tlsSettingsMissing: warning
sensitiveContainerEnvVar: danger
sensitiveConfigmapContent: danger
clusterrolePodExecAttach: danger
rolePodExecAttach: danger
clusterrolebindingPodExecAttach: danger
rolebindingClusterRolePodExecAttach: danger
rolebindingRolePodExecAttach: danger
clusterrolebindingClusterAdmin: danger
rolebindingClusterAdminClusterRole: danger
rolebindingClusterAdminRole: danger
mutations:
- pullPolicyNotAlways
exemptions:
- namespace: kube-system
controllerNames:
- dns-controller
- ebs-csi-controller
- ebs-csi-node
- kindnet
- kops-controller
- kube-dns
- kube-flannel-ds
- kube-proxy
- kube-scheduler
- vpa-recommender
rules:
- automountServiceAccountToken
- linuxHardening
- missingNetworkPolicy
- namespace: kube-system
controllerNames:
- coredns
rules:
- automountServiceAccountToken
- missingNetworkPolicy
- namespace: kube-system
controllerNames:
- ebs-csi-controller
rules:
- sensitiveContainerEnvVar
- namespace: kube-system
controllerNames:
- coredns-autoscaler
rules:
- linuxHardening
- namespace: local-path-storage
controllerNames:
- local-path-provisioner
rules:
- automountServiceAccountToken
- linuxHardening
- missingNetworkPolicy
- namespace: kube-system
controllerNames:
- kube-apiserver
@@ -54,7 +115,48 @@ exemptions:
- runAsPrivileged
- notReadOnlyRootFilesystem
- hostPIDSet
- namespace: datadog
controllerNames:
- datadogtoken
rules:
- sensitiveConfigmapContent
- namespace: datadog
controllerNames:
- datadog-cluster-agent-apiserver
rules:
- rolebindingClusterAdminRole
- rolebindingRolePodExecAttach
- controllerNames:
- ingress-nginx-controller
rules:
- sensitiveConfigmapContent
- controllerNames:
- ingress-nginx-controller
- ingress-nginx-default-backend
- polaris
- rbac-manager
rules:
- automountServiceAccountToken
- missingNetworkPolicy
- controllerNames:
- aws-iam-authenticator
- aws-load-balancer-controller
- docker-registry
- external-dns
- kube2iam
- metrics-server
rules:
- automountServiceAccountToken
- linuxHardening
- missingNetworkPolicy
- controllerNames:
- oauth2-proxy
rules:
- automountServiceAccountToken
- linuxHardening
- missingNetworkPolicy
- sensitiveContainerEnvVar
- controllerNames:
- kube-flannel-ds
rules:
@@ -72,6 +174,9 @@ exemptions:
- runAsRootAllowed
- readinessProbeMissing
- livenessProbeMissing
- automountServiceAccountToken
- linuxHardening
- missingNetworkPolicy
- controllerNames:
- cluster-autoscaler
@@ -79,6 +184,9 @@ exemptions:
- notReadOnlyRootFilesystem
- runAsRootAllowed
- readinessProbeMissing
- automountServiceAccountToken
- linuxHardening
- missingNetworkPolicy
- controllerNames:
- vpa
@@ -95,6 +203,10 @@ exemptions:
- readinessProbeMissing
- livenessProbeMissing
- notReadOnlyRootFilesystem
- automountServiceAccountToken
- linuxHardening
- missingNetworkPolicy
- sensitiveContainerEnvVar
- controllerNames:
- nginx-ingress-controller
@@ -6,32 +6,52 @@ checks:
pullPolicyNotAlways: warning
readinessProbeMissing: warning
livenessProbeMissing: warning
topologySpreadConstraint: warning
pdbDisruptionsIsZero: warning
missingPodDisruptionBudget: warning
metadataAndInstanceMismatched: warning
hpaMaxAvailability: warning
hpaMinAvailability: warning
pdbMinAvailableGreaterThanHPAMinReplicas: warning
# efficiency
cpuRequestsMissing: warning
cpuLimitsMissing: warning
memoryRequestsMissing: warning
memoryLimitsMissing: warning
# security
automountServiceAccountToken: warning
hostIPCSet: danger
hostPathSet: warning
hostProcess: warning
hostPIDSet: danger
linuxHardening: danger
missingNetworkPolicy: warning
notReadOnlyRootFilesystem: warning
privilegeEscalationAllowed: danger
procMount: warning
runAsRootAllowed: danger
runAsPrivileged: danger
dangerousCapabilities: danger
insecureCapabilities: warning
hostNetworkSet: danger
hostPortSet: warning
tlsSettingsMissing: warning
sensitiveContainerEnvVar: danger
sensitiveConfigmapContent: danger
clusterrolePodExecAttach: danger
rolePodExecAttach: danger
clusterrolebindingPodExecAttach: danger
rolebindingClusterRolePodExecAttach: danger
rolebindingRolePodExecAttach: danger
clusterrolebindingClusterAdmin: danger
rolebindingClusterAdminClusterRole: danger
rolebindingClusterAdminRole: danger
# custom
resourceLimits: warning
imageRegistry: danger
exemptions:
- controllerNames:
- my-network-controller
@@ -55,7 +75,7 @@ customChecks:
category: Resources
target: Container
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
required:
- resources
@@ -85,7 +105,7 @@ customChecks:
category: Images
target: Container
schema:
'$schema': http://json-schema.org/draft-07/schema
'$schema': https://json-schema.org/draft/2019-09/schema
type: object
properties:
image:
+45
View File
@@ -0,0 +1,45 @@
package config
import (
"gopkg.in/yaml.v3" // do not change the yaml import
)
func mergeYaml(defaultConfig, overridesConfig []byte) ([]byte, error) {
var defaultData, overrideConfig map[string]any
err := yaml.Unmarshal([]byte(defaultConfig), &defaultData)
if err != nil {
return nil, err
}
err = yaml.Unmarshal([]byte(overridesConfig), &overrideConfig)
if err != nil {
return nil, err
}
mergedData := mergeYAMLMaps(defaultData, overrideConfig)
mergedConfig, err := yaml.Marshal(mergedData)
if err != nil {
return nil, err
}
return mergedConfig, nil
}
func mergeYAMLMaps(defaults, overrides map[string]any) map[string]any {
for k, v := range overrides {
if vMap, ok := v.(map[string]any); ok {
// if the key exists in defaults and is a map, recursively merge
if mv1, ok := defaults[k].(map[string]any); ok {
defaults[k] = mergeYAMLMaps(mv1, vMap)
} else {
defaults[k] = vMap
}
} else {
// add or overwrite the value in defaults
defaults[k] = v
}
}
return defaults
}
+50
View File
@@ -0,0 +1,50 @@
package config
import (
"testing"
"github.com/stretchr/testify/assert"
)
var defaults = `
checks:
deploymentMissingReplicas: warning
priorityClassNotSet: warning
tagNotSpecified: danger
existing:
sub:
key: value
`
var overrides = `
checks:
pullPolicyNotAlways: ignore
tagNotSpecified: overrides
existing:
sub:
key1: value1
new: value
new:
key: value
`
func TestMergeYaml(t *testing.T) {
mergedContent, err := mergeYaml([]byte(defaults), []byte(overrides))
assert.NoError(t, err)
expectedYAML := `checks:
deploymentMissingReplicas: warning
priorityClassNotSet: warning
pullPolicyNotAlways: ignore
tagNotSpecified: overrides
existing:
new: value
sub:
key: value
key1: value1
new:
key: value
`
assert.Equal(t, expectedYAML, string(mergedContent))
}
+83 -51
View File
@@ -16,6 +16,7 @@ package config
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
@@ -23,9 +24,9 @@ import (
"strings"
"text/template"
"github.com/qri-io/jsonpointer"
"github.com/qri-io/jsonschema"
"github.com/thoas/go-funk"
"gomodules.xyz/jsonpatch/v2"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
k8sYaml "k8s.io/apimachinery/pkg/util/yaml"
@@ -53,10 +54,12 @@ var HandledTargets = []TargetKind{
TargetPodTemplate,
}
// MutationComment is the comments added to a mutated file
type MutationComment struct {
Find string `yaml:"find" json:"find"`
Comment string `yaml:"comment" json:"comment"`
// Mutation defines how to change a YAML file, in the style of JSON Patch
type Mutation struct {
Path string
Op string
Value interface{}
Comment string
}
// SchemaCheck is a Polaris check that runs using JSON Schema
@@ -71,18 +74,18 @@ type SchemaCheck struct {
SchemaTarget TargetKind `yaml:"schemaTarget" json:"schemaTarget"`
Schema map[string]interface{} `yaml:"schema" json:"schema"`
SchemaString string `yaml:"schemaString" json:"schemaString"`
Validator jsonschema.RootSchema `yaml:"-" json:"-"`
Validator jsonschema.Schema `yaml:"-" json:"-"`
AdditionalSchemas map[string]map[string]interface{} `yaml:"additionalSchemas" json:"additionalSchemas"`
AdditionalSchemaStrings map[string]string `yaml:"additionalSchemaStrings" json:"additionalSchemaStrings"`
AdditionalValidators map[string]jsonschema.RootSchema `yaml:"-" json:"-"`
Mutations []jsonpatch.Operation `yaml:"mutations" json:"mutations"`
Comments []MutationComment `yaml:"comments" json:"comments"`
AdditionalValidators map[string]jsonschema.Schema `yaml:"-" json:"-"`
Mutations []Mutation `yaml:"mutations" json:"mutations"`
}
type resourceMinimum string
type resourceMaximum string
func unmarshalYAMLOrJSON(raw []byte, dest interface{}) error {
// UnmarshalYAMLOrJSON is a helper function to unmarshal data in an arbitrary format
func UnmarshalYAMLOrJSON(raw []byte, dest interface{}) error {
reader := bytes.NewReader(raw)
d := k8sYaml.NewYAMLOrJSONDecoder(reader, 4096)
for {
@@ -99,7 +102,7 @@ func unmarshalYAMLOrJSON(raw []byte, dest interface{}) error {
// ParseCheck parses a check from a byte array
func ParseCheck(id string, rawBytes []byte) (SchemaCheck, error) {
check := SchemaCheck{}
err := unmarshalYAMLOrJSON(rawBytes, &check)
err := UnmarshalYAMLOrJSON(rawBytes, &check)
if err != nil {
return check, err
}
@@ -108,8 +111,9 @@ func ParseCheck(id string, rawBytes []byte) (SchemaCheck, error) {
}
func init() {
jsonschema.RegisterValidator("resourceMinimum", newResourceMinimum)
jsonschema.RegisterValidator("resourceMaximum", newResourceMaximum)
jsonschema.RegisterKeyword("resourceMinimum", newResourceMinimum)
jsonschema.RegisterKeyword("resourceMaximum", newResourceMaximum)
jsonschema.LoadDraft2019_09()
}
type includeExcludeList struct {
@@ -117,47 +121,68 @@ type includeExcludeList struct {
Exclude []string `yaml:"exclude"`
}
func newResourceMinimum() jsonschema.Validator {
func newResourceMinimum() jsonschema.Keyword {
return new(resourceMinimum)
}
func newResourceMaximum() jsonschema.Validator {
func newResourceMaximum() jsonschema.Keyword {
return new(resourceMaximum)
}
// Validate checks that a specified quanitity is not less than the minimum
func (min resourceMinimum) Validate(path string, data interface{}, errs *[]jsonschema.ValError) {
err := validateRange(path, string(min), data, true)
func (min resourceMinimum) ValidateKeyword(ctx context.Context, currentState *jsonschema.ValidationState, data interface{}) {
err := validateRange(string(min), data, true)
if err != nil {
errs := currentState.Errs
*errs = append(*errs, *err...)
currentState.Errs = errs
}
}
func (max resourceMaximum) ValidateKeyword(ctx context.Context, currentState *jsonschema.ValidationState, data interface{}) {
err := validateRange(string(max), data, false)
if err != nil {
errs := currentState.Errs
*errs = append(*errs, *err...)
currentState.Errs = errs
}
}
// Validate checks that a specified quanitity is not greater than the maximum
func (max resourceMaximum) Validate(path string, data interface{}, errs *[]jsonschema.ValError) {
err := validateRange(path, string(max), data, false)
if err != nil {
*errs = append(*errs, *err...)
}
func (min resourceMinimum) Resolve(pointer jsonpointer.Pointer, uri string) *jsonschema.Schema {
// Not implemented
return nil
}
func parseQuantity(i interface{}) (resource.Quantity, *[]jsonschema.ValError) {
func (min resourceMinimum) Register(uri string, registry *jsonschema.SchemaRegistry) {
// Not implemented
}
func (max resourceMaximum) Resolve(pointer jsonpointer.Pointer, uri string) *jsonschema.Schema {
// Not implemented
return nil
}
func (max resourceMaximum) Register(uri string, registry *jsonschema.SchemaRegistry) {
// Not implemented
}
func parseQuantity(i interface{}) (resource.Quantity, *[]jsonschema.KeyError) {
if resNum, ok := i.(float64); ok {
i = fmt.Sprintf("%f", resNum)
}
resStr, ok := i.(string)
if !ok {
return resource.Quantity{}, &[]jsonschema.ValError{
return resource.Quantity{}, &[]jsonschema.KeyError{
{Message: fmt.Sprintf("Resource quantity %v is not a string", i)},
}
}
q, err := resource.ParseQuantity(resStr)
if err != nil {
return resource.Quantity{}, &[]jsonschema.ValError{
return resource.Quantity{}, &[]jsonschema.KeyError{
{Message: fmt.Sprintf("Could not parse resource quantity: %s", resStr)},
}
}
return q, nil
}
func validateRange(path string, limit interface{}, data interface{}, isMinimum bool) *[]jsonschema.ValError {
func validateRange(limit interface{}, data interface{}, isMinimum bool) *[]jsonschema.KeyError {
limitQuantity, err := parseQuantity(limit)
if err != nil {
return err
@@ -169,14 +194,14 @@ func validateRange(path string, limit interface{}, data interface{}, isMinimum b
cmp := limitQuantity.Cmp(actualQuantity)
if isMinimum {
if cmp == 1 {
return &[]jsonschema.ValError{
{Message: fmt.Sprintf("%s quantity %v is > %v", path, actualQuantity, limitQuantity)},
return &[]jsonschema.KeyError{
{Message: fmt.Sprintf("quantity %v is > %v", actualQuantity, limitQuantity)},
}
}
} else {
if cmp == -1 {
return &[]jsonschema.ValError{
{Message: fmt.Sprintf("%s quantity %v is < %v", path, actualQuantity, limitQuantity)},
return &[]jsonschema.KeyError{
{Message: fmt.Sprintf("quantity %v is < %v", actualQuantity, limitQuantity)},
}
}
}
@@ -222,7 +247,10 @@ func (check SchemaCheck) TemplateForResource(res interface{}) (*SchemaCheck, err
newCheck.AdditionalSchemaStrings = map[string]string{}
for kind, tmplString := range templateStrings {
tmpl := template.New(newCheck.ID)
tmpl := template.New(newCheck.ID).Funcs(template.FuncMap{
"hasPrefix": strings.HasPrefix,
"hasSuffix": strings.HasSuffix,
})
tmpl, err := tmpl.Parse(tmplString)
if err != nil {
return nil, err
@@ -232,24 +260,28 @@ func (check SchemaCheck) TemplateForResource(res interface{}) (*SchemaCheck, err
if err != nil {
return nil, err
}
templated := w.String()
if strings.TrimSpace(templated) == "" {
continue
}
if kind == "" {
newCheck.SchemaString = w.String()
newCheck.SchemaString = templated
} else {
newCheck.AdditionalSchemaStrings[kind] = w.String()
newCheck.AdditionalSchemaStrings[kind] = templated
}
}
newCheck.AdditionalValidators = map[string]jsonschema.RootSchema{}
newCheck.AdditionalValidators = map[string]jsonschema.Schema{}
for kind, schemaStr := range newCheck.AdditionalSchemaStrings {
val := jsonschema.RootSchema{}
err := unmarshalYAMLOrJSON([]byte(schemaStr), &val)
val := jsonschema.Schema{}
err := UnmarshalYAMLOrJSON([]byte(schemaStr), &val)
if err != nil {
return nil, err
}
newCheck.AdditionalValidators[kind] = val
}
err := unmarshalYAMLOrJSON([]byte(newCheck.SchemaString), &newCheck.Validator)
err := UnmarshalYAMLOrJSON([]byte(newCheck.SchemaString), &newCheck.Validator)
if err != nil {
return nil, err
}
@@ -257,38 +289,38 @@ func (check SchemaCheck) TemplateForResource(res interface{}) (*SchemaCheck, err
}
// CheckPodSpec checks a pod spec against the schema
func (check SchemaCheck) CheckPodSpec(pod *corev1.PodSpec) (bool, []jsonschema.ValError, error) {
return check.CheckObject(pod)
func (check SchemaCheck) CheckPodSpec(ctx context.Context, pod *corev1.PodSpec) (bool, []jsonschema.KeyError, error) {
return check.CheckObject(ctx, pod)
}
// CheckPodTemplate checks a pod template against the schema
func (check SchemaCheck) CheckPodTemplate(podTemplate interface{}) (bool, []jsonschema.ValError, error) {
return check.CheckObject(podTemplate)
func (check SchemaCheck) CheckPodTemplate(ctx context.Context, podTemplate interface{}) (bool, []jsonschema.KeyError, error) {
return check.CheckObject(ctx, podTemplate)
}
// CheckController checks a controler's spec against the schema
func (check SchemaCheck) CheckController(bytes []byte) (bool, []jsonschema.ValError, error) {
errs, err := check.Validator.ValidateBytes(bytes)
func (check SchemaCheck) CheckController(ctx context.Context, bytes []byte) (bool, []jsonschema.KeyError, error) {
errs, err := check.Validator.ValidateBytes(ctx, bytes)
return len(errs) == 0, errs, err
}
// CheckContainer checks a container spec against the schema
func (check SchemaCheck) CheckContainer(container *corev1.Container) (bool, []jsonschema.ValError, error) {
return check.CheckObject(container)
func (check SchemaCheck) CheckContainer(ctx context.Context, container *corev1.Container) (bool, []jsonschema.KeyError, error) {
return check.CheckObject(ctx, container)
}
// CheckObject checks arbitrary data against the schema
func (check SchemaCheck) CheckObject(obj interface{}) (bool, []jsonschema.ValError, error) {
func (check SchemaCheck) CheckObject(ctx context.Context, obj interface{}) (bool, []jsonschema.KeyError, error) {
bytes, err := json.Marshal(obj)
if err != nil {
return false, nil, err
}
errs, err := check.Validator.ValidateBytes(bytes)
errs, err := check.Validator.ValidateBytes(ctx, bytes)
return len(errs) == 0, errs, err
}
// CheckAdditionalObjects looks for an object that passes the specified additional schema
func (check SchemaCheck) CheckAdditionalObjects(groupkind string, objects []interface{}) (bool, error) {
func (check SchemaCheck) CheckAdditionalObjects(ctx context.Context, groupkind string, objects []interface{}) (bool, error) {
val, ok := check.AdditionalValidators[groupkind]
if !ok {
return false, errors.New("No validator found for " + groupkind)
@@ -298,7 +330,7 @@ func (check SchemaCheck) CheckAdditionalObjects(groupkind string, objects []inte
if err != nil {
return false, err
}
errs, err := val.ValidateBytes(bytes)
errs, err := val.ValidateBytes(ctx, bytes)
if err != nil {
return false, err
}
+25 -28
View File
@@ -16,8 +16,11 @@ package dashboard
import (
"bytes"
"context"
"embed"
"encoding/json"
"html/template"
"io/fs"
"net/http"
"net/url"
"path"
@@ -26,7 +29,6 @@ import (
"github.com/fairwindsops/polaris/pkg/config"
"github.com/fairwindsops/polaris/pkg/kube"
"github.com/fairwindsops/polaris/pkg/validator"
packr "github.com/gobuffalo/packr/v2"
"github.com/gorilla/mux"
"github.com/sirupsen/logrus"
)
@@ -47,27 +49,12 @@ const (
)
var (
templateBox = (*packr.Box)(nil)
assetBox = (*packr.Box)(nil)
markdownBox = (*packr.Box)(nil)
//go:embed all:templates
templatesFS embed.FS
//go:embed all:assets
assetsFS embed.FS
)
// GetAssetBox returns a binary-friendly set of assets packaged from disk
func GetAssetBox() *packr.Box {
if assetBox == (*packr.Box)(nil) {
assetBox = packr.New("Assets", "assets")
}
return assetBox
}
// GetTemplateBox returns a binary-friendly set of templates for rendering the dash
func GetTemplateBox() *packr.Box {
if templateBox == (*packr.Box)(nil) {
templateBox = packr.New("Templates", "templates")
}
return templateBox
}
// templateData is passed to the dashboard HTML template
type templateData struct {
BasePath string
@@ -103,9 +90,8 @@ func GetBaseTemplate(name string) (*template.Template, error) {
}
func parseTemplateFiles(tmpl *template.Template, templateFileNames []string) (*template.Template, error) {
templateBox := GetTemplateBox()
for _, fname := range templateFileNames {
templateFile, err := templateBox.Find(fname)
templateFile, err := templatesFS.ReadFile("templates/" + fname)
if err != nil {
return nil, err
}
@@ -155,9 +141,15 @@ func stripUnselectedNamespaces(data *validator.AuditData, selectedNamespaces []s
}
// GetRouter returns a mux router serving all routes necessary for the dashboard
func GetRouter(c config.Configuration, auditPath string, port int, basePath string, auditData *validator.AuditData) *mux.Router {
func GetRouter(ctx context.Context, c config.Configuration, auditPath string, port int, basePath string, auditData *validator.AuditData) (*mux.Router, error) {
router := mux.NewRouter().PathPrefix(basePath).Subrouter()
fileServer := http.FileServer(GetAssetBox())
assetsSubFS, err := fs.Sub(assetsFS, "assets")
if err != nil {
return nil, err
}
fileServer := http.FileServer(http.FS(assetsSubFS))
router.PathPrefix("/static/").Handler(http.StripPrefix(path.Join(basePath, "/static/"), fileServer))
router.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
@@ -165,7 +157,7 @@ func GetRouter(c config.Configuration, auditPath string, port int, basePath stri
})
router.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
favicon, err := GetAssetBox().Find("favicon-32x32.png")
favicon, err := assetsFS.ReadFile("assets/favicon-32x32.png")
if err != nil {
logrus.Errorf("Error getting favicon: %v", err)
http.Error(w, "Error getting favicon", http.StatusInternalServerError)
@@ -185,7 +177,7 @@ func GetRouter(c config.Configuration, auditPath string, port int, basePath stri
}
var auditDataObj validator.AuditData
auditDataObj, err = validator.RunAudit(adjustedConf, k)
auditDataObj, err = validator.RunAudit(ctx, adjustedConf, k)
if err != nil {
http.Error(w, "Error Fetching Deployments", http.StatusInternalServerError)
return
@@ -204,12 +196,14 @@ func GetRouter(c config.Configuration, auditPath string, port int, basePath stri
router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" && r.URL.Path != basePath {
logrus.Warningf("Path not found: %s", r.URL.Path)
http.NotFound(w, r)
return
}
adjustedConf := getConfigForQuery(c, r.URL.Query())
if auditData == nil {
logrus.Infof("Creating resource provider")
k, err := kube.CreateResourceProvider(r.Context(), auditPath, "", c)
if err != nil {
logrus.Errorf("Error fetching Kubernetes resources %v", err)
@@ -217,20 +211,23 @@ func GetRouter(c config.Configuration, auditPath string, port int, basePath stri
return
}
logrus.Infof("Running audit")
var auditData validator.AuditData
auditData, err = validator.RunAudit(adjustedConf, k)
auditData, err = validator.RunAudit(ctx, adjustedConf, k)
if err != nil {
logrus.Errorf("Error getting audit data: %v", err)
http.Error(w, "Error running audit", 500)
return
}
logrus.Infof("Sending results")
MainHandler(w, r, adjustedConf, auditData, basePath)
} else {
logrus.Infof("Sending results")
MainHandler(w, r, adjustedConf, *auditData, basePath)
}
})
return router
return router, nil
}
// MainHandler gets template data and renders the dashboard with it.
+1
View File
@@ -5,6 +5,7 @@
<a href="https://www.fairwinds.com/polaris-user-insights-demo?utm_source=polaris&utm_medium=polaris&utm_campaign=polaris" target="_blank">
<img class="fw-logo" src="static/images/white_logo_fairwinds.svg" alt="Fairwinds" />
</a>
<div style="color: white;"> Want more? Automate Polaris with <a href="https://www.fairwinds.com/insights-signup/polaris"><strong>Fairwinds Insights</strong></a></div>
<div class="right-section p-0 d-flex justify-content-between">
<a href="https://github.com/FairwindsOps" target="_blank">
<img class="gh-logo" src="static/images/white_icon_github.svg" alt="Github" />
+160
View File
@@ -0,0 +1,160 @@
package fix
import (
"context"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/fairwindsops/polaris/pkg/config"
"github.com/fairwindsops/polaris/pkg/kube"
"github.com/fairwindsops/polaris/pkg/mutation"
"github.com/fairwindsops/polaris/pkg/validator"
)
const templateLineMarker = "# POLARIS_FIX_TMPL"
const templateOpenMarker = "POLARIS_OPEN_TMPL"
const templateCloseMarker = "POLARIS_CLOSE_TMPL"
var ErrFilesPathRequired = errors.New("files-path flag is required")
func Execute(ctx context.Context, config config.Configuration, filesPath string, isTemplate bool, checksToFix ...string) error {
if filesPath == "" {
return ErrFilesPathRequired
}
var yamlFiles []string
fileInfo, err := os.Stat(filesPath)
if err != nil {
return fmt.Errorf("error getting file info: %v", err)
}
if fileInfo.IsDir() {
baseDir := filesPath
if !strings.HasSuffix(filesPath, "/") {
baseDir = baseDir + "/"
}
yamlFiles, err = getYamlFiles(baseDir)
if err != nil {
return fmt.Errorf("error getting yaml files from directory: %v", err)
}
} else {
yamlFiles = append(yamlFiles, filesPath)
}
if len(checksToFix) > 0 {
if len(checksToFix) == 1 && checksToFix[0] == "all" {
allchecks := []string{}
for key := range config.Checks {
allchecks = append(allchecks, key)
}
config.Mutations = allchecks
} else if len(checksToFix) == 0 && checksToFix[0] == "none" {
config.Mutations = nil
} else {
config.Mutations = checksToFix
}
}
for _, fullFilePath := range yamlFiles {
yamlContent, err := os.ReadFile(fullFilePath)
if err != nil {
return fmt.Errorf("error reading file with file path %s: %v", fullFilePath, err)
}
if isTemplate {
yamlContent = []byte(detemplate(string(yamlContent)))
}
kubeResources, err := kube.CreateResourceProviderFromYaml(string(yamlContent))
if err != nil {
return fmt.Errorf("error creating resource provider from yaml: %v", err)
}
results, err := validator.ApplyAllSchemaChecksToResourceProvider(ctx, &config, kubeResources)
if err != nil {
return fmt.Errorf("error applying schema check to the resources %s: %v", fullFilePath, err)
}
allMutations := mutation.GetMutationsFromResults(results)
updatedYamlContent := ""
if len(allMutations) > 0 {
for _, resources := range kubeResources.Resources {
for _, resource := range resources {
key := fmt.Sprintf("%s/%s/%s", resource.Kind, resource.Resource.GetName(), resource.Resource.GetNamespace())
mutations := allMutations[key]
mutatedYamlContent, err := mutation.ApplyAllMutations(string(resource.OriginalObjectYAML), mutations)
if err != nil {
return fmt.Errorf("error applying schema mutations to the resource %s: %v", key, err)
}
if updatedYamlContent != "" {
updatedYamlContent += "\n---\n"
}
updatedYamlContent += mutatedYamlContent
}
}
}
if isTemplate {
updatedYamlContent = retemplate(updatedYamlContent)
}
if updatedYamlContent != "" {
err = os.WriteFile(fullFilePath, []byte(updatedYamlContent), 0644)
if err != nil {
return fmt.Errorf("error writing output to file: %v", err)
}
}
}
return nil
}
func detemplate(content string) string {
lines := strings.Split(content, "\n")
for idx, line := range lines {
lines[idx] = detemplateLine(line)
}
return strings.Join(lines, "\n")
}
func retemplate(content string) string {
lines := strings.Split(content, "\n")
for idx, line := range lines {
lines[idx] = retemplateLine(line)
}
return strings.Join(lines, "\n")
}
func detemplateLine(line string) string {
if !strings.HasPrefix(strings.TrimSpace(line), "{{") {
line = strings.ReplaceAll(line, "{", templateOpenMarker)
line = strings.ReplaceAll(line, "}", templateCloseMarker)
return line
}
tmplStart := strings.Index(line, "{{")
newLine := line[:tmplStart] + templateLineMarker + line[tmplStart:]
return newLine
}
func retemplateLine(line string) string {
if !strings.Contains(line, templateLineMarker) {
line = strings.ReplaceAll(line, templateOpenMarker, "{")
line = strings.ReplaceAll(line, templateCloseMarker, "}")
return line
}
return strings.Replace(line, templateLineMarker, "", 1)
}
func getYamlFiles(rootpath string) ([]string, error) {
var list []string
err := filepath.Walk(rootpath, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
}
if filepath.Ext(path) == ".yaml" || filepath.Ext(path) == ".yml" {
list = append(list, path)
}
return nil
})
return list, err
}
+43 -16
View File
@@ -20,6 +20,7 @@ import (
"fmt"
"github.com/sirupsen/logrus"
"github.com/thoas/go-funk"
"gopkg.in/yaml.v3"
kubeAPICoreV1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
@@ -29,6 +30,9 @@ import (
"k8s.io/client-go/dynamic"
)
// There are often many ReplicaSets that are orphaned (default 10 per deployment) so we don't cache all of them
var skipListCacheKinds = []string{"ReplicaSet", "Job"}
// GenericResource is a base implementation with some free methods for inherited structs
type GenericResource struct {
Kind string
@@ -37,6 +41,7 @@ type GenericResource struct {
PodSpec *kubeAPICoreV1.PodSpec
PodTemplate interface{}
OriginalObjectJSON []byte
OriginalObjectYAML []byte
}
// NewGenericResourceFromUnstructured creates a workload from an unstructured.Unstructured
@@ -128,11 +133,13 @@ func NewGenericResourceFromBytes(contentBytes []byte) (GenericResource, error) {
if err != nil {
return GenericResource{}, err
}
return NewGenericResourceFromUnstructured(unst, nil)
res, err := NewGenericResourceFromUnstructured(unst, nil)
res.OriginalObjectYAML = contentBytes
return res, err
}
// ResolveControllerFromPod builds a new workload for a given Pod
func ResolveControllerFromPod(ctx context.Context, podResource kubeAPICoreV1.Pod, dynamicClient *dynamic.Interface, restMapper *meta.RESTMapper, objectCache map[string]unstructured.Unstructured) (GenericResource, error) {
func ResolveControllerFromPod(ctx context.Context, podResource kubeAPICoreV1.Pod, dynamicClient dynamic.Interface, restMapper meta.RESTMapper, objectCache map[string]unstructured.Unstructured) (GenericResource, error) {
workload, err := resolveControllerFromPod(ctx, podResource, dynamicClient, restMapper, objectCache)
if err != nil {
return workload, err
@@ -143,7 +150,7 @@ func ResolveControllerFromPod(ctx context.Context, podResource kubeAPICoreV1.Pod
return workload, err
}
func resolveControllerFromPod(ctx context.Context, podResource kubeAPICoreV1.Pod, dynamicClient *dynamic.Interface, restMapper *meta.RESTMapper, objectCache map[string]unstructured.Unstructured) (GenericResource, error) {
func resolveControllerFromPod(ctx context.Context, podResource kubeAPICoreV1.Pod, dynamicClient dynamic.Interface, restMapper meta.RESTMapper, objectCache map[string]unstructured.Unstructured) (GenericResource, error) {
podWorkload, err := NewGenericResourceFromPod(podResource, nil)
if err != nil {
return podWorkload, err
@@ -167,9 +174,14 @@ func resolveControllerFromPod(ctx context.Context, podResource kubeAPICoreV1.Pod
lastKey = key
abstractObject, ok := objectCache[key]
if !ok {
err := cacheAllObjectsOfKind(ctx, firstOwner.APIVersion, firstOwner.Kind, dynamicClient, restMapper, objectCache)
var err error
if funk.Contains(skipListCacheKinds, firstOwner.Kind) {
err = cacheSingleObject(ctx, firstOwner.APIVersion, firstOwner.Kind, topMeta.GetNamespace(), firstOwner.Name, dynamicClient, restMapper, objectCache)
} else {
err = cacheAllObjectsOfKind(ctx, firstOwner.APIVersion, firstOwner.Kind, dynamicClient, restMapper, objectCache)
}
if err != nil {
logrus.Warnf("Error caching objects of Kind %s %v", firstOwner.Kind, err)
logrus.Warnf("error caching objects of Kind %s %v", firstOwner.Kind, err)
break
}
abstractObject, ok = objectCache[key]
@@ -181,7 +193,7 @@ func resolveControllerFromPod(ctx context.Context, podResource kubeAPICoreV1.Pod
objMeta, err := meta.Accessor(&abstractObject)
if err != nil {
logrus.Warnf("Error retrieving parent metadata %s of API %s and Kind %s because of error: %v ", firstOwner.Name, firstOwner.APIVersion, firstOwner.Kind, err)
logrus.Warnf("error retrieving parent metadata %s of API %s and Kind %s because of error: %v ", firstOwner.Name, firstOwner.APIVersion, firstOwner.Kind, err)
return GenericResource{}, err
}
podSpec := GetPodSpec(abstractObject.Object)
@@ -205,33 +217,48 @@ func resolveControllerFromPod(ctx context.Context, podResource kubeAPICoreV1.Pod
return workload, nil
}
func cacheAllObjectsOfKind(ctx context.Context, apiVersion, kind string, dynamicClient *dynamic.Interface, restMapper *meta.RESTMapper, objectCache map[string]unstructured.Unstructured) error {
fqKind := schema.FromAPIVersionAndKind(apiVersion, kind)
mapping, err := (*restMapper).RESTMapping(fqKind.GroupKind(), fqKind.Version)
func cacheSingleObject(ctx context.Context, apiVersion, kind, namespace, name string, dynamicClient dynamic.Interface, restMapper meta.RESTMapper, objectCache map[string]unstructured.Unstructured) error {
logrus.Debugf("Caching a single %s", kind)
object, err := GetObject(ctx, namespace, kind, apiVersion, name, dynamicClient, restMapper)
if err != nil {
logrus.Warnf("Error retrieving mapping of API %s and Kind %s because of error: %v", apiVersion, kind, err)
logrus.Warnf("error retrieving object %s/%s/%s/%s because of error: %v", kind, apiVersion, namespace, name, err)
return err
}
key := fmt.Sprintf("%s/%s/%s", object.GetKind(), object.GetNamespace(), object.GetName())
logrus.Debugf("Caching key %s", key)
objectCache[key] = *object
return nil
}
func cacheAllObjectsOfKind(ctx context.Context, apiVersion, kind string, dynamicClient dynamic.Interface, restMapper meta.RESTMapper, objectCache map[string]unstructured.Unstructured) error {
logrus.Debugf("Caching all %s", kind)
fqKind := schema.FromAPIVersionAndKind(apiVersion, kind)
mapping, err := restMapper.RESTMapping(fqKind.GroupKind(), fqKind.Version)
if err != nil {
logrus.Warnf("error retrieving mapping of API %s and Kind %s because of error: %v", apiVersion, kind, err)
return err
}
objects, err := (*dynamicClient).Resource(mapping.Resource).Namespace("").List(ctx, kubeAPIMetaV1.ListOptions{})
objects, err := dynamicClient.Resource(mapping.Resource).Namespace("").List(ctx, kubeAPIMetaV1.ListOptions{})
if err != nil {
logrus.Warnf("Error retrieving parent object API %s and Kind %s because of error: %v", mapping.Resource.Version, mapping.Resource.Resource, err)
logrus.Warnf("error retrieving parent object API %s and Kind %s because of error: %v", mapping.Resource.Version, mapping.Resource.Resource, err)
return err
}
for idx, object := range objects.Items {
key := fmt.Sprintf("%s/%s/%s", object.GetKind(), object.GetNamespace(), object.GetName())
logrus.Debugf(" caching key %s", key)
objectCache[key] = objects.Items[idx]
}
return nil
}
func getObject(ctx context.Context, namespace, kind, version, name string, dynamicClient *dynamic.Interface, restMapper *meta.RESTMapper) (*unstructured.Unstructured, error) {
fqKind := schema.ParseGroupKind(kind)
mapping, err := (*restMapper).RESTMapping(fqKind, version)
func GetObject(ctx context.Context, namespace, kind, version, name string, dynamicClient dynamic.Interface, restMapper meta.RESTMapper) (*unstructured.Unstructured, error) {
fqKind := schema.FromAPIVersionAndKind(version, kind)
mapping, err := restMapper.RESTMapping(fqKind.GroupKind(), fqKind.Version)
if err != nil {
return nil, err
}
object, err := (*dynamicClient).Resource(mapping.Resource).Namespace(namespace).Get(ctx, name, kubeAPIMetaV1.GetOptions{})
object, err := dynamicClient.Resource(mapping.Resource).Namespace(namespace).Get(ctx, name, kubeAPIMetaV1.GetOptions{})
return object, err
}
+83 -112
View File
@@ -20,13 +20,13 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strings"
"time"
"github.com/fairwindsops/controller-utils/pkg/controller"
conf "github.com/fairwindsops/polaris/pkg/config"
"github.com/sirupsen/logrus"
@@ -34,12 +34,12 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
k8sYaml "k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
_ "k8s.io/client-go/plugin/pkg/client/auth" // Required for other auth providers like GKE.
"k8s.io/client-go/rest"
"k8s.io/client-go/restmapper"
"sigs.k8s.io/controller-runtime/pkg/client/config"
)
@@ -94,12 +94,16 @@ func (rkm resourceKindMap) GetNumberOfControllers() int {
return total
}
var kindRewrites = map[string]string{
"Ingress": "networking.k8s.io/Ingress",
"PodDisruptionBudget": "policy/PodDisruptionBudget",
"HorizontalPodAutoscaler": "autoscaling/HorizontalPodAutoscaler",
}
// This is here for backward compatibility reasons
func maybeTransformKindIntoGroupKind(k string) string {
if k == "Ingress" {
return "networking.k8s.io/Ingress"
} else if k == "PodDisruptionBudget" {
return "policy/PodDisruptionBudget"
if val, ok := kindRewrites[k]; ok {
return val
}
return k
}
@@ -146,20 +150,13 @@ func CreateResourceProvider(ctx context.Context, directory, workload string, c c
// CreateResourceProviderFromResource creates a new ResourceProvider that just contains one workload
func CreateResourceProviderFromResource(ctx context.Context, workload string) (*ResourceProvider, error) {
kubeConf, configError := config.GetConfig()
if configError != nil {
logrus.Errorf("Error fetching KubeConfig: %v", configError)
return nil, configError
}
kube, err := kubernetes.NewForConfig(kubeConf)
dynamicClient, restMapper, clientSet, _, err := GetKubeClient(ctx, "")
if err != nil {
logrus.Errorf("Error creating Kubernetes client: %v", err)
return nil, err
}
serverVersion, err := kube.Discovery().ServerVersion()
serverVersion, err := clientSet.Discovery().ServerVersion()
if err != nil {
logrus.Errorf("Error fetching Cluster API version: %v", err)
return nil, err
return nil, fmt.Errorf("Error fetching Cluster API version: %w", err)
}
resources := newResourceProvider(serverVersion.Major+"."+serverVersion.Minor, "Resource", workload)
@@ -172,28 +169,14 @@ func CreateResourceProviderFromResource(ctx context.Context, workload string) (*
version := parts[2]
name := parts[3]
dynamicInterface, err := dynamic.NewForConfig(kubeConf)
obj, err := GetObject(ctx, namespace, kind, version, name, dynamicClient, restMapper)
if err != nil {
logrus.Errorf("Error connecting to dynamic interface: %v", err)
return nil, err
}
groupResources, err := restmapper.GetAPIGroupResources(kube.Discovery())
if err != nil {
logrus.Errorf("Error getting API Group resources: %v", err)
return nil, err
}
restMapper := restmapper.NewDiscoveryRESTMapper(groupResources)
obj, err := getObject(ctx, namespace, kind, version, name, &dynamicInterface, &restMapper)
if err != nil {
logrus.Errorf("Could not find workload %s: %v", workload, err)
return nil, err
return nil, fmt.Errorf("Could not find workload %s: %w", workload, err)
}
workloadObj, err := NewGenericResourceFromUnstructured(*obj, nil)
if err != nil {
logrus.Errorf("Could not parse workload %s: %v", workload, err)
return nil, err
return nil, fmt.Errorf("Could not parse workload %s: %w", workload, err)
}
resources.Resources.addResource(workloadObj)
return &resources, nil
}
@@ -216,14 +199,14 @@ func CreateResourceProviderFromPath(directory string) (*ResourceProvider, error)
if !strings.HasSuffix(path, ".yml") && !strings.HasSuffix(path, ".yaml") {
return nil
}
contents, err := ioutil.ReadFile(path)
contents, err := os.ReadFile(path)
if err != nil {
logrus.Errorf("Error reading file: %v", path)
return err
}
err = resources.addResourcesFromYaml(string(contents))
if err != nil {
logrus.Warnf("Skipping %s: cannot add resource from YAML: %v", path, err)
logrus.Warnf("skipping %s: cannot add resource from YAML: %v", path, err)
}
return nil
}
@@ -236,34 +219,52 @@ func CreateResourceProviderFromPath(directory string) (*ResourceProvider, error)
}
// CreateResourceProviderFromYaml returns a new ResourceProvider using the yaml
func CreateResourceProviderFromYaml(yamlContent string) *ResourceProvider {
func CreateResourceProviderFromYaml(yamlContent string) (*ResourceProvider, error) {
resources := newResourceProvider("unknown", "Content", "unknown")
resources.addResourcesFromYaml(string(yamlContent))
return &resources
err := resources.addResourcesFromYaml(string(yamlContent))
if err != nil {
return nil, err
}
return &resources, nil
}
// CreateResourceProviderFromCluster creates a new ResourceProvider using live data from a cluster
func CreateResourceProviderFromCluster(ctx context.Context, c conf.Configuration) (*ResourceProvider, error) {
kubeConf, configError := config.GetConfigWithContext(c.KubeContext)
if configError != nil {
logrus.Errorf("Error fetching KubeConfig: %v", configError)
return nil, configError
}
api, err := kubernetes.NewForConfig(kubeConf)
dynamicClient, _, clientSet, clusterHost, err := GetKubeClient(ctx, c.KubeContext)
if err != nil {
logrus.Errorf("Error creating Kubernetes client: %v", err)
return nil, err
}
dynamicInterface, err := dynamic.NewForConfig(kubeConf)
if err != nil {
logrus.Errorf("Error connecting to dynamic interface: %v", err)
return nil, err
return CreateResourceProviderFromAPI(ctx, clientSet, clusterHost, dynamicClient, c)
}
func GetKubeClient(ctx context.Context, kubeContext string) (dynamic.Interface, meta.RESTMapper, kubernetes.Interface, string, error) {
var kubeConf *rest.Config
var err error
if len(kubeContext) > 0 {
kubeConf, err = config.GetConfigWithContext(kubeContext)
} else {
kubeConf, err = config.GetConfig()
}
return CreateResourceProviderFromAPI(ctx, api, kubeConf.Host, &dynamicInterface, c)
if err != nil {
return nil, nil, nil, "", fmt.Errorf("Error fetching KubeConfig: %v", err)
}
clientSet, err := kubernetes.NewForConfig(kubeConf)
if err != nil {
return nil, nil, nil, "", fmt.Errorf("Error creating Kubernetes client: %v", err)
}
dynamicClient, err := dynamic.NewForConfig(kubeConf)
if err != nil {
return nil, nil, nil, "", fmt.Errorf("Error connecting to dynamic interface: %v", err)
}
resources, err := restmapper.GetAPIGroupResources(clientSet.Discovery())
if err != nil {
return nil, nil, nil, "", fmt.Errorf("Error getting API Group resources: %v", err)
}
return dynamicClient, restmapper.NewDiscoveryRESTMapper(resources), clientSet, kubeConf.Host, nil
}
// CreateResourceProviderFromAPI creates a new ResourceProvider from an existing k8s interface
func CreateResourceProviderFromAPI(ctx context.Context, kube kubernetes.Interface, clusterName string, dynamic *dynamic.Interface, c conf.Configuration) (*ResourceProvider, error) {
func CreateResourceProviderFromAPI(ctx context.Context, kube kubernetes.Interface, clusterName string, dynamic dynamic.Interface, c conf.Configuration) (*ResourceProvider, error) {
listOpts := metav1.ListOptions{}
serverVersion, err := kube.Discovery().ServerVersion()
if err != nil {
@@ -278,12 +279,14 @@ func CreateResourceProviderFromAPI(ctx context.Context, kube kubernetes.Interfac
}
provider := newResourceProvider(serverVersion.Major+"."+serverVersion.Minor, sourceType, clusterName)
logrus.Info("Loading nodes")
nodes, err := kube.CoreV1().Nodes().List(ctx, listOpts)
if err != nil {
logrus.Errorf("Error fetching Nodes: %v", err)
return nil, err
}
logrus.Info("Loading namespaces")
var namespaces *corev1.NamespaceList
if c.Namespace != "" {
ns, err := kube.CoreV1().Namespaces().Get(ctx, c.Namespace, metav1.GetOptions{})
@@ -301,12 +304,7 @@ func CreateResourceProviderFromAPI(ctx context.Context, kube kubernetes.Interfac
}
namespaces = nsList
}
pods, err := kube.CoreV1().Pods(c.Namespace).List(ctx, listOpts)
if err != nil {
logrus.Errorf("Error fetching Pods: %v", err)
return nil, err
}
logrus.Info("Setting up restmapper")
resources, err := restmapper.GetAPIGroupResources(kube.Discovery())
if err != nil {
logrus.Errorf("Error getting API Group resources: %v", err)
@@ -340,15 +338,20 @@ func CreateResourceProviderFromAPI(ctx context.Context, kube kubernetes.Interfac
var kubernetesResources []GenericResource
for _, kind := range additionalKinds {
groupKind := parseGroupKind(maybeTransformKindIntoGroupKind(string(kind)))
mapping, err := (restMapper).RESTMapping(groupKind)
mapping, err := restMapper.RESTMapping(groupKind)
if err != nil {
logrus.Warnf("Error retrieving mapping of Kind %s because of error: %v", kind, err)
logrus.Warnf("error retrieving mapping of Kind %s because of error: %v", kind, err)
return nil, err
}
if c.Namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameNamespace {
logrus.Infof("Skipping %s because of auditing specific namespace", mapping.GroupVersionKind)
continue
}
objects, err := (*dynamic).Resource(mapping.Resource).Namespace(c.Namespace).List(ctx, metav1.ListOptions{})
logrus.Info("Loading " + kind)
objects, err := dynamic.Resource(mapping.Resource).Namespace(c.Namespace).List(ctx, metav1.ListOptions{})
if err != nil {
logrus.Warnf("Error retrieving parent object API %s and Kind %s because of error: %v", mapping.Resource.Version, mapping.Resource.Resource, err)
logrus.Warnf("error retrieving parent object API %s and Kind %s because of error: %v", mapping.Resource.Version, mapping.Resource.Resource, err)
return nil, err
}
for _, obj := range objects.Items {
@@ -359,67 +362,34 @@ func CreateResourceProviderFromAPI(ctx context.Context, kube kubernetes.Interfac
kubernetesResources = append(kubernetesResources, res)
}
}
objectCache := map[string]unstructured.Unstructured{}
controllers, err := LoadControllers(ctx, pods.Items, dynamic, &restMapper, objectCache)
logrus.Info("Loading controllers")
client := controller.Client{
Context: ctx,
Dynamic: dynamic,
RESTMapper: restMapper,
}
topControllers, err := client.GetAllTopControllersSummary("")
if err != nil {
logrus.Errorf("Error loading controllers from pods: %v", err)
return nil, err
return nil, fmt.Errorf("error while getting all TopControllers: %v", err)
}
for _, workload := range topControllers {
topController := workload.TopController
workloadObj, err := NewGenericResourceFromUnstructured(topController, nil)
if err != nil {
return nil, fmt.Errorf("could not parse workload %v: %w", workload, err)
}
kubernetesResources = append(kubernetesResources, workloadObj)
}
// resources loaded from custom checks can also contain controllers and thus would be added twice to the provider
kubernetesResources = deduplicateControllers(append(kubernetesResources, controllers...))
provider.Nodes = nodes.Items
provider.Namespaces = namespaces.Items
provider.Resources.addResources(kubernetesResources)
logrus.Info("Done loading Kubernetes resources")
return &provider, nil
}
// LoadControllers loads a list of controllers from the kubeResources Pods
func LoadControllers(ctx context.Context, pods []corev1.Pod, dynamicClientPointer *dynamic.Interface, restMapperPointer *meta.RESTMapper, objectCache map[string]unstructured.Unstructured) ([]GenericResource, error) {
interfaces := []GenericResource{}
deduped := map[string]corev1.Pod{}
for _, pod := range pods {
owners := pod.ObjectMeta.OwnerReferences
if len(owners) == 0 {
deduped[pod.ObjectMeta.Namespace+"/Pod/"+pod.ObjectMeta.Name] = pod
continue
}
deduped[pod.ObjectMeta.Namespace+"/"+owners[0].Kind+"/"+owners[0].Name] = pod
}
for _, pod := range deduped {
workload, err := ResolveControllerFromPod(ctx, pod, dynamicClientPointer, restMapperPointer, objectCache)
if err != nil {
return nil, err
}
interfaces = append(interfaces, workload)
}
return interfaces, nil
}
// Because the controllers with an Owner take on the name of the Owner, this eliminates any duplicates.
// In cases like CronJobs older children can hang around, so this takes the most recent.
func deduplicateControllers(inputResources []GenericResource) []GenericResource {
controllerMap := make(map[string]GenericResource)
for _, controller := range inputResources {
key := controller.ObjectMeta.GetNamespace() + "/" + controller.Kind + "/" + controller.ObjectMeta.GetName()
oldController, ok := controllerMap[key]
if !ok || controller.ObjectMeta.GetCreationTimestamp().Time.After(oldController.ObjectMeta.GetCreationTimestamp().Time) {
controllerMap[key] = controller
}
}
results := make([]GenericResource, len(controllerMap))
idx := 0
for _, controller := range controllerMap {
results[idx] = controller
idx++
}
return results
}
func (resources *ResourceProvider) addResourcesFromReader(reader io.Reader) error {
contents, err := ioutil.ReadAll(reader)
contents, err := io.ReadAll(reader)
if err != nil {
logrus.Errorf("Error reading from %v: %v", reader, err)
return err
@@ -471,6 +441,7 @@ func (resources *ResourceProvider) addResourceFromString(contents string) error
if err != nil {
return err
}
workload.OriginalObjectYAML = contentBytes
resources.Resources.addResource(workload)
} else {
newResource, err := NewGenericResourceFromBytes(contentBytes)
+26 -21
View File
@@ -17,7 +17,8 @@ package kube
import (
"bytes"
"context"
"io/ioutil"
"fmt"
"os"
"testing"
"time"
@@ -47,8 +48,8 @@ func TestGetResourcesFromPath(t *testing.T) {
namespaceCount[controller.ObjectMeta.GetNamespace()]++
}
}
assert.Equal(t, 11, provider.Resources.GetLength())
assert.Equal(t, 10, namespaceCount[""])
assert.Equal(t, 10, provider.Resources.GetLength())
assert.Equal(t, 9, namespaceCount[""])
assert.Equal(t, 1, namespaceCount["two"])
}
@@ -64,8 +65,8 @@ func TestGetMultipleResourceFromSingleFile(t *testing.T) {
assert.Equal(t, 0, len(resources.Nodes), "Should not have any nodes")
assert.Equal(t, 1, len(resources.Resources["extensions/Deployment"]), "Should have one controller")
assert.Equal(t, "dashboard", resources.Resources["extensions/Deployment"][0].PodSpec.Containers[0].Name)
assert.Equal(t, 1, len(resources.Resources["apps/Deployment"]), "Should have one controller")
assert.Equal(t, "dashboard", resources.Resources["apps/Deployment"][0].PodSpec.Containers[0].Name)
assert.Equal(t, 2, len(resources.Namespaces), "Should have a namespace")
assert.Equal(t, "polaris", resources.Namespaces[0].ObjectMeta.Name)
@@ -78,7 +79,7 @@ func TestGetMultipleResourceFromBadFile(t *testing.T) {
}
func TestAddResourcesFromReader(t *testing.T) {
contents, err := ioutil.ReadFile("./test_files/test_2/multi.yaml")
contents, err := os.ReadFile("./test_files/test_2/multi.yaml")
assert.NoError(t, err)
reader := bytes.NewBuffer(contents)
resources := newResourceProvider("unknown", "Path", "-")
@@ -87,8 +88,8 @@ func TestAddResourcesFromReader(t *testing.T) {
assert.Equal(t, 0, len(resources.Nodes), "Should not have any nodes")
assert.Equal(t, 1, len(resources.Resources["extensions/Deployment"]), "Should have one controller")
assert.Equal(t, "dashboard", resources.Resources["extensions/Deployment"][0].PodSpec.Containers[0].Name)
assert.Equal(t, 1, len(resources.Resources["apps/Deployment"]), "Should have one controller")
assert.Equal(t, "dashboard", resources.Resources["apps/Deployment"][0].PodSpec.Containers[0].Name)
assert.Equal(t, 2, len(resources.Namespaces), "Should have a namespace")
assert.Equal(t, "polaris", resources.Namespaces[0].ObjectMeta.Name)
@@ -146,25 +147,29 @@ func TestGetResourceFromAPI(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
resources, err := CreateResourceProviderFromAPI(context.Background(), k8s, tt.clusterName, &dynamicInterface, tt.config)
resources, err := CreateResourceProviderFromAPI(context.Background(), k8s, tt.clusterName, dynamicInterface, tt.config)
if tt.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.want.SourceType, resources.SourceType)
assert.Equal(t, tt.want.SourceName, resources.SourceName)
assert.IsType(t, tt.want.CreationTime, resources.CreationTime)
assert.Equal(t, 0, len(resources.Nodes), "Should not have any nodes")
assert.Equal(t, 5, len(resources.Resources), "Should have 5 controllers")
if assert.NoError(t, err) {
assert.Equal(t, tt.want.SourceType, resources.SourceType)
assert.Equal(t, tt.want.SourceName, resources.SourceName)
assert.IsType(t, tt.want.CreationTime, resources.CreationTime)
assert.Equal(t, 0, len(resources.Nodes), "Should not have any nodes")
for k, v := range resources.Resources {
fmt.Println("cont", k, v)
}
assert.Equal(t, 5, len(resources.Resources), "Should have 5 controllers")
for _, controllers := range resources.Resources {
for _, ctrl := range controllers {
expectedNames[ctrl.ObjectMeta.GetName()] = true
for _, controllers := range resources.Resources {
for _, ctrl := range controllers {
expectedNames[ctrl.ObjectMeta.GetName()] = true
}
}
for name, val := range expectedNames {
assert.Equal(t, true, val, name)
}
}
for name, val := range expectedNames {
assert.Equal(t, true, val, name)
}
}
})
+1 -1
View File
@@ -1,4 +1,4 @@
apiVersion: batch/v1beta1
apiVersion: batch/v1
kind: CronJob
metadata:
name: test
+1 -1
View File
@@ -1,4 +1,4 @@
apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment
+1 -1
View File
@@ -1,4 +1,4 @@
apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment-2
@@ -1,19 +0,0 @@
apiVersion: v1
kind: ReplicationController
metadata:
name: test
spec:
replicas: 1
selector:
app: test
template:
metadata:
name: test
labels:
app: test
spec:
containers:
- name: test
image: busybox
command: ["tail"]
args: ["-f", "/dev/null"]
+1 -1
View File
@@ -6,7 +6,7 @@ metadata:
name: polaris
---
# Source: polaris/templates/dashboard.deployment.yaml
apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
+1 -1
View File
@@ -1,5 +1,5 @@
--
# Source: polaris/templates/dashboard.deployment.yaml
apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
::::

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