feat: add support for setting a unix binding's socket file mode (#3376)

fix: linter issues and set default unix socket permissions to 0660

Signed-off-by: Jan Larwig <jan@larwig.com>
Co-authored-by: Tristan <tristan@mangadex.org>
This commit is contained in:
Jan Larwig 2026-03-19 00:08:50 +08:00 committed by GitHub
parent cdbdb1128d
commit 9ae0b325a6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 113 additions and 5 deletions

View File

@ -17,6 +17,7 @@
- [#3365](https://github.com/oauth2-proxy/oauth2-proxy/pull/3365) fix: filter empty strings from allowed groups (@Br1an67) - [#3365](https://github.com/oauth2-proxy/oauth2-proxy/pull/3365) fix: filter empty strings from allowed groups (@Br1an67)
- [#3338](https://github.com/oauth2-proxy/oauth2-proxy/pull/3338) feat: add --config-test flag for validating configuration (@MayorFaj) - [#3338](https://github.com/oauth2-proxy/oauth2-proxy/pull/3338) feat: add --config-test flag for validating configuration (@MayorFaj)
- [#3347](https://github.com/oauth2-proxy/oauth2-proxy/pull/3347) feat: add same site option for csrf cookies (@jvnoije) - [#3347](https://github.com/oauth2-proxy/oauth2-proxy/pull/3347) feat: add same site option for csrf cookies (@jvnoije)
- [#3376](https://github.com/oauth2-proxy/oauth2-proxy/pull/3376) feat: allow setting unix socket file mode when declaring listener (@Tristan971 / @tuunit)
# V7.14.3 # V7.14.3

View File

@ -584,8 +584,8 @@ Server represents the configuration for an HTTP(S) server
| Field | Type | Description | | Field | Type | Description |
| ----- | ---- | ----------- | | ----- | ---- | ----------- |
| `bindAddress` | _string_ | BindAddress is the address on which to serve traffic.<br/>Leave blank or set to "-" to disable. | | `bindAddress` | _string_ | BindAddress is the address on which to serve traffic.<br/>Different types of bind addresses are supported:<br/>* `[http://]<addr>:<port>`<br/>* `fd:<int>` (case insensitive)<br/>* `unix://<path>`<br/>Unix sockets are created with default system umask mode, which can be overridden, e.g.: `unix://my-socket,mode=0777`<br/>Square brackets are required for ipv6 address, e.g. `http://[::1]:4180`<br/>Leave blank or set to "-" to disable. |
| `secureBindAddress` | _string_ | SecureBindAddress is the address on which to serve secure traffic.<br/>Leave blank or set to "-" to disable. | | `secureBindAddress` | _string_ | SecureBindAddress is the address on which to serve secure traffic.<br/>Secure bind addresses need to respond with valid SSL and use the following format:<br/>* `[https://]<addr>:<port>`<br/>Square brackets are required for ipv6 address, e.g. `https://[::1]:4180`<br/>Leave blank or set to "-" to disable. |
| `tls` | _[TLS](#tls)_ | TLS contains the information for loading the certificate and key for the<br/>secure traffic and further configuration for the TLS server. | | `tls` | _[TLS](#tls)_ | TLS contains the information for loading the certificate and key for the<br/>secure traffic and further configuration for the TLS server. |
### TLS ### TLS

View File

@ -264,7 +264,7 @@ Provider specific options can be found on their respective subpages.
| Flag / Config Field | Type | Description | Default | | Flag / Config Field | Type | Description | Default |
| ------------------------------------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | | ------------------------------------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
| flag: `--http-address`<br/>toml: `http_address` | string | `[http://]<addr>:<port>` or `unix://<path>` or `fd:<int>` (case insensitive) to listen on for HTTP clients. Square brackets are required for ipv6 address, e.g. `http://[::1]:4180` | `"127.0.0.1:4180"` | | flag: `--http-address`<br/>toml: `http_address` | string | `[http://]<addr>:<port>` or `unix://<path>` or `fd:<int>` (case insensitive) to listen on for HTTP clients. Unix sockets are created with default system umask mode, which can be overridden, e.g. `unix://my-socket,mode=0777`. Square brackets are required for ipv6 address, e.g. `http://[::1]:4180` | `"127.0.0.1:4180"` |
| flag: `--https-address`<br/>toml: `https_address` | string | `[https://]<addr>:<port>` to listen on for HTTPS clients. Square brackets are required for ipv6 address, e.g. `https://[::1]:443` | `":443"` | | flag: `--https-address`<br/>toml: `https_address` | string | `[https://]<addr>:<port>` to listen on for HTTPS clients. Square brackets are required for ipv6 address, e.g. `https://[::1]:443` | `":443"` |
| flag: `--metrics-address`<br/>toml: `metrics_address` | string | the address prometheus metrics will be scraped from | `""` | | flag: `--metrics-address`<br/>toml: `metrics_address` | string | the address prometheus metrics will be scraped from | `""` |
| flag: `--metrics-secure-address`<br/>toml: `metrics_secure_address` | string | the address prometheus metrics will be scraped from if using HTTPS | `""` | | flag: `--metrics-secure-address`<br/>toml: `metrics_secure_address` | string | the address prometheus metrics will be scraped from if using HTTPS | `""` |

View File

@ -3,10 +3,19 @@ package options
// Server represents the configuration for an HTTP(S) server // Server represents the configuration for an HTTP(S) server
type Server struct { type Server struct {
// BindAddress is the address on which to serve traffic. // BindAddress is the address on which to serve traffic.
// Different types of bind addresses are supported:
// * `[http://]<addr>:<port>`
// * `fd:<int>` (case insensitive)
// * `unix://<path>`
// Unix sockets are created with default system umask mode, which can be overridden, e.g.: `unix://my-socket,mode=0777`
// Square brackets are required for ipv6 address, e.g. `http://[::1]:4180`
// Leave blank or set to "-" to disable. // Leave blank or set to "-" to disable.
BindAddress string `yaml:"bindAddress,omitempty"` BindAddress string `yaml:"bindAddress,omitempty"`
// SecureBindAddress is the address on which to serve secure traffic. // SecureBindAddress is the address on which to serve secure traffic.
// Secure bind addresses need to respond with valid SSL and use the following format:
// * `[https://]<addr>:<port>`
// Square brackets are required for ipv6 address, e.g. `https://[::1]:4180`
// Leave blank or set to "-" to disable. // Leave blank or set to "-" to disable.
SecureBindAddress string `yaml:"secureBindAddress,omitempty"` SecureBindAddress string `yaml:"secureBindAddress,omitempty"`

View File

@ -8,6 +8,7 @@ import (
"net" "net"
"net/http" "net/http"
"os" "os"
"strconv"
"strings" "strings"
"time" "time"
@ -95,15 +96,62 @@ func (s *server) setupListener(opts Opts) error {
networkType := getNetworkScheme(opts.BindAddress) networkType := getNetworkScheme(opts.BindAddress)
listenAddr := getListenAddress(opts.BindAddress) listenAddr := getListenAddress(opts.BindAddress)
listener, err := net.Listen(networkType, listenAddr) listener, err := func() (net.Listener, error) {
if networkType == "unix" {
return setupUnixSocketListener(networkType, listenAddr)
}
return net.Listen(networkType, listenAddr)
}()
if err != nil { if err != nil {
return fmt.Errorf("listen (%s, %s) failed: %w", networkType, listenAddr, err) return fmt.Errorf("listen (%s, %s) failed: %w", networkType, listenAddr, err)
} }
s.listener = listener
s.listener = listener
return nil return nil
} }
func setupUnixSocketListener(networkType string, address string) (net.Listener, error) {
socketOpts := strings.Split(address, ",")
if len(socketOpts) < 2 {
return net.Listen(networkType, address)
}
socketPath := socketOpts[0]
var socketMode os.FileMode
hasSocketMode := false
for _, socketOpt := range socketOpts[1:] {
socketOpt := strings.SplitN(socketOpt, "=", 2)
if len(socketOpt) != 2 {
return nil, fmt.Errorf("unix socket option %s expects a value", socketOpt[0])
}
if socketOpt[0] == "mode" {
mode, err := strconv.ParseUint(socketOpt[1], 8, 32)
if err != nil {
return nil, fmt.Errorf("unix socket file mode has invalid value %s", socketOpt[1])
}
socketMode = os.FileMode(mode)
hasSocketMode = true
}
}
listener, err := net.Listen(networkType, socketPath)
if err != nil {
return nil, err
}
if hasSocketMode {
err = os.Chmod(socketPath, socketMode)
if err != nil {
return nil, fmt.Errorf("cannot set unix socket file mode on %s: %v", socketPath, err)
}
}
return listener, nil
}
func parseCipherSuites(names []string) ([]uint16, error) { func parseCipherSuites(names []string) ([]uint16, error) {
cipherNameMap := make(map[string]uint16) cipherNameMap := make(map[string]uint16)

View File

@ -28,6 +28,8 @@ var _ = Describe("Server", func() {
expectedErr error expectedErr error
expectHTTPListener bool expectHTTPListener bool
expectTLSListener bool expectTLSListener bool
expectedSocketMode os.FileMode
socketPath string
fdAddr string fdAddr string
ipv6 bool ipv6 bool
} }
@ -57,6 +59,12 @@ var _ = Describe("Server", func() {
s, ok := srv.(*server) s, ok := srv.(*server)
Expect(ok).To(BeTrue()) Expect(ok).To(BeTrue())
if in.socketPath != "" {
fileInfo, err := os.Stat(in.socketPath)
Expect(err).ToNot(HaveOccurred())
Expect(fileInfo.Mode().Perm()).To(Equal(in.expectedSocketMode.Perm()))
}
Expect(s.listener != nil).To(Equal(in.expectHTTPListener)) Expect(s.listener != nil).To(Equal(in.expectHTTPListener))
if in.expectHTTPListener { if in.expectHTTPListener {
Expect(s.listener.Close()).To(Succeed()) Expect(s.listener.Close()).To(Succeed())
@ -648,6 +656,48 @@ var _ = Describe("Server", func() {
expectTLSListener: true, expectTLSListener: true,
ipv6: true, ipv6: true,
}), }),
Entry("with a valid unix socket path", &newServerTableInput{
opts: Opts{
Handler: handler,
BindAddress: "unix:///tmp/oauth2-proxy.sock",
},
expectedErr: nil,
expectHTTPListener: true,
expectTLSListener: false,
ipv6: false,
}),
Entry("with a valid unix socket path and a valid socket file mode", &newServerTableInput{
opts: Opts{
Handler: handler,
BindAddress: "unix:///tmp/oauth2-proxy.sock,mode=0777",
},
expectedErr: nil,
expectHTTPListener: true,
expectTLSListener: false,
expectedSocketMode: 0o777,
socketPath: "/tmp/oauth2-proxy.sock",
ipv6: false,
}),
Entry("with a valid unix socket path and a value-less socket file mode argument", &newServerTableInput{
opts: Opts{
Handler: handler,
BindAddress: "unix:///tmp/oauth2-proxy.sock,mode",
},
expectedErr: errors.New("error setting up listener: listen (unix, /tmp/oauth2-proxy.sock,mode) failed: unix socket option mode expects a value"),
expectHTTPListener: false,
expectTLSListener: false,
ipv6: false,
}),
Entry("with a valid unix socket path and an invalid socket file mode value", &newServerTableInput{
opts: Opts{
Handler: handler,
BindAddress: "unix:///tmp/oauth2-proxy.sock,mode=-1",
},
expectedErr: errors.New("error setting up listener: listen (unix, /tmp/oauth2-proxy.sock,mode=-1) failed: unix socket file mode has invalid value -1"),
expectHTTPListener: false,
expectTLSListener: false,
ipv6: false,
}),
) )
}) })