Skip to content
Merged
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
2 changes: 1 addition & 1 deletion helm/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ apiVersion: v2
name: socket-firewall
description: Socket.dev Registry Firewall - Block vulnerable packages before they reach your cluster
type: application
version: 0.3.1
version: 0.4.0
appVersion: "1.1.328"
keywords:
- security
Expand Down
43 changes: 41 additions & 2 deletions helm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,20 @@ registries:
| `autoscaling.enabled` | Enable HorizontalPodAutoscaler | `false` |
| `podDisruptionBudget.enabled` | Keep pods available during node maintenance | `true` |
| `extraContainers` | Sidecar containers (auth proxies, log collectors) | `[]` |
| `resources.limits.cpu` | CPU limit | `1` |
| `resources.limits.memory` | Memory limit | `768Mi` |
| `resources.limits.cpu` | CPU limit | `4` |
| `resources.limits.memory` | Memory limit | `8Gi` |
| `terminationGracePeriodSeconds` | Pod grace period; set ≥ `forwardProxy.maxTunnelLifetimeSeconds` when CONNECT is enabled | `""` (30s) |
| **Forward Proxy (HTTP CONNECT)** | _CASB CONNECT tunnels — see [section below](#forward-proxy-http-connect)_ | |
| `forwardProxy.enabled` | Enable the CONNECT listener (requires image ≥ 1.1.275) | `false` |
| `forwardProxy.port` | CONNECT listener port | `3128` |
| `forwardProxy.maxTunnelLifetimeSeconds` | Hard cap on a single tunnel's lifetime | `600` |
| `forwardProxy.maxConnectionsPerSource` | Per-source-IP concurrent tunnel cap | `64` |
| `forwardProxy.proxyProtocolPort` | Internal loopback PROXY-protocol port | `8081` |
| `forwardProxy.skipStreamLuaCheck` | Bypass nginx stream-lua capability check (custom images only) | `false` |
| `forwardProxy.service.enabled` | Create a dedicated L4 Service for CONNECT (required to expose it externally) | `false` |
| `forwardProxy.service.type` | `LoadBalancer` (NLB) or `NodePort` — **not** behind an ALB/L7 ingress | `LoadBalancer` |
| `forwardProxy.service.annotations` | Annotations for the L4 Service (e.g. AWS NLB) | `{}` |
| `forwardProxy.service.loadBalancerSourceRanges` | CIDRs allowed to reach the CONNECT listener (your CASB egress) | `[]` |
| **Security** | | |
| `securityContext` | Container security context | PSS restricted (see values.yaml) |
| `podSecurityContext` | Pod-level security context | `{}` |
Expand Down Expand Up @@ -338,6 +350,9 @@ ingress:

### AWS ALB Ingress

> An ALB cannot carry the HTTP CONNECT method. For CASB CONNECT tunnels, see
> [Forward Proxy (HTTP CONNECT)](#forward-proxy-http-connect).

```yaml
ingress:
enabled: true
Expand Down Expand Up @@ -380,6 +395,30 @@ ingress:
- pypi.org
```

## Forward Proxy (HTTP CONNECT)

Some CASBs (e.g. Netskope or Zscaler in proxy-chaining mode) reach upstream
proxies via an HTTP `CONNECT` tunnel instead of a standard HTTPS request. Enable
the firewall's CONNECT listener with `forwardProxy.enabled` (requires image
≥ 1.1.275).

Because `CONNECT` is a raw TCP tunnel, it cannot pass through a Layer-7 Ingress
(nginx, Traefik, AWS ALB) — those terminate TLS and parse HTTP. Expose it with a
**Layer-4 (TCP passthrough) load balancer** by setting
`forwardProxy.service.enabled=true`, which creates a dedicated Service for the
CONNECT port. Your existing Ingress/Service keeps serving normal HTTPS traffic.

```yaml
forwardProxy:
enabled: true
service:
enabled: true
type: LoadBalancer # must be L4 (TCP passthrough), not an L7 ingress
```

See [`examples/forward-proxy.yaml`](examples/forward-proxy.yaml) for a complete
example.

## TLS Configuration

### Self-Signed (Default)
Expand Down
37 changes: 37 additions & 0 deletions helm/examples/forward-proxy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Forward Proxy (HTTP CONNECT) example — for CASBs (e.g. Netskope/Zscaler in
# proxy-chaining mode) that reach upstreams via a CONNECT tunnel. Exposes the
# CONNECT port on a Layer-4 (TCP passthrough) Service, since CONNECT cannot
# traverse an L7 Ingress.
#
# Usage:
# helm install socket-firewall . -f examples/forward-proxy.yaml \
# --set socket.apiToken=$SOCKET_API_TOKEN \
# --set pathRouting.domain=sfw.yourcompany.com

socket:
apiToken: "" # set via --set socket.apiToken=xxx

# Clients still target the firewall's own hostname/paths as usual.
pathRouting:
enabled: true
domain: sfw.yourcompany.com # override with --set
routes:
- path: /npm
upstream: https://registry.npmjs.org
registry: npm
- path: /pypi
upstream: https://pypi.org
registry: pypi

forwardProxy:
enabled: true
service:
enabled: true
type: LoadBalancer # must be L4 (TCP passthrough)
annotations: {} # provider-specific L4 LB annotations, if any
# Restrict to your CASB egress ranges (recommended).
loadBalancerSourceRanges: []

# Give in-flight tunnels time to drain on rollout/scale-down
# (set >= forwardProxy.maxTunnelLifetimeSeconds).
terminationGracePeriodSeconds: 660
20 changes: 20 additions & 0 deletions helm/templates/NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,26 @@ Configure package managers to use your custom domains:
{{- end }}
{{- end }}

{{- if .Values.forwardProxy.enabled }}

## Forward Proxy (HTTP CONNECT)

CONNECT listener enabled on port {{ .Values.forwardProxy.port }} — point your CASB here.
Expose it via a Layer-4 (TCP passthrough) load balancer; it cannot go through an Ingress.
{{- if .Values.forwardProxy.service.enabled }}

kubectl get svc {{ include "socket-firewall.fullname" . }}-connect -n {{ .Release.Namespace }}
{{- else }}

Set forwardProxy.service.enabled=true to create the Layer-4 Service for external access.
{{- end }}
{{- if not .Values.terminationGracePeriodSeconds }}

Tip: set terminationGracePeriodSeconds >= forwardProxy.maxTunnelLifetimeSeconds so
in-flight tunnels drain on rollout/scale-down.
{{- end }}
{{- end }}

## Verify

Test the health endpoint:
Expand Down
7 changes: 7 additions & 0 deletions helm/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ spec:
{{- include "socket-firewall.selectorLabels" . | nindent 8 }}
spec:
serviceAccountName: {{ include "socket-firewall.serviceAccountName" . }}
{{- if .Values.terminationGracePeriodSeconds }}
terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }}
{{- end }}
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
Expand Down Expand Up @@ -202,6 +205,10 @@ spec:
value: {{ (.Values.service.containerHttpsPort | default .Values.service.httpsPort) | quote }}
- name: CONFIG_FILE
value: /app/socket.yml
{{- if and .Values.forwardProxy.enabled .Values.forwardProxy.skipStreamLuaCheck }}
- name: SOCKET_SKIP_STREAM_LUA_CHECK
value: "1"
{{- end }}
{{- if and .Values.redis.enabled (or .Values.redis.password .Values.redis.existingSecret) }}
- name: REDIS_PASSWORD
valueFrom:
Expand Down
34 changes: 34 additions & 0 deletions helm/templates/service-forward-proxy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{{- if and .Values.forwardProxy.enabled .Values.forwardProxy.service.enabled }}
{{- /*
Dedicated Service for the CONNECT listener. CONNECT cannot traverse an L7
Ingress, so this must be a Layer-4 (TCP passthrough) load balancer
(type LoadBalancer or NodePort).
*/}}
apiVersion: v1
kind: Service
metadata:
name: {{ include "socket-firewall.fullname" . }}-connect
labels:
{{- include "socket-firewall.labels" . | nindent 4 }}
app.kubernetes.io/component: forward-proxy
{{- with .Values.forwardProxy.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.forwardProxy.service.type }}
{{- with .Values.forwardProxy.service.loadBalancerSourceRanges }}
loadBalancerSourceRanges:
{{- toYaml . | nindent 4 }}
{{- end }}
ports:
- port: {{ .Values.forwardProxy.port }}
targetPort: forward-proxy
protocol: TCP
name: forward-proxy
{{- if and (eq .Values.forwardProxy.service.type "NodePort") .Values.forwardProxy.service.nodePort }}
nodePort: {{ .Values.forwardProxy.service.nodePort }}
{{- end }}
selector:
{{- include "socket-firewall.selectorLabels" . | nindent 4 }}
{{- end }}
32 changes: 28 additions & 4 deletions helm/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -215,15 +215,31 @@ clientIp:
# Walk the header to find the originating IP
recursive: true

# HTTP CONNECT forward-proxy listener (for CASB-shaped traffic).
# Requires OpenResty / nginx with stream{} + ngx_stream_lua_module.
# When enabled, the chart exposes the CONNECT port on the container and Service.
# HTTP CONNECT forward-proxy listener, for CASBs (e.g. Netskope/Zscaler in
# proxy-chaining mode) that reach upstreams via a CONNECT tunnel. Requires the
# official image (>= 1.1.275). See README "Forward Proxy (HTTP CONNECT)".
forwardProxy:
enabled: false
port: 3128
# Hard cap on a single tunnel's lifetime (seconds).
maxTunnelLifetimeSeconds: 600
# Per-source-IP concurrent tunnel cap.
maxConnectionsPerSource: 64
# Internal loopback PROXY-protocol port (not exposed). Must differ from port.
proxyProtocolPort: 8081
# Set true only for a custom image you've confirmed supports stream-lua.
skipStreamLuaCheck: false
# Dedicated Service for the CONNECT port. CONNECT cannot pass through an L7
# Ingress, so this must be a Layer-4 (TCP passthrough) load balancer.
service:
enabled: false
type: LoadBalancer
# Provider-specific L4 load balancer annotations, if any.
annotations: {}
# Fixed nodePort (30000-32767) when type=NodePort. Empty = auto-assign.
nodePort: ""
# Restrict source CIDRs that may reach the listener (e.g. CASB egress).
loadBalancerSourceRanges: []

# Metadata filtering (removes blocked/warned packages from registry metadata responses)
metadataFiltering:
Expand Down Expand Up @@ -372,7 +388,10 @@ resources:
cpu: "2"
memory: 8Gi

# Health check configuration
# Health check configuration.
# Note: the CONNECT listener (forwardProxy) shares the same nginx master
# process as the HTTP/HTTPS listeners, so this /health probe also covers it
# — if :3128 fails to bind, nginx won't start and the probe fails too.
healthCheck:
enabled: true
path: /health
Expand All @@ -381,6 +400,11 @@ healthCheck:
timeoutSeconds: 10
failureThreshold: 3

# Pod termination grace period (seconds). Empty = Kubernetes default (30s).
# When forwardProxy is enabled, set this >= forwardProxy.maxTunnelLifetimeSeconds
# so in-flight CONNECT tunnels aren't killed mid-stream on rollout/scale-down.
terminationGracePeriodSeconds: ""

# Pod annotations
podAnnotations: {}

Expand Down