Kubernetes Egress Gateway with Squid Proxy
Squid is a mature, full-featured HTTP proxy and caching server that can be deployed on Kubernetes for egress control. This post explores using traditional proxy technology for modern Kubernetes egress requirements with access control, caching, and comprehensive logging.
Egress Gateway Series
This series covers Kubernetes egress gateway solutions:
- Part 1: Istio Ingress/Egress Gateway - Service mesh approach with mTLS and advanced traffic management
- Part 2: Cilium Egress Gateway - eBPF-based networking with Hubble observability
- Part 3: Antrea Egress Gateway - Open vSwitch CNI with ExternalNode support
- Part 4: Kube-OVN Egress Gateway - OVN-based CNI with Floating IP support
- Part 5: Monzo Egress Operator - AWS NAT Gateway automation via Kubernetes CRDs
- Part 6: Custom Envoy Proxy - Self-hosted L7 egress proxy with advanced routing
- Part 7: Squid Proxy on Kubernetes - Traditional HTTP proxy with caching and ACLs
- Part 8: Cloud NAT Solutions - AWS NAT Gateway, GCP Cloud NAT, Azure Firewall/NAT Gateway
- Part 9: Comparison & Recommendations - Decision matrix and use case guide
✓ All parts complete!
Why Squid Proxy?
Squid has been the industry-standard HTTP proxy for over 25 years, providing:
- ✅ Mature and stable - Battle-tested in production environments
- ✅ Access Control Lists (ACLs) - Fine-grained traffic control
- ✅ Caching - Reduce bandwidth and improve response times
- ✅ Comprehensive logging - Audit and compliance support
- ✅ SSL/TLS inspection - HTTPS traffic visibility
- ✅ Authentication - Integration with LDAP, AD, RADIUS
- ✅ Low resource usage - Efficient proxy operations
Architecture Overview
┌─────────────────────────────────────────────────────────────────┐
│ Kubernetes Cluster │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Pod A │ │ Pod B │ │ Pod C │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ └───────────────┼───────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────┐ │
│ │ Squid Egress Proxy │<─── Squid Config │
│ └───────────┬───────────┘ │
│ │ │
│ ┌────────────┴────────────┐ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ External HTTP/ │ │ Cache Storage │ │
│ │ HTTPS │ │ │ │
│ └──────────────────┘ └──────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
│
│ Access Logs
▼
┌──────────────────┐
│ ELK / Splunk │
└──────────────────┘
┌──────────────────┐
│ Auth Server │───┐
└──────────────────┘ │
│ (Authentication)
└───────────────┘
Traffic Flow
- Pods configured with HTTP_PROXY/HTTPS_PROXY environment variables
- HTTP/HTTPS traffic routed to Squid proxy service
- Squid evaluates ACLs for allow/deny decisions
- Cache lookup for frequently accessed content
- SSL inspection (optional) for HTTPS traffic
- Request forwarded to external destination
- Response cached and logged
Prerequisites
| Component | Version | Notes |
|---|---|---|
| Kubernetes | 1.25+ | Any distribution |
| Squid | 5.x+ | Latest stable |
| kubectl | Latest | Configured with cluster access |
| Storage | PV/PVC | For cache and logs |
Installation
Step 1: Create Squid Namespace
kubectl create namespace squid-proxy
Step 2: Create Squid Configuration
Create squid-config.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: squid-config
namespace: squid-proxy
data:
squid.conf: |
# Basic configuration
http_port 3128
visible_hostname squid-proxy
# Access Control Lists
acl localnet src 10.0.0.0/8
acl localnet src 172.16.0.0/12
acl localnet src 192.168.0.0/16
# SSL ports
acl SSL_ports port 443
acl Safe_ports port 80
acl Safe_ports port 443
acl Safe_ports port 21
acl Safe_ports port 70
acl Safe_ports port 210
acl Safe_ports port 1025-65535
# HTTP methods
acl CONNECT method CONNECT
acl GET method GET
acl POST method POST
# Allowed domains
acl allowed_domains dstdomain .github.com
acl allowed_domains dstdomain .docker.io
acl allowed_domains dstdomain .quay.io
acl allowed_domains dstdomain .maven.org
acl allowed_domains dstdomain .npmjs.com
acl allowed_domains dstdomain .pypi.org
# Access rules
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access allow localhost
http_access allow allowed_domains
http_access allow localnet
http_access deny all
# Caching configuration
cache_dir ufs /var/spool/squid 1000 16 256
cache_mem 256 MB
maximum_object_size_in_memory 4 MB
maximum_object_size 100 MB
cache_swap_low 98
cache_swap_high 99
# Logging
access_log /var/log/squid/access.log squid
cache_log /var/log/squid/cache.log
cache_store_log /var/log/squid/store.log
# Performance tuning
cache_mem_high_watermark 95
read_ahead_gap 128 KB
positive_dns_ttl 6 hours
negative_dns_ttl 1 minute
# Refresh patterns (cache control)
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
refresh_pattern . 0 20% 4320
Step 3: Create Squid Deployment
Create squid-deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: squid-proxy
namespace: squid-proxy
labels:
app: squid-proxy
spec:
replicas: 2 # High availability
selector:
matchLabels:
app: squid-proxy
template:
metadata:
labels:
app: squid-proxy
spec:
containers:
- name: squid
image: ubuntu/squid:5.2-22.04_beta
ports:
- containerPort: 3128
name: http
volumeMounts:
- name: squid-config
mountPath: /etc/squid/squid.conf
subPath: squid.conf
readOnly: true
- name: squid-cache
mountPath: /var/spool/squid
- name: squid-logs
mountPath: /var/log/squid
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: 1000m
memory: 2Gi
livenessProbe:
tcpSocket:
port: 3128
initialDelaySeconds: 30
periodSeconds: 30
readinessProbe:
tcpSocket:
port: 3128
initialDelaySeconds: 10
periodSeconds: 10
volumes:
- name: squid-config
configMap:
name: squid-config
- name: squid-cache
persistentVolumeClaim:
claimName: squid-cache-pvc
- name: squid-logs
emptyDir: {}
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: squid-proxy
topologyKey: kubernetes.io/hostname
Step 4: Create Persistent Volume Claim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: squid-cache-pvc
namespace: squid-proxy
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: standard
Step 5: Create Service
apiVersion: v1
kind: Service
metadata:
name: squid-proxy
namespace: squid-proxy
labels:
app: squid-proxy
spec:
selector:
app: squid-proxy
ports:
- name: http
port: 3128
targetPort: 3128
protocol: TCP
type: ClusterIP
Step 6: Apply Configuration
kubectl apply -f squid-config.yaml
kubectl apply -f squid-deployment.yaml
kubectl apply -f squid-pvc.yaml
kubectl apply -f squid-service.yaml
Step 7: Verify Deployment
# Check pods are running
kubectl get pods -n squid-proxy
# Expected output:
# NAME READY STATUS
# squid-proxy-xxxxxxxxxx-xxxxx 1/1 Running
# squid-proxy-yyyyyyyyyy-yyyyy 1/1 Running
# Check service
kubectl get svc -n squid-proxy
# Test proxy connectivity
kubectl run test-pod --image=curlimages/curl -it --rm --restart=Never \
-- curl -x http://squid-proxy.squid-proxy.svc:3128 \
https://www.google.com
Advanced Configuration
Authentication with Basic Auth
# Add to squid.conf
data:
squid.conf: |
# Basic authentication
auth_param basic program /usr/lib/squid/basic_ncsa_auth /etc/squid/passwd
auth_param basic children 5
auth_param basic realm "Squid Proxy"
auth_param basic credentialsttl 2 hours
acl authenticated proxy_auth REQUIRED
http_access allow authenticated allowed_domains
http_access deny all
# Create password file
kubectl create secret generic squid-auth \
--from-literal=users=$(htpasswd -cb - user1 password123) \
--namespace squid-proxy
LDAP/Active Directory Authentication
# Add to squid.conf
data:
squid.conf: |
# LDAP authentication
auth_param ldap program /usr/lib/squid/ldap_auth \
-b "dc=example,dc=com" \
-D "cn=admin,dc=example,dc=com" \
-w "admin_password" \
-f "(sAMAccountName=%s)" \
-H ldap://ad.example.com
auth_param ldap children 5
auth_param ldap realm "Squid Proxy"
auth_param ldap credentialsttl 2 hours
acl ldap_users proxy_auth REQUIRED
http_access allow ldap_users allowed_domains
SSL/TLS Bump (HTTPS Inspection)
# Add to squid.conf
data:
squid.conf: |
# SSL Bump configuration
https_port 3129 intercept ssl-bump \
cert=/etc/squid/ssl/squid.crt \
key=/etc/squid/ssl/squid.key
ssl_bump peek all
ssl_bump splice allowed_domains
ssl_bump terminate all
# ACLs for SSL bump
acl step1 at_step SslBump1
acl step2 at_step SslBump2
acl step3 at_step SslBump3
ssl_bump peek step1
ssl_bump peek step2
ssl_bump splice step3
# Generate CA certificate for SSL bump
openssl req -new -newkey rsa:2048 -sha256 -days 3650 -nodes -x509 \
-subj "/C=US/ST=State/L=City/O=Organization/CN=Squid Proxy CA" \
-keyout squid-ca.key -out squid-ca.crt
# Create secret
kubectl create secret tls squid-ssl-cert \
--cert=squid-ca.crt \
--key=squid-ca.key \
--namespace squid-proxy
Content Filtering
# Add to squid.conf
data:
squid.conf: |
# Block specific categories
acl blocked_sites dstdomain .facebook.com
acl blocked_sites dstdomain .twitter.com
acl blocked_sites dstdomain .youtube.com
# Block file types
acl blocked_files urlpath_regex -i \.(exe|zip|rar|mp4|avi)$
# Block keywords
acl blocked_keywords urlpath_regex -i (gambling|casino|porn)
# Apply blocks
http_access deny blocked_sites
http_access deny blocked_files
http_access deny blocked_keywords
Rate Limiting
# Add to squid.conf
data:
squid.conf: |
# Rate limiting by IP
acl too_many_ips maxconn 10
http_access deny too_many_ips
# Rate limiting by bandwidth
delay_pools 1
delay_class 1 2
delay_parameters 1 1000000/1000000 50000/50000
delay_access 1 allow all
# Connection limits
conn_limit_max 100
conn_limit_threshold 80
Routing Traffic to Squid Proxy
Method 1: Environment Variables
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: api-server
template:
metadata:
labels:
app: api-server
spec:
containers:
- name: api
image: myapp/api:v1.0
env:
- name: HTTP_PROXY
value: "http://squid-proxy.squid-proxy.svc:3128"
- name: HTTPS_PROXY
value: "http://squid-proxy.squid-proxy.svc:3128"
- name: NO_PROXY
value: "localhost,.svc.cluster.local,.cluster.local,10.0.0.0/8"
Method 2: Init Container Configuration
spec:
initContainers:
- name: set-proxy
image: busybox
command: ['sh', '-c', 'echo "export HTTP_PROXY=http://squid-proxy:3128" >> /etc/profile.d/proxy.sh']
volumeMounts:
- name: proxy-config
mountPath: /etc/profile.d
containers:
- name: app
image: myapp/api:v1.0
volumes:
- name: proxy-config
emptyDir: {}
Method 3: NetworkPolicy (CNI-dependent)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: force-squid-proxy
namespace: production
spec:
podSelector:
matchLabels:
app: api-server
policyTypes:
- Egress
egress:
# Allow DNS
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
# Force all HTTP/HTTPS through Squid
- to:
- namespaceSelector:
matchLabels:
name: squid-proxy
podSelector:
matchLabels:
app: squid-proxy
ports:
- protocol: TCP
port: 3128
Monitoring and Logging
Access Logs
# View access logs
kubectl logs -n squid-proxy squid-proxy-xxxxx -- squid
# Stream logs
kubectl logs -n squid-proxy squid-proxy-xxxxx -f -- squid
# Export logs
kubectl logs -n squid-proxy squid-proxy-xxxxx -- squid > squid-access.log
Log Format Customization
# Add to squid.conf
data:
squid.conf: |
# Custom log format
logformat squidextended %ts.%03tu %6tr %>a %Ss/%03>Hs %<st %rm %ru %un %Sh/%<A %mt
access_log /var/log/squid/access.log squidextended
Prometheus Metrics
# Deploy squid-exporter
apiVersion: apps/v1
kind: Deployment
metadata:
name: squid-exporter
namespace: squid-proxy
spec:
replicas: 1
selector:
matchLabels:
app: squid-exporter
template:
metadata:
labels:
app: squid-exporter
spec:
containers:
- name: exporter
image: boynux/squid-exporter:latest
ports:
- containerPort: 9301
args:
- "-squid.host=squid-proxy.squid-proxy.svc"
- "-squid.port=3128"
---
apiVersion: v1
kind: Service
metadata:
name: squid-exporter
namespace: squid-proxy
spec:
selector:
app: squid-exporter
ports:
- port: 9301
targetPort: 9301
Grafana Dashboard
apiVersion: v1
kind: ConfigMap
metadata:
name: squid-proxy-dashboard
namespace: monitoring
data:
squid-proxy.json: |
{
"dashboard": {
"title": "Squid Proxy",
"panels": [
{
"title": "Request Rate",
"targets": [
{
"expr": "rate(squid_requests_total[5m])"
}
]
},
{
"title": "Cache Hit Ratio",
"targets": [
{
"expr": "rate(squid_cache_hits_total[5m]) / rate(squid_requests_total[5m])"
}
]
},
{
"title": "Bandwidth Usage",
"targets": [
{
"expr": "rate(squid_kbytes_read_total[5m]) * 1024"
}
]
},
{
"title": "Active Connections",
"targets": [
{
"expr": "squid_current_connections"
}
]
},
{
"title": "Denied Requests",
"targets": [
{
"expr": "rate(squid_acl_denied_total[5m])"
}
]
}
]
}
}
Security Best Practices
1. Restrict Allowed Destinations
# Add to squid.conf
data:
squid.conf: |
# Whitelist specific domains
acl allowed_api dstdomain .api.stripe.com
acl allowed_api dstdomain .api.github.com
acl allowed_api dstdomain .registry.npmjs.org
# Whitelist IP ranges
acl allowed_ips dst 52.0.0.0/8
acl allowed_ips dst 35.0.0.0/8
# Deny everything else
http_access allow allowed_api
http_access allow allowed_ips
http_access deny all
2. Enable Request Body Logging
# Add to squid.conf
data:
squid.conf: |
# Log request headers
logformat detailed %ts.%03tu %6tr %>a %Ss/%03>Hs %<st %rm %ru %un %Sh/%<A %mt %{Referer}>h %{User-Agent}>h
access_log /var/log/squid/detailed.log detailed
3. Implement SSL Bump for Inspection
# See SSL/TLS Bump section above
# Important: Distribute CA cert to all pods for trust
4. Regular Configuration Audits
# Validate Squid configuration
kubectl exec -n squid-proxy squid-proxy-xxxxx -- squid -k check
# Check configuration syntax
kubectl exec -n squid-proxy squid-proxy-xxxxx -- squid -k parse
Troubleshooting
Issue: Pods Can’t Access External Services
# Check Squid pods are running
kubectl get pods -n squid-proxy
# Verify Squid configuration
kubectl exec -n squid-proxy squid-proxy-xxxxx -- squid -k check
# Test from inside Squid pod
kubectl exec -n squid-proxy squid-proxy-xxxxx -it -- \
curl -x localhost:3128 https://www.google.com
# Check pod proxy configuration
kubectl get pod api-server-xxxxx -n production -o yaml | grep -i proxy
Issue: Cache Not Working
# Check cache directory
kubectl exec -n squid-proxy squid-proxy-xxxxx -- ls -la /var/spool/squid
# View cache stats
kubectl exec -n squid-proxy squid-proxy-xxxxx -- squidclient mgr:info
# Check cache hit ratio
kubectl exec -n squid-proxy squid-proxy-xxxxx -- squidclient mgr:info | grep -i "hit ratio"
Issue: SSL Bump Not Working
# Verify SSL certificate
kubectl exec -n squid-proxy squid-proxy-xxxxx -- openssl x509 -in /etc/squid/ssl/squid.crt -text
# Check SSL port configuration
kubectl exec -n squid-proxy squid-proxy-xxxxx -- netstat -tlnp | grep 3129
# Test SSL bump
kubectl exec -n squid-proxy squid-proxy-xxxxx -it -- \
curl -x localhost:3129 -k https://www.google.com
Common Problems and Solutions
| Problem | Cause | Solution |
|---|---|---|
| Connection refused | Squid not listening | Check port configuration |
| 403 Forbidden | ACL blocking traffic | Review http_access rules |
| 503 Service Unavailable | Cache directory full | Increase cache size |
| SSL errors | Certificate not trusted | Distribute CA to clients |
| High memory usage | Cache too large | Reduce cache_mem setting |
Comparison with Other Solutions
| Feature | Squid | Envoy | Istio | Cilium |
|---|---|---|---|---|
| Protocol | HTTP/HTTPS | HTTP/1,2,3, TCP | HTTP/1,2,3, TCP | L3/L4 |
| Caching | ✅ Full | ❌ No | ❌ No | ❌ No |
| ACLs | ✅ Advanced | ✅ Advanced | ✅ Advanced | ⚠️ Limited |
| SSL Inspection | ✅ Full | ✅ Full | ✅ Full | ❌ No |
| Authentication | ✅ LDAP/AD/RADIUS | ⚠️ Manual | ✅ mTLS | ❌ No |
| Logging | ✅ Comprehensive | ✅ Comprehensive | ✅ Comprehensive | ✅ Hubble |
| Maturity | 25+ years | 8 years | 7 years | 8 years |
| Resource Usage | Low | Low | High | Low |
When to Choose Squid
Choose Squid when:
- ✅ Need HTTP caching to reduce bandwidth
- ✅ Require mature, stable proxy solution
- ✅ Need LDAP/AD authentication
- ✅ Comprehensive access logging required
- ✅ Content filtering needed
- ✅ Team has proxy administration experience
Consider alternatives when:
- 📋 Need TCP/UDP proxying (choose Envoy)
- 📋 Want automatic mTLS (choose Istio)
- 📋 Need eBPF performance (choose Cilium)
- 📋 gRPC/HTTP2 primary protocols (choose Envoy)
Next Steps
In the next post of this series:
- Cloud NAT Solutions - GCP Cloud NAT, Azure Firewall
- Managed services comparison
- Cost analysis
Conclusion
Squid Proxy provides:
Advantages:
- ✅ Mature, battle-tested technology (25+ years)
- ✅ HTTP caching reduces bandwidth costs
- ✅ Advanced ACLs for fine-grained control
- ✅ Comprehensive access logging
- ✅ LDAP/AD/RADIUS authentication
- ✅ Content filtering capabilities
- ✅ Low resource usage
- ✅ SSL/TLS inspection support
Considerations:
- 📋 HTTP/HTTPS focused (not TCP/UDP)
- 📋 Self-managed (operations overhead)
- 📋 Manual mTLS configuration
- 📋 Less suited for gRPC/HTTP2
For organizations needing a mature HTTP proxy with caching, authentication, and comprehensive logging, Squid remains an excellent choice that has stood the test of time.