Merge pull request #1985 from isodude/systemd-socket
Add support for systemd socket
This commit is contained in:
commit
4d2b5c30a1
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
- [#2800](https://github.com/oauth2-proxy/oauth2-proxy/pull/2800) Add some opencontainer labels to docker image (@halkeye)
|
- [#2800](https://github.com/oauth2-proxy/oauth2-proxy/pull/2800) Add some opencontainer labels to docker image (@halkeye)
|
||||||
- [#2755](https://github.com/oauth2-proxy/oauth2-proxy/pull/2755) feat: add X-Envoy-External-Address as supported header (@bjencks)
|
- [#2755](https://github.com/oauth2-proxy/oauth2-proxy/pull/2755) feat: add X-Envoy-External-Address as supported header (@bjencks)
|
||||||
|
- [#1985](https://github.com/oauth2-proxy/oauth2-proxy/pull/1985) Add support for systemd socket (@isodude)
|
||||||
|
|
||||||
# V7.7.1
|
# V7.7.1
|
||||||
|
|
||||||
|
|
@ -58,6 +59,7 @@
|
||||||
- [#2790](https://github.com/oauth2-proxy/oauth2-proxy/pull/2790) chore(deps): update all golang dependencies (@tuunit)
|
- [#2790](https://github.com/oauth2-proxy/oauth2-proxy/pull/2790) chore(deps): update all golang dependencies (@tuunit)
|
||||||
- [#2607](https://github.com/oauth2-proxy/oauth2-proxy/pull/2607) fix(csrf): fix possible infinite loop (@Primexz)
|
- [#2607](https://github.com/oauth2-proxy/oauth2-proxy/pull/2607) fix(csrf): fix possible infinite loop (@Primexz)
|
||||||
|
|
||||||
|
|
||||||
# V7.6.0
|
# V7.6.0
|
||||||
|
|
||||||
## Release Highlights
|
## Release Highlights
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,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>` 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. 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 | `""` |
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
---
|
||||||
|
id: systemd_socket
|
||||||
|
title: Systemd Socket Activation
|
||||||
|
---
|
||||||
|
|
||||||
|
Pass an existing listener created by systemd.socket to oauth2-proxy.
|
||||||
|
|
||||||
|
To do this create a socket:
|
||||||
|
|
||||||
|
oauth2-proxy.socket
|
||||||
|
```
|
||||||
|
[Socket]
|
||||||
|
ListenStream=%t/oauth2.sock
|
||||||
|
SocketGroup=www-data
|
||||||
|
SocketMode=0660
|
||||||
|
```
|
||||||
|
|
||||||
|
Now it's possible to call this socket from e.g. nginx:
|
||||||
|
```
|
||||||
|
server {
|
||||||
|
location /oauth2/ {
|
||||||
|
proxy_pass http://unix:/run/oauth2-proxy/oauth2.sock;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The oauth2-proxy should have `--http-address=fd:3` as a parameter.
|
||||||
|
Here fd is case insensitive and means file descriptor. The number 3 refers to the first non-stdin/stdout/stderr file descriptor,
|
||||||
|
systemd-socket-activate (which is what systemd.socket uses), listens to what it is told and passes
|
||||||
|
the listener it created onto the process, starting with file descriptor 3.
|
||||||
|
|
||||||
|
```
|
||||||
|
./oauth2-proxy \
|
||||||
|
--http-address="fd:3" \
|
||||||
|
--email-domain="yourcompany.com" \
|
||||||
|
--upstream=http://127.0.0.1:8080/ \
|
||||||
|
--cookie-secret=... \
|
||||||
|
--cookie-secure=true \
|
||||||
|
--provider=... \
|
||||||
|
--client-id=... \
|
||||||
|
--client-secret=...
|
||||||
|
```
|
||||||
|
|
||||||
|
Currently TLS is not supported (but it's doable).
|
||||||
|
|
@ -29,3 +29,4 @@ title: Installation
|
||||||
2. [Select a Provider and Register an OAuth Application with a Provider](configuration/providers/index.md)
|
2. [Select a Provider and Register an OAuth Application with a Provider](configuration/providers/index.md)
|
||||||
3. [Configure OAuth2 Proxy using config file, command line options, or environment variables](configuration/overview.md)
|
3. [Configure OAuth2 Proxy using config file, command line options, or environment variables](configuration/overview.md)
|
||||||
4. [Configure SSL or Deploy behind an SSL endpoint](configuration/tls.md) (example provided for Nginx)
|
4. [Configure SSL or Deploy behind an SSL endpoint](configuration/tls.md) (example provided for Nginx)
|
||||||
|
5. [Configure OAuth2 Proxy using systemd.socket](configuration/systemd_socket.md) (example provided for Nginx/Systemd)
|
||||||
|
|
|
||||||
1
go.mod
1
go.mod
|
|
@ -11,6 +11,7 @@ require (
|
||||||
github.com/bitly/go-simplejson v0.5.1
|
github.com/bitly/go-simplejson v0.5.1
|
||||||
github.com/bsm/redislock v0.9.4
|
github.com/bsm/redislock v0.9.4
|
||||||
github.com/coreos/go-oidc/v3 v3.11.0
|
github.com/coreos/go-oidc/v3 v3.11.0
|
||||||
|
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
|
||||||
github.com/fsnotify/fsnotify v1.7.0
|
github.com/fsnotify/fsnotify v1.7.0
|
||||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344
|
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344
|
||||||
github.com/go-jose/go-jose/v3 v3.0.1
|
github.com/go-jose/go-jose/v3 v3.0.1
|
||||||
|
|
|
||||||
2
go.sum
2
go.sum
|
|
@ -42,6 +42,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI=
|
github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI=
|
||||||
github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0=
|
github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0=
|
||||||
|
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
|
||||||
|
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
|
|
|
||||||
|
|
@ -606,7 +606,9 @@ func (p *OAuthProxy) isAPIPath(req *http.Request) bool {
|
||||||
|
|
||||||
// isTrustedIP is used to check if a request comes from a trusted client IP address.
|
// isTrustedIP is used to check if a request comes from a trusted client IP address.
|
||||||
func (p *OAuthProxy) isTrustedIP(req *http.Request) bool {
|
func (p *OAuthProxy) isTrustedIP(req *http.Request) bool {
|
||||||
if p.trustedIPs == nil {
|
// RemoteAddr @ means unix socket
|
||||||
|
// https://github.com/golang/go/blob/0fa53e41f122b1661d0678a6d36d71b7b5ad031d/src/syscall/syscall_linux.go#L506-L511
|
||||||
|
if p.trustedIPs == nil && req.RemoteAddr != "@" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -470,7 +470,7 @@ func legacyServerFlagset() *pflag.FlagSet {
|
||||||
flagSet.String("metrics-secure-address", "", "the address /metrics will be served on for HTTPS clients (e.g. \":9100\")")
|
flagSet.String("metrics-secure-address", "", "the address /metrics will be served on for HTTPS clients (e.g. \":9100\")")
|
||||||
flagSet.String("metrics-tls-cert-file", "", "path to certificate file for secure metrics server")
|
flagSet.String("metrics-tls-cert-file", "", "path to certificate file for secure metrics server")
|
||||||
flagSet.String("metrics-tls-key-file", "", "path to private key file for secure metrics server")
|
flagSet.String("metrics-tls-key-file", "", "path to private key file for secure metrics server")
|
||||||
flagSet.String("http-address", "127.0.0.1:4180", "[http://]<addr>:<port> or unix://<path> to listen on for HTTP clients")
|
flagSet.String("http-address", "127.0.0.1:4180", "[http://]<addr>:<port> or unix://<path> or fd:<int> (case insensitive) to listen on for HTTP clients")
|
||||||
flagSet.String("https-address", ":443", "<addr>:<port> to listen on for HTTPS clients")
|
flagSet.String("https-address", ":443", "<addr>:<port> to listen on for HTTPS clients")
|
||||||
flagSet.String("tls-cert-file", "", "path to certificate file")
|
flagSet.String("tls-cert-file", "", "path to certificate file")
|
||||||
flagSet.String("tls-key-file", "", "path to private key file")
|
flagSet.String("tls-key-file", "", "path to private key file")
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,27 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/coreos/go-systemd/activation"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options/util"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options/util"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// listenFdsStart corresponds to `SD_LISTEN_FDS_START`.
|
||||||
|
// Since the 3 first file descriptors in every linux process is
|
||||||
|
// stdin, stdout and stderr. The first usable file descriptor is 3.
|
||||||
|
// systemd-socket-activate will always assume that the first socket will be
|
||||||
|
// 3 and the rest follow.
|
||||||
|
const (
|
||||||
|
listenFdsStart = 3
|
||||||
|
)
|
||||||
|
|
||||||
// Server represents an HTTP or HTTPS server.
|
// Server represents an HTTP or HTTPS server.
|
||||||
type Server interface {
|
type Server interface {
|
||||||
// Start blocks and runs the server.
|
// Start blocks and runs the server.
|
||||||
|
|
@ -35,6 +47,9 @@ type Opts struct {
|
||||||
|
|
||||||
// TLS is the TLS configuration for the server.
|
// TLS is the TLS configuration for the server.
|
||||||
TLS *options.TLS
|
TLS *options.TLS
|
||||||
|
|
||||||
|
// Let testing infrastructure circumvent parsing file descriptors
|
||||||
|
fdFiles []*os.File
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewServer creates a new Server from the options given.
|
// NewServer creates a new Server from the options given.
|
||||||
|
|
@ -42,6 +57,11 @@ func NewServer(opts Opts) (Server, error) {
|
||||||
s := &server{
|
s := &server{
|
||||||
handler: opts.Handler,
|
handler: opts.Handler,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(opts.fdFiles) > 0 {
|
||||||
|
s.fdFiles = opts.fdFiles
|
||||||
|
}
|
||||||
|
|
||||||
if err := s.setupListener(opts); err != nil {
|
if err := s.setupListener(opts); err != nil {
|
||||||
return nil, fmt.Errorf("error setting up listener: %v", err)
|
return nil, fmt.Errorf("error setting up listener: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -58,6 +78,30 @@ type server struct {
|
||||||
|
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
tlsListener net.Listener
|
tlsListener net.Listener
|
||||||
|
|
||||||
|
// ensure activation.Files are called once
|
||||||
|
fdFiles []*os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert a string filedescriptor to an actual listener
|
||||||
|
func (s *server) fdToListener(bindAddress string) (net.Listener, error) {
|
||||||
|
fd, err := strconv.Atoi(bindAddress)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("listen failed: fd with name is not implemented yet")
|
||||||
|
}
|
||||||
|
fdIndex := fd - listenFdsStart
|
||||||
|
|
||||||
|
if len(s.fdFiles) == 0 {
|
||||||
|
s.fdFiles = activation.Files(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
l := len(s.fdFiles)
|
||||||
|
|
||||||
|
if fdIndex < 0 || fdIndex >= l || l == 0 {
|
||||||
|
return nil, fmt.Errorf("listen failed: fd outside of range of available file descriptors")
|
||||||
|
}
|
||||||
|
|
||||||
|
return net.FileListener(s.fdFiles[fdIndex])
|
||||||
}
|
}
|
||||||
|
|
||||||
// setupListener sets the server listener if the HTTP server is enabled.
|
// setupListener sets the server listener if the HTTP server is enabled.
|
||||||
|
|
@ -69,6 +113,22 @@ func (s *server) setupListener(opts Opts) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use fd: as a prefix for systemd socket activation, it's generic
|
||||||
|
// enough and short.
|
||||||
|
// The most common usage would be --http-address fd:3.
|
||||||
|
// This causes oauth2-proxy to just assume that the third fd passed
|
||||||
|
// to the program is indeed a net.Listener and starts using it
|
||||||
|
// without setting up a new listener.
|
||||||
|
if strings.HasPrefix(strings.ToLower(opts.BindAddress), "fd:") {
|
||||||
|
listenAddr := opts.BindAddress[3:]
|
||||||
|
listener, err := s.fdToListener(listenAddr)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("listen (%s, %s) failed: %v", "file", listenAddr, err)
|
||||||
|
}
|
||||||
|
s.listener = listener
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
networkType := getNetworkScheme(opts.BindAddress)
|
networkType := getNetworkScheme(opts.BindAddress)
|
||||||
listenAddr := getListenAddress(opts.BindAddress)
|
listenAddr := getListenAddress(opts.BindAddress)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
|
@ -17,16 +18,17 @@ import (
|
||||||
const hello = "Hello World!"
|
const hello = "Hello World!"
|
||||||
|
|
||||||
var _ = Describe("Server", func() {
|
var _ = Describe("Server", func() {
|
||||||
|
|
||||||
handler := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
handler := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
rw.Write([]byte(hello))
|
rw.Write([]byte(hello))
|
||||||
})
|
})
|
||||||
|
|
||||||
Context("NewServer", func() {
|
Context("NewServer", func() {
|
||||||
type newServerTableInput struct {
|
type newServerTableInput struct {
|
||||||
opts Opts
|
opts Opts
|
||||||
expectedErr error
|
expectedErr error
|
||||||
expectHTTPListener bool
|
expectHTTPListener bool
|
||||||
expectTLSListener bool
|
expectTLSListener bool
|
||||||
|
fdAddr string
|
||||||
ipv6 bool
|
ipv6 bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,6 +36,15 @@ var _ = Describe("Server", func() {
|
||||||
if in.ipv6 {
|
if in.ipv6 {
|
||||||
skipDevContainer()
|
skipDevContainer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if in.fdAddr != "" {
|
||||||
|
l, err := net.Listen("tcp", in.fdAddr)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
f, err := l.(*net.TCPListener).File()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
in.opts.fdFiles = []*os.File{f}
|
||||||
|
}
|
||||||
|
|
||||||
srv, err := NewServer(in.opts)
|
srv, err := NewServer(in.opts)
|
||||||
if in.expectedErr != nil {
|
if in.expectedErr != nil {
|
||||||
Expect(err).To(MatchError(ContainSubstring(in.expectedErr.Error())))
|
Expect(err).To(MatchError(ContainSubstring(in.expectedErr.Error())))
|
||||||
|
|
@ -55,6 +66,46 @@ var _ = Describe("Server", func() {
|
||||||
Expect(s.tlsListener.Close()).To(Succeed())
|
Expect(s.tlsListener.Close()).To(Succeed())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Entry("with a valid non-lowercase fd IPv4 bind address", &newServerTableInput{
|
||||||
|
opts: Opts{
|
||||||
|
Handler: handler,
|
||||||
|
BindAddress: "Fd:3",
|
||||||
|
},
|
||||||
|
expectedErr: nil,
|
||||||
|
expectHTTPListener: true,
|
||||||
|
expectTLSListener: false,
|
||||||
|
fdAddr: "127.0.0.1:0",
|
||||||
|
}),
|
||||||
|
Entry("with a valid fd IPv4 bind address", &newServerTableInput{
|
||||||
|
opts: Opts{
|
||||||
|
Handler: handler,
|
||||||
|
BindAddress: "fd:3",
|
||||||
|
},
|
||||||
|
expectedErr: nil,
|
||||||
|
expectHTTPListener: true,
|
||||||
|
expectTLSListener: false,
|
||||||
|
fdAddr: "127.0.0.1:0",
|
||||||
|
}),
|
||||||
|
Entry("with a invalid fd named bind address", &newServerTableInput{
|
||||||
|
opts: Opts{
|
||||||
|
Handler: handler,
|
||||||
|
BindAddress: "fd:hello",
|
||||||
|
},
|
||||||
|
expectedErr: fmt.Errorf("error setting up listener: listen (file, %s) failed: listen failed: fd with name is not implemented yet", "hello"),
|
||||||
|
expectHTTPListener: true,
|
||||||
|
expectTLSListener: false,
|
||||||
|
fdAddr: "127.0.0.1:0",
|
||||||
|
}),
|
||||||
|
Entry("with a invalid fd IPv4 bind address", &newServerTableInput{
|
||||||
|
opts: Opts{
|
||||||
|
Handler: handler,
|
||||||
|
BindAddress: "fd:4",
|
||||||
|
},
|
||||||
|
expectedErr: fmt.Errorf("error setting up listener: listen (file, %d) failed: listen failed: fd outside of range of available file descriptors", 4),
|
||||||
|
expectHTTPListener: true,
|
||||||
|
expectTLSListener: false,
|
||||||
|
fdAddr: "127.0.0.1:0",
|
||||||
|
}),
|
||||||
Entry("with an ipv4 valid http bind address", &newServerTableInput{
|
Entry("with an ipv4 valid http bind address", &newServerTableInput{
|
||||||
opts: Opts{
|
opts: Opts{
|
||||||
Handler: handler,
|
Handler: handler,
|
||||||
|
|
@ -86,6 +137,21 @@ var _ = Describe("Server", func() {
|
||||||
expectHTTPListener: false,
|
expectHTTPListener: false,
|
||||||
expectTLSListener: true,
|
expectTLSListener: true,
|
||||||
}),
|
}),
|
||||||
|
Entry("with a both a fd valid http and ipv4 valid https bind address, and valid TLS config", &newServerTableInput{
|
||||||
|
opts: Opts{
|
||||||
|
Handler: handler,
|
||||||
|
BindAddress: "fd:3",
|
||||||
|
SecureBindAddress: "127.0.0.1:0",
|
||||||
|
TLS: &options.TLS{
|
||||||
|
Key: &ipv4KeyDataSource,
|
||||||
|
Cert: &ipv4CertDataSource,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedErr: nil,
|
||||||
|
expectHTTPListener: true,
|
||||||
|
expectTLSListener: true,
|
||||||
|
fdAddr: "127.0.0.1:0",
|
||||||
|
}),
|
||||||
Entry("with a both a ipv4 valid http and ipv4 valid https bind address, and valid TLS config", &newServerTableInput{
|
Entry("with a both a ipv4 valid http and ipv4 valid https bind address, and valid TLS config", &newServerTableInput{
|
||||||
opts: Opts{
|
opts: Opts{
|
||||||
Handler: handler,
|
Handler: handler,
|
||||||
|
|
@ -300,6 +366,27 @@ var _ = Describe("Server", func() {
|
||||||
expectHTTPListener: false,
|
expectHTTPListener: false,
|
||||||
expectTLSListener: true,
|
expectTLSListener: true,
|
||||||
}),
|
}),
|
||||||
|
Entry("with valid fd IPv6 bind address", &newServerTableInput{
|
||||||
|
opts: Opts{
|
||||||
|
Handler: handler,
|
||||||
|
BindAddress: "fd:3",
|
||||||
|
},
|
||||||
|
expectedErr: nil,
|
||||||
|
expectHTTPListener: true,
|
||||||
|
expectTLSListener: false,
|
||||||
|
fdAddr: "[::1]:0",
|
||||||
|
ipv6: true,
|
||||||
|
}),
|
||||||
|
Entry("with a invalid fd IPv6 bind address", &newServerTableInput{
|
||||||
|
opts: Opts{
|
||||||
|
Handler: handler,
|
||||||
|
BindAddress: "fd:4",
|
||||||
|
},
|
||||||
|
expectedErr: fmt.Errorf("error setting up listener: listen (file, %d) failed: listen failed: fd outside of range of available file descriptors", 4),
|
||||||
|
expectHTTPListener: true,
|
||||||
|
expectTLSListener: false,
|
||||||
|
fdAddr: "[::1]:0",
|
||||||
|
}),
|
||||||
Entry("with an ipv6 valid http bind address", &newServerTableInput{
|
Entry("with an ipv6 valid http bind address", &newServerTableInput{
|
||||||
opts: Opts{
|
opts: Opts{
|
||||||
Handler: handler,
|
Handler: handler,
|
||||||
|
|
@ -334,6 +421,22 @@ var _ = Describe("Server", func() {
|
||||||
expectTLSListener: true,
|
expectTLSListener: true,
|
||||||
ipv6: true,
|
ipv6: true,
|
||||||
}),
|
}),
|
||||||
|
Entry("with a both a fd valid http and ipv6 valid https bind address, and valid TLS config", &newServerTableInput{
|
||||||
|
opts: Opts{
|
||||||
|
Handler: handler,
|
||||||
|
BindAddress: "fd:3",
|
||||||
|
SecureBindAddress: "[::1]:0",
|
||||||
|
TLS: &options.TLS{
|
||||||
|
Key: &ipv6KeyDataSource,
|
||||||
|
Cert: &ipv6CertDataSource,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedErr: nil,
|
||||||
|
expectHTTPListener: true,
|
||||||
|
expectTLSListener: true,
|
||||||
|
fdAddr: "[::1]:0",
|
||||||
|
ipv6: true,
|
||||||
|
}),
|
||||||
Entry("with a both a ipv6 valid http and ipv6 valid https bind address, and valid TLS config", &newServerTableInput{
|
Entry("with a both a ipv6 valid http and ipv6 valid https bind address, and valid TLS config", &newServerTableInput{
|
||||||
opts: Opts{
|
opts: Opts{
|
||||||
Handler: handler,
|
Handler: handler,
|
||||||
|
|
@ -563,6 +666,58 @@ var _ = Describe("Server", func() {
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Context("with an fd ipv4 http server", func() {
|
||||||
|
var listenAddr string
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
f, err := l.(*net.TCPListener).File()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
srv, err = NewServer(Opts{
|
||||||
|
Handler: handler,
|
||||||
|
BindAddress: "fd:3",
|
||||||
|
fdFiles: []*os.File{f},
|
||||||
|
})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
listenAddr = fmt.Sprintf("http://%s/", l.Addr().String())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Starts the server and serves the handler", func() {
|
||||||
|
go func() {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
Expect(srv.Start(ctx)).To(Succeed())
|
||||||
|
}()
|
||||||
|
|
||||||
|
resp, err := httpGet(ctx, listenAddr)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(resp.StatusCode).To(Equal(http.StatusOK))
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(string(body)).To(Equal(hello))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Stops the server when the context is cancelled", func() {
|
||||||
|
go func() {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
Expect(srv.Start(ctx)).To(Succeed())
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err := httpGet(ctx, listenAddr)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
Eventually(func() error {
|
||||||
|
_, err := httpGet(ctx, listenAddr)
|
||||||
|
return err
|
||||||
|
}).Should(HaveOccurred())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
Context("with an ipv4 http server", func() {
|
Context("with an ipv4 http server", func() {
|
||||||
var listenAddr string
|
var listenAddr string
|
||||||
|
|
||||||
|
|
@ -682,6 +837,88 @@ var _ = Describe("Server", func() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Context("with a fd ipv4 http and an ipv4 https server", func() {
|
||||||
|
var listenAddr, secureListenAddr string
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
f, err := l.(*net.TCPListener).File()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
srv, err = NewServer(Opts{
|
||||||
|
Handler: handler,
|
||||||
|
BindAddress: "fd:3",
|
||||||
|
fdFiles: []*os.File{f},
|
||||||
|
SecureBindAddress: "127.0.0.1:0",
|
||||||
|
TLS: &options.TLS{
|
||||||
|
Key: &ipv4KeyDataSource,
|
||||||
|
Cert: &ipv4CertDataSource,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
s, ok := srv.(*server)
|
||||||
|
Expect(ok).To(BeTrue())
|
||||||
|
|
||||||
|
listenAddr = fmt.Sprintf("http://%s/", l.Addr().String())
|
||||||
|
secureListenAddr = fmt.Sprintf("https://%s/", s.tlsListener.Addr().String())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Starts the server and serves the handler on http", func() {
|
||||||
|
go func() {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
Expect(srv.Start(ctx)).To(Succeed())
|
||||||
|
}()
|
||||||
|
|
||||||
|
resp, err := httpGet(ctx, listenAddr)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(resp.StatusCode).To(Equal(http.StatusOK))
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(string(body)).To(Equal(hello))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Starts the server and serves the handler on https", func() {
|
||||||
|
go func() {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
Expect(srv.Start(ctx)).To(Succeed())
|
||||||
|
}()
|
||||||
|
|
||||||
|
resp, err := httpGet(ctx, secureListenAddr)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(resp.StatusCode).To(Equal(http.StatusOK))
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(string(body)).To(Equal(hello))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Stops both servers when the context is cancelled", func() {
|
||||||
|
go func() {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
Expect(srv.Start(ctx)).To(Succeed())
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err := httpGet(ctx, listenAddr)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
_, err = httpGet(ctx, secureListenAddr)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
Eventually(func() error {
|
||||||
|
_, err := httpGet(ctx, listenAddr)
|
||||||
|
return err
|
||||||
|
}).Should(HaveOccurred())
|
||||||
|
Eventually(func() error {
|
||||||
|
_, err := httpGet(ctx, secureListenAddr)
|
||||||
|
return err
|
||||||
|
}).Should(HaveOccurred())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
Context("with both an ipv4 http and an ipv4 https server", func() {
|
Context("with both an ipv4 http and an ipv4 https server", func() {
|
||||||
var listenAddr, secureListenAddr string
|
var listenAddr, secureListenAddr string
|
||||||
|
|
||||||
|
|
@ -880,6 +1117,89 @@ var _ = Describe("Server", func() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Context("with an fd ipv6 http and an ipv6 https server", func() {
|
||||||
|
var listenAddr, secureListenAddr string
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
skipDevContainer()
|
||||||
|
l, err := net.Listen("tcp", "[::1]:0")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
f, err := l.(*net.TCPListener).File()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
srv, err = NewServer(Opts{
|
||||||
|
Handler: handler,
|
||||||
|
BindAddress: "fd:3",
|
||||||
|
fdFiles: []*os.File{f},
|
||||||
|
SecureBindAddress: "[::1]:0",
|
||||||
|
TLS: &options.TLS{
|
||||||
|
Key: &ipv6KeyDataSource,
|
||||||
|
Cert: &ipv6CertDataSource,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
s, ok := srv.(*server)
|
||||||
|
Expect(ok).To(BeTrue())
|
||||||
|
|
||||||
|
listenAddr = fmt.Sprintf("http://%s/", l.Addr().String())
|
||||||
|
secureListenAddr = fmt.Sprintf("https://%s/", s.tlsListener.Addr().String())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Starts the server and serves the handler on http", func() {
|
||||||
|
go func() {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
Expect(srv.Start(ctx)).To(Succeed())
|
||||||
|
}()
|
||||||
|
|
||||||
|
resp, err := httpGet(ctx, listenAddr)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(resp.StatusCode).To(Equal(http.StatusOK))
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(string(body)).To(Equal(hello))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Starts the server and serves the handler on https", func() {
|
||||||
|
go func() {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
Expect(srv.Start(ctx)).To(Succeed())
|
||||||
|
}()
|
||||||
|
|
||||||
|
resp, err := httpGet(ctx, secureListenAddr)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(resp.StatusCode).To(Equal(http.StatusOK))
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(string(body)).To(Equal(hello))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Stops both servers when the context is cancelled", func() {
|
||||||
|
go func() {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
Expect(srv.Start(ctx)).To(Succeed())
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err := httpGet(ctx, listenAddr)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
_, err = httpGet(ctx, secureListenAddr)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
Eventually(func() error {
|
||||||
|
_, err := httpGet(ctx, listenAddr)
|
||||||
|
return err
|
||||||
|
}).Should(HaveOccurred())
|
||||||
|
Eventually(func() error {
|
||||||
|
_, err := httpGet(ctx, secureListenAddr)
|
||||||
|
return err
|
||||||
|
}).Should(HaveOccurred())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
Context("with both an ipv6 http and an ipv6 https server", func() {
|
Context("with both an ipv6 http and an ipv6 https server", func() {
|
||||||
var listenAddr, secureListenAddr string
|
var listenAddr, secureListenAddr string
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue