diff --git a/docs/reference/configuration/custom resources/packages-v1alpha1-cr.md b/docs/reference/configuration/custom resources/packages-v1alpha1-cr.md
index f01c2655e..5d9da603e 100644
--- a/docs/reference/configuration/custom resources/packages-v1alpha1-cr.md
+++ b/docs/reference/configuration/custom resources/packages-v1alpha1-cr.md
@@ -124,7 +124,7 @@ tableOfContents:
- description | string | A description of the policy, this will become part of the policy name |
direction | string (enum): | The direction of the traffic |
labels | | The labels to apply to the policy |
podLabels | | Deprecated: use selector |
port | number | The port to allow (protocol is always TCP) |
ports | number[] | A list of ports to allow (protocol is always TCP) |
remoteCidr | string | Custom generated policy CIDR |
remoteGenerated | string (enum):KubeAPI IntraNamespace CloudMetadata Anywhere
| Custom generated remote selector for the policy |
remoteNamespace | string | The remote namespace to allow traffic to/from. Use * or empty string to allow all namespaces |
remotePodLabels | | Deprecated: use remoteSelector |
remoteSelector | | The remote pod selector labels to allow traffic to/from |
selector | | Labels to match pods in the namespace to apply the policy to. Leave empty to apply to all pods in the namespace |
+ description | string | A description of the policy, this will become part of the policy name |
direction | string (enum): | The direction of the traffic |
labels | | The labels to apply to the policy |
podLabels | | Deprecated: use selector |
port | number | The port to allow (protocol is always TCP) |
ports | number[] | A list of ports to allow (protocol is always TCP) |
remoteCidr | string | Custom generated policy CIDR |
remoteGenerated | string (enum):KubeAPI KubeNodes IntraNamespace CloudMetadata Anywhere
| Custom generated remote selector for the policy |
remoteNamespace | string | The remote namespace to allow traffic to/from. Use * or empty string to allow all namespaces |
remotePodLabels | | Deprecated: use remoteSelector |
remoteSelector | | The remote pod selector labels to allow traffic to/from |
selector | | Labels to match pods in the namespace to apply the policy to. Leave empty to apply to all pods in the namespace |
diff --git a/docs/reference/configuration/uds-networking-configuration.md b/docs/reference/configuration/uds-networking-configuration.md
index f71c77e55..3e3577641 100644
--- a/docs/reference/configuration/uds-networking-configuration.md
+++ b/docs/reference/configuration/uds-networking-configuration.md
@@ -25,6 +25,25 @@ This configuration directs the operator to use the specified CIDR range (`172.0.
When configuring a static CIDR range, it is important to make the range as restrictive as possible to limit the potential for unexpected networking access. An overly broad range could inadvertently allow egress traffic to destinations beyond the intended scope. Additionally, careful alignment with the actual IP addresses used by the Kubernetes API server is essential. A mismatch between the specified CIDR range and the cluster's configuration can result in network policy enforcement issues or disrupted connectivity.
+## KubeNodes CIDRs
+
+The UDS operator is responsible for dynamically updating network policies that use the `remoteGenerated: KubeNodes` custom selector, in response to changes to nodes in the Kubernetes cluster. As nodes are added, updated, or removed from a cluster, the operator will ensure that policies remain accurate and include all the nodes in the cluster.
+
+UDS operator provides an option to configure a set of static CIDR ranges in place of offering a dynamically updated list by setting an override to `operator.KUBENODE_CIDRS` in your bundle as a value or variable. The value should be a single string of comma (`,`) separated values for the individual IP addresses, using `/32` notation. For example:
+
+```yaml
+packages:
+ - name: uds-core
+ repository: ghcr.io/defenseunicorns/packages/uds/core
+ ref: x.x.x
+ overrides:
+ uds-operator-config:
+ uds-operator-config:
+ values:
+ - path: operator.KUBENODE_CIDRS
+ value: "172.28.0.2/32,172.28.0.3/32,172.28.0.4/32"
+```
+
## Additional Network Allowances
Applications deployed in UDS Core utilize [Network Policies](https://kubernetes.io/docs/concepts/services-networking/network-policies/) with a "Deny by Default" configuration to ensure network traffic is restricted to only what is necessary. Some applications in UDS Core allow for overrides to accommodate environment-specific requirements.
diff --git a/src/pepr/config.ts b/src/pepr/config.ts
index a51288f18..9ae7d4bbe 100644
--- a/src/pepr/config.ts
+++ b/src/pepr/config.ts
@@ -39,6 +39,9 @@ export const UDSConfig = {
// Static CIDR range to use for KubeAPI instead of k8s watch
kubeApiCidr: process.env.KUBEAPI_CIDR,
+ // Static CIDRs to use for KubeNodes instead of k8s watch. Comma separated list of CIDRs.
+ kubeNodeCidrs: process.env.KUBENODE_CIDRS,
+
// Track if UDS Core identity-authorization layer is deployed
isIdentityDeployed: false,
};
diff --git a/src/pepr/operator/controllers/network/generate.ts b/src/pepr/operator/controllers/network/generate.ts
index 6ead5ba1b..a3d087a8f 100644
--- a/src/pepr/operator/controllers/network/generate.ts
+++ b/src/pepr/operator/controllers/network/generate.ts
@@ -11,6 +11,7 @@ import { anywhere, anywhereInCluster } from "./generators/anywhere";
import { cloudMetadata } from "./generators/cloudMetadata";
import { intraNamespace } from "./generators/intraNamespace";
import { kubeAPI } from "./generators/kubeAPI";
+import { kubeNodes } from "./generators/kubeNodes";
import { remoteCidr } from "./generators/remoteCidr";
function isWildcardNamespace(namespace: string) {
@@ -26,6 +27,10 @@ function getPeers(policy: Allow): V1NetworkPolicyPeer[] {
peers = kubeAPI();
break;
+ case RemoteGenerated.KubeNodes:
+ peers = kubeNodes();
+ break;
+
case RemoteGenerated.CloudMetadata:
peers = cloudMetadata;
break;
@@ -93,7 +98,7 @@ export function generate(namespace: string, policy: Allow): kind.NetworkPolicy {
};
}
- // Add the generated policy label (used to track KubeAPI policies)
+ // Add the generated policy label (used to track KubeAPI and KubeNodes policies)
if (policy.remoteGenerated) {
generated.metadata!.labels!["uds/generated"] = policy.remoteGenerated;
}
diff --git a/src/pepr/operator/controllers/network/generators/kubeNodes.spec.ts b/src/pepr/operator/controllers/network/generators/kubeNodes.spec.ts
new file mode 100644
index 000000000..9ddd137df
--- /dev/null
+++ b/src/pepr/operator/controllers/network/generators/kubeNodes.spec.ts
@@ -0,0 +1,218 @@
+/**
+ * Copyright 2024 Defense Unicorns
+ * SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial
+ */
+
+import { beforeEach, beforeAll, describe, expect, it, jest } from "@jest/globals";
+
+import {
+ initAllNodesTarget,
+ kubeNodes,
+ updateKubeNodesFromCreateUpdate,
+ updateKubeNodesFromDelete,
+} from "./kubeNodes";
+import { K8s, kind } from "pepr";
+import { V1NetworkPolicyList } from "@kubernetes/client-node";
+import { anywhere } from "./anywhere";
+
+type KubernetesList