Skip to content

Run vScope in Kubernetes with Restricted Privileges

The Kubernetes manifests in Installation and Discovery Proxies run vScope as root inside the container, which is the recommended setup. Use this guide if your cluster policies require restricted privileges.

Choose one of the options below. They are listed in order of preference. To understand what each option changes for discovery, see Container privileges.

  • Use a user namespace: vScope keeps root inside the container, mapped to an unprivileged user on the node.
  • Run as non-root: vScope runs as a regular user. Use this when your policies require non-root containers, for example the Pod Security restricted profile.

Both options change only the Deployment. Make the changes in the manifest you saved during installation, then apply it again with kubectl apply. You can keep the existing PVC.

  • Kubernetes 1.33 or later. Kubernetes 1.30–1.32 needs the UserNamespacesSupport feature gate.
  • Linux kernel 6.3 or later on the nodes.
  • containerd 2.0 or later, or CRI-O 1.25 or later.
  • The persistent volume mounted at /data must use a filesystem that supports idmapped mounts, such as ext4 or xfs. Some network filesystems, such as NFS, may not support it.

See System Requirements.

  1. In the server Deployment, add hostUsers: false under spec.template.spec:

    spec:
    template:
    spec:
    hostUsers: false
    terminationGracePeriodSeconds: 330
    containers:
    - name: vscope-server
    # ...unchanged
  2. Apply the manifest and wait for the rollout:

    Terminal window
    kubectl apply -f vscope-server.yaml
    kubectl -n default rollout status deployment/vscope-server --timeout=600s
  3. Check that the pod runs in a user namespace:

    Terminal window
    kubectl -n default exec deployment/vscope-server -- cat /proc/self/uid_map

    The output should map user 0 to a high ID, for example 0 1882324992 65536. If the output is 0 0 4294967295, the pod is not in a user namespace and still runs as root on the node. Clusters that do not support user namespaces ignore hostUsers without reporting an error.

  4. For each proxy, add hostUsers: false in the same place in vscope-proxy.yaml, apply the manifest, and run the same check against deployment/vscope-proxy.

  • The cluster must allow the sysctls net.ipv4.ip_unprivileged_port_start and net.ipv4.ping_group_range. Both are safe sysctls and are allowed by default in Kubernetes 1.22 or later.

The examples run vScope with user and group ID 1000. You can use another non-zero ID; use the same group ID in ping_group_range.

  1. In the server Deployment, add a pod-level securityContext under spec.template.spec, add a container-level securityContext, and add -Duser.home=/data to JAVA_OPTS:

    spec:
    template:
    spec:
    securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    runAsGroup: 1000
    fsGroup: 1000
    fsGroupChangePolicy: OnRootMismatch
    seccompProfile:
    type: RuntimeDefault
    sysctls:
    - name: net.ipv4.ip_unprivileged_port_start
    value: "80"
    - name: net.ipv4.ping_group_range
    value: "1000 1000"
    terminationGracePeriodSeconds: 330
    containers:
    - name: vscope-server
    env:
    - name: JAVA_OPTS
    value: "-Xmx16g -Duser.home=/data"
    securityContext:
    allowPrivilegeEscalation: false
    capabilities:
    drop:
    - ALL
    # ...image, ports, resources and volumeMounts unchanged
    • sysctls is only valid in the pod-level securityContext. Kubernetes rejects it in the container-level one.
    • ip_unprivileged_port_start lets vScope listen on port 80 without root. ping_group_range lets the group send ping requests.
    • fsGroup makes /data writable for the group, including data written by an earlier root installation. If your storage does not apply fsGroup, for example some NFS volumes, change the ownership of the volume to the user and group ID.
  2. Apply the manifest and wait for the rollout:

    Terminal window
    kubectl apply -f vscope-server.yaml
    kubectl -n default rollout status deployment/vscope-server --timeout=600s
  3. Check that vScope runs as the configured user and can ping:

    Terminal window
    kubectl -n default exec deployment/vscope-server -- id
    kubectl -n default exec deployment/vscope-server -- ping -c 1 <target-ip>

    Expect uid=1000 gid=1000 and a ping reply. id may also report that it cannot find a name for the group ID, which is expected.

  4. Open the vScope web address and sign in.

  5. For each proxy, make the same changes in vscope-proxy.yaml, but leave out the ip_unprivileged_port_start sysctl because the proxy does not listen on port 80. Add -Duser.home=/data to the existing JAVA_OPTS:

    spec:
    template:
    spec:
    securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    runAsGroup: 1000
    fsGroup: 1000
    fsGroupChangePolicy: OnRootMismatch
    seccompProfile:
    type: RuntimeDefault
    sysctls:
    - name: net.ipv4.ping_group_range
    value: "1000 1000"
    terminationGracePeriodSeconds: 330
    containers:
    - name: vscope-proxy
    env:
    - name: JAVA_OPTS
    value: >-
    -Xmx4g
    -Dproxy.master.host=YOUR-VSCOPE-MASTER
    -Dproxy.master.port=4445
    -Duser.home=/data
    securityContext:
    allowPrivilegeEscalation: false
    capabilities:
    drop:
    - ALL
    # ...image, resources and volumeMounts unchanged

    Apply the manifest and run the same checks against deployment/vscope-proxy.

When running as non-root, discovery may report Could not initialize raw ping socket for scanned ranges. This is expected: vScope cannot use raw sockets and continues with the ping tool instead.

If /data/log/debug.log also shows System ping not available, run ping -c 1 127.0.0.1 in the pod. If it fails with ping: socket: Operation not permitted, ping_group_range does not include the pod’s group ID. Until this is fixed, vScope falls back to a TCP-based reachability check, which finds fewer hosts.