Add fields with Kustomize patches without overwriting

Published August 10, 2022

The reason for this post is that we ran into this issue a few days ago and could not find sufficent information on how to set fields without overwriting them using Kustomize, so here it is:

To patch resources using Kustomize with either a strategic merge patch or a JSON6902 patch you have to add a target selector and a patch document to your Kustomization resource.

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
metadata:
  name: patch
  namespace: namespace-to-patch
spec:
  patches:
    - patch: |
        - op: add
          path: /spec/template/spec/securityContext
          value:
            runAsUser: 10000
            fsGroup: 1337
        - op: add
          path: /spec/template/spec/containers/0/securityContext
          value:
            readOnlyRootFilesystem: true
            allowPrivilegeEscalation: false
            runAsNonRoot: true
            capabilities:
              drop:
                - ALL                
      target:
        kind: Deployment
        namespace: apps

The problem with the above JSON6902 patches is that they are going to completely replace any other values inside your securityContext, instead of appending/adding the new values to them. If you want to replace them, then of course it is fine, but in my case we had to set a few other values next to the ones already present.

The way you can accomplish adding/appending values is the following:

patches:
- patch: |
    - op: add
      # First we create the `capabilities` field, to which we give the value of `drop` with a 1 element list containing ˙"ALL" ̇
      path: /spec/template/spec/containers/0/securityContext/capabilities
      value: 
        drop: ["ALL"]
    - op: add
      path: /spec/template/spec/containers/0/securityContext/readOnlyRootFilesystem
      value: true
    - op: add
      path: /spec/template/spec/containers/0/securityContext/allowPrivilegeEscalation
      value: true
    - op: add
      path: /spec/template/spec/containers/0/securityContext/runAsNonRoot
      value: true    

By referencing fields which are currently non-existent in your manifests e.g: readOnlyRootFilesystem, allowPrivilegeEscalation and giving them values, they are going to be created inside the newly built manifests next to the already present ones, but of course the downside of this is that a typo could easily ruin your manifests.