diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0e0a4b23..ffd8f6de 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,7 @@
- [#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)
- [#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
diff --git a/docs/docs/configuration/alpha_config.md b/docs/docs/configuration/alpha_config.md
index d8cce916..ee1883bb 100644
--- a/docs/docs/configuration/alpha_config.md
+++ b/docs/docs/configuration/alpha_config.md
@@ -584,8 +584,8 @@ Server represents the configuration for an HTTP(S) server
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `bindAddress` | _string_ | BindAddress is the address on which to serve traffic.
Leave blank or set to "-" to disable. |
-| `secureBindAddress` | _string_ | SecureBindAddress is the address on which to serve secure traffic.
Leave blank or set to "-" to disable. |
+| `bindAddress` | _string_ | BindAddress is the address on which to serve traffic.
Different types of bind addresses are supported:
* `[http://]:`
* `fd:` (case insensitive)
* `unix://`
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. |
+| `secureBindAddress` | _string_ | 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://]:`
Square brackets are required for ipv6 address, e.g. `https://[::1]:4180`
Leave blank or set to "-" to disable. |
| `tls` | _[TLS](#tls)_ | TLS contains the information for loading the certificate and key for the
secure traffic and further configuration for the TLS server. |
### TLS
diff --git a/docs/docs/configuration/overview.md b/docs/docs/configuration/overview.md
index c225228e..37f385c7 100644
--- a/docs/docs/configuration/overview.md
+++ b/docs/docs/configuration/overview.md
@@ -264,7 +264,7 @@ Provider specific options can be found on their respective subpages.
| Flag / Config Field | Type | Description | Default |
| ------------------------------------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
-| flag: `--http-address`
toml: `http_address` | string | `[http://]:` or `unix://` or `fd:` (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`
toml: `http_address` | string | `[http://]:` or `unix://` or `fd:` (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`
toml: `https_address` | string | `[https://]:` to listen on for HTTPS clients. Square brackets are required for ipv6 address, e.g. `https://[::1]:443` | `":443"` |
| flag: `--metrics-address`
toml: `metrics_address` | string | the address prometheus metrics will be scraped from | `""` |
| flag: `--metrics-secure-address`
toml: `metrics_secure_address` | string | the address prometheus metrics will be scraped from if using HTTPS | `""` |
diff --git a/pkg/apis/options/server.go b/pkg/apis/options/server.go
index 8fa41af8..830ea09a 100644
--- a/pkg/apis/options/server.go
+++ b/pkg/apis/options/server.go
@@ -3,10 +3,19 @@ package options
// Server represents the configuration for an HTTP(S) server
type Server struct {
// BindAddress is the address on which to serve traffic.
+ // Different types of bind addresses are supported:
+ // * `[http://]:`
+ // * `fd:` (case insensitive)
+ // * `unix://`
+ // 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.
BindAddress string `yaml:"bindAddress,omitempty"`
// 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://]:`
+ // Square brackets are required for ipv6 address, e.g. `https://[::1]:4180`
// Leave blank or set to "-" to disable.
SecureBindAddress string `yaml:"secureBindAddress,omitempty"`
diff --git a/pkg/proxyhttp/server.go b/pkg/proxyhttp/server.go
index a0fc6054..2982e1fc 100644
--- a/pkg/proxyhttp/server.go
+++ b/pkg/proxyhttp/server.go
@@ -8,6 +8,7 @@ import (
"net"
"net/http"
"os"
+ "strconv"
"strings"
"time"
@@ -95,15 +96,62 @@ func (s *server) setupListener(opts Opts) error {
networkType := getNetworkScheme(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 {
return fmt.Errorf("listen (%s, %s) failed: %w", networkType, listenAddr, err)
}
- s.listener = listener
+ s.listener = listener
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) {
cipherNameMap := make(map[string]uint16)
diff --git a/pkg/proxyhttp/server_test.go b/pkg/proxyhttp/server_test.go
index d97dcec2..f6d12436 100644
--- a/pkg/proxyhttp/server_test.go
+++ b/pkg/proxyhttp/server_test.go
@@ -28,6 +28,8 @@ var _ = Describe("Server", func() {
expectedErr error
expectHTTPListener bool
expectTLSListener bool
+ expectedSocketMode os.FileMode
+ socketPath string
fdAddr string
ipv6 bool
}
@@ -57,6 +59,12 @@ var _ = Describe("Server", func() {
s, ok := srv.(*server)
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))
if in.expectHTTPListener {
Expect(s.listener.Close()).To(Succeed())
@@ -648,6 +656,48 @@ var _ = Describe("Server", func() {
expectTLSListener: 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,
+ }),
)
})