Skip to content

Commit 35e6259

Browse files
authored
Merge pull request #26 from wollomatic/develop
Add configuration through environment variables
2 parents b19b3d2 + 2cf1be3 commit 35e6259

File tree

6 files changed

+110
-44
lines changed

6 files changed

+110
-44
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# syntax=docker/dockerfile:1
2-
FROM --platform=$BUILDPLATFORM golang:1.22.5-alpine3.20 AS build
2+
FROM --platform=$BUILDPLATFORM golang:1.22.6-alpine3.20 AS build
33
WORKDIR /application
44
COPY . ./
55
ARG TARGETOS

README.md

Lines changed: 29 additions & 17 deletions
Large diffs are not rendered by default.

cmd/socket-proxy/handlehttprequest.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package main
22

33
import (
44
"errors"
5-
"github.com/wollomatic/socket-proxy/internal/config"
65
"log/slog"
76
"net"
87
"net/http"
@@ -25,7 +24,7 @@ func handleHttpRequest(w http.ResponseWriter, r *http.Request) {
2524
}
2625

2726
// check if the request is allowed
28-
allowed, exists := config.AllowedRequests[r.Method]
27+
allowed, exists := cfg.AllowedRequests[r.Method]
2928
if !exists { // method not in map -> not allowed
3029
communicateBlockedRequest(w, r, "method not allowed", http.StatusMethodNotAllowed)
3130
return

cmd/socket-proxy/main.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ import (
1818
)
1919

2020
const (
21-
programUrl = "github.com/wollomatic/socket-proxy"
21+
programUrl = "github.com/wollomatic/socket-proxy"
22+
logAddSource = false // set to true to log the source position (file and line) of the log message
2223
)
2324

2425
var (
@@ -37,7 +38,7 @@ func main() {
3738

3839
// setup logging
3940
logOpts := &slog.HandlerOptions{
40-
AddSource: config.LogSourcePosition,
41+
AddSource: logAddSource,
4142
Level: cfg.LogLevel,
4243
}
4344
var logger *slog.Logger
@@ -59,14 +60,14 @@ func main() {
5960

6061
// print request allow list
6162
if cfg.LogJSON {
62-
for method, regex := range config.AllowedRequests {
63+
for method, regex := range cfg.AllowedRequests {
6364
slog.Info("configured allowed request", "method", method, "regex", regex)
6465
}
6566
} else {
6667
// don't use slog here, as we want to print the regexes as they are
6768
// see https://github.com/wollomatic/socket-proxy/issues/11
6869
fmt.Printf("Request allowlist:\n %-8s %s\n", "Method", "Regex")
69-
for method, regex := range config.AllowedRequests {
70+
for method, regex := range cfg.AllowedRequests {
7071
fmt.Printf(" %-8s %s\n", method, regex)
7172
}
7273
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module github.com/wollomatic/socket-proxy
22

3-
go 1.22.2
3+
go 1.22.6

internal/config/config.go

Lines changed: 73 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,27 @@ import (
77
"log/slog"
88
"net"
99
"net/http"
10+
"os"
1011
"regexp"
12+
"strconv"
1113
"strings"
1214
)
1315

14-
const LogSourcePosition = false // set to true to log the source position (file and line) of the log message
15-
16-
const (
16+
var (
1717
defaultAllowFrom = "127.0.0.1/32" // allowed IPs to connect to the proxy
1818
defaultAllowHealthcheck = false // allow health check requests (HEAD http://localhost:55555/health)
1919
defaultLogJSON = false // if true, log in JSON format
2020
defaultLogLevel = "INFO" // log level as string
2121
defaultListenIP = "127.0.0.1" // ip address to bind the server to
22-
defaultProxyPort = 2375 // tcp port to listen on
22+
defaultProxyPort = uint(2375) // tcp port to listen on
2323
defaultSocketPath = "/var/run/docker.sock" // path to the unix socket
2424
defaultShutdownGraceTime = uint(10) // Maximum time in seconds to wait for the server to shut down gracefully
2525
defaultWatchdogInterval = uint(0) // watchdog interval in seconds (0 to disable)
2626
defaultStopOnWatchdog = false // set to true to stop the program when the socket gets unavailable (otherwise log only)
2727
)
2828

2929
type Config struct {
30+
AllowedRequests map[string]*regexp.Regexp
3031
AllowFrom string
3132
AllowHealthcheck bool
3233
LogJSON bool
@@ -38,19 +39,17 @@ type Config struct {
3839
SocketPath string
3940
}
4041

41-
var (
42-
AllowedRequests map[string]*regexp.Regexp
43-
)
44-
4542
// used for list of allowed requests
4643
type methodRegex struct {
47-
method string
48-
regexString string
44+
method string
45+
regexStringFromEnv string
46+
regexStringFromParam string
4947
}
5048

5149
// mr is the allowlist of requests per http method
52-
// default: regegString is empty, so regexCompiled stays nil and the request is blocked
53-
// if regexString is set with a command line parameter, all requests matching the method and path matching the regex are allowed
50+
// default: regexStringFromEnv and regexStringFromParam are empty, so regexCompiled stays nil and the request is blocked
51+
// if regexStringParam is set with a command line parameter, all requests matching the method and path matching the regex are allowed
52+
// else if regexStringEnv from Environment ist checked
5453
var mr = []methodRegex{
5554
{method: http.MethodGet},
5655
{method: http.MethodHead},
@@ -70,6 +69,55 @@ func InitConfig() (*Config, error) {
7069
proxyPort uint
7170
logLevel string
7271
)
72+
73+
if val, ok := os.LookupEnv("SP_ALLOWFROM"); ok && val != "" {
74+
defaultAllowFrom = val
75+
}
76+
if val, ok := os.LookupEnv("SP_ALLOWHEALTHCHECK"); ok {
77+
if parsedVal, err := strconv.ParseBool(val); err == nil {
78+
defaultAllowHealthcheck = parsedVal
79+
}
80+
}
81+
if val, ok := os.LookupEnv("SP_LOGJSON"); ok {
82+
if parsedVal, err := strconv.ParseBool(val); err == nil {
83+
defaultLogJSON = parsedVal
84+
}
85+
}
86+
if val, ok := os.LookupEnv("SP_LISTENIP"); ok && val != "" {
87+
defaultListenIP = val
88+
}
89+
if val, ok := os.LookupEnv("SP_LOGLEVEL"); ok && val != "" {
90+
defaultLogLevel = val
91+
}
92+
if val, ok := os.LookupEnv("SP_PROXYPORT"); ok && val != "" {
93+
if parsedVal, err := strconv.ParseUint(val, 10, 32); err == nil {
94+
defaultProxyPort = uint(parsedVal)
95+
}
96+
}
97+
if val, ok := os.LookupEnv("SP_SHUTDOWNGRACETIME"); ok && val != "" {
98+
if parsedVal, err := strconv.ParseUint(val, 10, 32); err == nil {
99+
defaultShutdownGraceTime = uint(parsedVal)
100+
}
101+
}
102+
if val, ok := os.LookupEnv("SP_SOCKETPATH"); ok && val != "" {
103+
defaultSocketPath = val
104+
}
105+
if val, ok := os.LookupEnv("SP_STOPONWATCHDOG"); ok {
106+
if parsedVal, err := strconv.ParseBool(val); err == nil {
107+
defaultStopOnWatchdog = parsedVal
108+
}
109+
}
110+
if val, ok := os.LookupEnv("SP_WATCHDOGINTERVAL"); ok && val != "" {
111+
if parsedVal, err := strconv.ParseUint(val, 10, 32); err == nil {
112+
defaultWatchdogInterval = uint(parsedVal)
113+
}
114+
}
115+
for i := 0; i < len(mr); i++ {
116+
if val, ok := os.LookupEnv("SP_ALLOW_" + mr[i].method); ok && val != "" {
117+
mr[i].regexStringFromEnv = val
118+
}
119+
}
120+
73121
flag.StringVar(&cfg.AllowFrom, "allowfrom", defaultAllowFrom, "allowed IPs or hostname to connect to the proxy")
74122
flag.BoolVar(&cfg.AllowHealthcheck, "allowhealthcheck", defaultAllowHealthcheck, "allow health check requests (HEAD http://localhost:55555/health)")
75123
flag.BoolVar(&cfg.LogJSON, "logjson", defaultLogJSON, "log in JSON format (otherwise log in plain text")
@@ -81,11 +129,11 @@ func InitConfig() (*Config, error) {
81129
flag.BoolVar(&cfg.StopOnWatchdog, "stoponwatchdog", defaultStopOnWatchdog, "stop the program when the socket gets unavailable (otherwise log only)")
82130
flag.UintVar(&cfg.WatchdogInterval, "watchdoginterval", defaultWatchdogInterval, "watchdog interval in seconds (0 to disable)")
83131
for i := 0; i < len(mr); i++ {
84-
flag.StringVar(&mr[i].regexString, "allow"+mr[i].method, mr[i].regexString, "regex for "+mr[i].method+" requests (not set means method is not allowed)")
132+
flag.StringVar(&mr[i].regexStringFromParam, "allow"+mr[i].method, "", "regex for "+mr[i].method+" requests (not set means method is not allowed)")
85133
}
86134
flag.Parse()
87135

88-
// pcheck listenIP and proxyPort
136+
// check listenIP and proxyPort
89137
if net.ParseIP(listenIP) == nil {
90138
return nil, fmt.Errorf("invalid IP \"%s\" for listenip", listenIP)
91139
}
@@ -109,14 +157,20 @@ func InitConfig() (*Config, error) {
109157
}
110158

111159
// compile regexes for allowed requests
112-
AllowedRequests = make(map[string]*regexp.Regexp)
160+
cfg.AllowedRequests = make(map[string]*regexp.Regexp)
113161
for _, rx := range mr {
114-
if rx.regexString != "" {
115-
r, err := regexp.Compile("^" + rx.regexString + "$")
162+
if rx.regexStringFromParam != "" {
163+
r, err := regexp.Compile("^" + rx.regexStringFromParam + "$")
164+
if err != nil {
165+
return nil, fmt.Errorf("invalid regex \"%s\" for method %s in command line parameter: %s", rx.regexStringFromParam, rx.method, err)
166+
}
167+
cfg.AllowedRequests[rx.method] = r
168+
} else if rx.regexStringFromEnv != "" {
169+
r, err := regexp.Compile("^" + rx.regexStringFromEnv + "$")
116170
if err != nil {
117-
return nil, fmt.Errorf("invalid regex \"%s\" for method %s: %s", rx.regexString, rx.method, err)
171+
return nil, fmt.Errorf("invalid regex \"%s\" for method %s in env variable: %s", rx.regexStringFromParam, rx.method, err)
118172
}
119-
AllowedRequests[rx.method] = r
173+
cfg.AllowedRequests[rx.method] = r
120174
}
121175
}
122176
return &cfg, nil

0 commit comments

Comments
 (0)