Value propagation pattern #

Generating a string value and propagating that value to another place (or many other places) in your configuration is a very common pattern. In this guide, we will go through the recommended technique to do this value propagation using our starlark and apply-replacements KRM functions.

String generation function #

Sometimes, the value that we need to propagate is a concatenation of other values that come from various other resource fields. In order to generate the value we need to propagate, we can make use of the starlark function.

For example, let’s say we have a few context resources:

# gcloud-config.yaml

apiVersion: v1
kind: ConfigMap
metadata:
   name: gcloud-config.kpt.dev
   annotations:
      config.kubernetes.io/local-config: "true"
data:
   domain: domain
   orgId: org-ID
   projectID: project
   region: region
   zone: zone
# package-context.yaml

apiVersion: v1
kind: ConfigMap
metadata:
   name: kptfile.kpt.dev
   annotations:
      config.kubernetes.io/local-config: "true"
data:
   name: namespace

and a RoleBinding as follows:

# rolebinding.yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: app-admin
  namespace: myns
subjects:
- kind: Group
  name: example-admin@example.com
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: app-admin
  apiGroup: rbac.authorization.k8s.io

For this example, our goal is to change the RoleBinding’s Group name from example-admin@example.com to the value project-namespace-role@domain. In order to generate this value, we will need to look at various fields from our context resources, concatenate them together, and then store the generated value somewhere.

We can create a ConfigMap named value-store, which we will use to store the generated string in its data.group field:

# value-store.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: value-store
  annotations:
    config.kubernetes.io/local-config: "true"
data:
  group: example-group

Now we can use the starlark function to generate and store the desired string value. This function allows you to run a Starlark script to modify or generate resources. In our case, the functionConfig should look like the following:

# generate-rolebinding-group.yaml

apiVersion: fn.kpt.dev/v1alpha1
kind: StarlarkRun
metadata:
  name: generate-rolebinding-group.yaml
  annotations:
    config.kubernetes.io/local-config: "true"
source: |-
  load("krmfn.star", "krmfn")
  
  def generate_group(resources, role):
    group = ""
    value_store = {}
    for r in resources:
      if krmfn.match_gvk(r, "v1", "ConfigMap") and krmfn.match_name(r, "gcloud-config.kpt.dev"):
        project = r["data"]["projectID"]
        domain = r["data"]["domain"]
      if krmfn.match_gvk(r, "v1", "ConfigMap") and krmfn.match_name(r, "kptfile.kpt.dev"):
        namespace = r["data"]["name"]
      if krmfn.match_gvk(r, "v1", "ConfigMap") and krmfn.match_name(r, "value-store"):
        value_store = r
    group = project + "-" + namespace + "-" + role + "@" + domain
    value_store["data"]["group"] = group
  generate_group(ctx.resource_list["items"], "app-admin")  

Value propagation function #

Now that we have a function that can generate the desired value, we will need to configure another function to propagate the value to the desired place(s).

We can achieve this with the apply-replacements function. The apply-replacements function is a wrapper for the kustomize replacements feature, and can be used to copy a value from a provided source to any number of specified targets. In our case, the functionConfig looks like the following:

# propagate-rolebinding-group.yaml

apiVersion: fn.kpt.dev/v1alpha1
kind: ApplyReplacements
metadata:
   name: propagate-rolebinding-group
   annotations:
      config.kubernetes.io/local-config: "true"
replacements:
   - source:
        kind: ConfigMap
        name: value-store
        fieldPath: data.group
     targets:
        - select:
             kind: RoleBinding
             name: app-admin
          fieldPaths:
             - subjects.[kind=Group].name

This functionConfig will configure apply-replacements to copy the value we stored in value-store to the RoleBinding Group.

Running the functions #

In order to run the configured functions, we can have the following pipeline in our Kptfile:

# Kptfile

apiVersion: kpt.dev/v1
kind: Kptfile
metadata:
  name: example
pipeline:
  mutators:
    - image: gcr.io/kpt-fn/starlark:v0.4
      configPath: generate-rolebinding-group.yaml
    - image: gcr.io/kpt-fn/apply-replacements:v0.1
      configPath: propagate-rolebinding-group.yaml

After running these two functions with kpt fn render, we should see the value of our RoleBinding group change from example-admin@example.com to project-namespace-role@domain as desired.

Summary #

With the above pattern and workflow, you can easily generate and propagate common values to various places of your configuration.

Last modified June 16, 2025: Move docs to hugo (#4215) (2f0d4026)