Sign inSign up

invisible/ocp-proxy

By invisible

•Updated 8 months ago

Minimal HTTP proxy written in Go

Image
Networking
0

494

invisible/ocp-proxy repository overview

⁠OCP Proxy

A minimal HTTP proxy written in Go with two operating modes:

  1. CONNECT mode - HTTPS tunneling for Microsoft Entra ID (Azure AD) authentication
  2. Reverse mode - HTTP reverse proxy for log forwarding (e.g., to OpenSearch)

⁠Purpose

In environments where applications do not have direct internet access, this proxy enables:

  • CONNECT mode: Authentication through external Identity Providers by establishing TCP tunnels via HTTP CONNECT method
  • Reverse mode: Forwarding logs from HTTP to HTTPS endpoints with proper Host header handling

⁠Features

⁠Common
  • Two operation modes - CONNECT tunneling or Reverse proxy
  • Client IP filtering - Restrict access by IP/CIDR
  • Configurable timeouts - All timeouts customizable via environment variables
  • Minimal image - Built from scratch (~5 MB)
⁠CONNECT Mode
  • HTTP CONNECT tunneling - Proxy accepts HTTP, tunnels HTTPS end-to-end
  • Host-based filtering - Only allowed hosts can be tunneled
  • Wildcard subdomain support - e.g., *.microsoft.com
  • Proxy chaining - Forward through upstream proxy
  • No CA certificates needed - Proxy doesn't terminate TLS
⁠Reverse Mode
  • HTTP to HTTPS forwarding - Forward requests with correct Host header
  • Proxy chaining - Chain multiple reverse proxies via TARGET_URL
  • TLS verification control - Option to skip certificate validation
  • Connection pooling - Reuse connections to target

⁠Configuration

⁠Common Settings
Environment VariableDefault ValueDescription
PROXY_MODE(required)Operation mode: connect or reverse
LISTEN_ADDR:8443 (connect) / :9200 (reverse)Address and port to listen on
ALLOWED_CLIENTS(empty = all allowed)Allowed client IPs/CIDRs
READ_TIMEOUT60sHTTP server read timeout
WRITE_TIMEOUT60sHTTP server write timeout
⁠LISTEN_ADDR Formats
FormatExampleDescription
:port:8443Listen on all interfaces (IPv4/IPv6)
port8443Shorthand for :port (all interfaces)
ip:port127.0.0.1:8443Listen on specific IPv4 interface
[ip6]:port[::1]:8443Listen on specific IPv6 interface
⁠CONNECT Mode Settings
Environment VariableDefault ValueDescription
ALLOWED_HOSTSlogin.microsoftonline.com,graph.microsoft.com,...Allowed destination hosts
ALLOWED_PORTS443Allowed destination ports
UPSTREAM_PROXY(empty = direct connection)Upstream proxy for chaining (host:port)
DIAL_TIMEOUT10sConnection dial timeout
TLS_TIMEOUT10sTLS/CONNECT handshake timeout
⁠Reverse Mode Settings
Environment VariableDefault ValueDescription
TARGET_URL(required)Target URL for forwarding (e.g., https://opensearch.example.com:9200)
TARGET_HOST(auto from TARGET_URL)Host header to set (override if different from URL)
INSECURE_TLSfalseSkip TLS certificate verification
CUSTOM_CA(empty)Path to custom CA certificate file (e.g., /app/certs/internal-ca.crt)
MAX_BODY_SIZE50MBMaximum allowed request body size (e.g., 10MB, 1GB)
ALLOWED_METHODS(empty = all allowed)Allowed HTTP methods (e.g., GET,POST,PUT,HEAD)
TARGET_TIMEOUT60sRequest timeout to target
IDLE_CONN_TIMEOUT90sIdle connection timeout
DIAL_TIMEOUT10sConnection dial timeout
TLS_TIMEOUT10sTLS handshake timeout

Timeout format: Use Go duration format, e.g., 30s, 1m, 2m30s, 1h.

⁠Host Filtering (Outbound - CONNECT Mode only)

Only allowed hosts can be accessed through the proxy. This setting is ignored in Reverse Proxy mode.

ALLOWED_HOSTS="login.microsoftonline.com,graph.microsoft.com,graph.windows.net,pas.windows.net"
⁠Client Filtering (Inbound)
# Allow only specific IPs
ALLOWED_CLIENTS="10.0.0.5,10.0.0.6"

# Allow CIDR ranges
ALLOWED_CLIENTS="10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"

# Allow all (default if not set)
ALLOWED_CLIENTS=""
⁠Custom CA Certification (Reverse Mode)

If your TARGET_URL uses a private or corporate CA, you can mount your CA certificate into the container and point to it:

docker run -d \
  -e PROXY_MODE=reverse \
  -e TARGET_URL="https://internal-service:9200" \
  -e CUSTOM_CA="/certs/internal-ca.crt" \
  -v /path/to/my-ca.crt:/certs/internal-ca.crt:ro \
  docker.io/invisible/ocp-proxy:latest
# Podman
podman run -d \
  -e PROXY_MODE=reverse \
  -e TARGET_URL="https://internal-service:9200" \
  -e CUSTOM_CA="/certs/internal-ca.crt" \
  -v /path/to/my-ca.crt:/certs/internal-ca.crt:ro \
  docker.io/invisible/ocp-proxy:latest

⁠Running

Important: Use --network host to preserve real client IPs for ALLOWED_CLIENTS filtering.

⁠CONNECT Mode (Identity Provider Proxy)

Use CONNECT mode for HTTPS tunneling (e.g., Microsoft Entra ID authentication).

Architecture example:

Keycloak (HTTPS) --> CONNECT Proxy (HTTP :8443) --> Entra ID (HTTPS)
                     ALLOWED_HOSTS=login.microsoftonline.com
⁠Docker
docker run -d \
  --name keycloak-proxy \
  --network host \
  --restart unless-stopped \
  -e PROXY_MODE=connect \
  -e ALLOWED_HOSTS="login.microsoftonline.com,graph.microsoft.com,graph.windows.net,pas.windows.net" \
  -e ALLOWED_CLIENTS="10.0.0.0/8,192.168.0.0/16" \
  docker.io/invisible/ocp-proxy:latest
podman run -d \
  --name keycloak-proxy \
  --network host \
  --restart unless-stopped \
  -e PROXY_MODE=connect \
  -e ALLOWED_HOSTS="login.microsoftonline.com,graph.microsoft.com,graph.windows.net,pas.windows.net" \
  -e ALLOWED_CLIENTS="10.0.0.0/8,192.168.0.0/16" \
  docker.io/invisible/ocp-proxy:latest
⁠Proxy Chaining Example (CONNECT Mode)

When you need to route traffic through multiple proxies (e.g., in multi-tier network environments):

Keycloak (10.0.0.100) --> Proxy 1 (10.0.0.1:8443) --> Proxy 2 (10.0.0.2:8443) --> Entra ID

Proxy 1 (with upstream proxy):

# Docker
docker run -d \
  --name keycloak-proxy \
  --network host \
  --restart unless-stopped \
  -e PROXY_MODE=connect \
  -e ALLOWED_HOSTS="login.microsoftonline.com,graph.microsoft.com,graph.windows.net,pas.windows.net" \
  -e ALLOWED_CLIENTS="10.0.0.100" \
  -e UPSTREAM_PROXY="10.0.0.2:8443" \
  docker.io/invisible/ocp-proxy:latest
# Podman
podman run -d \
  --name keycloak-proxy \
  --network host \
  --restart unless-stopped \
  -e PROXY_MODE=connect \
  -e ALLOWED_HOSTS="login.microsoftonline.com,graph.microsoft.com,graph.windows.net,pas.windows.net" \
  -e ALLOWED_CLIENTS="10.0.0.100" \
  -e UPSTREAM_PROXY="10.0.0.2:8443" \
  docker.io/invisible/ocp-proxy:latest

Proxy 2 (direct connection to internet):

# Docker
docker run -d \
  --name keycloak-proxy \
  --network host \
  --restart unless-stopped \
  -e PROXY_MODE=connect \
  -e ALLOWED_HOSTS="login.microsoftonline.com,graph.microsoft.com,graph.windows.net,pas.windows.net" \
  -e ALLOWED_CLIENTS="10.0.0.1" \
  docker.io/invisible/ocp-proxy:latest
# Podman
podman run -d \
  --name keycloak-proxy \
  --network host \
  --restart unless-stopped \
  -e PROXY_MODE=connect \
  -e ALLOWED_HOSTS="login.microsoftonline.com,graph.microsoft.com,graph.windows.net,pas.windows.net" \
  -e ALLOWED_CLIENTS="10.0.0.1" \
  docker.io/invisible/ocp-proxy:latest

⁠Reverse Proxy Mode (Log Forwarding)

Use reverse proxy mode to forward logs from HTTP to HTTPS endpoints (e.g., OpenSearch, Elasticsearch).

Architecture example:

Application (HTTP) --> Reverse Proxy (HTTP :9200) --> OpenSearch (HTTPS)
                       TARGET_URL=https://opensearch.example.com:9200
                       TARGET_HOST=opensearch.example.com
⁠Docker
docker run -d \
  --name log-proxy \
  --network host \
  --restart unless-stopped \
  -e PROXY_MODE=reverse \
  -e TARGET_URL="https://opensearch.example.com:9200" \
  -e TARGET_HOST="opensearch.example.com" \
  -e ALLOWED_METHODS="POST" \
  -e ALLOWED_CLIENTS="10.0.0.0/8,172.16.0.0/12" \
  docker.io/invisible/ocp-proxy:latest
⁠Podman
podman run -d \
  --name log-proxy \
  --network host \
  --restart unless-stopped \
  -e PROXY_MODE=reverse \
  -e TARGET_URL="https://opensearch.example.com:9200" \
  -e TARGET_HOST="opensearch.example.com" \
  -e ALLOWED_METHODS="POST" \
  -e ALLOWED_CLIENTS="10.0.0.0/8,172.16.0.0/12" \
  docker.io/invisible/ocp-proxy:latest
⁠Proxy Chaining Example (Reverse Mode)

To chain multiple reverse proxies, set TARGET_URL to point to the next proxy:

App (10.0.0.100) --> Proxy 1 (10.0.0.1:9200) --> Proxy 2 (10.0.0.2:9200) --> OpenSearch
                     TARGET_URL=http://10.0.0.2:9200

Proxy 1 (in restricted network):

# Docker
docker run -d \
  --name log-proxy-1 \
  --network host \
  --restart unless-stopped \
  -e PROXY_MODE=reverse \
  -e TARGET_URL="http://10.0.0.2:9200" \
  -e ALLOWED_METHODS="POST" \
  -e ALLOWED_CLIENTS="10.0.0.100" \
  docker.io/invisible/ocp-proxy:latest
# Podman
podman run -d \
  --name log-proxy-1 \
  --network host \
  --restart unless-stopped \
  -e PROXY_MODE=reverse \
  -e TARGET_URL="http://10.0.0.2:9200" \
  -e ALLOWED_METHODS="POST" \
  -e ALLOWED_CLIENTS="10.0.0.100" \
  docker.io/invisible/ocp-proxy:latest

Proxy 2 (with access to OpenSearch):

# Docker
docker run -d \
  --name log-proxy-2 \
  --network host \
  --restart unless-stopped \
  -e PROXY_MODE=reverse \
  -e TARGET_URL="https://opensearch.example.com:9200" \
  -e TARGET_HOST="opensearch.example.com" \
  -e ALLOWED_METHODS="POST" \
  -e ALLOWED_CLIENTS="10.0.0.1" \
  docker.io/invisible/ocp-proxy:latest
# Podman
podman run -d \
  --name log-proxy-2 \
  --network host \
  --restart unless-stopped \
  -e PROXY_MODE=reverse \
  -e TARGET_URL="https://opensearch.example.com:9200" \
  -e TARGET_HOST="opensearch.example.com" \
  -e ALLOWED_METHODS="POST" \
  -e ALLOWED_CLIENTS="10.0.0.1" \
  docker.io/invisible/ocp-proxy:latest
⁠Client Configuration (Example: Keycloak)

Configure the client (e.g., Keycloak) to use the proxy:

JAVA_OPTS_APPEND="-Dhttp.proxyHost=keycloak-proxy -Dhttp.proxyPort=8443 -Dhttp.nonProxyHosts=localhost|127.0.0.1|postgres"
ParameterDescription
http.proxyHostProxy hostname
http.proxyPortProxy port
http.nonProxyHostsHosts to bypass (pipe-separated)

Important: nonProxyHosts is required to prevent the client from proxying internal connections (PostgreSQL, etc.).

⁠Testing

⁠CONNECT Mode
# Test OpenID configuration (should return JSON)
curl -x http://localhost:8443 https://login.microsoftonline.com/common/.well-known/openid-configuration
# Test blocked host (should return 403 Forbidden)
curl -v -x http://localhost:8443 https://google.com
⁠Reverse Mode
# Test reverse proxy (forward log to OpenSearch)
curl -X POST http://localhost:9200/_bulk \
  -H "Content-Type: application/json" \
  -d '{"index":{"_index":"logs"}}
{"message":"test log entry","@timestamp":"2024-01-01T00:00:00Z"}'
# Check proxy health (should forward to target and return response)
curl -I http://localhost:9200/

⁠Logs

# Docker
docker logs -f keycloak-proxy
docker logs -f log-proxy
# Podman
podman logs -f keycloak-proxy
podman logs -f log-proxy

Tag summary

Content type

Image

Digest

sha256:71fe22544…

Size

2.6 MB

Last updated

8 months ago

docker pull invisible/ocp-proxy