4.3 Restrict build-pod network access
Your source now names internal inputs, and your pipeline is wired to prepare a Maven cache. Before running it, replace the build namespace’s allow-all egress policy with explicit internal destinations. Continue in the Showroom terminal; the policy applies to build pods, not to your terminal.
Why this control exists
Source configuration expresses the intended fetch path. NetworkPolicy adds a separate control over pod traffic, so a command cannot silently use an unlisted public endpoint. The workshop allows Nexus for prefetch and uses Maven’s offline flag during the image build. This is a constrained workshop build path, not a physically air-gapped cluster.
NetworkPolicies are additive: any policy selecting a pod can grant egress. Tightening build-egress is insufficient if another selected policy still allows everything. Inspect all policies in the build namespace as part of your review.
Learning objectives
By the end of this module, you will be able to:
-
Replace the build namespace’s allow-all egress with explicit destinations.
-
Match namespace selectors and destination ports to the cluster configuration.
-
Discover the Kubernetes API addresses needed by the build Task.
-
Explain the policy’s scope and inspect other policies that could grant access.
Record the starting policy
Discover the build namespace and save a new evidence directory for this attempt. Expect the initial build-egress to contain egress: [{}], which allows all destinations. If you already tightened it, preserve your work and compare it with the criteria below.
BUILD_NS="$(oc -n gitea get configmap lab-gitea -o jsonpath='{.data.student_build_namespace}')"
mkdir -p ~/lightwell-build-evidence
NP_EVIDENCE="$(mktemp -d "$HOME/lightwell-build-evidence/network.XXXXXX")"
oc -n "$BUILD_NS" get networkpolicy build-egress -o yaml > "$NP_EVIDENCE/before.yaml"
cat "$NP_EVIDENCE/before.yaml"
oc -n "$BUILD_NS" get configmap lab-networkpolicy -o yaml
oc -n "$BUILD_NS" get networkpolicy
Exercise
Identify the allowed destinations
Use ConfigMap lab-networkpolicy for the namespaces and ports. The table lists the workshop defaults and why each destination is needed. OpenShift matches destination pod ports after service translation; for example, Central’s Service port 443 maps to pod port 8443.
| Destination | Protocol and port | Purpose |
|---|---|---|
|
UDP and TCP |
Resolve service names |
|
TCP |
Access internal images |
|
TCP |
Nexus Maven and destination registry |
|
TCP |
Clone application source internally |
Kubernetes API ClusterIP and endpoints |
TCP |
Start and inspect BuildConfig builds |
|
TCP |
Pipeline ACS checks |
|
TCP |
TUF, Fulcio HTTP/gRPC, and Rekor |
|
TCP |
Later TPA access |
Discover the API ClusterIP and endpoint addresses. These vary by claim. The API endpoints are host-network control-plane addresses, so a namespace selector alone does not cover them.
oc -n default get svc kubernetes \
-o jsonpath='clusterIP={.spec.clusterIP} port={.spec.ports[0].port}{"\n"}'
oc -n default get endpoints kubernetes \
-o jsonpath='{.subsets[*].addresses[*].ip}{" "}{.subsets[*].ports[*].port}{"\n"}'
Author the build policy
Create ~/lightwell-build-evidence/build-egress.yaml in your editor. Begin with the following structure. Set metadata.namespace to your discovered build namespace. This is a partial policy: add all remaining table destinations before applying it.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: build-egress
namespace: lw-poc-build
spec:
podSelector: {}
policyTypes: [Egress]
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: openshift-dns
ports:
- protocol: UDP
port: 5353
- protocol: TCP
port: 5353
For each remaining named namespace, add another egress entry with its own namespaceSelector and TCP ports from the table. Keep each namespace paired with its ports. For the API, add one entry with an ipBlock.cidr for the ClusterIP and port 443, then entries for each endpoint address and port 6443. Use /32 for each IPv4 address (/128 for IPv6). Do not add a broad address range or an empty rule.
Namespace selectors allow matching pods in the named namespace on the listed ports; they do not identify one specific Service. Keep podSelector: {} so the policy selects every pod in the build namespace. Remove the seed’s empty egress rule entirely. Keep public registries, public DNS, and the ingress namespace off this allow-list. Build tasks use the internal Gitea, Nexus, and signing-service URLs.
Apply and inspect your policy
Validate the authored object with the API before applying it. A successful dry run checks the object’s schema, not whether every required connection will work. Apply only after comparing each destination with the table and discovered values.
oc -n "$BUILD_NS" apply --dry-run=server -f ~/lightwell-build-evidence/build-egress.yaml
oc -n "$BUILD_NS" apply -f ~/lightwell-build-evidence/build-egress.yaml
oc -n "$BUILD_NS" get networkpolicy build-egress -o yaml > "$NP_EVIDENCE/after.yaml"
diff -u "$NP_EVIDENCE/before.yaml" "$NP_EVIDENCE/after.yaml"
diff returns status 1 when it finds differences; that is expected here. The meaningful change is the explicit destination and port list replacing allow-all egress.
Review
Inspect all policies in the build namespace, including their selectors. Confirm there is no remaining allow-all rule that selects build pods. Check that build-egress has not been copied into staging or production and that their app-operate policies remain present. Track 6 owns application egress.
oc -n "$BUILD_NS" get networkpolicy -o yaml
oc -n lw-poc-staging get networkpolicy
oc -n lw-poc-prod get networkpolicy
These observations establish the policy configuration. Module 4.4 tests the intended build path and records a negative build attempt. If clone or prefetch fails there, check the internal URL, matching namespace, and pod port before changing a rule.
Kubelet image pulls occur on nodes and are outside this pod-egress policy. Task images can therefore still come from public registries. A public image-pull failure alone does not prove NetworkPolicy enforcement; inspect the failing operation and its logs. The Dockerfile’s internal references and Maven offline mode remain separate controls.
Carry the result into module 4.4
Keep the before/after policy evidence. Next run the committed pipeline and correlate its task results with the produced image and SBOM.
Official documentation
-
Lightwell Network Java repository (why Nexus port
8081stays on the allow-list)