-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal for extending forEach to cover generate rules #52
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
# Support `forEach` in Generate Rules | ||
|
||
- **Authors**: [Mariam Fahmy](https://github.com/MariamFahmy98) | ||
- **Created**: Nov 11th, 2023 | ||
- **Abstract**: Supporting `forEach` in Generate Rules | ||
|
||
# Table of Contents | ||
- [Overview](#overview) | ||
- [Definitions](#definitions) | ||
- [Motivation](#motivation) | ||
- [Proposal](#proposal) | ||
- [Implementation](#implementation) | ||
- [Drawbacks](#drawbacks) | ||
- [Alternatives](#alternatives) | ||
- [Prior Art](#prior-art) | ||
- [Unresolved Questions](#unresolved-questions) | ||
|
||
# Overview | ||
[overview]: #overview | ||
Generate rules are in charge of creating new resources. The rule can either define the new resource using the `data` object or use an existing resource in the cluster with the `clone` object. Currently, only one resource can be generated. | ||
|
||
This proposal is to extend the `forEach` to cover generate rules. | ||
|
||
# Definitions | ||
[definitions]: #definitions | ||
|
||
1. Trigger: It refers to the resource responsible for triggering the generate rule as defined in a combination of `match` and `exclude` blocks. | ||
|
||
2. Downstream: It refers to the generated resource(s). | ||
|
||
3. Source: It refers to the clone source when generating new resources from existing ones in the cluster. | ||
|
||
# Motivation | ||
[motivation]: #motivation | ||
|
||
There are some use cases where a single "trigger" resource should result in the creation of multiple downstream resources. | ||
|
||
Examples: | ||
1. Generating a list of new network policies based on a comma separated string in an annotation using a `forEach` and `Split()`. | ||
2. Migrating from ingress to Kubernetes Gateway API requires generating at least two resources: `Gateway` and `HTTPRoute`. | ||
|
||
# Proposal | ||
In this proposal, Kyverno generate rule can be extended to allowing the generation of multiple resources using `forEach`. | ||
This could be done by using the `list` attribute which is a JMESPath expression that defines the sub-elements it processes. | ||
|
||
Examples: | ||
1. Generate multiple network policies when a new namespace is created: | ||
```yaml | ||
spec: | ||
rules: | ||
- name: generate-network-policies | ||
match: | ||
any: | ||
- resources: | ||
kinds: | ||
- Namespace | ||
generate: | ||
synchronize: true | ||
foreach: | ||
- list: request.object.metadata.labels.networkpolicies | split(@, ',') | ||
resources: | ||
- apiVersion: v1 | ||
kind: NetworkPolicy | ||
name: '{{ element }}' | ||
namespace: "{{request.object.metadata.name}}" | ||
data: | ||
spec: | ||
podSelector: {} | ||
policyTypes: | ||
- Ingress | ||
- Egress | ||
``` | ||
|
||
2. Generate ConfigMap and Secret for each container: | ||
```yaml | ||
spec: | ||
rules: | ||
- name: generate-configmaps-and-secrets | ||
match: | ||
any: | ||
- resources: | ||
kinds: | ||
- Pod | ||
generate: | ||
synchronize: true | ||
foreach: | ||
- list: request.object.spec.containers | ||
resources: | ||
- apiVersion: v1 | ||
kind: ConfigMap | ||
name: cm | ||
namespace: "{{request.object.metadata.namespace}}" | ||
data: | ||
foo: bar | ||
- apiVersion: v1 | ||
kind: Secret | ||
name: secret | ||
namespace: "{{request.object.metadata.namespace}}" | ||
data: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we support There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No. Since There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using For example, we can clone a secret depending on the number of containers. For each container, the same secret will be cloned. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would this handle the case of cloning a resource into multiple namespaces? For example matching on This is a case we can't currently do with Kyverno (so far as I could tell). It's a task tools like KubeD or Reflector perform as their primary purpose. (Along with many others) I'm looking for a replacement for the former and was hoping I'd be able to write a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You might consider using external-secrets kubernetes provider along with its PushSecret custom resource to replace many kubed use cases. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @pinkfloydx33 - this is an interesting use case. I have crafted an example rule which looks up a list of namespaces by the label and clone the secret to multiple namespaces. spec:
rules:
- name: clone-seret-to-multiple-namespace
match:
any:
- resources:
kinds:
- Secret
namespaces:
- default
context:
- variable:
name: selector
jmesPath: request.object.metadata.labels.sync
default: a=b
- name: namespaces
apiCall:
urlPath: /api/v1/namespaces?labelSelector={{selector}}?limit=5
generate:
synchronize: false
foreach:
- list: "{{namespaces}}"
cloneList:
- source:
namespace: default
name: regcred
kind: v1
apiVersion: Secret
target:
namespace: "{{element}}"
name: regcred What do you think? |
||
foo: bar | ||
``` | ||
|
||
3. Generate Gateway and HTTPRoute from Ingress: | ||
```yaml | ||
spec: | ||
rules: | ||
- name: generate-gatewayapi | ||
match: | ||
any: | ||
- resources: | ||
kinds: | ||
- Ingress | ||
generate: | ||
synchronize: false | ||
foreach: | ||
- list: request.object.spec.rules | ||
resources: | ||
- apiVersion: gateway.networking.k8s.io/v1beta1 | ||
kind: HTTPRoute | ||
# the name must be unique | ||
name: httproute | ||
namespace: "{{request.object.metadata.namespace}}" | ||
data: | ||
spec: | ||
hostnames: | ||
- '{{ element.host }}' | ||
- list: request.object.spec.ingressClassName | ||
resources: | ||
- apiVersion: gateway.networking.k8s.io/v1beta1 | ||
kind: Gateway | ||
name: gateway | ||
data: | ||
spec: | ||
gatewayClassName: '{{ element }}' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Currently the mapping for a generate rule is - one rule can support M There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For simplicity, we can limit the rule to have 1 |
||
``` | ||
|
||
# Implementation | ||
|
||
We will extend the generate rule as follows: | ||
```go | ||
type Generation struct { | ||
ForEachGeneration []ForEachGeneration `json:"foreach,omitempty" yaml:"foreach,omitempty"` | ||
} | ||
``` | ||
|
||
```go | ||
type ForEachGeneration struct { | ||
List string `json:"list,omitempty" yaml:"list,omitempty"` | ||
|
||
Resource []Resource `json:"resources,omitempty" yaml:"resources,omitempty"` | ||
} | ||
``` | ||
|
||
```go | ||
type Resource struct { | ||
ResourceSpec `json:",omitempty" yaml:",omitempty"` | ||
|
||
RawData *apiextv1.JSON `json:"data,omitempty" yaml:"data,omitempty"` | ||
} | ||
``` | ||
|
||
- `foreach` will only support generating Kubernetes resources that are defined as a part of the rule. | ||
|
||
- Nested `foreach` can be supported but there is no real use case for it. | ||
|
||
- At least one of the following: `data`, `clone`, or `foreach` must be declared. | ||
|
||
# Drawbacks | ||
|
||
N/A | ||
|
||
# Alternatives | ||
|
||
N/A | ||
|
||
# Prior Art | ||
|
||
N/A | ||
|
||
# Unresolved Questions | ||
|
||
N/A |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be good to clarify the built-in variables for generate
foreach
type of rule.