mirror of
https://github.com/yusing/godoxy.git
synced 2026-03-20 16:23:53 +01:00
feat(docker): add Docker socket proxy support and related configurations
- Introduced Docker socket proxy handling in the agent. - Added environment variables for Docker socket configuration. - Implemented new Docker handler with endpoint permissions based on environment settings. - Added tests for Docker handler functionality. - Updated go.mod to include gorilla/mux for routing.
This commit is contained in:
@@ -4,9 +4,12 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/yusing/go-proxy/agent/pkg/agent"
|
||||
"github.com/yusing/go-proxy/agent/pkg/env"
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
"github.com/yusing/go-proxy/internal/logging/memlogger"
|
||||
"github.com/yusing/go-proxy/internal/metrics/systeminfo"
|
||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
||||
@@ -47,3 +50,153 @@ func NewAgentHandler() http.Handler {
|
||||
mux.ServeMux.HandleFunc("/", DockerSocketHandler())
|
||||
return mux
|
||||
}
|
||||
|
||||
func endpointNotAllowed(w http.ResponseWriter, _ *http.Request) {
|
||||
http.Error(w, "Endpoint not allowed", http.StatusForbidden)
|
||||
}
|
||||
|
||||
// ref: https://github.com/Tecnativa/docker-socket-proxy/blob/master/haproxy.cfg
|
||||
func NewDockerHandler() http.Handler {
|
||||
r := mux.NewRouter()
|
||||
var socketHandler http.HandlerFunc
|
||||
if common.IsTest {
|
||||
socketHandler = mockDockerSocketHandler()
|
||||
} else {
|
||||
socketHandler = DockerSocketHandler()
|
||||
}
|
||||
|
||||
const apiVersionPrefix = `/{version:(?:v[\d\.]+)?}`
|
||||
const containerPath = "/containers/{id:[a-zA-Z0-9_.-]+}"
|
||||
|
||||
allowedPaths := []string{}
|
||||
deniedPaths := []string{}
|
||||
|
||||
if env.DockerContainers {
|
||||
allowedPaths = append(allowedPaths, "/containers")
|
||||
if !env.DockerRestarts {
|
||||
deniedPaths = append(deniedPaths, containerPath+"/stop")
|
||||
deniedPaths = append(deniedPaths, containerPath+"/restart")
|
||||
deniedPaths = append(deniedPaths, containerPath+"/kill")
|
||||
}
|
||||
if !env.DockerStart {
|
||||
deniedPaths = append(deniedPaths, containerPath+"/start")
|
||||
}
|
||||
if !env.DockerStop && env.DockerRestarts {
|
||||
deniedPaths = append(deniedPaths, containerPath+"/stop")
|
||||
}
|
||||
}
|
||||
if env.DockerAuth {
|
||||
allowedPaths = append(allowedPaths, "/auth")
|
||||
}
|
||||
if env.DockerBuild {
|
||||
allowedPaths = append(allowedPaths, "/build")
|
||||
}
|
||||
if env.DockerCommit {
|
||||
allowedPaths = append(allowedPaths, "/commit")
|
||||
}
|
||||
if env.DockerConfigs {
|
||||
allowedPaths = append(allowedPaths, "/configs")
|
||||
}
|
||||
if env.DockerDistributions {
|
||||
allowedPaths = append(allowedPaths, "/distributions")
|
||||
}
|
||||
if env.DockerEvents {
|
||||
allowedPaths = append(allowedPaths, "/events")
|
||||
}
|
||||
if env.DockerExec {
|
||||
allowedPaths = append(allowedPaths, "/exec")
|
||||
}
|
||||
if env.DockerGrpc {
|
||||
allowedPaths = append(allowedPaths, "/grpc")
|
||||
}
|
||||
if env.DockerImages {
|
||||
allowedPaths = append(allowedPaths, "/images")
|
||||
}
|
||||
if env.DockerInfo {
|
||||
allowedPaths = append(allowedPaths, "/info")
|
||||
}
|
||||
if env.DockerNetworks {
|
||||
allowedPaths = append(allowedPaths, "/networks")
|
||||
}
|
||||
if env.DockerNodes {
|
||||
allowedPaths = append(allowedPaths, "/nodes")
|
||||
}
|
||||
if env.DockerPing {
|
||||
allowedPaths = append(allowedPaths, "/_ping")
|
||||
}
|
||||
if env.DockerPlugins {
|
||||
allowedPaths = append(allowedPaths, "/plugins")
|
||||
}
|
||||
if env.DockerSecrets {
|
||||
allowedPaths = append(allowedPaths, "/secrets")
|
||||
}
|
||||
if env.DockerServices {
|
||||
allowedPaths = append(allowedPaths, "/services")
|
||||
}
|
||||
if env.DockerSession {
|
||||
allowedPaths = append(allowedPaths, "/session")
|
||||
}
|
||||
if env.DockerSwarm {
|
||||
allowedPaths = append(allowedPaths, "/swarm")
|
||||
}
|
||||
if env.DockerSystem {
|
||||
allowedPaths = append(allowedPaths, "/system")
|
||||
}
|
||||
if env.DockerTasks {
|
||||
allowedPaths = append(allowedPaths, "/tasks")
|
||||
}
|
||||
if env.DockerVersion {
|
||||
allowedPaths = append(allowedPaths, "/version")
|
||||
}
|
||||
if env.DockerVolumes {
|
||||
allowedPaths = append(allowedPaths, "/volumes")
|
||||
}
|
||||
|
||||
// Helper to determine if a path should be treated as a prefix
|
||||
isPrefixPath := func(path string) bool {
|
||||
return strings.Count(path, "/") == 1
|
||||
}
|
||||
|
||||
// 1. Register Denied Paths (specific)
|
||||
for _, path := range deniedPaths {
|
||||
// Handle with version prefix
|
||||
r.HandleFunc(apiVersionPrefix+path, endpointNotAllowed)
|
||||
// Handle without version prefix
|
||||
r.HandleFunc(path, endpointNotAllowed)
|
||||
}
|
||||
|
||||
// 2. Register Allowed Paths
|
||||
for _, p := range allowedPaths {
|
||||
fullPathWithVersion := apiVersionPrefix + p
|
||||
if isPrefixPath(p) {
|
||||
r.PathPrefix(fullPathWithVersion).Handler(socketHandler)
|
||||
r.PathPrefix(p).Handler(socketHandler)
|
||||
} else {
|
||||
r.HandleFunc(fullPathWithVersion, socketHandler)
|
||||
r.HandleFunc(p, socketHandler)
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Add fallback for any other routes
|
||||
r.PathPrefix("/").HandlerFunc(endpointNotAllowed)
|
||||
|
||||
// HTTP method filtering
|
||||
if !env.DockerPost {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
switch req.Method {
|
||||
case http.MethodGet:
|
||||
r.ServeHTTP(w, req)
|
||||
default:
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
}
|
||||
})
|
||||
}
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
switch req.Method {
|
||||
case http.MethodPost, http.MethodGet:
|
||||
r.ServeHTTP(w, req)
|
||||
default:
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user