Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions docs/docs/guides/09-pod-annotations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ This document provides a comprehensive reference for all pod annotations availab
InterLink supports several categories of annotations:

- **[VPN & Networking](#vpn--networking)**: Configure pod IP allocation and VPN connectivity
- **[Mesh Networking](#mesh-networking)**: Control bidirectional mesh networking for offloaded pods
- **[Wstunnel Integration](#wstunnel-integration)**: Control websocket tunneling for exposed ports
- **[Job Management](#job-management)**: Handle remote job execution and tracking
- **[System Annotations](#system-annotations)**: Internal annotations used by interLink components
Expand Down Expand Up @@ -77,6 +78,36 @@ spec:

---

## Mesh Networking

### `interlink.eu/mesh-network`

Disables mesh networking for a specific offloaded pod when set to `"disabled"`.

**Usage:**
```yaml
apiVersion: v1
kind: Pod
metadata:
name: my-pod
annotations:
interlink.eu/mesh-network: "disabled"
spec:
containers:
- name: app
image: nginx:latest
```

**Behavior:**
- When set to `"disabled"`, the pod is offloaded **without** mesh networking even if the global `FullMesh` configuration is enabled
- Disables the WireGuard/wstunnel bidirectional communication setup for this pod
- All other pods without this annotation continue to use mesh networking as configured
- Value matching is case-insensitive (e.g., `"Disabled"`, `"DISABLED"` also work)

**Default:** Not set (mesh networking follows global `FullMesh` configuration)

---

## Wstunnel Integration

### `interlink.virtual-kubelet.io/wstunnel-timeout`
Expand Down Expand Up @@ -385,6 +416,7 @@ kubectl get deployment,service,ingress -l interlink.virtual-kubelet.io/type=wstu
| `JobID` | v0.1.0+ | Remote job management |
| `interlink.virtual-kubelet.io/wstunnel-timeout` | v0.6.0+ | Wstunnel integration |
| `interlink.virtual-kubelet.io/ping-response` | v0.2.0+ | Health check responses |
| `interlink.eu/mesh-network` | v0.6.x+ | Per-pod mesh networking opt-out |

---

Expand Down
19 changes: 19 additions & 0 deletions docs/docs/guides/13-mesh-network-configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,25 @@ virtualNode:
meshScriptTemplatePath: "/path/to/custom/mesh.sh"
```

### Disabling Mesh Networking for Specific Pods

When `fullMesh` is enabled globally, you can opt individual pods out of mesh networking by adding the `interlink.eu/mesh-network: "disabled"` annotation:

```yaml
apiVersion: v1
kind: Pod
metadata:
name: my-pod
annotations:
interlink.eu/mesh-network: "disabled"
spec:
containers:
- name: app
image: nginx:latest
```

With this annotation, the pod is offloaded **without** mesh networking (no WireGuard tunnel is created), while all other pods continue to use the global `fullMesh` setting.

### Configuration Options

#### Network CIDRs
Expand Down
32 changes: 32 additions & 0 deletions docs/versioned_docs/version-0.6.x/guides/09-pod-annotations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ This document provides a comprehensive reference for all pod annotations availab
InterLink supports several categories of annotations:

- **[VPN & Networking](#vpn--networking)**: Configure pod IP allocation and VPN connectivity
- **[Mesh Networking](#mesh-networking)**: Control bidirectional mesh networking for offloaded pods
- **[Wstunnel Integration](#wstunnel-integration)**: Control websocket tunneling for exposed ports
- **[Job Management](#job-management)**: Handle remote job execution and tracking
- **[System Annotations](#system-annotations)**: Internal annotations used by interLink components
Expand Down Expand Up @@ -77,6 +78,36 @@ spec:

---

## Mesh Networking

### `interlink.eu/mesh-network`

Disables mesh networking for a specific offloaded pod when set to `"disabled"`.

**Usage:**
```yaml
apiVersion: v1
kind: Pod
metadata:
name: my-pod
annotations:
interlink.eu/mesh-network: "disabled"
spec:
containers:
- name: app
image: nginx:latest
```

**Behavior:**
- When set to `"disabled"`, the pod is offloaded **without** mesh networking even if the global `FullMesh` configuration is enabled
- Disables the WireGuard/wstunnel bidirectional communication setup for this pod
- All other pods without this annotation continue to use mesh networking as configured
- Value matching is case-insensitive (e.g., `"Disabled"`, `"DISABLED"` also work)

**Default:** Not set (mesh networking follows global `FullMesh` configuration)

---

## Wstunnel Integration

### `interlink.virtual-kubelet.io/wstunnel-timeout`
Expand Down Expand Up @@ -385,6 +416,7 @@ kubectl get deployment,service,ingress -l interlink.virtual-kubelet.io/type=wstu
| `JobID` | v0.1.0+ | Remote job management |
| `interlink.virtual-kubelet.io/wstunnel-timeout` | v0.6.0+ | Wstunnel integration |
| `interlink.virtual-kubelet.io/ping-response` | v0.2.0+ | Health check responses |
| `interlink.eu/mesh-network` | v0.6.x+ | Per-pod mesh networking opt-out |

---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,25 @@ virtualNode:
meshScriptTemplatePath: "/path/to/custom/mesh.sh"
```

### Disabling Mesh Networking for Specific Pods

When `fullMesh` is enabled globally, you can opt individual pods out of mesh networking by adding the `interlink.eu/mesh-network: "disabled"` annotation:

```yaml
apiVersion: v1
kind: Pod
metadata:
name: my-pod
annotations:
interlink.eu/mesh-network: "disabled"
spec:
containers:
- name: app
image: nginx:latest
```

With this annotation, the pod is offloaded **without** mesh networking (no WireGuard tunnel is created), while all other pods continue to use the global `fullMesh` setting.

### Configuration Options

#### Network CIDRs
Expand Down
10 changes: 5 additions & 5 deletions pkg/interlink/api/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ func isSafeURL(rawurl string) bool {
return true
}

// urlSafetyChecker is the URL safety function used by ReqWithError.
// It can be overridden in tests.
var urlSafetyChecker = isSafeURL

// InterLinkHandler handles HTTP requests for the interLink API server.
// It acts as a proxy between the Virtual Kubelet and sidecar plugins,
// forwarding requests and managing pod lifecycle operations.
Expand Down Expand Up @@ -117,11 +121,7 @@ func ReqWithError(
// Add session number for end-to-end trace
AddSessionContext(req, sessionContext)

if !isSafeURL(req.URL.String()) {
return nil, fmt.Errorf("potential SSRF detected: %s", req.URL.String())
}
// SSRF protection: ensure URL is safe before making the request
if !isSafeURL(req.URL.String()) {
if !urlSafetyChecker(req.URL.String()) {
return nil, fmt.Errorf("potential SSRF detected: %s", req.URL.String())
}
resp, err := clientHTTP.Do(req) // #nosec G704
Expand Down
7 changes: 7 additions & 0 deletions pkg/interlink/api/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"io"
"net/http"
"net/http/httptest"
"os"
"testing"
"time"

Expand All @@ -15,6 +16,12 @@ import (
"go.opentelemetry.io/otel/sdk/trace/tracetest"
)

func TestMain(m *testing.M) {
// Allow loopback URLs so httptest servers work in unit tests.
urlSafetyChecker = func(string) bool { return true }
os.Exit(m.Run())
}

func TestGetSessionContext(t *testing.T) {
tests := []struct {
name string
Expand Down
6 changes: 5 additions & 1 deletion pkg/virtualkubelet/execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ func isSafeURL(rawurl string) bool {
return true
}

// urlSafetyChecker is the URL safety function used by doRequestWithClient.
// It can be overridden in tests.
var urlSafetyChecker = isSafeURL

const (
PodPhaseInitialize = "Initializing"
PodPhaseCompleted = "Completed"
Expand Down Expand Up @@ -256,7 +260,7 @@ func doRequestWithClient(req *http.Request, token string, httpClient *http.Clien
req.Header.Add("Authorization", "Bearer "+token)
}
req.Header.Set("Content-Type", "application/json")
if !isSafeURL(req.URL.String()) {
if !urlSafetyChecker(req.URL.String()) {
return nil, fmt.Errorf("potential SSRF detected: %s", req.URL.String())
}
return httpClient.Do(req) // #nosec G704
Expand Down
27 changes: 27 additions & 0 deletions pkg/virtualkubelet/execute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ func TestDoRequestWithClient(t *testing.T) {
}))
defer testServer.Close()

// Allow loopback URLs for the test server
origChecker := urlSafetyChecker
urlSafetyChecker = func(string) bool { return true }
defer func() { urlSafetyChecker = origChecker }()

tests := []struct {
name string
token string
Expand Down Expand Up @@ -160,6 +165,28 @@ func TestDoRequestWithClient(t *testing.T) {
}
}

func TestIsSafeURL(t *testing.T) {
tests := []struct {
name string
url string
want bool
}{
{"valid http", "http://example.com/api", true},
{"valid https", "https://example.com/api", true},
{"localhost blocked", "http://localhost:8080", false},
{"127.0.0.1 blocked", "http://127.0.0.1:8080", false},
{"::1 blocked", "http://[::1]:8080", false},
{".internal blocked", "http://service.internal/api", false},
{"unix scheme blocked", "unix:///var/run/test.sock", false},
{"invalid url blocked", "://bad-url", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, isSafeURL(tt.url))
})
}
}

func TestAddSessionContext(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/test", nil)
sessionID := "test-session-123"
Expand Down
4 changes: 2 additions & 2 deletions pkg/virtualkubelet/mesh.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,8 @@ func (p *Provider) addWstunnelClientAnnotation(ctx context.Context, pod *v1.Pod,
ingressEndpoint = td.Name
}

// Check if FullMesh mode is enabled
if p.config.Network.FullMesh {
// Check if FullMesh mode is enabled and not disabled for this specific pod
if p.config.Network.FullMesh && !isMeshNetworkingDisabled(pod) {
log.G(ctx).Infof("FullMesh mode enabled, generating pre-exec script for pod %s/%s", pod.Namespace, pod.Name)

// Generate full mesh script
Expand Down
Loading
Loading