Introduction
Meadow Supply should show live availability and calculate training basket quotes through its API. In this independent scene, the original applications are running, but an old API egress migration rule permits broad TCP connections and forgot DNS. The catalogue therefore shows an availability error. Repair the required dependencies, then retire the old rule's unnecessary permissions without breaking the shop or the separate dispatch service.
Use the namespace, role, policy, terminal and real-request methods taught in the previous guided lab. This lab explains egress, DNS protocol/port requirements, a terminal variable and policy unions before you use them. The prepared real single-node cluster independently contains the complete application and approved stock ingress; no files or processes from your previous VM are needed. No cluster installation or application programming is required. The duration is an author estimate, not measured beginner timing. All products and dispatch notes are synthetic, and training quotes do not reserve, order or charge anything.
Restore the Required API Dependencies
In this step, you will restore real DNS and stock connections for the Shop API without opening every destination.
Open Shop. The expected complete result is the same three-product Meadow Supply catalogue as before: Glass water bottle costs $18.00 with 6 units, Everyday notebook $14.00 with 4, and Canvas market bag $24.00 with 0. In the initial scene, the page instead says Live availability unavailable. Prices remain visible, but the application has no stock fallback and cannot produce a valid quote. This is the intended dependency failure to repair; do not mistake it for an empty stock collection. Reference should still show the two original dispatch notes. Switch to Workspace.
The independent workspace is /home/labex/project/stock-policy. Use the same path recovery as before: pwd, ls, and the absolute cd if needed. Read the supplied scope:
cd /home/labex/project/stock-policy
cat scope.json
The stock ingress boundary has already been prepared in this VM. It allows the API role in meadow-shop; keep that policy unchanged. The API's outgoing connections are controlled separately. Egress means traffic leaving selected Pods. A selecting Egress policy isolates those Pods for that direction, and the union of all applicable egress rules determines what may leave. Reply traffic for an allowed connection is implicitly allowed.
Read the existing migration policy in the API namespace:
kubectl --context=labex-v135 -n meadow-shop get networkpolicies
kubectl --context=labex-v135 -n meadow-shop describe networkpolicy legacy-egress
legacy-egress selects role=shop-api and allows TCP port 8080 to any destination. It did not include DNS. CoreDNS is the prepared cluster name service. A Service name needs a DNS query before an HTTP connection can use its address. DNS (Domain Name System) translates names to addresses. UDP (User Datagram Protocol) sends individual datagrams; TCP (Transmission Control Protocol) establishes connections. This cluster’s DNS service accepts both on port 53, so both paths to the DNS Pods in kube-system are required.
The provided diagnostic tool's dns mode sends a fresh UDP DNS query to the resolver in that Pod; dns-tcp sends a fresh TCP query. Neither relies on a cached application result. Test the actual API identity:
./tools/network-test api dns stock.meadow-stock.svc.cluster.local
./tools/network-test api dns-tcp stock.meadow-stock.svc.cluster.local
Both should report NETWORK_TIMEOUT and a nonzero exit. These expected failures concern the DNS connection. To distinguish them from a stopped stock process, make one explicit diagnostic request to the original stock Service address.
The following assignment captures a command's output with $(...) into the shell variable stock_ip. -o jsonpath='{.spec.clusterIP}' selects only the Service's spec.clusterIP field; quotes keep the expression together. This variable belongs to the current Workspace terminal session. It is a diagnostic value, not a policy target or permanent Pod address. If you reconnect to a new shell, repeat the assignment before using it.
stock_ip=$(kubectl --context=labex-v135 -n meadow-stock get service stock -o jsonpath='{.spec.clusterIP}')
printf prints the captured string; %s means a string and \n ends the line. Double quotes preserve the expanded value as one argument:
printf '%s\n' "$stock_ip"
${stock_ip} expands that variable inside the request URL. The existing broad TCP rule permits this connection without needing DNS:
./tools/network-test api http "http://${stock_ip}:8080/stock.json"
Expect HTTP_REPLY 200 and the original stock records. TCP access exists; resolving the name is a separate dependency. Never put that address into the finished policy: use the stable namespace and role relationships.
Inspect the real DNS labels before selecting them. -l k8s-app=kube-dns selects the prepared DNS Pods:
kubectl --context=labex-v135 get namespace kube-system --show-labels
kubectl --context=labex-v135 -n kube-system get pods -l k8s-app=kube-dns --show-labels
Create your own api-egress policy. It selects the API role. Its two to rules are alternatives: DNS in kube-system on UDP/TCP 53, or inventory in meadow-stock on TCP 8080. Within each individual peer, namespace and Pod selectors are combined with AND. Each rule's ports apply only to that rule's destinations.
mkdir -p keeps an existing release directory. As taught before, the quoted here-document and > write only your editable release file:
mkdir -p release
cat > release/api-egress.yaml <<'YAML'
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-egress
namespace: meadow-shop
spec:
podSelector:
matchLabels:
role: shop-api
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: meadow-stock
podSelector:
matchLabels:
role: inventory
ports:
- protocol: TCP
port: 8080
YAML
Read, apply and inspect the saved manifest:
cat release/api-egress.yaml
kubectl --context=labex-v135 apply -f release/api-egress.yaml
kubectl --context=labex-v135 -n meadow-shop describe networkpolicy api-egress
Confirm both real DNS transports and the stock connection by name. Enforcement can take a few seconds after an apply; repeat a request after a short wait if the previous boundary is still visible.
./tools/network-test api dns stock.meadow-stock.svc.cluster.local
./tools/network-test api dns-tcp stock.meadow-stock.svc.cluster.local
./tools/network-test api http http://stock.meadow-stock.svc.cluster.local:8080/stock.json
Expect DNS_REPLY UDP, DNS_REPLY TCP, then HTTP_REPLY 200 with all original stock data. Switch to Shop and reload. Live availability should return. Open Glass water bottle, select Quantity 2, and use Try a basket quote. Expect Ready for collection, total $36.00 and 6 available units, with the no-reservation training notice. Return through Back to product and Back to collection.
Compare the restored live catalogue with this actual running result:

This completes the required connection repair, but does not yet prove that unrelated destinations are denied. Another policy can still add permissions. Continue to the next step before treating this as the final boundary.
For a typo, return with pwd, ls and the absolute cd. For a malformed manifest or failed dependency request, read your saved file, describe output and the taught real labels/ports, correct the file and reapply it. DNS_REPLY is a name-service result; HTTP_REPLY is an application response; NETWORK_TIMEOUT means no response within the prepared network timeout; CONNECTION_REFUSED indicates a destination that refused the connection. The tool's bounded REQUEST_TIMEOUT includes the whole request and DNS. A generic failure does not establish a correct policy. Do not change application code, labels, source files, original Pods, stock ingress, Services, host networking or DNS infrastructure.
Retire the Old Broad Permission
In this step, you will remove the old migration policy's unnecessary allowance while preserving the repaired customer journey and separate dispatch service.
Start in Workspace at /home/labex/project/stock-policy. Your new policy allows DNS and stock only. Test the unrelated dispatch service from the API:
./tools/network-test api http http://dispatch.meadow-stock.svc.cluster.local:8080/notes.json
It currently returns HTTP_REPLY 200 and the two dispatch notes. This success reveals a permission leak; the Shop API does not need dispatch access. The new narrow policy does not override the existing broad one. NetworkPolicies add allowed connections together, regardless of application order. For a connection to work, the source's egress and the destination's ingress must both allow it.
List both policies again, then read the managed migration policy and its original source:
kubectl --context=labex-v135 -n meadow-shop get networkpolicies
kubectl --context=labex-v135 -n meadow-shop describe networkpolicy legacy-egress
cat starter/legacy-egress.yaml
The legacy rule allows TCP port 8080 without a to destination restriction. That permission still applies to the selected API Pods. In this release, keep the original managed legacy-egress object and retire its permissions in place. Save it with no egress allow entries, represented by the empty list egress: []. Your separate api-egress policy continues to provide the two required connections. Keep the read-only starter unchanged.
cat > release/legacy-egress.yaml <<'YAML'
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: legacy-egress
namespace: meadow-shop
spec:
podSelector:
matchLabels:
role: shop-api
policyTypes:
- Egress
egress: []
YAML
Read and apply the saved managed policy. Do not delete and recreate it:
cat release/legacy-egress.yaml
kubectl --context=labex-v135 apply -f release/legacy-egress.yaml
kubectl --context=labex-v135 -n meadow-shop describe networkpolicy legacy-egress
It should still select the API role but contribute no outgoing allowance. Your final release directory contains both saved policies. The prepared stock ingress policy remains unchanged.
Now the API's unrelated dispatch request must time out, while the customer's control request to that exact service still succeeds:
./tools/network-test api http http://dispatch.meadow-stock.svc.cluster.local:8080/notes.json
./tools/network-test customer http http://dispatch.meadow-stock.svc.cluster.local:8080/notes.json
Expect NETWORK_TIMEOUT with a nonzero exit for API, then HTTP_REPLY 200 with both unchanged notes for Customer. This pair prevents a stopped service from masquerading as correct isolation. If the API request still succeeds immediately after applying, wait a few seconds and repeat until the actual new boundary is observed.
Confirm the approved stock path and both DNS protocols again:
./tools/network-test api http http://stock.meadow-stock.svc.cluster.local:8080/stock.json
./tools/network-test api dns stock.meadow-stock.svc.cluster.local
./tools/network-test api dns-tcp stock.meadow-stock.svc.cluster.local
Switch to Shop, reload and repeat the Glass water bottle quote for Quantity 2: Ready for collection, $36.00, 6 units. Then quote Canvas market bag, Quantity 1: Not enough stock, $24.00, 0 units. Return to the collection and open Our approach to confirm the training scope. Switch to Reference and reload; both original pickup notes remain. Use Download notes and inspect the actual two-record download. This browser download is separate from the terminal workspace and need not be copied there.
Your handoff is release/api-egress.yaml plus release/legacy-egress.yaml, applied to the original policy identities. Both live and saved permissions must match the taught namespace/role and protocol/port boundaries: DNS UDP/TCP 53 and stock TCP 8080, with legacy contributing no allowance. Keep all original application resources, Pods, namespace labels, data and supplied sources. If a correction breaks the shop, inspect the taught DNS and stock paths, fix only the editable policy files and apply them again. Do not add another allow-all rule or change the application to bypass DNS. These finite TCP/UDP observations do not prove a production network security boundary against nodes or administrators.
Summary
You separated name resolution from an application connection, restored the API's real DNS and stock dependencies, and kept the live customer quotes working. You also found why a narrow policy did not remove a permission supplied by another policy, then retired that legacy allowance without stopping the unrelated service.
The final saved release and live policy union allow the required DNS and stock paths while denying API access to dispatch. Policy order is not precedence; evaluate the combined permissions and preserve positive controls when interpreting failures.



