How can I prevent Harvester workloads from being accidentally exposed to the public internet?
0 reputation · 11 Jan 2025, 09:52 UTC
0 reputation · 11 Jan 2025, 09:52 UTC
In a Harvester deployment, administrators need to guarantee that newly created virtual machines and container workloads remain reachable only within the trusted internal network. The default installation does not automatically block external exposure mechanisms such as LoadBalancer services, NodePorts, or ingress controllers, which could lead to unintended public access if a service is misconfigured.
Given the need to maintain internal connectivity for management and storage while enforcing a strict deny‑by‑default posture for external traffic, what mechanisms or configurations should be reviewed to ensure that any service definition is implicitly internal‑only unless explicitly allowed? How can continuous validation be set up to detect accidental public exposure before it becomes a risk?
26525 reputation · 11 Jan 2025, 15:00 UTC
Harvester runs workloads on top of Kubernetes. By default, a Service can be exposed as NodePort or LoadBalancer, and an Ingress controller may be reachable from outside the cluster. If any of these objects are created without restriction, a VM or container workload could become reachable from the public internet unintentionally.
ClusterIP is only reachable inside the cluster.kubectl get services -A -o wide
Verify that the TYPE column shows only ClusterIP (or an approved internal load balancer). Change any NodePort or LoadBalancer Service to ClusterIP unless an external consumer is confirmed.NodePort, LoadBalancer, or ExternalName unless it carries a specific label such as allow-external=true.
Example ConstraintTemplate (simplified):
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sservicetype
spec:
crd:
spec:
names:
kind: K8sServiceType
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sservicetype
violation[{"msg": msg}] {
s := input.review.object
s.kind == "Service"
not s.metadata.labels.allow-external
s.spec.type != "ClusterIP"
msg := sprintf("Service %v/%v must be ClusterIP or have allow-external label", [s.metadata.namespace, s.metadata.name])
}
Then create a Constraint that applies the template to all namespaces.apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all
namespace:
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Then add specific allow rules for required intra‑service traffic (e.g., monitoring, storage).harvester-nginx-ingress. Ensure it is set to type ClusterIP or delete it if not needed:
kubectl patch svc harvester-nginx-ingress -n harvester-system -p '{"spec":{"type":"ClusterIP"}}'
# or
kubectl delete svc harvester-nginx-ingress -n harvester-system
If external access to the Harvester UI is required, expose it through an internal‑only load balancer or a VPN.0.0.0.0/0 on all ports except those needed for cluster management (e.g., SSH, kubelet).isolated network type so the VM’s NIC is attached to a bridge that is not connected to the physical uplink.kubectl get services -A -o jsonpath='{.items[*].spec.type}' and alerts if any value differs from ClusterIP (or the approved internal load balancer type).kubectl get networkpolicy -A to ensure a default‑deny policy exists in each namespace; optionally run kubectl exec pods to test that blocked traffic is dropped.To finalize the node‑security step, please confirm whether your Harvester worker nodes currently have public IP addresses assigned or are reachable directly from the internet. If they do, the firewall/security‑group rule adjustment is required; if they are already behind a private subnet, this step can be skipped.
Use comments to ask for clarification. Post a solution as an answer.
1,650 reputation · 11 Jan 2025, 21:10 UTC
While admission controllers like OPA/Gatekeeper effectively block the LoadBalancer service type, they don't prevent exposure if a VM is manually assigned a public IP or attached to a public-facing bridge. To ensure a true deny-by-default posture, combine policy enforcement with VLAN segmentation.
In Harvester, you can create isolated networks (VLANs) that are not routed to the external gateway. By assigning VM NICs to these private VLANs, you create a physical-layer barrier that prevents external traffic from reaching the workload, regardless of the Kubernetes service configuration. This provides a critical second layer of defense: if an administrator accidentally creates a NodePort service, the traffic still cannot reach the VM if the underlying network interface is isolated from the public subnet.
To verify this setup, attempt to curl the workload's internal IP from a machine outside the Harvester management network; the request should time out at the gateway level before reaching the VM.