> ## Documentation Index
> Fetch the complete documentation index at: https://docs.siderolabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration Patches

> In this guide, we'll patch the generated machine configuration.

export const VersionWarningBanner = () => {
  const latestVersion = "v1.13";
  const [latestUrl, setLatestUrl] = useState(null);
  const [currentVersion, setCurrentVersion] = useState(null);
  const [isBeta, setIsBeta] = useState(false);
  const parseVersion = v => v.replace("v", "").split(".").map(Number);
  const isGreaterVersion = (a, b) => {
    const [aMajor, aMinor] = parseVersion(a);
    const [bMajor, bMinor] = parseVersion(b);
    if (aMajor > bMajor) return true;
    if (aMajor === bMajor && aMinor > bMinor) return true;
    return false;
  };
  useEffect(() => {
    if (typeof window === "undefined") return;
    const {pathname, hash, search} = window.location;
    const match = pathname.match(/\/talos\/(v\d+\.\d+)\//);
    if (!match) return;
    const detectedVersion = match[1];
    if (detectedVersion === latestVersion) return;
    setCurrentVersion(detectedVersion);
    if (isGreaterVersion(detectedVersion, latestVersion)) {
      setIsBeta(true);
    }
    const newPath = pathname.replace(`/talos/${detectedVersion}/`, `/talos/${latestVersion}/`);
    setLatestUrl(`${newPath}${search}${hash}`);
  }, []);
  if (!latestUrl || !currentVersion) return null;
  return <div className="not-prose sticky top-6 z-50 my-6">
      <div className="border border-yellow-500/30 bg-yellow-500/10 px-4 py-3 rounded-xl">
        <div className="text-sm">
          {isBeta ? <>
              ⚠️ You are viewing a <strong>beta version</strong> of Talos ({currentVersion}).
              This version may be unstable.
              <a href={latestUrl} className="ml-2 underline text-yellow-400 hover:text-yellow-300 font-medium">
                View latest stable version {latestVersion} →
              </a>
            </> : <>
              ⚠️ You are viewing an older version of Talos ({currentVersion}).
              <a href={latestUrl} className="ml-2 underline text-yellow-400 hover:text-yellow-300 font-medium">
                View the latest version {latestVersion} →
              </a>
            </>}
        </div>
      </div>
    </div>;
};

<VersionWarningBanner />

Talos generates machine configuration for two types of machines: controlplane and worker machines.
Many configuration options can be adjusted using `talosctl gen config` but not all of them.
Configuration patching allows modifying machine configuration to fit it for the cluster or a specific machine.

## Configuration Patch Formats

Talos supports two configuration patch formats:

* strategic merge patches
* RFC6902 (JSON patches)

Strategic merge patches are the easiest to use, but JSON patches allow more precise configuration adjustments.

> Note: Talos 1.5+ supports [multi-document machine configuration](../../reference/configuration/overview).
> JSON patches don't support multi-document machine configuration, while strategic merge patches do.

### Strategic Merge patches

Strategic merge patches look like incomplete machine configuration files:

```yaml theme={null}
machine:
  network:
    hostname: worker1
```

When applied to the machine configuration, the patch gets merged with the respective section of the machine configuration:

```yaml theme={null}
machine:
  network:
    interfaces:
      - interface: eth0
        addresses:
          - 10.0.0.2/24
    hostname: worker1
```

In general, machine configuration contents are merged with the contents of the strategic merge patch, with strategic merge patch
values overriding machine configuration values.
There are some special rules:

* If the field value is a list, the patch value is appended to the list, with the following exceptions:
  * values of the fields `cluster.network.podSubnets` and `cluster.network.serviceSubnets` are overwritten on merge
  * `network.interfaces` section is merged with the value in the machine config if there is a match on `interface:` or `deviceSelector:` keys
  * `network.interfaces.vlans` section is merged with the value in the machine config if there is a match on the `vlanId:` key
  * `cluster.apiServer.auditPolicy` value is replaced on merge
  * `ExtensionServiceConfig.configFiles` section is merged matching on `mountPath` (replacing `content` if matches)

When patching a [multi-document machine configuration](../../reference/configuration/overview), following rules apply:

* for each document in the patch, the document is merged with the respective document in the machine configuration (matching by `kind`, `apiVersion` and `name` for named documents)
* if the patch document doesn't exist in the machine configuration, it is appended to the machine configuration

The strategic merge patch itself might be a multi-document YAML, and each document will be applied as a patch to the base machine configuration.
Keep in mind that you can't patch the same document multiple times with the same patch.

You can also delete parts from the configuration using `$patch: delete` syntax similar to the
[Kubernetes](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-api-machinery/strategic-merge-patch.md#delete-directive)
strategic merge patch.

For example, with configuration:

```yaml theme={null}
machine:
  network:
    interfaces:
      - interface: eth0
        addresses:
          - 10.0.0.2/24
    hostname: worker1
```

and patch document:

```yaml theme={null}
machine:
  network:
    interfaces:
    - interface: eth0
      $patch: delete
    hostname: worker1
```

The resulting configuration will be:

```yaml theme={null}
machine:
  network:
    hostname: worker1
```

You can also delete entire docs (but not the main `v1alpha1` configuration!) using this syntax:

```yaml theme={null}
apiVersion: v1alpha1
kind: SideroLinkConfig
$patch: delete
---
apiVersion: v1alpha1
kind: ExtensionServiceConfig
name: foo
$patch: delete
```

This will remove the documents `SideroLinkConfig` and `ExtensionServiceConfig` with name `foo` from the configuration.

### RFC6902 (JSON Patches)

[JSON patches](https://jsonpatch.com/) can be written either in JSON or YAML format.
A proper JSON patch requires an `op` field that depends on the machine configuration contents: whether the path already exists or not.

For example, the strategic merge patch from the previous section can be written either as:

```yaml theme={null}
- op: replace
  path: /machine/network/hostname
  value: worker1
```

or:

```yaml theme={null}
- op: add
  path: /machine/network/hostname
  value: worker1
```

The correct `op` depends on whether the `/machine/network/hostname` section exists already in the machine config or not.

## Examples

### Machine Network

Base machine configuration:

```yaml theme={null}
# ...
machine:
  network:
    interfaces:
      - interface: eth0
        dhcp: false
        addresses:
          - 192.168.10.3/24
```

The goal is to add a virtual IP `192.168.10.50` to the `eth0` interface and add another interface `eth1` with DHCP enabled.

<Tabs>
  <Tab title="Strategic merge patch">
    ```yaml theme={null}
      machine:
        network:
          interfaces:
            - interface: eth0
              vip:
                ip: 192.168.10.50
            - interface: eth1
              dhcp: true
    ```
  </Tab>

  <Tab title="JSON patch">
    ```json theme={null}
    - op: add
      path: /machine/network/interfaces/0/vip
      value:
        ip: 192.168.10.50
    - op: add
      path: /machine/network/interfaces/-
      value:
        interface: eth1
        dhcp: true
    ```
  </Tab>
</Tabs>

Patched machine configuration:

```yaml theme={null}
machine:
  network:
    interfaces:
      - interface: eth0
        dhcp: false
        addresses:
          - 192.168.10.3/24
        vip:
          ip: 192.168.10.50
      - interface: eth1
        dhcp: true
```

### Cluster Network

Base machine configuration:

```yaml theme={null}
cluster:
  network:
    dnsDomain: cluster.local
    podSubnets:
      - 10.244.0.0/16
    serviceSubnets:
      - 10.96.0.0/12
```

The goal is to update pod and service subnets and disable default CNI (Flannel).

<Tabs>
  <Tab title="Strategic merge patch">
    ```yaml theme={null}
    cluster:
      network:
        podSubnets:
          - 192.168.0.0/16
        serviceSubnets:
          - 192.0.0.0/12
        cni:
          name: none
    ```
  </Tab>

  <Tab title="JSON patch">
    ```json theme={null}
    - op: replace
      path: /cluster/network/podSubnets
      value:
        - 192.168.0.0/16
    - op: replace
      path: /cluster/network/serviceSubnets
      value:
        - 192.0.0.0/12
    - op: add
      path: /cluster/network/cni
      value:
        name: none
    ```
  </Tab>
</Tabs>

Patched machine configuration:

```yaml theme={null}
cluster:
  network:
    dnsDomain: cluster.local
    podSubnets:
      - 192.168.0.0/16
    serviceSubnets:
      - 192.0.0.0/12
    cni:
      name: none
```

### Kubelet

Base machine configuration:

```yaml theme={null}
# ...
machine:
  kubelet: {}
```

The goal is to set the `kubelet` node IP to come from the subnet `192.168.10.0/24`.

<Tabs>
  <Tab title="Strategic merge patch">
    ```yaml theme={null}
    machine:
      kubelet:
        nodeIP:
          validSubnets:
            - 192.168.10.0/24
    ```
  </Tab>

  <Tab title="JSON patch">
    ```json theme={null}
    - op: add
      path: /machine/kubelet/nodeIP
      value:
        validSubnets:
          - 192.168.10.0/24
    ```
  </Tab>
</Tabs>

Patched machine configuration:

```yaml theme={null}
machine:
  kubelet:
    nodeIP:
      validSubnets:
        - 192.168.10.0/24
```

### Admission Control: Pod Security Policy

Base machine configuration:

```yaml theme={null}
cluster:
  apiServer:
    admissionControl:
      - name: PodSecurity
        configuration:
          apiVersion: pod-security.admission.config.k8s.io/v1alpha1
          defaults:
            audit: restricted
            audit-version: latest
            enforce: baseline
            enforce-version: latest
            warn: restricted
            warn-version: latest
          exemptions:
            namespaces:
              - kube-system
            runtimeClasses: []
            usernames: []
          kind: PodSecurityConfiguration
```

The goal is to add an exemption for the namespace `rook-ceph`.

<Tabs>
  <Tab title="Strategic merge patch">
    ```yaml theme={null}
      cluster:
        apiServer:
          admissionControl:
            - name: PodSecurity
              configuration:
                exemptions:
                  namespaces:
                    - rook-ceph
    ```
  </Tab>

  <Tab title="JSON patch">
    ```json theme={null}
      - op: add
        path: /cluster/apiServer/admissionControl/0/configuration/exemptions/namespaces/-
        value: rook-ceph

    ```
  </Tab>
</Tabs>

Patched machine configuration:

```yaml theme={null}
cluster:
  apiServer:
    admissionControl:
      - name: PodSecurity
        configuration:
          apiVersion: pod-security.admission.config.k8s.io/v1alpha1
          defaults:
            audit: restricted
            audit-version: latest
            enforce: baseline
            enforce-version: latest
            warn: restricted
            warn-version: latest
          exemptions:
            namespaces:
              - kube-system
              - rook-ceph
            runtimeClasses: []
            usernames: []
          kind: PodSecurityConfiguration
```

## Configuration Patching with `talosctl` CLI

Several `talosctl` commands accept config patches as command-line flags.
Config patches might be passed either as an inline value or as a reference to a file with `@file.patch` syntax:

```shell theme={null}
talosctl ... --patch '[{"op": "add", "path": "/machine/network/hostname", "value": "worker1"}]' --patch @file.patch
```

If multiple config patches are specified, they are applied in the order of appearance.
The format of the patch (JSON patch or strategic merge patch) is detected automatically.

Talos machine configuration can be patched at the moment of generation with `talosctl gen config`:

```shell theme={null}
talosctl gen config test-cluster https://172.20.0.1:6443 \
  --config-patch '[{"op": "add", "path": "/machine/certSANs", "value": ["10.0.0.10"]}]' \
  --config-patch @all.yaml \
  --config-patch-control-plane @cp.yaml \
  --config-patch-worker @worker.yaml
```

Generated machine configuration can also be patched after the fact with `talosctl machineconfig patch`

```shell theme={null}
talosctl machineconfig patch worker.yaml --patch @patch.yaml -o worker1.yaml
```

Machine configuration on the running Talos node can be patched with `talosctl patch`:

```shell theme={null}
talosctl patch mc --nodes 172.20.0.2 --patch @patch.yaml
```
