mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-14 11:57:48 +00:00
remove wildcard permissions (#10785)
* remove wildcard permissions Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update codegen Signed-off-by: Jim Bugwadia <jim@nirmata.com> * codegen Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix background controller perms Signed-off-by: Jim Bugwadia <jim@nirmata.com> * remove secrets perm Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix reports-controller role Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add wildcard check and limit generate policy checks based on `synchronize` Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update manifest Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix permissions Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix wildcard check Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update default QPS and burst for better performance and to prevent test failure Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix test permissions Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix test permissions Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix test permissions Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix test permissions Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix test permissions Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix test permissions Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix test permissions Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix perms Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix perms Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix test permissions Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix test permissions Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix merge issues Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix merge issues Signed-off-by: Jim Bugwadia <jim@nirmata.com> --------- Signed-off-by: Jim Bugwadia <jim@nirmata.com> Co-authored-by: Mariam Fahmy <mariam.fahmy@nirmata.com>
This commit is contained in:
parent
0c2a88638b
commit
f06399200c
189 changed files with 2232 additions and 311 deletions
|
@ -358,6 +358,8 @@ The chart values are organised per component.
|
|||
| admissionController.featuresOverride | object | `{"admissionReports":{"backPressureThreshold":1000}}` | Overrides features defined at the root level |
|
||||
| admissionController.featuresOverride.admissionReports.backPressureThreshold | int | `1000` | Max number of admission reports allowed in flight until the admission controller stops creating new ones |
|
||||
| admissionController.rbac.create | bool | `true` | Create RBAC resources |
|
||||
| admissionController.rbac.createViewRoleBinding | bool | `true` | Create rolebinding to view role |
|
||||
| admissionController.rbac.viewRoleName | string | `"view"` | The view role to use in the rolebinding |
|
||||
| admissionController.rbac.serviceAccount.name | string | `nil` | The ServiceAccount name |
|
||||
| admissionController.rbac.serviceAccount.annotations | object | `{}` | Annotations for the ServiceAccount |
|
||||
| admissionController.rbac.coreClusterRole.extraResources | list | See [values.yaml](values.yaml) | Extra resource permissions to add in the core cluster role. This was introduced to avoid breaking change in the chart but should ideally be moved in `clusterRole.extraResources`. |
|
||||
|
@ -454,6 +456,8 @@ The chart values are organised per component.
|
|||
| backgroundController.featuresOverride | object | `{}` | Overrides features defined at the root level |
|
||||
| backgroundController.enabled | bool | `true` | Enable background controller. |
|
||||
| backgroundController.rbac.create | bool | `true` | Create RBAC resources |
|
||||
| backgroundController.rbac.createViewRoleBinding | bool | `true` | Create rolebinding to view role |
|
||||
| backgroundController.rbac.viewRoleName | string | `"view"` | The view role to use in the rolebinding |
|
||||
| backgroundController.rbac.serviceAccount.name | string | `nil` | Service account name |
|
||||
| backgroundController.rbac.serviceAccount.annotations | object | `{}` | Annotations for the ServiceAccount |
|
||||
| backgroundController.rbac.coreClusterRole.extraResources | list | See [values.yaml](values.yaml) | Extra resource permissions to add in the core cluster role. This was introduced to avoid breaking change in the chart but should ideally be moved in `clusterRole.extraResources`. |
|
||||
|
@ -606,6 +610,8 @@ The chart values are organised per component.
|
|||
| reportsController.featuresOverride | object | `{}` | Overrides features defined at the root level |
|
||||
| reportsController.enabled | bool | `true` | Enable reports controller. |
|
||||
| reportsController.rbac.create | bool | `true` | Create RBAC resources |
|
||||
| reportsController.rbac.createViewRoleBinding | bool | `true` | Create rolebinding to view role |
|
||||
| reportsController.rbac.viewRoleName | string | `"view"` | The view role to use in the rolebinding |
|
||||
| reportsController.rbac.serviceAccount.name | string | `nil` | Service account name |
|
||||
| reportsController.rbac.serviceAccount.annotations | object | `{}` | Annotations for the ServiceAccount |
|
||||
| reportsController.rbac.coreClusterRole.extraResources | list | See [values.yaml](values.yaml) | Extra resource permissions to add in the core cluster role. This was introduced to avoid breaking change in the chart but should ideally be moved in `clusterRole.extraResources`. |
|
||||
|
|
|
@ -7,6 +7,8 @@ metadata:
|
|||
{{- include "kyverno.admission-controller.labels" . | nindent 4 }}
|
||||
aggregationRule:
|
||||
clusterRoleSelectors:
|
||||
- matchLabels:
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
- matchLabels:
|
||||
{{- include "kyverno.admission-controller.matchLabels" . | nindent 8 }}
|
||||
---
|
||||
|
|
|
@ -13,4 +13,21 @@ subjects:
|
|||
- kind: ServiceAccount
|
||||
name: {{ template "kyverno.admission-controller.serviceAccountName" . }}
|
||||
namespace: {{ template "kyverno.namespace" . }}
|
||||
{{- if .Values.admissionController.rbac.createViewRoleBinding }}
|
||||
---
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: {{ template "kyverno.admission-controller.roleName" . }}:view
|
||||
labels:
|
||||
{{- include "kyverno.admission-controller.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: {{ .Values.admissionController.rbac.viewRoleName }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ template "kyverno.admission-controller.serviceAccountName" . }}
|
||||
namespace: {{ template "kyverno.namespace" . }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
|
|
@ -131,6 +131,7 @@ spec:
|
|||
- --caSecretName={{ template "kyverno.admission-controller.serviceName" . }}.{{ template "kyverno.namespace" . }}.svc.kyverno-tls-ca
|
||||
- --tlsSecretName={{ template "kyverno.admission-controller.serviceName" . }}.{{ template "kyverno.namespace" . }}.svc.kyverno-tls-pair
|
||||
- --backgroundServiceAccountName=system:serviceaccount:{{ include "kyverno.namespace" . }}:{{ include "kyverno.background-controller.serviceAccountName" . }}
|
||||
- --reportsServiceAccountName=system:serviceaccount:{{ include "kyverno.namespace" . }}:{{ include "kyverno.reports-controller.serviceAccountName" . }}
|
||||
- --servicePort={{ .Values.admissionController.service.port }}
|
||||
- --webhookServerPort={{ .Values.admissionController.webhookServer.port }}
|
||||
{{- if .Values.admissionController.tracing.enabled }}
|
||||
|
|
|
@ -8,6 +8,8 @@ metadata:
|
|||
{{- include "kyverno.background-controller.labels" . | nindent 4 }}
|
||||
aggregationRule:
|
||||
clusterRoleSelectors:
|
||||
- matchLabels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
- matchLabels:
|
||||
{{- include "kyverno.background-controller.matchLabels" . | nindent 8 }}
|
||||
---
|
||||
|
@ -28,7 +30,9 @@ rules:
|
|||
- kyverno.io
|
||||
resources:
|
||||
- policies
|
||||
- policies/status
|
||||
- clusterpolicies
|
||||
- clusterpolicies/status
|
||||
- policyexceptions
|
||||
- updaterequests
|
||||
- updaterequests/status
|
||||
|
|
|
@ -11,8 +11,25 @@ roleRef:
|
|||
kind: ClusterRole
|
||||
name: {{ template "kyverno.background-controller.roleName" . }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ template "kyverno.background-controller.serviceAccountName" . }}
|
||||
namespace: {{ template "kyverno.namespace" . }}
|
||||
{{- if .Values.backgroundController.rbac.createViewRoleBinding }}
|
||||
---
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: {{ template "kyverno.background-controller.roleName" . }}:view
|
||||
labels:
|
||||
{{- include "kyverno.background-controller.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: {{ .Values.backgroundController.rbac.viewRoleName }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ template "kyverno.background-controller.serviceAccountName" . }}
|
||||
namespace: {{ template "kyverno.namespace" . }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
|
|
@ -8,6 +8,8 @@ metadata:
|
|||
{{- include "kyverno.cleanup-controller.labels" . | nindent 4 }}
|
||||
aggregationRule:
|
||||
clusterRoleSelectors:
|
||||
- matchLabels:
|
||||
rbac.kyverno.io/aggregate-to-cleanup-controller: "true"
|
||||
- matchLabels:
|
||||
{{- include "kyverno.cleanup-controller.matchLabels" . | nindent 8 }}
|
||||
---
|
||||
|
|
|
@ -8,6 +8,8 @@ metadata:
|
|||
{{- include "kyverno.reports-controller.labels" . | nindent 4 }}
|
||||
aggregationRule:
|
||||
clusterRoleSelectors:
|
||||
- matchLabels:
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
- matchLabels:
|
||||
{{- include "kyverno.reports-controller.matchLabels" . | nindent 8 }}
|
||||
---
|
||||
|
@ -27,7 +29,6 @@ rules:
|
|||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
- configmaps
|
||||
- namespaces
|
||||
verbs:
|
||||
|
|
|
@ -11,8 +11,25 @@ roleRef:
|
|||
kind: ClusterRole
|
||||
name: {{ template "kyverno.reports-controller.roleName" . }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ template "kyverno.reports-controller.serviceAccountName" . }}
|
||||
namespace: {{ template "kyverno.namespace" . }}
|
||||
{{- if .Values.reportsController.rbac.createViewRoleBinding }}
|
||||
---
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: {{ template "kyverno.reports-controller.roleName" . }}:view
|
||||
labels:
|
||||
{{- include "kyverno.reports-controller.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: {{ .Values.reportsController.rbac.viewRoleName }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ template "kyverno.reports-controller.serviceAccountName" . }}
|
||||
namespace: {{ template "kyverno.namespace" . }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
|
|
@ -19,6 +19,14 @@ rules:
|
|||
resourceNames:
|
||||
- {{ include "kyverno.config.configMapName" . }}
|
||||
- {{ include "kyverno.config.metricsConfigMapName" . }}
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- coordination.k8s.io
|
||||
resources:
|
||||
|
|
|
@ -697,6 +697,12 @@ admissionController:
|
|||
# -- Create RBAC resources
|
||||
create: true
|
||||
|
||||
# -- Create rolebinding to view role
|
||||
createViewRoleBinding: true
|
||||
|
||||
# -- The view role to use in the rolebinding
|
||||
viewRoleName: view
|
||||
|
||||
serviceAccount:
|
||||
# -- The ServiceAccount name
|
||||
name:
|
||||
|
@ -709,15 +715,7 @@ admissionController:
|
|||
# -- Extra resource permissions to add in the core cluster role.
|
||||
# This was introduced to avoid breaking change in the chart but should ideally be moved in `clusterRole.extraResources`.
|
||||
# @default -- See [values.yaml](values.yaml)
|
||||
extraResources:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
extraResources: []
|
||||
|
||||
clusterRole:
|
||||
# -- Extra resource permissions to add in the cluster role
|
||||
|
@ -1108,6 +1106,12 @@ backgroundController:
|
|||
# -- Create RBAC resources
|
||||
create: true
|
||||
|
||||
# -- Create rolebinding to view role
|
||||
createViewRoleBinding: true
|
||||
|
||||
# -- The view role to use in the rolebinding
|
||||
viewRoleName: view
|
||||
|
||||
serviceAccount:
|
||||
# -- Service account name
|
||||
name:
|
||||
|
@ -1121,14 +1125,6 @@ backgroundController:
|
|||
# This was introduced to avoid breaking change in the chart but should ideally be moved in `clusterRole.extraResources`.
|
||||
# @default -- See [values.yaml](values.yaml)
|
||||
extraResources:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- networking.k8s.io
|
||||
resources:
|
||||
|
@ -1154,7 +1150,6 @@ backgroundController:
|
|||
- ''
|
||||
resources:
|
||||
- configmaps
|
||||
- secrets
|
||||
- resourcequotas
|
||||
- limitranges
|
||||
verbs:
|
||||
|
@ -1718,6 +1713,12 @@ reportsController:
|
|||
# -- Create RBAC resources
|
||||
create: true
|
||||
|
||||
# -- Create rolebinding to view role
|
||||
createViewRoleBinding: true
|
||||
|
||||
# -- The view role to use in the rolebinding
|
||||
viewRoleName: view
|
||||
|
||||
serviceAccount:
|
||||
# -- Service account name
|
||||
name:
|
||||
|
@ -1730,15 +1731,7 @@ reportsController:
|
|||
# -- Extra resource permissions to add in the core cluster role.
|
||||
# This was introduced to avoid breaking change in the chart but should ideally be moved in `clusterRole.extraResources`.
|
||||
# @default -- See [values.yaml](values.yaml)
|
||||
extraResources:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
extraResources: []
|
||||
|
||||
clusterRole:
|
||||
# -- Extra resource permissions to add in the cluster role
|
||||
|
|
|
@ -273,7 +273,8 @@ func (c *ApplyCommandConfig) applyPolicytoResource(
|
|||
validPolicies := make([]kyvernov1.PolicyInterface, 0, len(policies))
|
||||
for _, pol := range policies {
|
||||
// TODO we should return this info to the caller
|
||||
_, err := policyvalidation.Validate(pol, nil, nil, nil, true, config.KyvernoUserName(config.KyvernoServiceAccountName()))
|
||||
sa := config.KyvernoUserName(config.KyvernoServiceAccountName())
|
||||
_, err := policyvalidation.Validate(pol, nil, nil, nil, true, sa, sa)
|
||||
if err != nil {
|
||||
log.Log.Error(err, "policy validation error")
|
||||
rc.IncrementError(1)
|
||||
|
|
|
@ -40,7 +40,8 @@ func (o options) execute(ctx context.Context, dir string, keychain authn.Keychai
|
|||
return fmt.Errorf("unable to read policy file or directory %s (%w)", dir, err)
|
||||
}
|
||||
for _, policy := range results.Policies {
|
||||
if _, err := policyvalidation.Validate(policy, nil, nil, nil, true, config.KyvernoUserName(config.KyvernoServiceAccountName())); err != nil {
|
||||
sa := config.KyvernoUserName(config.KyvernoServiceAccountName())
|
||||
if _, err := policyvalidation.Validate(policy, nil, nil, nil, true, sa, sa); err != nil {
|
||||
return fmt.Errorf("validating policy %s: %v", policy.GetName(), err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -153,7 +153,8 @@ func runTest(out io.Writer, testCase test.TestCase, registryAccess bool) ([]engi
|
|||
validPolicies := make([]kyvernov1.PolicyInterface, 0, len(results.Policies))
|
||||
for _, pol := range results.Policies {
|
||||
// TODO we should return this info to the caller
|
||||
_, err := policyvalidation.Validate(pol, nil, nil, nil, true, config.KyvernoUserName(config.KyvernoServiceAccountName()))
|
||||
sa := config.KyvernoUserName(config.KyvernoServiceAccountName())
|
||||
_, err := policyvalidation.Validate(pol, nil, nil, nil, true, sa, sa)
|
||||
if err != nil {
|
||||
log.Log.Error(err, "skipping invalid policy", "name", pol.GetName())
|
||||
continue
|
||||
|
|
|
@ -144,8 +144,8 @@ type options struct {
|
|||
|
||||
func newOptions() options {
|
||||
return options{
|
||||
clientRateLimitQPS: 20,
|
||||
clientRateLimitBurst: 50,
|
||||
clientRateLimitQPS: 100,
|
||||
clientRateLimitBurst: 200,
|
||||
eventsRateLimitQPS: 1000,
|
||||
eventsRateLimitBurst: 2000,
|
||||
}
|
||||
|
|
|
@ -247,6 +247,7 @@ func main() {
|
|||
servicePort int
|
||||
webhookServerPort int
|
||||
backgroundServiceAccountName string
|
||||
reportsServiceAccountName string
|
||||
maxAPICallResponseLength int64
|
||||
renewBefore time.Duration
|
||||
maxAuditWorkers int
|
||||
|
@ -267,7 +268,8 @@ func main() {
|
|||
flagset.BoolVar(&admissionReports, "admissionReports", true, "Enable or disable admission reports.")
|
||||
flagset.IntVar(&servicePort, "servicePort", 443, "Port used by the Kyverno Service resource and for webhook configurations.")
|
||||
flagset.IntVar(&webhookServerPort, "webhookServerPort", 9443, "Port used by the webhook server.")
|
||||
flagset.StringVar(&backgroundServiceAccountName, "backgroundServiceAccountName", "", "Background service account name.")
|
||||
flagset.StringVar(&backgroundServiceAccountName, "backgroundServiceAccountName", "", "Background controller service account name.")
|
||||
flagset.StringVar(&reportsServiceAccountName, "reportsServiceAccountName", "", "Reports controller service account name.")
|
||||
flagset.StringVar(&caSecretName, "caSecretName", "", "Name of the secret containing CA.")
|
||||
flagset.StringVar(&tlsSecretName, "tlsSecretName", "", "Name of the secret containing TLS pair.")
|
||||
flagset.Int64Var(&maxAPICallResponseLength, "maxAPICallResponseLength", 10*1000*1000, "Configure the value of maximum allowed GET response size from API Calls")
|
||||
|
@ -516,6 +518,7 @@ func main() {
|
|||
setup.KyvernoDynamicClient,
|
||||
setup.KyvernoClient,
|
||||
backgroundServiceAccountName,
|
||||
reportsServiceAccountName,
|
||||
)
|
||||
ephrs, err := StartAdmissionReportsCounter(signalCtx, setup.MetadataClient)
|
||||
if err != nil {
|
||||
|
@ -544,6 +547,7 @@ func main() {
|
|||
eventGenerator,
|
||||
admissionReports,
|
||||
backgroundServiceAccountName,
|
||||
reportsServiceAccountName,
|
||||
setup.Jp,
|
||||
maxAuditWorkers,
|
||||
maxAuditCapacity,
|
||||
|
|
|
@ -47215,6 +47215,8 @@ metadata:
|
|||
app.kubernetes.io/version: latest
|
||||
aggregationRule:
|
||||
clusterRoleSelectors:
|
||||
- matchLabels:
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
- matchLabels:
|
||||
app.kubernetes.io/component: admission-controller
|
||||
app.kubernetes.io/instance: kyverno
|
||||
|
@ -47346,14 +47348,6 @@ rules:
|
|||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
|
@ -47366,6 +47360,8 @@ metadata:
|
|||
app.kubernetes.io/version: latest
|
||||
aggregationRule:
|
||||
clusterRoleSelectors:
|
||||
- matchLabels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
- matchLabels:
|
||||
app.kubernetes.io/component: background-controller
|
||||
app.kubernetes.io/instance: kyverno
|
||||
|
@ -47391,7 +47387,9 @@ rules:
|
|||
- kyverno.io
|
||||
resources:
|
||||
- policies
|
||||
- policies/status
|
||||
- clusterpolicies
|
||||
- clusterpolicies/status
|
||||
- policyexceptions
|
||||
- updaterequests
|
||||
- updaterequests/status
|
||||
|
@ -47427,14 +47425,6 @@ rules:
|
|||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- networking.k8s.io
|
||||
resources:
|
||||
|
@ -47460,7 +47450,6 @@ rules:
|
|||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
- secrets
|
||||
- resourcequotas
|
||||
- limitranges
|
||||
verbs:
|
||||
|
@ -47480,6 +47469,8 @@ metadata:
|
|||
app.kubernetes.io/version: latest
|
||||
aggregationRule:
|
||||
clusterRoleSelectors:
|
||||
- matchLabels:
|
||||
rbac.kyverno.io/aggregate-to-cleanup-controller: "true"
|
||||
- matchLabels:
|
||||
app.kubernetes.io/component: cleanup-controller
|
||||
app.kubernetes.io/instance: kyverno
|
||||
|
@ -47770,6 +47761,8 @@ metadata:
|
|||
app.kubernetes.io/version: latest
|
||||
aggregationRule:
|
||||
clusterRoleSelectors:
|
||||
- matchLabels:
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
- matchLabels:
|
||||
app.kubernetes.io/component: reports-controller
|
||||
app.kubernetes.io/instance: kyverno
|
||||
|
@ -47794,7 +47787,6 @@ rules:
|
|||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
- configmaps
|
||||
- namespaces
|
||||
verbs:
|
||||
|
@ -47856,14 +47848,6 @@ rules:
|
|||
verbs:
|
||||
- create
|
||||
- patch
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
---
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
|
@ -47885,6 +47869,24 @@ subjects:
|
|||
---
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: kyverno:admission-controller:view
|
||||
labels:
|
||||
app.kubernetes.io/component: admission-controller
|
||||
app.kubernetes.io/instance: kyverno
|
||||
app.kubernetes.io/part-of: kyverno
|
||||
app.kubernetes.io/version: latest
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: view
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: kyverno-admission-controller
|
||||
namespace: kyverno
|
||||
---
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: kyverno:background-controller
|
||||
labels:
|
||||
|
@ -47903,6 +47905,24 @@ subjects:
|
|||
---
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: kyverno:background-controller:view
|
||||
labels:
|
||||
app.kubernetes.io/component: background-controller
|
||||
app.kubernetes.io/instance: kyverno
|
||||
app.kubernetes.io/part-of: kyverno
|
||||
app.kubernetes.io/version: latest
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: view
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: kyverno-background-controller
|
||||
namespace: kyverno
|
||||
---
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: kyverno:cleanup-controller
|
||||
labels:
|
||||
|
@ -47937,6 +47957,24 @@ subjects:
|
|||
name: kyverno-reports-controller
|
||||
namespace: kyverno
|
||||
---
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: kyverno:reports-controller:view
|
||||
labels:
|
||||
app.kubernetes.io/component: reports-controller
|
||||
app.kubernetes.io/instance: kyverno
|
||||
app.kubernetes.io/part-of: kyverno
|
||||
app.kubernetes.io/version: latest
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: view
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: kyverno-reports-controller
|
||||
namespace: kyverno
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
|
@ -48119,6 +48157,14 @@ rules:
|
|||
resourceNames:
|
||||
- kyverno
|
||||
- kyverno-metrics
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- coordination.k8s.io
|
||||
resources:
|
||||
|
@ -48441,6 +48487,7 @@ spec:
|
|||
- --caSecretName=kyverno-svc.kyverno.svc.kyverno-tls-ca
|
||||
- --tlsSecretName=kyverno-svc.kyverno.svc.kyverno-tls-pair
|
||||
- --backgroundServiceAccountName=system:serviceaccount:kyverno:kyverno-background-controller
|
||||
- --reportsServiceAccountName=system:serviceaccount:kyverno:kyverno-reports-controller
|
||||
- --servicePort=443
|
||||
- --webhookServerPort=9443
|
||||
- --disableMetrics=false
|
||||
|
|
|
@ -2,22 +2,21 @@ package auth
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/kyverno/kyverno/pkg/auth"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
)
|
||||
|
||||
// Operations provides methods to performing operations on resource
|
||||
type Operations interface {
|
||||
// CanICreate returns 'true' if self can 'create' resource
|
||||
CanICreate(ctx context.Context, gvk, namespace, name, subresource string) (bool, error)
|
||||
// CanIUpdate returns 'true' if self can 'update' resource
|
||||
CanIUpdate(ctx context.Context, gvk, namespace, name, subresource string) (bool, error)
|
||||
// CanIDelete returns 'true' if self can 'delete' resource
|
||||
CanIDelete(ctx context.Context, gvk, namespace, name, subresource string) (bool, error)
|
||||
// CanIGet returns 'true' if self can 'get' resource
|
||||
CanIGet(ctx context.Context, gvk, namespace, name, subresource string) (bool, error)
|
||||
// AuthChecks provides methods to performing operations on resource
|
||||
type AuthChecks interface {
|
||||
// User returns the subject
|
||||
User() string
|
||||
// CanI returns 'true' if user has permissions for all specified verbs.
|
||||
// When the result is 'false' a message with details on missing verbs is returned.
|
||||
CanI(ctx context.Context, verbs []string, gvk, namespace, name, subresource string) (bool, string, error)
|
||||
}
|
||||
|
||||
// Auth provides implementation to check if caller/self/kyverno has access to perofrm operations
|
||||
|
@ -37,9 +36,36 @@ func NewAuth(client dclient.Interface, user string, log logr.Logger) *Auth {
|
|||
return &a
|
||||
}
|
||||
|
||||
func (a *Auth) User() string {
|
||||
return a.user
|
||||
}
|
||||
|
||||
func (a *Auth) CanI(ctx context.Context, verbs []string, gvk, namespace, name, subresource string) (bool, string, error) {
|
||||
var failedVerbs []string
|
||||
for _, v := range verbs {
|
||||
if ok, err := a.check(ctx, v, gvk, namespace, name, subresource); err != nil {
|
||||
return false, "", err
|
||||
} else if !ok {
|
||||
failedVerbs = append(failedVerbs, v)
|
||||
}
|
||||
}
|
||||
|
||||
if len(failedVerbs) > 0 {
|
||||
msg := buildMessage(gvk, subresource, failedVerbs, a.user, namespace)
|
||||
return false, msg, nil
|
||||
}
|
||||
|
||||
return true, "", nil
|
||||
}
|
||||
|
||||
// CanICreate returns 'true' if self can 'create' resource
|
||||
func (a *Auth) CanICreate(ctx context.Context, gvk, namespace, name, subresource string) (bool, error) {
|
||||
canI := auth.NewCanI(a.client.Discovery(), a.client.GetKubeClient().AuthorizationV1().SubjectAccessReviews(), gvk, namespace, name, "create", "", a.user)
|
||||
return a.check(ctx, "create", gvk, namespace, name, subresource)
|
||||
}
|
||||
|
||||
func (a *Auth) check(ctx context.Context, verb, gvk, namespace, name, subresource string) (bool, error) {
|
||||
subjectReview := a.client.GetKubeClient().AuthorizationV1().SubjectAccessReviews()
|
||||
canI := auth.NewCanI(a.client.Discovery(), subjectReview, gvk, namespace, name, verb, subresource, a.user)
|
||||
ok, _, err := canI.RunAccessCheck(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
|
@ -47,32 +73,16 @@ func (a *Auth) CanICreate(ctx context.Context, gvk, namespace, name, subresource
|
|||
return ok, nil
|
||||
}
|
||||
|
||||
// CanIUpdate returns 'true' if self can 'update' resource
|
||||
func (a *Auth) CanIUpdate(ctx context.Context, gvk, namespace, name, subresource string) (bool, error) {
|
||||
canI := auth.NewCanI(a.client.Discovery(), a.client.GetKubeClient().AuthorizationV1().SubjectAccessReviews(), gvk, namespace, name, "update", "", a.user)
|
||||
ok, _, err := canI.RunAccessCheck(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
func buildMessage(gvk string, subresource string, failedVerbs []string, user string, namespace string) string {
|
||||
resource := gvk
|
||||
if subresource != "" {
|
||||
resource = gvk + "/" + subresource
|
||||
}
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
// CanIDelete returns 'true' if self can 'delete' resource
|
||||
func (a *Auth) CanIDelete(ctx context.Context, gvk, namespace, name, subresource string) (bool, error) {
|
||||
canI := auth.NewCanI(a.client.Discovery(), a.client.GetKubeClient().AuthorizationV1().SubjectAccessReviews(), gvk, namespace, name, "delete", "", a.user)
|
||||
ok, _, err := canI.RunAccessCheck(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
permissions := strings.Join(failedVerbs, ",")
|
||||
msg := fmt.Sprintf("%s requires permissions %s for resource %s", user, permissions, resource)
|
||||
if namespace != "" {
|
||||
msg = fmt.Sprintf("%s in namespace %s", msg, namespace)
|
||||
}
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
// CanIGet returns 'true' if self can 'get' resource
|
||||
func (a *Auth) CanIGet(ctx context.Context, gvk, namespace, name, subresource string) (bool, error) {
|
||||
canI := auth.NewCanI(a.client.Discovery(), a.client.GetKubeClient().AuthorizationV1().SubjectAccessReviews(), gvk, namespace, name, "get", "", a.user)
|
||||
ok, _, err := canI.RunAccessCheck(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return ok, nil
|
||||
return msg
|
||||
}
|
||||
|
|
|
@ -11,6 +11,14 @@ func NewFakeAuth() *FakeAuth {
|
|||
return &a
|
||||
}
|
||||
|
||||
func (a *FakeAuth) User() string {
|
||||
return "fake"
|
||||
}
|
||||
|
||||
func (a *FakeAuth) CanI(ctx context.Context, verbs []string, gvk, namespace, name, subresource string) (bool, string, error) {
|
||||
return true, "", nil
|
||||
}
|
||||
|
||||
// CanICreate returns 'true'
|
||||
func (a *FakeAuth) CanICreate(_ context.Context, kind, namespace, name, sub string) (bool, error) {
|
||||
return true, nil
|
||||
|
|
|
@ -17,7 +17,7 @@ type FakeGenerate struct {
|
|||
func NewFakeGenerate(rule kyvernov1.Generation) *FakeGenerate {
|
||||
g := FakeGenerate{}
|
||||
g.rule = rule
|
||||
g.authCheck = fake.NewFakeAuth()
|
||||
g.authChecker = fake.NewFakeAuth()
|
||||
g.log = logging.GlobalLogger()
|
||||
return &g
|
||||
}
|
||||
|
|
|
@ -17,33 +17,30 @@ import (
|
|||
|
||||
// Generate provides implementation to validate 'generate' rule
|
||||
type Generate struct {
|
||||
user string
|
||||
// rule to hold 'generate' rule specifications
|
||||
rule kyvernov1.Generation
|
||||
// authCheck to check access for operations
|
||||
authCheck auth.Operations
|
||||
// logger
|
||||
log logr.Logger
|
||||
user string
|
||||
rule kyvernov1.Generation
|
||||
authChecker auth.AuthChecks
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
// NewGenerateFactory returns a new instance of Generate validation checker
|
||||
func NewGenerateFactory(client dclient.Interface, rule kyvernov1.Generation, user string, log logr.Logger) *Generate {
|
||||
g := Generate{
|
||||
user: user,
|
||||
rule: rule,
|
||||
authCheck: auth.NewAuth(client, user, log),
|
||||
log: log,
|
||||
user: user,
|
||||
rule: rule,
|
||||
authChecker: auth.NewAuth(client, user, log),
|
||||
log: log,
|
||||
}
|
||||
|
||||
return &g
|
||||
}
|
||||
|
||||
// Validate validates the 'generate' rule
|
||||
func (g *Generate) Validate(ctx context.Context) (string, error) {
|
||||
func (g *Generate) Validate(ctx context.Context) (warnings []string, path string, err error) {
|
||||
rule := g.rule
|
||||
if rule.CloneList.Selector != nil {
|
||||
if wildcard.ContainsWildcard(rule.CloneList.Selector.String()) {
|
||||
return "selector", fmt.Errorf("wildcard characters `*/?` not supported")
|
||||
return nil, "selector", fmt.Errorf("wildcard characters `*/?` not supported")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,7 +48,7 @@ func (g *Generate) Validate(ctx context.Context) (string, error) {
|
|||
// TODO: is this required ?? as anchors can only be on pattern and not resource
|
||||
// we can add this check by not sure if its needed here
|
||||
if path, err := common.ValidatePattern(target, "/", nil); err != nil {
|
||||
return fmt.Sprintf("data.%s", path), fmt.Errorf("anchors not supported on generate resources: %v", err)
|
||||
return nil, fmt.Sprintf("data.%s", path), fmt.Errorf("anchors not supported on generate resources: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,19 +59,20 @@ func (g *Generate) Validate(ctx context.Context) (string, error) {
|
|||
// If kind and namespace contain variables, then we cannot resolve then so we skip the processing
|
||||
if rule.ForEachGeneration != nil {
|
||||
for _, forEach := range rule.ForEachGeneration {
|
||||
if err := g.canIGeneratePatterns(ctx, forEach.GeneratePatterns); err != nil {
|
||||
return "foreach", err
|
||||
if err := g.validateAuth(ctx, forEach.GeneratePatterns); err != nil {
|
||||
return nil, "foreach", err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err := g.canIGeneratePatterns(ctx, rule.GeneratePatterns); err != nil {
|
||||
return "", err
|
||||
if err := g.validateAuth(ctx, rule.GeneratePatterns); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
return nil, "", nil
|
||||
}
|
||||
|
||||
func (g *Generate) canIGeneratePatterns(ctx context.Context, generate kyvernov1.GeneratePatterns) error {
|
||||
// validateAuth returns a error if kyverno cannot perform operations
|
||||
func (g *Generate) validateAuth(ctx context.Context, generate kyvernov1.GeneratePatterns) error {
|
||||
if len(generate.CloneList.Kinds) != 0 {
|
||||
for _, kind := range generate.CloneList.Kinds {
|
||||
gvk, sub := parseCloneKind(kind)
|
||||
|
@ -87,44 +85,24 @@ func (g *Generate) canIGeneratePatterns(ctx context.Context, generate kyvernov1.
|
|||
return nil
|
||||
}
|
||||
|
||||
// canIGenerate returns a error if kyverno cannot perform operations
|
||||
func (g *Generate) canIGenerate(ctx context.Context, gvk, namespace, subresource string) error {
|
||||
// Skip if there is variable defined
|
||||
authCheck := g.authCheck
|
||||
if !regex.IsVariable(gvk) {
|
||||
ok, err := authCheck.CanICreate(ctx, gvk, namespace, "", subresource)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("%s does not have permissions to 'create' resource %s/%s/%s. Grant proper permissions to the background controller", g.user, gvk, subresource, namespace)
|
||||
}
|
||||
if regex.IsVariable(gvk) {
|
||||
g.log.V(2).Info("resource Kind uses variables; skipping authorization checks.")
|
||||
return nil
|
||||
}
|
||||
|
||||
ok, err = authCheck.CanIUpdate(ctx, gvk, namespace, "", subresource)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("%s does not have permissions to 'update' resource %s/%s/%s. Grant proper permissions to the background controller", g.user, gvk, subresource, namespace)
|
||||
}
|
||||
verbs := []string{"get", "create"}
|
||||
if g.rule.Synchronize {
|
||||
verbs = []string{"get", "create", "update", "delete"}
|
||||
}
|
||||
|
||||
ok, err = authCheck.CanIGet(ctx, gvk, namespace, "", subresource)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("%s does not have permissions to 'get' resource %s/%s/%s. Grant proper permissions to the background controller", g.user, gvk, subresource, namespace)
|
||||
}
|
||||
ok, msg, err := g.authChecker.CanI(ctx, verbs, gvk, namespace, "", subresource)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ok, err = authCheck.CanIDelete(ctx, gvk, namespace, "", subresource)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("%s does not have permissions to 'delete' resource %s/%s/%s. Grant proper permissions to the background controller", g.user, gvk, subresource, namespace)
|
||||
}
|
||||
} else {
|
||||
g.log.V(2).Info("resource Kind uses variables, so cannot be resolved. Skipping Auth Checks.")
|
||||
if !ok {
|
||||
return fmt.Errorf(msg)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -36,7 +36,7 @@ func Test_Validate_Generate_HasAnchors(t *testing.T) {
|
|||
err = json.Unmarshal(rawGenerate, &genRule)
|
||||
assert.NilError(t, err)
|
||||
checker := NewFakeGenerate(genRule)
|
||||
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||
if _, _, err := checker.Validate(context.TODO()); err != nil {
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ func Test_Validate_Generate_HasAnchors(t *testing.T) {
|
|||
err = json.Unmarshal(rawGenerate, &genRule)
|
||||
assert.NilError(t, err)
|
||||
checker = NewFakeGenerate(genRule)
|
||||
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||
if _, _, err := checker.Validate(context.TODO()); err != nil {
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,11 @@ import (
|
|||
"strings"
|
||||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/engine/variables/regex"
|
||||
"github.com/kyverno/kyverno/pkg/logging"
|
||||
"github.com/kyverno/kyverno/pkg/policy/auth"
|
||||
"github.com/kyverno/kyverno/pkg/policy/auth/fake"
|
||||
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
||||
"go.uber.org/multierr"
|
||||
)
|
||||
|
@ -15,48 +18,53 @@ import (
|
|||
// Mutate provides implementation to validate 'mutate' rule
|
||||
type Mutate struct {
|
||||
mutation kyvernov1.Mutation
|
||||
user string
|
||||
authChecker auth.Operations
|
||||
authChecker auth.AuthChecks
|
||||
}
|
||||
|
||||
// NewMutateFactory returns a new instance of Mutate validation checker
|
||||
func NewMutateFactory(m kyvernov1.Mutation, authChecker auth.Operations, user string) *Mutate {
|
||||
func NewMutateFactory(m kyvernov1.Mutation, client dclient.Interface, mock bool, backgroundSA string) *Mutate {
|
||||
var authCheck auth.AuthChecks
|
||||
if mock {
|
||||
authCheck = fake.NewFakeAuth()
|
||||
} else {
|
||||
authCheck = auth.NewAuth(client, backgroundSA, logging.GlobalLogger())
|
||||
}
|
||||
|
||||
return &Mutate{
|
||||
mutation: m,
|
||||
user: user,
|
||||
authChecker: authChecker,
|
||||
authChecker: authCheck,
|
||||
}
|
||||
}
|
||||
|
||||
// Validate validates the 'mutate' rule
|
||||
func (m *Mutate) Validate(ctx context.Context) (string, error) {
|
||||
func (m *Mutate) Validate(ctx context.Context) (warnings []string, path string, err error) {
|
||||
if m.hasForEach() {
|
||||
if m.hasPatchStrategicMerge() || m.hasPatchesJSON6902() {
|
||||
return "foreach", fmt.Errorf("only one of `foreach`, `patchStrategicMerge`, or `patchesJson6902` is allowed")
|
||||
return nil, "foreach", fmt.Errorf("only one of `foreach`, `patchStrategicMerge`, or `patchesJson6902` is allowed")
|
||||
}
|
||||
|
||||
return m.validateForEach("", m.mutation.ForEachMutation)
|
||||
}
|
||||
|
||||
if m.hasPatchesJSON6902() && m.hasPatchStrategicMerge() {
|
||||
return "foreach", fmt.Errorf("only one of `patchStrategicMerge` or `patchesJson6902` is allowed")
|
||||
return nil, "foreach", fmt.Errorf("only one of `patchStrategicMerge` or `patchesJson6902` is allowed")
|
||||
}
|
||||
|
||||
if m.mutation.Targets != nil {
|
||||
if err := m.validateAuth(ctx, m.mutation.Targets); err != nil {
|
||||
return "targets", fmt.Errorf("auth check fails, additional privileges are required for the service account '%s': %v", m.user, err)
|
||||
return nil, "targets", fmt.Errorf("auth check fails, additional privileges are required for the service account '%s': %v", m.authChecker.User(), err)
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
return nil, "", nil
|
||||
}
|
||||
|
||||
func (m *Mutate) validateForEach(tag string, foreach []kyvernov1.ForEachMutation) (string, error) {
|
||||
func (m *Mutate) validateForEach(tag string, foreach []kyvernov1.ForEachMutation) (warnings []string, path string, err error) {
|
||||
for i, fe := range foreach {
|
||||
tag = tag + fmt.Sprintf("foreach[%d]", i)
|
||||
fem := fe.GetForEachMutation()
|
||||
if len(fem) > 0 {
|
||||
if fe.Context != nil || fe.AnyAllConditions != nil || fe.PatchesJSON6902 != "" || fe.GetPatchStrategicMerge() != nil {
|
||||
return tag, fmt.Errorf("a nested foreach cannot contain other declarations")
|
||||
if fe.Context != nil || fe.AnyAllConditions != nil || fe.PatchesJSON6902 != "" || fe.RawPatchStrategicMerge != nil {
|
||||
return nil, tag, fmt.Errorf("a nested foreach cannot contain other declarations")
|
||||
}
|
||||
|
||||
return m.validateNestedForEach(tag, fem)
|
||||
|
@ -64,19 +72,19 @@ func (m *Mutate) validateForEach(tag string, foreach []kyvernov1.ForEachMutation
|
|||
|
||||
psm := fe.GetPatchStrategicMerge()
|
||||
if (fe.PatchesJSON6902 == "" && psm == nil) || (fe.PatchesJSON6902 != "" && psm != nil) {
|
||||
return tag, fmt.Errorf("only one of `patchStrategicMerge` or `patchesJson6902` is allowed")
|
||||
return nil, tag, fmt.Errorf("only one of `patchStrategicMerge` or `patchesJson6902` is allowed")
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil
|
||||
return nil, "", nil
|
||||
}
|
||||
|
||||
func (m *Mutate) validateNestedForEach(tag string, j []kyvernov1.ForEachMutation) (string, error) {
|
||||
func (m *Mutate) validateNestedForEach(tag string, j []kyvernov1.ForEachMutation) (warnings []string, path string, err error) {
|
||||
if j != nil {
|
||||
return m.validateForEach(tag, j)
|
||||
}
|
||||
|
||||
return "", nil
|
||||
return nil, "", nil
|
||||
}
|
||||
|
||||
func (m *Mutate) hasForEach() bool {
|
||||
|
@ -94,25 +102,20 @@ func (m *Mutate) hasPatchesJSON6902() bool {
|
|||
func (m *Mutate) validateAuth(ctx context.Context, targets []kyvernov1.TargetResourceSpec) error {
|
||||
var errs []error
|
||||
for _, target := range targets {
|
||||
if !regex.IsVariable(target.Kind) {
|
||||
_, _, k, sub := kubeutils.ParseKindSelector(target.Kind)
|
||||
srcKey := k
|
||||
if sub != "" {
|
||||
srcKey = srcKey + "/" + sub
|
||||
}
|
||||
|
||||
if ok, err := m.authChecker.CanIUpdate(ctx, strings.Join([]string{target.APIVersion, k}, "/"), target.Namespace, target.Name, sub); err != nil {
|
||||
errs = append(errs, err)
|
||||
} else if !ok {
|
||||
errs = append(errs, fmt.Errorf("cannot %s/%s/%s in namespace %s", "update", target.APIVersion, srcKey, target.Namespace))
|
||||
}
|
||||
|
||||
if ok, err := m.authChecker.CanIGet(ctx, strings.Join([]string{target.APIVersion, k}, "/"), target.Namespace, target.Name, sub); err != nil {
|
||||
errs = append(errs, err)
|
||||
} else if !ok {
|
||||
errs = append(errs, fmt.Errorf("cannot %s/%s/%s in namespace %s", "get", target.APIVersion, srcKey, target.Namespace))
|
||||
}
|
||||
if regex.IsVariable(target.Kind) {
|
||||
continue
|
||||
}
|
||||
_, _, k, sub := kubeutils.ParseKindSelector(target.Kind)
|
||||
gvk := strings.Join([]string{target.APIVersion, k}, "/")
|
||||
verbs := []string{"get", "update"}
|
||||
ok, msg, err := m.authChecker.CanI(ctx, verbs, gvk, target.Namespace, target.Name, sub)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
errs = append(errs, fmt.Errorf(msg))
|
||||
}
|
||||
}
|
||||
|
||||
return multierr.Combine(errs...)
|
||||
}
|
||||
|
|
|
@ -5,32 +5,53 @@ import (
|
|||
"fmt"
|
||||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/ext/wildcard"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/engine/anchor"
|
||||
"github.com/kyverno/kyverno/pkg/logging"
|
||||
"github.com/kyverno/kyverno/pkg/policy/auth"
|
||||
"github.com/kyverno/kyverno/pkg/policy/auth/fake"
|
||||
"github.com/kyverno/kyverno/pkg/policy/common"
|
||||
)
|
||||
|
||||
// Validate validates a 'validate' rule
|
||||
type Validate struct {
|
||||
// rule to hold 'validate' rule specifications
|
||||
rule *kyvernov1.Validation
|
||||
rule *kyvernov1.Rule
|
||||
validationRule *kyvernov1.Validation
|
||||
authChecker auth.AuthChecks
|
||||
}
|
||||
|
||||
// NewValidateFactory returns a new instance of Mutate validation checker
|
||||
func NewValidateFactory(rule *kyvernov1.Validation) *Validate {
|
||||
m := Validate{
|
||||
rule: rule,
|
||||
func NewValidateFactory(rule *kyvernov1.Rule, client dclient.Interface, mock bool, reportsSA string) *Validate {
|
||||
var authChecker auth.AuthChecks
|
||||
if mock {
|
||||
authChecker = fake.NewFakeAuth()
|
||||
} else {
|
||||
authChecker = auth.NewAuth(client, reportsSA, logging.GlobalLogger())
|
||||
}
|
||||
|
||||
return &m
|
||||
return &Validate{
|
||||
rule: rule,
|
||||
validationRule: &rule.Validation,
|
||||
authChecker: authChecker,
|
||||
}
|
||||
}
|
||||
|
||||
func NewMockValidateFactory(rule *kyvernov1.Rule) *Validate {
|
||||
return &Validate{
|
||||
rule: rule,
|
||||
validationRule: &rule.Validation,
|
||||
authChecker: fake.NewFakeAuth(),
|
||||
}
|
||||
}
|
||||
|
||||
// Validate validates the 'validate' rule
|
||||
func (v *Validate) Validate(ctx context.Context) (string, error) {
|
||||
func (v *Validate) Validate(ctx context.Context) (warnings []string, path string, err error) {
|
||||
if err := v.validateElements(); err != nil {
|
||||
return "", err
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
if target := v.rule.GetPattern(); target != nil {
|
||||
if target := v.validationRule.GetPattern(); target != nil {
|
||||
if path, err := common.ValidatePattern(target, "/", func(a anchor.Anchor) bool {
|
||||
return anchor.IsCondition(a) ||
|
||||
anchor.IsExistence(a) ||
|
||||
|
@ -38,14 +59,14 @@ func (v *Validate) Validate(ctx context.Context) (string, error) {
|
|||
anchor.IsNegation(a) ||
|
||||
anchor.IsGlobal(a)
|
||||
}); err != nil {
|
||||
return fmt.Sprintf("pattern.%s", path), err
|
||||
return nil, fmt.Sprintf("pattern.%s", path), err
|
||||
}
|
||||
}
|
||||
|
||||
if target := v.rule.GetAnyPattern(); target != nil {
|
||||
anyPattern, err := v.rule.DeserializeAnyPattern()
|
||||
if target := v.validationRule.GetAnyPattern(); target != nil {
|
||||
anyPattern, err := v.validationRule.DeserializeAnyPattern()
|
||||
if err != nil {
|
||||
return "anyPattern", fmt.Errorf("failed to deserialize anyPattern, expect array: %v", err)
|
||||
return nil, "anyPattern", fmt.Errorf("failed to deserialize anyPattern, expect array: %v", err)
|
||||
}
|
||||
for i, pattern := range anyPattern {
|
||||
if path, err := common.ValidatePattern(pattern, "/", func(a anchor.Anchor) bool {
|
||||
|
@ -55,76 +76,102 @@ func (v *Validate) Validate(ctx context.Context) (string, error) {
|
|||
anchor.IsNegation(a) ||
|
||||
anchor.IsGlobal(a)
|
||||
}); err != nil {
|
||||
return fmt.Sprintf("anyPattern[%d].%s", i, path), err
|
||||
return nil, fmt.Sprintf("anyPattern[%d].%s", i, path), err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if v.rule.ForEachValidation != nil {
|
||||
for _, foreach := range v.rule.ForEachValidation {
|
||||
if v.validationRule.ForEachValidation != nil {
|
||||
for _, foreach := range v.validationRule.ForEachValidation {
|
||||
if err := v.validateForEach(foreach); err != nil {
|
||||
return "", err
|
||||
return nil, "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if v.rule.CEL != nil {
|
||||
for _, expression := range v.rule.CEL.Expressions {
|
||||
if v.validationRule.CEL != nil {
|
||||
for _, expression := range v.validationRule.CEL.Expressions {
|
||||
if expression.Expression == "" {
|
||||
return "", fmt.Errorf("cel.expressions.expression is required")
|
||||
return nil, "", fmt.Errorf("cel.expressions.expression is required")
|
||||
}
|
||||
}
|
||||
|
||||
if v.rule.CEL.ParamKind != nil {
|
||||
if v.rule.CEL.ParamKind.APIVersion == "" {
|
||||
return "", fmt.Errorf("cel.paramKind.apiVersion is required")
|
||||
if v.validationRule.CEL.ParamKind != nil {
|
||||
if v.validationRule.CEL.ParamKind.APIVersion == "" {
|
||||
return nil, "", fmt.Errorf("cel.paramKind.apiVersion is required")
|
||||
}
|
||||
|
||||
if v.rule.CEL.ParamKind.Kind == "" {
|
||||
return "", fmt.Errorf("cel.paramKind.kind is required")
|
||||
if v.validationRule.CEL.ParamKind.Kind == "" {
|
||||
return nil, "", fmt.Errorf("cel.paramKind.kind is required")
|
||||
}
|
||||
|
||||
if v.rule.CEL.ParamRef == nil {
|
||||
return "", fmt.Errorf("cel.paramRef is required")
|
||||
if v.validationRule.CEL.ParamRef == nil {
|
||||
return nil, "", fmt.Errorf("cel.paramRef is required")
|
||||
}
|
||||
}
|
||||
|
||||
if v.rule.CEL.ParamRef != nil {
|
||||
if v.rule.CEL.ParamRef.Name == "" && v.rule.CEL.ParamRef.Selector == nil {
|
||||
return "", fmt.Errorf("one of cel.paramRef.name or cel.paramRef.selector must be set")
|
||||
if v.validationRule.CEL.ParamRef != nil {
|
||||
if v.validationRule.CEL.ParamRef.Name == "" && v.validationRule.CEL.ParamRef.Selector == nil {
|
||||
return nil, "", fmt.Errorf("one of cel.paramRef.name or cel.paramRef.selector must be set")
|
||||
}
|
||||
|
||||
if v.rule.CEL.ParamRef.Name != "" && v.rule.CEL.ParamRef.Selector != nil {
|
||||
return "", fmt.Errorf("one of cel.paramRef.name or cel.paramRef.selector must be set")
|
||||
if v.validationRule.CEL.ParamRef.Name != "" && v.validationRule.CEL.ParamRef.Selector != nil {
|
||||
return nil, "", fmt.Errorf("one of cel.paramRef.name or cel.paramRef.selector must be set")
|
||||
}
|
||||
|
||||
if v.rule.CEL.ParamRef.ParameterNotFoundAction == nil {
|
||||
return "", fmt.Errorf("cel.paramRef.parameterNotFoundAction is required")
|
||||
if v.validationRule.CEL.ParamRef.ParameterNotFoundAction == nil {
|
||||
return nil, "", fmt.Errorf("cel.paramRef.parameterNotFoundAction is required")
|
||||
}
|
||||
|
||||
if v.rule.CEL.ParamKind == nil {
|
||||
return "", fmt.Errorf("cel.paramKind is required")
|
||||
if v.validationRule.CEL.ParamKind == nil {
|
||||
return nil, "", fmt.Errorf("cel.paramKind is required")
|
||||
}
|
||||
}
|
||||
|
||||
if v.rule.CEL.AuditAnnotations != nil {
|
||||
for _, auditAnnotation := range v.rule.CEL.AuditAnnotations {
|
||||
if v.validationRule.CEL.AuditAnnotations != nil {
|
||||
for _, auditAnnotation := range v.validationRule.CEL.AuditAnnotations {
|
||||
if auditAnnotation.Key == "" {
|
||||
return "", fmt.Errorf("cel.auditAnnotation.key is required")
|
||||
return nil, "", fmt.Errorf("cel.auditAnnotation.key is required")
|
||||
}
|
||||
|
||||
if auditAnnotation.ValueExpression == "" {
|
||||
return "", fmt.Errorf("cel.auditAnnotation.valueExpression is required")
|
||||
return nil, "", fmt.Errorf("cel.auditAnnotation.valueExpression is required")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil
|
||||
if w, err := v.validateAuth(ctx); err != nil {
|
||||
return nil, "", err
|
||||
} else if len(w) > 0 {
|
||||
warnings = append(warnings, w...)
|
||||
}
|
||||
|
||||
return warnings, "", nil
|
||||
}
|
||||
|
||||
func (v *Validate) validateAuth(ctx context.Context) (warnings []string, err error) {
|
||||
kinds := v.rule.MatchResources.GetKinds()
|
||||
for _, k := range kinds {
|
||||
if wildcard.ContainsWildcard(k) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
verbs := []string{"get", "list", "watch"}
|
||||
ok, msg, err := v.authChecker.CanI(ctx, verbs, k, "", "", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !ok {
|
||||
return []string{msg}, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (v *Validate) validateElements() error {
|
||||
count := validationElemCount(v.rule)
|
||||
count := validationElemCount(v.validationRule)
|
||||
if count == 0 {
|
||||
return fmt.Errorf("one of pattern, anyPattern, deny, foreach, cel must be specified")
|
||||
}
|
||||
|
|
|
@ -13,12 +13,12 @@ func Test_Validate_OverlayPattern_Empty(t *testing.T) {
|
|||
rawValidation := []byte(`
|
||||
{}`)
|
||||
|
||||
var validation kyverno.Validation
|
||||
err := json.Unmarshal(rawValidation, &validation)
|
||||
var rule kyverno.Rule
|
||||
err := json.Unmarshal(rawValidation, &rule)
|
||||
assert.NilError(t, err)
|
||||
|
||||
checker := NewValidateFactory(&validation)
|
||||
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||
checker := NewMockValidateFactory(&rule)
|
||||
if _, _, err := checker.Validate(context.TODO()); err != nil {
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
}
|
||||
|
@ -31,8 +31,8 @@ func Test_Validate_OverlayPattern_Nil_PatternAnypattern(t *testing.T) {
|
|||
var validation kyverno.Validation
|
||||
err := json.Unmarshal(rawValidation, &validation)
|
||||
assert.NilError(t, err)
|
||||
checker := NewValidateFactory(&validation)
|
||||
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||
checker := NewMockValidateFactory(&kyverno.Rule{Validation: validation})
|
||||
if _, _, err := checker.Validate(context.TODO()); err != nil {
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
}
|
||||
|
@ -69,8 +69,8 @@ func Test_Validate_OverlayPattern_Exist_PatternAnypattern(t *testing.T) {
|
|||
var validation kyverno.Validation
|
||||
err := json.Unmarshal(rawValidation, &validation)
|
||||
assert.NilError(t, err)
|
||||
checker := NewValidateFactory(&validation)
|
||||
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||
checker := NewMockValidateFactory(&kyverno.Rule{Validation: validation})
|
||||
if _, _, err := checker.Validate(context.TODO()); err != nil {
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
}
|
||||
|
@ -107,8 +107,8 @@ func Test_Validate_OverlayPattern_Valid(t *testing.T) {
|
|||
var validation kyverno.Validation
|
||||
err := json.Unmarshal(rawValidation, &validation)
|
||||
assert.NilError(t, err)
|
||||
checker := NewValidateFactory(&validation)
|
||||
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||
checker := NewMockValidateFactory(&kyverno.Rule{Validation: validation})
|
||||
if _, _, err := checker.Validate(context.TODO()); err != nil {
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
}
|
||||
|
@ -140,8 +140,8 @@ func Test_Validate_ExistingAnchor_AnchorOnMap(t *testing.T) {
|
|||
var validation kyverno.Validation
|
||||
err := json.Unmarshal(rawValidation, &validation)
|
||||
assert.NilError(t, err)
|
||||
checker := NewValidateFactory(&validation)
|
||||
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||
checker := NewMockValidateFactory(&kyverno.Rule{Validation: validation})
|
||||
if _, _, err := checker.Validate(context.TODO()); err != nil {
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
}
|
||||
|
@ -170,8 +170,8 @@ func Test_Validate_ExistingAnchor_AnchorOnString(t *testing.T) {
|
|||
var validation kyverno.Validation
|
||||
err := json.Unmarshal(rawValidation, &validation)
|
||||
assert.NilError(t, err)
|
||||
checker := NewValidateFactory(&validation)
|
||||
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||
checker := NewMockValidateFactory(&kyverno.Rule{Validation: validation})
|
||||
if _, _, err := checker.Validate(context.TODO()); err != nil {
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
}
|
||||
|
@ -203,8 +203,8 @@ func Test_Validate_ExistingAnchor_Valid(t *testing.T) {
|
|||
|
||||
err = json.Unmarshal(rawValidation, &validation)
|
||||
assert.NilError(t, err)
|
||||
checker := NewValidateFactory(&validation)
|
||||
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||
checker := NewMockValidateFactory(&kyverno.Rule{Validation: validation})
|
||||
if _, _, err := checker.Validate(context.TODO()); err != nil {
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
rawValidation = []byte(`
|
||||
|
@ -228,8 +228,8 @@ func Test_Validate_ExistingAnchor_Valid(t *testing.T) {
|
|||
} `)
|
||||
err = json.Unmarshal(rawValidation, &validation)
|
||||
assert.NilError(t, err)
|
||||
checker = NewValidateFactory(&validation)
|
||||
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||
checker = NewMockValidateFactory(&kyverno.Rule{Validation: validation})
|
||||
if _, _, err := checker.Validate(context.TODO()); err != nil {
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
||||
|
@ -269,8 +269,8 @@ func Test_Validate_Validate_ValidAnchor(t *testing.T) {
|
|||
err = json.Unmarshal(rawValidate, &validate)
|
||||
assert.NilError(t, err)
|
||||
|
||||
checker := NewValidateFactory(&validate)
|
||||
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||
checker := NewMockValidateFactory(&kyverno.Rule{Validation: validate})
|
||||
if _, _, err := checker.Validate(context.TODO()); err != nil {
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
|
@ -291,8 +291,8 @@ func Test_Validate_Validate_ValidAnchor(t *testing.T) {
|
|||
err = json.Unmarshal(rawValidate, &validate)
|
||||
assert.NilError(t, err)
|
||||
|
||||
checker = NewValidateFactory(&validate)
|
||||
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||
checker = NewMockValidateFactory(&kyverno.Rule{Validation: validate})
|
||||
if _, _, err := checker.Validate(context.TODO()); err != nil {
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
}
|
||||
|
@ -318,8 +318,8 @@ func Test_Validate_Validate_Mismatched(t *testing.T) {
|
|||
var validate kyverno.Validation
|
||||
err := json.Unmarshal(rawValidate, &validate)
|
||||
assert.NilError(t, err)
|
||||
checker := NewValidateFactory(&validate)
|
||||
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||
checker := NewMockValidateFactory(&kyverno.Rule{Validation: validate})
|
||||
if _, _, err := checker.Validate(context.TODO()); err != nil {
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
}
|
||||
|
@ -348,8 +348,8 @@ func Test_Validate_Validate_Unsupported(t *testing.T) {
|
|||
|
||||
err = json.Unmarshal(rawValidate, &validate)
|
||||
assert.NilError(t, err)
|
||||
checker := NewValidateFactory(&validate)
|
||||
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||
checker := NewMockValidateFactory(&kyverno.Rule{Validation: validate})
|
||||
if _, _, err := checker.Validate(context.TODO()); err != nil {
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
||||
|
@ -374,8 +374,8 @@ func Test_Validate_Validate_Unsupported(t *testing.T) {
|
|||
err = json.Unmarshal(rawValidate, &validate)
|
||||
assert.NilError(t, err)
|
||||
|
||||
checker = NewValidateFactory(&validate)
|
||||
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||
checker = NewMockValidateFactory(&kyverno.Rule{Validation: validate})
|
||||
if _, _, err := checker.Validate(context.TODO()); err != nil {
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
||||
|
|
|
@ -73,18 +73,15 @@ func validateAuth(ctx context.Context, client dclient.Interface, policy kyvernov
|
|||
resourceFilters := spec.MatchResources.GetResourceFilters()
|
||||
for _, res := range resourceFilters {
|
||||
for _, kind := range res.Kinds {
|
||||
if len(res.Names) == 0 {
|
||||
err := canI(ctx, client, kind, namespace, "", "")
|
||||
names := res.Names
|
||||
if len(names) == 0 {
|
||||
names = append(names, "")
|
||||
}
|
||||
for _, name := range names {
|
||||
err := canI(ctx, client, kind, namespace, name, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
for _, name := range res.Names {
|
||||
err := canI(ctx, client, kind, namespace, name, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,6 @@ import (
|
|||
authChecker "github.com/kyverno/kyverno/pkg/auth/checker"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/logging"
|
||||
"github.com/kyverno/kyverno/pkg/policy/auth"
|
||||
"github.com/kyverno/kyverno/pkg/policy/auth/fake"
|
||||
"github.com/kyverno/kyverno/pkg/policy/generate"
|
||||
"github.com/kyverno/kyverno/pkg/policy/mutate"
|
||||
"github.com/kyverno/kyverno/pkg/policy/validate"
|
||||
|
@ -20,51 +18,47 @@ import (
|
|||
|
||||
// Validation provides methods to validate a rule
|
||||
type Validation interface {
|
||||
Validate(ctx context.Context) (string, error)
|
||||
Validate(ctx context.Context) (warnings []string, path string, err error)
|
||||
}
|
||||
|
||||
// validateAction performs validation on the rule actions
|
||||
// - Mutate
|
||||
// - Validation
|
||||
// - Generate
|
||||
func validateActions(idx int, rule *kyvernov1.Rule, client dclient.Interface, mock bool, username string) (string, error) {
|
||||
func validateActions(idx int, rule *kyvernov1.Rule, client dclient.Interface, mock bool, backgroundSA, reportsSA string) (warnings []string, err error) {
|
||||
if rule == nil {
|
||||
return "", nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var checker Validation
|
||||
|
||||
// Mutate
|
||||
if rule.HasMutate() {
|
||||
var authChecker auth.Operations
|
||||
if mock {
|
||||
authChecker = fake.NewFakeAuth()
|
||||
} else {
|
||||
authChecker = auth.NewAuth(client, username, logging.GlobalLogger())
|
||||
}
|
||||
checker = mutate.NewMutateFactory(rule.Mutation, authChecker, username)
|
||||
if path, err := checker.Validate(context.TODO()); err != nil {
|
||||
return "", fmt.Errorf("path: spec.rules[%d].mutate.%s.: %v", idx, path, err)
|
||||
checker = mutate.NewMutateFactory(rule.Mutation, client, mock, backgroundSA)
|
||||
if w, path, err := checker.Validate(context.TODO()); err != nil {
|
||||
return nil, fmt.Errorf("path: spec.rules[%d].mutate.%s.: %v", idx, path, err)
|
||||
} else if w != nil {
|
||||
warnings = append(warnings, w...)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate
|
||||
if rule.HasValidate() {
|
||||
checker = validate.NewValidateFactory(&rule.Validation)
|
||||
if path, err := checker.Validate(context.TODO()); err != nil {
|
||||
return "", fmt.Errorf("path: spec.rules[%d].validate.%s.: %v", idx, path, err)
|
||||
checker = validate.NewValidateFactory(rule, client, mock, reportsSA)
|
||||
if w, path, err := checker.Validate(context.TODO()); err != nil {
|
||||
return nil, fmt.Errorf("path: spec.rules[%d].validate.%s.: %v", idx, path, err)
|
||||
} else if w != nil {
|
||||
warnings = append(warnings, w...)
|
||||
}
|
||||
|
||||
// In case generateValidatingAdmissionPolicy flag is set to true, check the required permissions.
|
||||
if rule.HasValidateCEL() && toggle.FromContext(context.TODO()).GenerateValidatingAdmissionPolicy() {
|
||||
authCheck := authChecker.NewSelfChecker(client.GetKubeClient().AuthorizationV1().SelfSubjectAccessReviews())
|
||||
// check if the controller has the required permissions to generate validating admission policies.
|
||||
if !validatingadmissionpolicy.HasValidatingAdmissionPolicyPermission(authCheck) {
|
||||
return "insufficient permissions to generate ValidatingAdmissionPolicies", nil
|
||||
warnings = append(warnings, "insufficient permissions to generate ValidatingAdmissionPolicies")
|
||||
}
|
||||
|
||||
// check if the controller has the required permissions to generate validating admission policy bindings.
|
||||
if !validatingadmissionpolicy.HasValidatingAdmissionPolicyBindingPermission(authCheck) {
|
||||
return "insufficient permissions to generate ValidatingAdmissionPolicyBindings", nil
|
||||
warnings = append(warnings, "insufficient permissions to generate ValidatingAdmissionPolicies")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,20 +70,24 @@ func validateActions(idx int, rule *kyvernov1.Rule, client dclient.Interface, mo
|
|||
// this need to modified to use different implementation for online and offline mode
|
||||
if mock {
|
||||
checker = generate.NewFakeGenerate(rule.Generation)
|
||||
if path, err := checker.Validate(context.TODO()); err != nil {
|
||||
return "", fmt.Errorf("path: spec.rules[%d].generate.%s.: %v", idx, path, err)
|
||||
if w, path, err := checker.Validate(context.TODO()); err != nil {
|
||||
return nil, fmt.Errorf("path: spec.rules[%d].generate.%s.: %v", idx, path, err)
|
||||
} else if warnings != nil {
|
||||
warnings = append(warnings, w...)
|
||||
}
|
||||
} else {
|
||||
checker = generate.NewGenerateFactory(client, rule.Generation, username, logging.GlobalLogger())
|
||||
if path, err := checker.Validate(context.TODO()); err != nil {
|
||||
return "", fmt.Errorf("path: spec.rules[%d].generate.%s.: %v", idx, path, err)
|
||||
checker = generate.NewGenerateFactory(client, rule.Generation, backgroundSA, logging.GlobalLogger())
|
||||
if w, path, err := checker.Validate(context.TODO()); err != nil {
|
||||
return nil, fmt.Errorf("path: spec.rules[%d].generate.%s.: %v", idx, path, err)
|
||||
} else if warnings != nil {
|
||||
warnings = append(warnings, w...)
|
||||
}
|
||||
}
|
||||
|
||||
if slices.Contains(rule.MatchResources.Kinds, rule.Generation.Kind) {
|
||||
return "", fmt.Errorf("generation kind and match resource kind should not be the same")
|
||||
return nil, fmt.Errorf("generation kind and match resource kind should not be the same")
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil
|
||||
return warnings, nil
|
||||
}
|
||||
|
|
|
@ -14,6 +14,6 @@ func FuzzValidatePolicy(f *testing.F) {
|
|||
p := &kyverno.ClusterPolicy{}
|
||||
ff.GenerateStruct(p)
|
||||
|
||||
Validate(p, nil, nil, nil, true, "admin")
|
||||
Validate(p, nil, nil, nil, true, "admin", "admin")
|
||||
})
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@ func checkValidationFailureAction(validationFailureAction kyvernov1.ValidationFa
|
|||
}
|
||||
|
||||
// Validate checks the policy and rules declarations for required configurations
|
||||
func Validate(policy, oldPolicy kyvernov1.PolicyInterface, client dclient.Interface, kyvernoClient versioned.Interface, mock bool, username string) ([]string, error) {
|
||||
func Validate(policy, oldPolicy kyvernov1.PolicyInterface, client dclient.Interface, kyvernoClient versioned.Interface, mock bool, backgroundSA, reportsSA string) ([]string, error) {
|
||||
var warnings []string
|
||||
spec := policy.GetSpec()
|
||||
background := spec.BackgroundProcessingEnabled()
|
||||
|
@ -322,13 +322,11 @@ func Validate(policy, oldPolicy kyvernov1.PolicyInterface, client dclient.Interf
|
|||
}
|
||||
}
|
||||
|
||||
msg, err := validateActions(i, &rules[i], client, mock, username)
|
||||
w, err := validateActions(i, &rules[i], client, mock, backgroundSA, reportsSA)
|
||||
if err != nil {
|
||||
return warnings, err
|
||||
} else {
|
||||
if len(msg) != 0 {
|
||||
warnings = append(warnings, msg)
|
||||
}
|
||||
} else if len(w) > 0 {
|
||||
warnings = append(warnings, w...)
|
||||
}
|
||||
|
||||
if rule.HasVerifyImages() {
|
||||
|
|
|
@ -17,13 +17,15 @@ type policyHandlers struct {
|
|||
client dclient.Interface
|
||||
kyvernoClient versioned.Interface
|
||||
backgroundServiceAccountName string
|
||||
reportsServiceAccountName string
|
||||
}
|
||||
|
||||
func NewHandlers(client dclient.Interface, kyvernoClient versioned.Interface, serviceaccount string) webhooks.PolicyHandlers {
|
||||
func NewHandlers(client dclient.Interface, kyvernoClient versioned.Interface, backgroundSA, reportsSA string) webhooks.PolicyHandlers {
|
||||
return &policyHandlers{
|
||||
client: client,
|
||||
kyvernoClient: kyvernoClient,
|
||||
backgroundServiceAccountName: serviceaccount,
|
||||
backgroundServiceAccountName: backgroundSA,
|
||||
reportsServiceAccountName: reportsSA,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,7 +35,7 @@ func (h *policyHandlers) Validate(ctx context.Context, logger logr.Logger, reque
|
|||
logger.Error(err, "failed to unmarshal policies from admission request")
|
||||
return admissionutils.Response(request.UID, err)
|
||||
}
|
||||
warnings, err := policyvalidate.Validate(policy, oldPolicy, h.client, h.kyvernoClient, false, h.backgroundServiceAccountName)
|
||||
warnings, err := policyvalidate.Validate(policy, oldPolicy, h.client, h.kyvernoClient, false, h.backgroundServiceAccountName, h.reportsServiceAccountName)
|
||||
if err != nil {
|
||||
logger.Error(err, "policy validation errors")
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ func NewGenerationHandler(
|
|||
eventGen event.Interface,
|
||||
metrics metrics.MetricsConfigManager,
|
||||
backgroundServiceAccountName string,
|
||||
reportsServiceAccountName string,
|
||||
) GenerationHandler {
|
||||
return &generationHandler{
|
||||
log: log,
|
||||
|
@ -57,6 +58,7 @@ func NewGenerationHandler(
|
|||
eventGen: eventGen,
|
||||
metrics: metrics,
|
||||
backgroundServiceAccountName: backgroundServiceAccountName,
|
||||
reportsServiceAccountName: reportsServiceAccountName,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,6 +75,7 @@ type generationHandler struct {
|
|||
eventGen event.Interface
|
||||
metrics metrics.MetricsConfigManager
|
||||
backgroundServiceAccountName string
|
||||
reportsServiceAccountName string
|
||||
}
|
||||
|
||||
func (h *generationHandler) Handle(
|
||||
|
|
|
@ -63,6 +63,7 @@ type resourceHandlers struct {
|
|||
|
||||
admissionReports bool
|
||||
backgroundServiceAccountName string
|
||||
reportsServiceAccountName string
|
||||
auditPool *pond.WorkerPool
|
||||
reportsBreaker breaker.Breaker
|
||||
}
|
||||
|
@ -82,6 +83,7 @@ func NewHandlers(
|
|||
eventGen event.Interface,
|
||||
admissionReports bool,
|
||||
backgroundServiceAccountName string,
|
||||
reportsServiceAccountName string,
|
||||
jp jmespath.Interface,
|
||||
maxAuditWorkers int,
|
||||
maxAuditCapacity int,
|
||||
|
@ -103,6 +105,7 @@ func NewHandlers(
|
|||
pcBuilder: webhookutils.NewPolicyContextBuilder(configuration, jp),
|
||||
admissionReports: admissionReports,
|
||||
backgroundServiceAccountName: backgroundServiceAccountName,
|
||||
reportsServiceAccountName: reportsServiceAccountName,
|
||||
auditPool: pond.New(maxAuditWorkers, maxAuditCapacity, pond.Strategy(pond.Lazy())),
|
||||
reportsBreaker: reportsBreaker,
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ func (h *resourceHandlers) handleGenerate(ctx context.Context, logger logr.Logge
|
|||
return
|
||||
}
|
||||
|
||||
gh := generation.NewGenerationHandler(logger, h.engine, h.client, h.kyvernoClient, h.nsLister, h.urLister, h.cpolLister, h.polLister, h.urGenerator, h.eventGen, h.metricsConfig, h.backgroundServiceAccountName)
|
||||
gh := generation.NewGenerationHandler(logger, h.engine, h.client, h.kyvernoClient, h.nsLister, h.urLister, h.cpolLister, h.polLister, h.urGenerator, h.eventGen, h.metricsConfig, h.backgroundServiceAccountName, h.reportsServiceAccountName)
|
||||
var policies []kyvernov1.PolicyInterface
|
||||
for _, p := range generatePolicies {
|
||||
new := skipBackgroundRequests(p, logger, h.backgroundServiceAccountName, policyContext.AdmissionInfo().AdmissionUserInfo.Username)
|
||||
|
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: chainsaw-step-01-apply-1-1.yaml
|
||||
- apply:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-091a1b
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: chainsaw-step-01-apply-1-1.yaml
|
||||
- apply:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-819b1b
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: chainsaw-step-01-apply-1-1.yaml
|
||||
- apply:
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:role-and-rolebinding
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- rbac.authorization.k8s.io
|
||||
resources:
|
||||
- roles
|
||||
- rolebindings
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: chainsaw-step-01-apply-1-1.yaml
|
||||
- apply:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-19hs91
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: chainsaw-step-01-apply-1-1.yaml
|
||||
- apply:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-la91n1
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: chainsaw-step-01-apply-1-1.yaml
|
||||
- apply:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-1pq1b
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: chainsaw-step-01-apply-1-1.yaml
|
||||
- apply:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-91ys8
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: policy.yaml
|
||||
- assert:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-k8312
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: policy.yaml
|
||||
- assert:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-kao19a
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: chainsaw-step-01-apply-1-1.yaml
|
||||
- apply:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-kaa11
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: chainsaw-step-01-apply-1-1.yaml
|
||||
- apply:
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets:view
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets:generate
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: chainsaw-step-01-apply-1-1.yaml
|
||||
- apply:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-018m1
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: chainsaw-step-01-apply-1-1.yaml
|
||||
- apply:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-10ga3
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: chainsaw-step-01-apply-1-1.yaml
|
||||
- apply:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-1kq1a
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: chainsaw-step-01-apply-1-1.yaml
|
||||
- apply:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-mabt11
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: chainsaw-step-01-apply-1-1.yaml
|
||||
- assert:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-nqu34
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: chainsaw-step-01-apply-1-1.yaml
|
||||
- assert:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-l1k10
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: policy.yaml
|
||||
- assert:
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-view-91ja1
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets:edit-1k1o2
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: policy.yaml
|
||||
- assert:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-a12xk
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -10,6 +10,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: roles.yaml
|
||||
- name: step-02
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:rbac
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- rbac.authorization.k8s.io
|
||||
resources:
|
||||
- clusterroles
|
||||
- clusterrolebindings
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: chainsaw-step-01-apply-1-1.yaml
|
||||
- assert:
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:rbac
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- rbac.authorization.k8s.io
|
||||
resources:
|
||||
- roles
|
||||
- rolebindings
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -12,4 +12,38 @@ rules:
|
|||
resources:
|
||||
- deployments
|
||||
verbs:
|
||||
- update
|
||||
- update
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-jqo11
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets:manage-1lh1k
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -12,4 +12,38 @@ rules:
|
|||
resources:
|
||||
- deployments
|
||||
verbs:
|
||||
- update
|
||||
- update
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-kak13
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets:manage-ja51n
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: manifests.yaml
|
||||
- apply:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-lal13
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: chainsaw-step-01-apply-1-1.yaml
|
||||
- apply:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-kqo1
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: chainsaw-step-01-apply-1-1.yaml
|
||||
- apply:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-k113f
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -13,6 +13,8 @@ spec:
|
|||
file: policy-ready.yaml
|
||||
- name: step-02
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: ns.yaml
|
||||
- assert:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-skh1
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: policy.yaml
|
||||
- assert:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-0191s
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: policy.yaml
|
||||
- assert:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-la1lk
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: chainsaw-step-01-apply-1-1.yaml
|
||||
- apply:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-ka32a
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: policy.yaml
|
||||
- assert:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-oa11s
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: policy.yaml
|
||||
- assert:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-nsalj
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: chainsaw-step-01-apply-1-1.yaml
|
||||
- apply:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-lkjso
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: manifests.yaml
|
||||
- apply:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: kyverno:secrets-xaeqi
|
||||
labels:
|
||||
rbac.kyverno.io/aggregate-to-background-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-reports-controller: "true"
|
||||
rbac.kyverno.io/aggregate-to-admission-controller: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ''
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- delete
|
|
@ -7,6 +7,8 @@ spec:
|
|||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: permissions.yaml
|
||||
- apply:
|
||||
file: chainsaw-step-01-apply-1-1.yaml
|
||||
- apply:
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue