From d9362d3bb92e610ace7edff59db686783f379a54 Mon Sep 17 00:00:00 2001 From: Martin Campbell Date: Fri, 24 Jan 2020 17:54:13 +0000 Subject: [PATCH] Add reverse proxy setting (#331) * Add reverse proxy setting (#321) --- CHANGELOG.md | 3 +++ contrib/oauth2_proxy.cfg.example | 3 +++ docs/4_tls.md | 1 + docs/configuration/configuration.md | 5 +++-- main.go | 1 + options.go | 2 ++ pkg/logger/logger.go | 29 +++++++++++++++++++++++------ 7 files changed, 36 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6013977..2bb6384c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ ## Breaking Changes +- [#321](https://github.com/pusher/oauth2_proxy/pull/331) Add reverse proxy boolean flag to control whether headers like `X-Real-Ip` are accepted. + This defaults to false. **Usage behind a reverse proxy will require this flag to be set to avoid logging the reverse proxy IP address**. + ## Changes since v4.1.0 - [#339](https://github.com/pusher/oauth2_proxy/pull/339) Add configuration for cookie 'SameSite' value. (@pgroudas) diff --git a/contrib/oauth2_proxy.cfg.example b/contrib/oauth2_proxy.cfg.example index f42bf08e..24dfb5a8 100644 --- a/contrib/oauth2_proxy.cfg.example +++ b/contrib/oauth2_proxy.cfg.example @@ -5,6 +5,9 @@ # http_address = "127.0.0.1:4180" # https_address = ":443" +## Are we running behind a reverse proxy? Will not accept headers like X-Real-Ip unless this is set. +# reverse_proxy = true + ## TLS Settings # tls_cert_file = "" # tls_key_file = "" diff --git a/docs/4_tls.md b/docs/4_tls.md index 5e54dd91..c6d40d74 100644 --- a/docs/4_tls.md +++ b/docs/4_tls.md @@ -68,6 +68,7 @@ There are two recommended configurations. --cookie-secret=... \ --cookie-secure=true \ --provider=... \ + --reverse-proxy=true \ --client-id=... \ --client-secret=... ``` diff --git a/docs/configuration/configuration.md b/docs/configuration/configuration.md index 4d041f2c..1c5cd613 100644 --- a/docs/configuration/configuration.md +++ b/docs/configuration/configuration.md @@ -91,6 +91,7 @@ An example [oauth2_proxy.cfg]({{ site.gitweb }}/contrib/oauth2_proxy.cfg.example | `-request-logging` | bool | Log requests | true | | `-request-logging-format` | string | Template for request log lines | see [Logging Configuration](#logging-configuration) | | `-resource` | string | The resource that is protected (Azure AD only) | | +| `-reverse-proxy` | bool | are we running behind a reverse proxy, controls whether headers like X-Real-Ip are accepted | false | | `-scope` | string | OAuth scope specification | | | `-session-store-type` | string | Session data storage backend | cookie | | `-set-xauthrequest` | bool | set X-Auth-Request-User and X-Auth-Request-Email response headers (useful in Nginx auth_request mode) | false | @@ -174,7 +175,7 @@ Available variables for auth logging: | Variable | Example | Description | | --- | --- | --- | -| Client | 74.125.224.72 | The client/remote IP address. Will use the X-Real-IP header it if exists. | +| Client | 74.125.224.72 | The client/remote IP address. Will use the X-Real-IP header it if exists & reverse-proxy is set to true. | | Host | domain.com | The value of the Host header. | | Protocol | HTTP/1.0 | The request protocol. | | RequestMethod | GET | The request method. | @@ -202,7 +203,7 @@ Available variables for request logging: | Variable | Example | Description | | --- | --- | --- | -| Client | 74.125.224.72 | The client/remote IP address. Will use the X-Real-IP header it if exists. | +| Client | 74.125.224.72 | The client/remote IP address. Will use the X-Real-IP header it if exists & reverse-proxy is set to true. | | Host | domain.com | The value of the Host header. | | Protocol | HTTP/1.0 | The request protocol. | | RequestDuration | 0.001 | The time in seconds that a request took to process. | diff --git a/main.go b/main.go index 9105390f..e4e4bc76 100644 --- a/main.go +++ b/main.go @@ -32,6 +32,7 @@ func main() { flagSet.String("http-address", "127.0.0.1:4180", "[http://]: or unix:// to listen on for HTTP clients") flagSet.String("https-address", ":443", ": to listen on for HTTPS clients") + flagSet.Bool("reverse-proxy", false, "are we running behind a reverse proxy, controls whether headers like X-Real-Ip are accepted") flagSet.Bool("force-https", false, "force HTTPS redirect for HTTP requests") flagSet.String("tls-cert-file", "", "path to certificate file") flagSet.String("tls-key-file", "", "path to private key file") diff --git a/options.go b/options.go index 5c83958f..5355177b 100644 --- a/options.go +++ b/options.go @@ -34,6 +34,7 @@ type Options struct { ProxyWebSockets bool `flag:"proxy-websockets" cfg:"proxy_websockets" env:"OAUTH2_PROXY_PROXY_WEBSOCKETS"` HTTPAddress string `flag:"http-address" cfg:"http_address" env:"OAUTH2_PROXY_HTTP_ADDRESS"` HTTPSAddress string `flag:"https-address" cfg:"https_address" env:"OAUTH2_PROXY_HTTPS_ADDRESS"` + ReverseProxy bool `flag:"reverse-proxy" cfg:"reverse_proxy" env:"OAUTH2_PROXY_REVERSE_PROXY"` ForceHTTPS bool `flag:"force-https" cfg:"force_https" env:"OAUTH2_PROXY_FORCE_HTTPS"` RedirectURL string `flag:"redirect-url" cfg:"redirect_url" env:"OAUTH2_PROXY_REDIRECT_URL"` ClientID string `flag:"client-id" cfg:"client_id" env:"OAUTH2_PROXY_CLIENT_ID"` @@ -617,6 +618,7 @@ func setupLogger(o *Options, msgs []string) []string { logger.SetStandardTemplate(o.StandardLoggingFormat) logger.SetAuthTemplate(o.AuthLoggingFormat) logger.SetReqTemplate(o.RequestLoggingFormat) + logger.SetReverseProxy(o.ReverseProxy) excludePaths := make([]string, 0) excludePaths = append(excludePaths, strings.Split(o.ExcludeLoggingPaths, ",")...) diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 1b6017bb..962a2c93 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -88,6 +88,7 @@ type Logger struct { stdEnabled bool authEnabled bool reqEnabled bool + reverseProxy bool excludePaths map[string]struct{} stdLogTemplate *template.Template authTemplate *template.Template @@ -102,6 +103,7 @@ func New(flag int) *Logger { stdEnabled: true, authEnabled: true, reqEnabled: true, + reverseProxy: false, excludePaths: nil, stdLogTemplate: template.Must(template.New("std-log").Parse(DefaultStandardLoggingFormat)), authTemplate: template.Must(template.New("auth-log").Parse(DefaultAuthLoggingFormat)), @@ -151,7 +153,7 @@ func (l *Logger) PrintAuth(username string, req *http.Request, status AuthStatus username = "-" } - client := GetClient(req) + client := GetClient(req, l.reverseProxy) l.mu.Lock() defer l.mu.Unlock() @@ -199,7 +201,7 @@ func (l *Logger) PrintReq(username, upstream string, req *http.Request, url url. } } - client := GetClient(req) + client := GetClient(req, l.reverseProxy) l.mu.Lock() defer l.mu.Unlock() @@ -251,10 +253,12 @@ func (l *Logger) GetFileLineString(calldepth int) string { } // GetClient parses an HTTP request for the client/remote IP address. -func GetClient(req *http.Request) string { - client := req.Header.Get("X-Real-IP") - if client == "" { - client = req.RemoteAddr +func GetClient(req *http.Request, reverseProxy bool) string { + client := req.RemoteAddr + if reverseProxy { + if ip := req.Header.Get("X-Real-IP"); ip != "" { + client = ip + } } if c, _, err := net.SplitHostPort(client); err == nil { @@ -308,6 +312,13 @@ func (l *Logger) SetReqEnabled(e bool) { l.reqEnabled = e } +// SetReverseProxy controls whether logging will trust headers that can be set by a reverse proxy. +func (l *Logger) SetReverseProxy(e bool) { + l.mu.Lock() + defer l.mu.Unlock() + l.reverseProxy = e +} + // SetExcludePaths sets the paths to exclude from logging. func (l *Logger) SetExcludePaths(s []string) { l.mu.Lock() @@ -381,6 +392,12 @@ func SetReqEnabled(e bool) { std.SetReqEnabled(e) } +// SetReverseProxy controls whether logging will trust headers that can be set +// by a reverse proxy for the standard logger. +func SetReverseProxy(e bool) { + std.SetReverseProxy(e) +} + // SetExcludePaths sets the path to exclude from logging, eg: health checks func SetExcludePaths(s []string) { std.SetExcludePaths(s)