1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-28 18:38:40 +00:00

feat: add exclude roles/cluster roles support in configmap ()

* feat: add exclude roles/cluster roles support in configmap

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* update chart

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* filter handler

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

---------

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2023-04-04 13:59:02 +02:00 committed by GitHub
parent 80fc3013d3
commit 298e250693
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 87 additions and 22 deletions

View file

@ -8,6 +8,7 @@
- Refactored `kyverno` chart, migration instructions are available in chart `README.md`.
- Image references in the json context are not mutated to canonical form anymore, do not assume a registry domain is always present.
- Added support for configuring webhook annotations in the config map through `webhookAnnotations` stanza.
- Added `excludeRoles` and `excludeClusterRoles` support in configuration.
## v1.9.0-rc.1

View file

@ -40,3 +40,5 @@ annotations:
description: allow overriding PDB api version
- kind: fixed
description: missing image pull secrets in helm hooks
- kind: added
description: support `excludeRoles` and `excludeClusterRoles` in config

View file

@ -174,6 +174,8 @@ In `v3` chart values changed significantly, please read the instructions below t
- Image references are now using the `registry` setting, if you override the registry or repository fields please use `registry` (`--set image.registry=ghcr.io --set image.repository=kyverno/kyverno` instead of `--set image.repository=ghcr.io/kyverno/kyverno`).
- Admission controller `Deployment` name changed from `kyverno` to `kyverno-admission-controller`.
- `config.excludeUsername` was renamed to `config.excludeUsernames`
- `config.excludeGroupRole` was renamed to `config.excludeGroups`
## Uninstalling the Chart
@ -200,8 +202,8 @@ The command removes all the Kubernetes components associated with the chart and
| config.annotations | object | `{}` | Additional annotations to add to the configmap. |
| config.enableDefaultRegistryMutation | bool | `true` | Enable registry mutation for container images. Enabled by default. |
| config.defaultRegistry | string | `"docker.io"` | The registry hostname used for the image mutation. |
| config.excludeGroupRole | list | `[]` | Exclude group role |
| config.excludeUsername | list | `[]` | Exclude username |
| config.excludeGroups | list | `[]` | Exclude groups |
| config.excludeUsernames | list | `[]` | Exclude usernames |
| config.excludeBackgroundUsernames | list | `[]` | Exclude usernames for mutateExisting and generate policies |
| config.generateSuccessEvents | bool | `false` | Generate success events. |
| config.resourceFilters | list | See [values.yaml](values.yaml) | Resource types to be skipped by the Kyverno policy engine. Make sure to surround each entry in quotes so that it doesn't get parsed as a nested YAML list. These are joined together without spaces, run through `tpl`, and the result is set in the config map. |

View file

@ -174,6 +174,8 @@ In `v3` chart values changed significantly, please read the instructions below t
- Image references are now using the `registry` setting, if you override the registry or repository fields please use `registry` (`--set image.registry=ghcr.io --set image.repository=kyverno/kyverno` instead of `--set image.repository=ghcr.io/kyverno/kyverno`).
- Admission controller `Deployment` name changed from `kyverno` to `kyverno-admission-controller`.
- `config.excludeUsername` was renamed to `config.excludeUsernames`
- `config.excludeGroupRole` was renamed to `config.excludeGroups`
## Uninstalling the Chart

View file

@ -16,8 +16,17 @@ data:
defaultRegistry: {{ . | quote }}
{{- end }}
generateSuccessEvents: {{ .Values.config.generateSuccessEvents | quote }}
{{- with .Values.config.excludeGroupRole }}
excludeGroupRole: {{ join "," . | quote }}
{{- with .Values.config.excludeGroups }}
excludeGroups: {{ join "," . | quote }}
{{- end -}}
{{- with .Values.config.excludeUsernames }}
excludeUsernames: {{ join "," . | quote }}
{{- end -}}
{{- with .Values.config.excludeRoles }}
excludeRoles: {{ join "," . | quote }}
{{- end -}}
{{- with .Values.config.excludeClusterRoles }}
excludeClusterRoles: {{ join "," . | quote }}
{{- end -}}
{{- $backgroundUsernames := (printf "system:serviceaccount:%s:%s" (include "kyverno.namespace" .) (include "kyverno.background-controller.serviceAccountName" .)) }}
{{- if .Values.config.excludeBackgroundUsernames }}
@ -26,9 +35,6 @@ data:
{{- else }}
excludeBackgroundUsernames: {{ $backgroundUsernames }}
{{- end -}}
{{- with .Values.config.excludeUsername }}
excludeUsername: {{ join "," . | quote }}
{{- end -}}
{{- if .Values.config.resourceFilters }}
resourceFilters: {{ include "kyverno.config.resourceFilters" . | quote }}
{{- end -}}

View file

@ -49,11 +49,11 @@ config:
# -- The registry hostname used for the image mutation.
defaultRegistry: docker.io
# -- Exclude group role
excludeGroupRole: []
# -- Exclude groups
excludeGroups: []
# -- Exclude username
excludeUsername: []
# -- Exclude usernames
excludeUsernames: []
# -- Exclude usernames for mutateExisting and generate policies
excludeBackgroundUsernames: []

View file

@ -139,10 +139,14 @@ type Configuration interface {
GetEnableDefaultRegistryMutation() bool
// ToFilter checks if the given resource is set to be filtered in the configuration
ToFilter(kind, namespace, name string) bool
// GetExcludedGroups return exclude groups
// GetExcludedGroups return excluded groups
GetExcludedGroups() []string
// GetExcludedUsernames return exclude usernames
// GetExcludedUsernames return excluded usernames
GetExcludedUsernames() []string
// GetExcludedRoles return excluded roles
GetExcludedRoles() []string
// GetExcludedClusterRoles return excluded roles
GetExcludedClusterRoles() []string
// GetExcludedBackgroundUsernames return exclude usernames for mutateExisting and generate policies
GetExcludedBackgroundUsernames() []string
// GetGenerateSuccessEvents return if should generate success events
@ -161,6 +165,8 @@ type configuration struct {
enableDefaultRegistryMutation bool
excludedGroups []string
excludedUsernames []string
excludedRoles []string
excludedClusterRoles []string
excludeBackgroundUsernames []string
filters []filter
generateSuccessEvents bool
@ -227,6 +233,18 @@ func (cd *configuration) GetExcludedUsernames() []string {
return cd.excludedUsernames
}
func (cd *configuration) GetExcludedRoles() []string {
cd.mux.RLock()
defer cd.mux.RUnlock()
return cd.excludedRoles
}
func (cd *configuration) GetExcludedClusterRoles() []string {
cd.mux.RLock()
defer cd.mux.RUnlock()
return cd.excludedClusterRoles
}
func (cd *configuration) GetExcludedBackgroundUsernames() []string {
cd.mux.RLock()
defer cd.mux.RUnlock()
@ -276,6 +294,8 @@ func (cd *configuration) load(cm *corev1.ConfigMap) {
cd.filters = []filter{}
cd.excludedUsernames = []string{}
cd.excludedGroups = []string{}
cd.excludedRoles = []string{}
cd.excludedClusterRoles = []string{}
cd.generateSuccessEvents = false
cd.webhooks = nil
cd.excludedGroups = append(cd.excludedGroups, defaultExcludedGroups...)
@ -305,25 +325,39 @@ func (cd *configuration) load(cm *corev1.ConfigMap) {
cd.enableDefaultRegistryMutation = newEnableDefaultRegistryMutation
}
// load excludeGroupRole
excludedGroups, ok := cm.Data["excludeGroupRole"]
excludedGroups, ok := cm.Data["excludeGroups"]
if !ok {
logger.V(6).Info("configuration: No excludeGroupRole defined in ConfigMap")
logger.V(6).Info("configuration: No excludeGroups defined in ConfigMap")
} else {
cd.excludedGroups = parseRbac(excludedGroups)
cd.excludedGroups = parseStrings(excludedGroups)
}
// load excludeUsername
excludedUsernames, ok := cm.Data["excludeUsername"]
excludedUsernames, ok := cm.Data["excludeUsernames"]
if !ok {
logger.V(6).Info("configuration: No excludeUsername defined in ConfigMap")
logger.V(6).Info("configuration: No excludeUsernames defined in ConfigMap")
} else {
cd.excludedUsernames = parseRbac(excludedUsernames)
cd.excludedUsernames = parseStrings(excludedUsernames)
}
// load excludeRoles
excludedRoles, ok := cm.Data["excludeRoles"]
if !ok {
logger.V(6).Info("configuration: No excludeRoles defined in ConfigMap")
} else {
cd.excludedRoles = parseStrings(excludedRoles)
}
// load excludeClusterRoles
excludedClusterRoles, ok := cm.Data["excludeClusterRoles"]
if !ok {
logger.V(6).Info("configuration: No excludeClusterRoles defined in ConfigMap")
} else {
cd.excludedClusterRoles = parseStrings(excludedClusterRoles)
}
// load excludeBackgroundUsernames
excludeBackgroundUsernames, ok := cm.Data["excludeBackgroundUsernames"]
if !ok {
logger.V(6).Info("configuration: No excludeBackgroundUsernames defined in ConfigMap")
} else {
cd.excludeBackgroundUsernames = parseRbac(excludeBackgroundUsernames)
cd.excludeBackgroundUsernames = parseStrings(excludeBackgroundUsernames)
}
// load generateSuccessEvents
generateSuccessEvents, ok := cm.Data["generateSuccessEvents"]
@ -365,6 +399,8 @@ func (cd *configuration) unload() {
cd.enableDefaultRegistryMutation = true
cd.excludedUsernames = []string{}
cd.excludedGroups = []string{}
cd.excludedRoles = []string{}
cd.excludedClusterRoles = []string{}
cd.generateSuccessEvents = false
cd.webhooks = nil
cd.webhookAnnotations = nil

View file

@ -21,7 +21,7 @@ func parseWebhooks(in string) ([]WebhookConfig, error) {
return webhookCfgs, nil
}
func parseRbac(in string) []string {
func parseStrings(in string) []string {
var out []string
for _, in := range strings.Split(in, ",") {
in := strings.TrimSpace(in)

View file

@ -37,7 +37,7 @@ func Test_parseRbac(t *testing.T) {
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := parseRbac(tt.args.in); !reflect.DeepEqual(got, tt.want) {
if got := parseStrings(tt.args.in); !reflect.DeepEqual(got, tt.want) {
t.Errorf("parseRbac() = %v, want %v", got, tt.want)
}
})

View file

@ -41,6 +41,22 @@ func (inner AdmissionHandler) withFilter(c config.Configuration) AdmissionHandle
}
}
}
// filter by roles
for _, role := range c.GetExcludedRoles() {
for _, candidate := range request.Roles {
if wildcard.Match(role, candidate) {
return admissionutils.ResponseSuccess(request.UID)
}
}
}
// filter by cluster roles
for _, clusterRole := range c.GetExcludedClusterRoles() {
for _, candidate := range request.ClusterRoles {
if wildcard.Match(clusterRole, candidate) {
return admissionutils.ResponseSuccess(request.UID)
}
}
}
// filter by resource filters
if c.ToFilter(request.Kind.Kind, request.Namespace, request.Name) {
return admissionutils.ResponseSuccess(request.UID)