3

I am curious to know if there is a way to do a Kustomize replacement or other operation to inject the contents of a non-yaml file into a yaml file using Kustomize. I know Kustomize is not a template engine and that this could be accomplished with Helm, but using the tool I am already using, is this possible?

My use case is to store OPA policies as native rego, which allows use of OPA unit tests, and to inject the content of these rego files into Gatekeeper constraints during Kustomize deployment. This will remove the requirement for custom pipeline processing or manual copy/paste to accomplish this.

Example opaRule.rego file

package k8sdisallowedtags

violation[{"msg": msg}] {
    container := input_containers[_]
    tags := [forbid | tag = input.parameters.tags[_] ; forbid = endswith(container.image, concat(":", ["", tag]))]
    any(tags)
    msg := sprintf("container <%v> uses a disallowed tag <%v>; disallowed tags are %v", [container.name, container.image, input.parameters.tags])
}
...

Example constraintTemplate.yaml file

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8sdisallowedtags
  namespace: kube-system
  annotations:
    description: Requires container images to have an image tag different
      from the ones in a specified list.
spec:
  crd:
    spec:
      names:
        kind: K8sDisallowedTags
      validation:
        openAPIV3Schema:
          properties:
            tags:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |-
        {CONTENT OF OPA RULE POLICY HERE}
  • What `kustomize` version are you running? If it's built-in in `kubectl` then what version of `kubectl`? I'll need to have a look at documents to see if this is possible. – moonkotte Jul 20 '21 at 19:55
  • 1
    The deployment is through Flux v2 with kustomize-controller v0.13.1. - kubectl v1.18.9 - kustomize v4.2.0 – Michael L Rhyndress Jul 21 '21 at 19:39

2 Answers2

1

Answer will contain two parts:

  • idea on how to address the asked question (because no built-in functionality is available for it + integrate with the second part)
  • using patches (can be useful for others in community)

Create own plugin

Kustomize allows to create plugins to extend its functionality. And there are almost zero limitations including security - this should be handled by author of the plugin.

There are two kinds of plugins:

All available information can be found in Extending Kustomize - documentation.

Example of exec plugin. Note! correct flag is --enable-alpha-plugins (with -, not with _ as in example).

Using patches

Patches (also call overlays) add or override fields on resources. They are provided using the patches Kustomization field.

The patches field contains a list of patches to be applied in the order they are specified.

Each patch may:

  • be either a strategic merge patch, or a JSON6902 patch
  • be either a file, or an inline string target
  • a single resource or multiple resources

Reference to kustomize - patches

Below is example how to patch gatekeeper.yaml object.

Structure:

$ tree

.
├── gatekeeper.yaml
├── kustomization.yaml
└── opa-gk.yaml

$ cat gatekeeper.yaml

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8sdisallowedtags
  namespace: kube-system
  annotations:
    description: Requires container images to have an image tag different
      from the ones in a specified list.
spec:
  crd:
    spec:
      names:
        kind: K8sDisallowedTags
      validation:
        openAPIV3Schema:
          properties:
            tags:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |-
        {CONTENT OF OPA RULE POLICY HERE}

$ cat kustomization.yaml

resources:
- gatekeeper.yaml

patches:
- path: opa-gk.yaml
  target:
    group: templates.gatekeeper.sh
    version: v1beta1
    kind: ConstraintTemplate
    name: k8sdisallowedtags

$ cat opa-gk.yaml

- op: add
  path: /spec/targets/0/rego
  value: |
    package k8sdisallowedtags
    
    violation[{"msg": msg}] {
        container := input_containers[_]
        tags := [forbid | tag = input.parameters.tags[_] ; forbid = endswith(container.image, concat(":", ["", tag]))]
        any(tags)
        msg := sprintf("container <%v> uses a disallowed tag <%v>; disallowed tags are %v", [container.name, container.image, input.parameters.tags])
    }
    ...

End result:

$ kubectl kustomize .

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  annotations:
    description: Requires container images to have an image tag different from the
      ones in a specified list.
  name: k8sdisallowedtags
  namespace: kube-system
spec:
  crd:
    spec:
      names:
        kind: K8sDisallowedTags
      validation:
        openAPIV3Schema:
          properties:
            tags:
              items:
                type: string
              type: array
  targets:
  - rego: |
      package k8sdisallowedtags

      violation[{"msg": msg}] {
          container := input_containers[_]
          tags := [forbid | tag = input.parameters.tags[_] ; forbid = endswith(container.image, concat(":", ["", tag]))]
          any(tags)
          msg := sprintf("container <%v> uses a disallowed tag <%v>; disallowed tags are %v", [container.name, container.image, input.parameters.tags])
      }
      ...
    target: admission.k8s.gatekeeper.sh
moonkotte
  • 3,661
  • 2
  • 10
  • 25
  • 2
    Marked this as the answer as it does confirm this is not something that can be accomplished natively. Will pursue a custom plugin as suggested in part 1. The patching method (part 2) does not fit my use case, just moves the same problem to the patch file. Thanks @moonkotte – Michael L Rhyndress Aug 05 '21 at 17:36
  • patches can help if you move the common patches somewhere up in the directory and its now just a matter of having every specific kustomization.yaml to refer to each of the common patches – bhantol Sep 23 '22 at 21:11
0

You could use yaml-include-transformer (it's my project) - A YAML processor that implements include directives for YAML files. It can be used as a standalone utility as well as a plugin for Kustomize. It allows to include files as text fields using directives like

some_key_name!textfile:  somefile.ext

Here an example:

$ cat gatekeeper.yaml

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8sdisallowedtags
  namespace: kube-system
  annotations:
    description: Requires container images to have an image tag different
      from the ones in a specified list.
spec:
  crd:
    spec:
      names:
        kind: K8sDisallowedTags
      validation:
        openAPIV3Schema:
          properties:
            tags:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego!textfile: opaRule.rego

Run yaml processor:

yaml-include-transformer < examples.yaml

Output:

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  annotations:
    description: Requires container images to have an image tag different from the ones in a specified list.
  name: k8sdisallowedtags
  namespace: kube-system
spec:
  crd:
    spec:
      names:
        kind: K8sDisallowedTags
      validation:
        openAPIV3Schema:
          properties:
            tags:
              items:
                type: string
              type: array
  targets:
    - rego: |
        package k8sdisallowedtags

        violation[{"msg": msg}] {
            container := input_containers[_]
            tags := [forbid | tag = input.parameters.tags[_] ; forbid = endswith(container.image, concat(":", ["", tag]))]
            any(tags)
            msg := sprintf("container <%v> uses a disallowed tag <%v>; disallowed tags are %v", [container.name, container.image, input.parameters.tags])
        }
      target: admission.k8s.gatekeeper.sh

To use this tool as a Kustomize plugin you need to create a plugin configuration file and add it as a transformer to the kustomization.yaml file like:

transformers:
  - include-plugin.yaml

There are several types of plugins that are supported by kustomize, the exact way to install and configure yaml-include-transformer as a plugin depends on plugin type that you choose to use. yaml-include-transformer can install itself and generate configuration files for different plugin types.

For example, to configure it as a legacy exec plugin you need to generate the configuration file:

yaml-include-transformer --plugin-conf -legacy > include-plugin.yaml

and to install plugin the plugin binary:

$ yaml-include-transformer --install --legacy --exec
Installing kustomize exec plugin /home/username/.config/kustomize/plugin/kustomize-utils.dudinea.org/v1/yamlincludetransformer
copy '/home/username/go/bin/yaml-include-transformer' to '/home/username/.config/kustomize/plugin/kustomize-utils.dudinea.org/v1/yamlincludetransformer/YamlIncludeTransformer'
/home/username/go/bin/yaml-include-transformer: Kustomize exec plugin Installation complete

Now you can run build:

kustomize build --enable-alpha-plugins
eugene.d
  • 1
  • 2