Installing Windows Mesh Expansion (WME)
The installation method for BEL Windows Mesh Expansion is the bel-wme-installer.msi, a WiX v6 MSI that installs runtime components, registers the driver, and starts the harness service in a single step.
Supported Platforms
The driver included in this release is signed by Microsoft for Windows Server 2025. Microsoft’s kernel signing policy for Server 2025 also covers Windows 11, so the same driver loads on both platforms.
| OS | Architecture |
|---|---|
| Windows Server 2025 | x64 |
| Windows 11 | x64 |
Prerequisites
1. Control Plane Reachability
The harness must connect to three Linkerd control plane services. By default, the installer resolves these using standard Kubernetes DNS names:
| Service | Default Address |
|---|---|
| Autoregistration | linkerd-autoregistration.linkerd.svc.cluster.local:8081 |
| Destination | linkerd-dst.linkerd.svc.cluster.local:8086 |
| Policy | linkerd-policy.linkerd.svc.cluster.local:8090 |
The VM must resolve these names and reach the addresses. It is recommended to
run CoreDNS on the VM configured to forward *.cluster.local queries to the
cluster’s DNS service.
- To use a non-default cluster domain, pass
CLUSTER_DOMAIN=<domain>. - To override individual addresses, set
CONTROL_ADDRESS,DESTINATION_SVC_ADDR, orPOLICY_SVC_ADDRdirectly.
2. SPIRE
A SPIRE agent must be running on the VM before the MSI executes, connected to a
SPIRE server. The documented configuration runs a SPIRE server locally on each
VM; a centralized SPIRE server shared across multiple VMs is architecturally
valid but untested with BEL WME.
For security and mutual TLS (mTLS) trust, the setup relies on a specific PKI
chain:
- SVID Issuance: The VM’s SPIRE server uses a dedicated SPIRE Upstream CA
Certificate (an intermediate CA with
pathlen:1), which is signed by the Linkerd root CA, to issue local SPIFFE SVIDs. This approach limits the blast radius, as the VM never holds the root private key. - Control Plane Verification: The data-plane proxy requires the Cluster Root CA Certificate to verify the Linkerd control plane’s TLS certificates.
Certificate Provisioning
Ensure the following necessary certificate files are provisioned on the VM. Note: These paths reflect the expected layout from the BEL WME SPIRE setup script and may vary based on your deployment decision (the files are typically pulled from cluster secrets and configmaps):
C:\spire\certs\ca.crt: The SPIRE upstream CA certificate (intermediate).C:\spire\certs\ca.key: The SPIRE upstream CA private key.C:\spire\certs\bundle.crt: The concatenated trust bundle built by combining the SPIRE upstream CA cert (ca.crt) with the cluster root CA cert (root-ca.crt).
Verification
Before running the installer, ensure the SPIRE agent’s named pipe is ready:
Test-Path "\\.\pipe\spire-agent\public\api"
3. Windows Firewall
The driver intercepts outbound traffic only. Inbound mTLS connections from the
cluster arrive directly at the proxy’s inbound listening port
(PROXY_INBOUND_PORT, default 4143, bound on all interfaces). The driver
plays no role in the inbound path - any inbound port that is not the proxy’s
listening port receives no mTLS enforcement from the mesh. Windows Firewall is
the appropriate control for restricting inbound access.
Allow the required ports and set the firewall profile default to block all other unsolicited inbound traffic:
New-NetFirewallRule -DisplayName "Linkerd Inbound Proxy (4143)" -Direction Inbound -Protocol TCP -LocalPort 4143 -Action Allow
New-NetFirewallRule -DisplayName "Linkerd Admin (4191)" -Direction Inbound -Protocol TCP -LocalPort 4191 -Action Allow
New-NetFirewallRule -DisplayName "Linkerd Harness Readiness (4192)" -Direction Inbound -Protocol TCP -LocalPort 4192 -Action Allow
# Recommended: set the default inbound action to Block. The allow rules above still permit the required ports.
# The mesh does not enforce mTLS on traffic arriving at any other port.
Set-NetFirewallProfile -Profile Domain,Private,Public -DefaultInboundAction Block
If you changed PROXY_INBOUND_PORT from its default, substitute that port in
the first rule. If you set a default inbound block policy, add any other needed
allow rules for ports your workload needs to accept directly before applying it.
4. ExternalGroup
An ExternalGroup resource must exist in the target namespace before
installation. The installer properties WORKLOAD_GROUP_NAME and
WORKLOAD_GROUP_NAMESPACE must match this resource.
apiVersion: workload.buoyant.io/v1alpha1
kind: ExternalGroup
metadata:
name: <WORKLOAD\_GROUP\_NAME>
namespace: <WORKLOAD\_GROUP\_NAMESPACE>
spec:
probes:
- failureThreshold: 3
httpGet:
path: /ready
port: 4192
scheme: HTTP
host: 127.0.0.1
initialDelaySeconds: 5
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 2
template:
metadata:
labels:
app: <WORKLOAD\_LABEL>
ports:
- port: <SERVICE\_PORT>
name: <PORT\_NAME>
Adjust template.metadata.labels and template.ports to match your workload. The probe target (4192) is fixed.
Install
Required Values
Ensure you have the following information:
- VM IP Address: Reachable from the cluster (
INBOUND_NETWORK_ADDRESS). - ExternalGroup: The name and namespace of the ExternalGroup created in prerequisite 4.
Execution
Run the installer silently using msiexec. For non-automated deployments, you
can also run the MSI interactively via the GUI.
Standard Installation:
msiexec /i bel_wme_installer.msi /quiet /l*vx C:\temp\install.log `
INBOUND_NETWORK_ADDRESS="<THIS_VM_IP>" `
WORKLOAD_GROUP_NAME="<GROUP_NAME>" `
WORKLOAD_GROUP_NAMESPACE="<NAMESPACE>"
Non-Default Configuration
If your cluster domain is not cluster.local, pass CLUSTER_DOMAIN and the installer derives all three control plane addresses automatically:
msiexec /i bel_wme_installer.msi /quiet /l*vx C:\temp\install.log `
INBOUND_NETWORK_ADDRESS="<THIS_VM_IP>" `
WORKLOAD_GROUP_NAME="<GROUP_NAME>" `
WORKLOAD_GROUP_NAMESPACE="<NAMESPACE>" `
CLUSTER_DOMAIN="<CLUSTER_DOMAIN>"
If the control plane is only reachable by IP (DNS does not resolve the cluster domain), override the three addresses directly instead:
msiexec /i bel_wme_installer.msi /quiet /l*vx C:\temp\install.log `
INBOUND_NETWORK_ADDRESS="<THIS_VM_IP>" `
WORKLOAD_GROUP_NAME="<GROUP_NAME>" `
WORKLOAD_GROUP_NAMESPACE="<NAMESPACE>" `
CONTROL_ADDRESS="<AUTOREGISTRATION_IP>:<AUTOREGISTRATION_PORT>" `
DESTINATION_SVC_ADDR="<DESTINATION_IP>:<DESTINATION_PORT>" `
POLICY_SVC_ADDR="<POLICY_IP>:<POLICY_PORT>"
MSI Properties
| Property | Default | Description |
|---|---|---|
INBOUND_NETWORK_ADDRESS | (required) | VM IP reachable from the cluster |
WORKLOAD_GROUP_NAME | (required) | ExternalGroup name |
WORKLOAD_GROUP_NAMESPACE | (required) | ExternalGroup namespace |
CLUSTER_DOMAIN | cluster.local | Cluster DNS domain |
CONTROL_ADDRESS | linkerd-autoregistration.linkerd.svc.<CD>:8081 | Control plane host:port |
DESTINATION_SVC_ADDR | linkerd-dst.linkerd.svc.<CD>:8086 | Destination service host:port |
POLICY_SVC_ADDR | linkerd-policy.linkerd.svc.<CD>:8090 | Policy service host:port |
INSTALLFOLDER | %ProgramFiles%\Buoyant\Linkerd | Installation directory |
CONTROL_SERVER_NAME | linkerd-autoregistration.linkerd.serviceaccount.identity.linkerd.<CLUSTER_DOMAIN> | TLS server name for control plane |
SPIRE_SOCKET_ADDR | \\.\pipe\spire-agent\public\api | SPIRE agent named pipe path |
LOGDIR | [INSTALLFOLDER] | Harness log output directory |
LOG_LEVEL | info | Trace, debug, info, warn, error |
PROXY_INBOUND_PORT | 4143 | Port the proxy binds for inbound connections (0.0.0.0:<port>). The driver does not redirect inbound traffic - this configures the proxy’s own listening address only. Must match the firewall allow rule above. |
PROXY_OUTBOUND_PORT | 4140 | Driver outbound redirect port |
OUTBOUND_PORTS_TO_IGNORE | 8081 | Ports excluded from outbound redirection. Default 8081 exempts SPIRE agent traffic; harness/proxy PIDs are always exempt |
Post-Install Configuration
Service Dependency
One step must be applied manually after install to prevent the harness from starting before SPIRE is available:
sc.exe config linkerd-proxy-harness depend= spire-agent
Note: spire-agent must match the actual SCM service name for the SPIRE agent on your VM. This reflects the name registered by the BEL WME SPIRE setup script.
The installer automatically configures SCM recovery (restart on failure). The following is an optional override for different recovery settings:
sc.exe failure linkerd-proxy-harness reset= 60 actions= restart/5000/restart/10000/restart/30000
Verify Installation
Check Services:
sc query linkerdtcpredirectandsc query linkerd-proxy-harnessshould both beRUNNING.Check Logs: Check the harness log for successful identity acquisition and control plane connection status. See the Logs section in Troubleshooting for the path and command.
Cluster Registration: Run
kubectl get externalworkload -n <namespace> -wfrom a machine with cluster access.READYshould becomeTruewithin 30-90 seconds.
Uninstall
msiexec /x bel_wme_installer.msi /quiet /l*vx C:\temp\uninstall.log
Troubleshooting
Logs
The MSI registers an ETW AutoLogger session automatically. Traces are written to
[INSTALLFOLDER]\linkerd-tcp-redirect-driver.etl (default:
%ProgramFiles%\Buoyant\Linkerd\linkerd-tcp-redirect-driver.etl). To decode:
$d = "$env:ProgramFiles\Buoyant\Linkerd"
tracefmt -p "$d\driver" -o "$d\driver.log" "$d\linkerd-tcp-redirect-driver.etl"
To check the harness service log:
Get-Content "$env:ProgramFiles\Buoyant\Linkerd\harness.log" -Tail 30
Quick Diagnostics
Run these PowerShell commands for initial checks. All service should be running and Test-Path should return True.
Test-Path "\\.\pipe\spire-agent\public\api"
sc.exe query linkerdtcpredirect
sc.exe query linkerd-proxy-harness
# ExternalWorkload registration (run on cluster)
kubectl get externalworkload -n <namespace>
SPIRE / Certificate Issues
invalid peer certificate: UnknownIssuer
This error can be caused by two issues:
- VM Side (Incomplete Trust Bundle): SPIRE’s cached trust bundle may be missing the root CA. Verify the bundle contains both the SPIRE sub-CA and the cluster root CA. Force a re-bootstrap if only one cert appears.
- Cluster Side (Stale Trust Bundle): Application proxies in the cluster
started before the SPIRE CA was added to
linkerd-identity-trust-roots.- Fix: Restart application pods to force proxies to reload the current
trust bundle:
kubectl rollout restart deployment -n <namespace>
- Fix: Restart application pods to force proxies to reload the current
trust bundle:
Re-Attestation (Expired SVID)
Re-attestation is required. Contact support or refer to the SPIRE documentation for the necessary re-attestation script, which must run as SYSTEM via a scheduled task.
Harness / Service Issues
Harness Service Won’t Stop
If the harness is in a connection retry loop, kill the process directly:
Get-Process -Name "*harness*" -ErrorAction SilentlyContinue | Stop-Process -Force
Harness Not Starting After Install
- Verify SPIRE was running before install.
- Check the install log (at the path you specified in the msiexec /l*vx argument) and harness log (refer to the Logs section above).
- Verify the SPIRE pipe is present:
Test-Path "\\.\pipe\spire-agent\public\api"
Harness Fails to Connect to Control Plane
- Verify control plane IPs/NodePorts are correct.
- Test connectivity from the VM using the correct IPs for your environment:
Test-NetConnection <AUTOREGISTRATION_IP> -Port <AUTOREGISTRATION_PORT>
Test-NetConnection <DESTINATION_IP> -Port <DESTINATION_PORT>
Test-NetConnection <POLICY_IP> -Port <POLICY_PORT>
Use the ports from your CONTROL_ADDRESS, DESTINATION_SVC_ADDR, and
POLICY_SVC_ADDR values (defaults: 8081, 8086, 8090).
ExternalWorkload Not Registering
This is a common failure during the first installation. If the workload does not
appear as READY, check the harness log (see Logs above) for connectivity
errors and ensure the cluster check in Quick Diagnostics shows the
ExternalWorkload exists.
Harness Won’t Stop / Uninstaller Hangs
If the harness is in a control-plane connection retry loop (typically when the cluster is unreachable), it will not respond to Stop-Service or Restart-Service within the SCM timeout. The uninstaller stalls for the same reason - the MSI stop step times out waiting for the service. In either case, kill the process directly:
Get-Process -Name "*harness*" -ErrorAction SilentlyContinue | Stop-Process -Force
Then re-run the uninstaller or restart the service as needed.