git.iko.soy/typeable/oauth2-proxy
on master help sign in
Merge pull request #548 from oauth2-proxy/move-logging-options

Separate logging options out of main options structure

commita17c48810fc2b5267be256cb4812584c14ccb9d1 authorJoel Speed <Joel.speed@hotmail.co.uk> dateSun 31 May 2020, 14:15 (6 years ago) parentf7b28cb94e31f8
5 files changed+157−113
CHANGELOG.md+5 pkg/apis/options/logging.go+74 pkg/apis/options/options.go+10−54 pkg/validation/logging.go+62 pkg/validation/options.go+6−59
CHANGELOG.md+5
@@ -48,9 +48,14 @@
4848 This lead to confusion and misconfiguration as it was not obvious when a session should be encrypted.
4949 - Cookie Secrets must now be 16, 24 or 32 bytes.
5050 - If you need to change your secret, this will force users to reauthenticate.
51+- [#548](https://github.com/oauth2-proxy/oauth2-proxy/pull/548) Separate logging options out of main options structure
52+ - Fixes an inconsistency in the `--exclude-logging-paths` option by renaming it to `--exclude-logging-option`.
53+ - This flag may now be given multiple times as with other list options
54+ - This flag also accepts comma separated values
5155
5256## Changes since v5.1.1
5357
58+- [#548](https://github.com/oauth2-proxy/oauth2-proxy/pull/548) Separate logging options out of main options structure (@JoelSpeed)
5459- [#536](https://github.com/oauth2-proxy/oauth2-proxy/pull/536) Improvements to Session State code (@JoelSpeed)
5560- [#573](https://github.com/oauth2-proxy/oauth2-proxy/pull/573) Properly parse redis urls for cluster and sentinel connections (@amnay-mo)
5661- [#574](https://github.com/oauth2-proxy/oauth2-proxy/pull/574) render error page on 502 proxy status (@amnay-mo)
pkg/apis/options/logging.gonew file+74
@@ -0,0 +1,74 @@
1+package options
2+
3+import (
4+ "github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
5+ "github.com/spf13/pflag"
6+)
7+
8+// Logging contains all options required for configuring the logging
9+type Logging struct {
10+ AuthEnabled bool `flag:"auth-logging" cfg:"auth_logging"`
11+ AuthFormat string `flag:"auth-logging-format" cfg:"auth_logging_format"`
12+ RequestEnabled bool `flag:"request-logging" cfg:"request_logging"`
13+ RequestFormat string `flag:"request-logging-format" cfg:"request_logging_format"`
14+ StandardEnabled bool `flag:"standard-logging" cfg:"standard_logging"`
15+ StandardFormat string `flag:"standard-logging-format" cfg:"standard_logging_format"`
16+ ExcludePaths []string `flag:"exclude-logging-path" cfg:"exclude_logging_paths"`
17+ LocalTime bool `flag:"logging-local-time" cfg:"logging_local_time"`
18+ SilencePing bool `flag:"silence-ping-logging" cfg:"silence_ping_logging"`
19+ File LogFileOptions `cfg:",squash"`
20+}
21+
22+// LogFileOptions contains options for configuring logging to a file
23+type LogFileOptions struct {
24+ Filename string `flag:"logging-filename" cfg:"logging_filename"`
25+ MaxSize int `flag:"logging-max-size" cfg:"logging_max_size"`
26+ MaxAge int `flag:"logging-max-age" cfg:"logging_max_age"`
27+ MaxBackups int `flag:"logging-max-backups" cfg:"logging_max_backups"`
28+ Compress bool `flag:"logging-compress" cfg:"logging_compress"`
29+}
30+
31+func loggingFlagSet() *pflag.FlagSet {
32+ flagSet := pflag.NewFlagSet("logging", pflag.ExitOnError)
33+
34+ flagSet.Bool("auth-logging", true, "Log authentication attempts")
35+ flagSet.String("auth-logging-format", logger.DefaultAuthLoggingFormat, "Template for authentication log lines")
36+ flagSet.Bool("standard-logging", true, "Log standard runtime information")
37+ flagSet.String("standard-logging-format", logger.DefaultStandardLoggingFormat, "Template for standard log lines")
38+ flagSet.Bool("request-logging", true, "Log HTTP requests")
39+ flagSet.String("request-logging-format", logger.DefaultRequestLoggingFormat, "Template for HTTP request log lines")
40+
41+ flagSet.StringSlice("exclude-logging-path", []string{}, "Exclude logging requests to paths (eg: '/path1,/path2,/path3')")
42+ flagSet.Bool("logging-local-time", true, "If the time in log files and backup filenames are local or UTC time")
43+ flagSet.Bool("silence-ping-logging", false, "Disable logging of requests to ping endpoint")
44+
45+ flagSet.String("logging-filename", "", "File to log requests to, empty for stdout")
46+ flagSet.Int("logging-max-size", 100, "Maximum size in megabytes of the log file before rotation")
47+ flagSet.Int("logging-max-age", 7, "Maximum number of days to retain old log files")
48+ flagSet.Int("logging-max-backups", 0, "Maximum number of old log files to retain; 0 to disable")
49+ flagSet.Bool("logging-compress", false, "Should rotated log files be compressed using gzip")
50+
51+ return flagSet
52+}
53+
54+// loggingDefaults creates a Logging structure, populating each field with its default value
55+func loggingDefaults() Logging {
56+ return Logging{
57+ ExcludePaths: nil,
58+ LocalTime: true,
59+ SilencePing: false,
60+ AuthEnabled: true,
61+ AuthFormat: logger.DefaultAuthLoggingFormat,
62+ RequestEnabled: true,
63+ RequestFormat: logger.DefaultRequestLoggingFormat,
64+ StandardEnabled: true,
65+ StandardFormat: logger.DefaultStandardLoggingFormat,
66+ File: LogFileOptions{
67+ Filename: "",
68+ MaxSize: 100,
69+ MaxAge: 7,
70+ MaxBackups: 0,
71+ Compress: false,
72+ },
73+ }
74+}
pkg/apis/options/options.go+10−54
@@ -9,7 +9,6 @@ import (
99 oidc "github.com/coreos/go-oidc"
1010 ipapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/ip"
1111 sessionsapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
12− "github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
1312 "github.com/oauth2-proxy/oauth2-proxy/providers"
1413 "github.com/spf13/pflag"
1514)
@@ -61,6 +60,7 @@ type Options struct {
6160
6261 Cookie CookieOptions `cfg:",squash"`
6362 Session SessionOptions `cfg:",squash"`
63+ Logging Logging `cfg:",squash"`
6464
6565 Upstreams []string `flag:"upstream" cfg:"upstreams"`
6666 SkipAuthRegex []string `flag:"skip-auth-regex" cfg:"skip_auth_regex"`
@@ -101,27 +101,12 @@ type Options struct {
101101 ApprovalPrompt string `flag:"approval-prompt" cfg:"approval_prompt"` // Deprecated by OIDC 1.0
102102 UserIDClaim string `flag:"user-id-claim" cfg:"user_id_claim"`
103103
104− // Configuration values for logging
105− LoggingFilename string `flag:"logging-filename" cfg:"logging_filename"`
106− LoggingMaxSize int `flag:"logging-max-size" cfg:"logging_max_size"`
107− LoggingMaxAge int `flag:"logging-max-age" cfg:"logging_max_age"`
108− LoggingMaxBackups int `flag:"logging-max-backups" cfg:"logging_max_backups"`
109− LoggingLocalTime bool `flag:"logging-local-time" cfg:"logging_local_time"`
110− LoggingCompress bool `flag:"logging-compress" cfg:"logging_compress"`
111− StandardLogging bool `flag:"standard-logging" cfg:"standard_logging"`
112− StandardLoggingFormat string `flag:"standard-logging-format" cfg:"standard_logging_format"`
113− RequestLogging bool `flag:"request-logging" cfg:"request_logging"`
114− RequestLoggingFormat string `flag:"request-logging-format" cfg:"request_logging_format"`
115− ExcludeLoggingPaths string `flag:"exclude-logging-paths" cfg:"exclude_logging_paths"`
116− SilencePingLogging bool `flag:"silence-ping-logging" cfg:"silence_ping_logging"`
117− AuthLogging bool `flag:"auth-logging" cfg:"auth_logging"`
118− AuthLoggingFormat string `flag:"auth-logging-format" cfg:"auth_logging_format"`
119− SignatureKey string `flag:"signature-key" cfg:"signature_key"`
120− AcrValues string `flag:"acr-values" cfg:"acr_values"`
121− JWTKey string `flag:"jwt-key" cfg:"jwt_key"`
122− JWTKeyFile string `flag:"jwt-key-file" cfg:"jwt_key_file"`
123− PubJWKURL string `flag:"pubjwk-url" cfg:"pubjwk_url"`
124− GCPHealthChecks bool `flag:"gcp-healthchecks" cfg:"gcp_healthchecks"`
104+ SignatureKey string `flag:"signature-key" cfg:"signature_key"`
105+ AcrValues string `flag:"acr-values" cfg:"acr_values"`
106+ JWTKey string `flag:"jwt-key" cfg:"jwt_key"`
107+ JWTKeyFile string `flag:"jwt-key-file" cfg:"jwt_key_file"`
108+ PubJWKURL string `flag:"pubjwk-url" cfg:"pubjwk_url"`
109+ GCPHealthChecks bool `flag:"gcp-healthchecks" cfg:"gcp_healthchecks"`
125110
126111 // internal values that are set after config validation
127112 redirectURL *url.URL
@@ -197,20 +182,7 @@ func NewOptions() *Options {
197182 UserIDClaim: "email",
198183 InsecureOIDCAllowUnverifiedEmail: false,
199184 SkipOIDCDiscovery: false,
200− LoggingFilename: "",
201− LoggingMaxSize: 100,
202− LoggingMaxAge: 7,
203− LoggingMaxBackups: 0,
204− LoggingLocalTime: true,
205− LoggingCompress: false,
206− ExcludeLoggingPaths: "",
207− SilencePingLogging: false,
208− StandardLogging: true,
209− StandardLoggingFormat: logger.DefaultStandardLoggingFormat,
210− RequestLogging: true,
211− RequestLoggingFormat: logger.DefaultRequestLoggingFormat,
212− AuthLogging: true,
213− AuthLoggingFormat: logger.DefaultAuthLoggingFormat,
185+ Logging: loggingDefaults(),
214186 }
215187}
216188
@@ -293,24 +265,6 @@ func NewFlagSet() *pflag.FlagSet {
293265 flagSet.Bool("redis-use-cluster", false, "Connect to redis cluster. Must set --redis-cluster-connection-urls to use this feature")
294266 flagSet.StringSlice("redis-cluster-connection-urls", []string{}, "List of Redis cluster connection URLs (eg redis://HOST[:PORT]). Used in conjunction with --redis-use-cluster")
295267
296− flagSet.String("logging-filename", "", "File to log requests to, empty for stdout")
297− flagSet.Int("logging-max-size", 100, "Maximum size in megabytes of the log file before rotation")
298− flagSet.Int("logging-max-age", 7, "Maximum number of days to retain old log files")
299− flagSet.Int("logging-max-backups", 0, "Maximum number of old log files to retain; 0 to disable")
300− flagSet.Bool("logging-local-time", true, "If the time in log files and backup filenames are local or UTC time")
301− flagSet.Bool("logging-compress", false, "Should rotated log files be compressed using gzip")
302−
303− flagSet.Bool("standard-logging", true, "Log standard runtime information")
304− flagSet.String("standard-logging-format", logger.DefaultStandardLoggingFormat, "Template for standard log lines")
305−
306− flagSet.Bool("request-logging", true, "Log HTTP requests")
307− flagSet.String("request-logging-format", logger.DefaultRequestLoggingFormat, "Template for HTTP request log lines")
308− flagSet.String("exclude-logging-paths", "", "Exclude logging requests to paths (eg: '/path1,/path2,/path3')")
309− flagSet.Bool("silence-ping-logging", false, "Disable logging of requests to ping endpoint")
310−
311− flagSet.Bool("auth-logging", true, "Log authentication attempts")
312− flagSet.String("auth-logging-format", logger.DefaultAuthLoggingFormat, "Template for authentication log lines")
313−
314268 flagSet.String("provider", "google", "OAuth provider")
315269 flagSet.String("provider-display-name", "", "Provider display name")
316270 flagSet.String("oidc-issuer-url", "", "OpenID Connect issuer URL (ie: https://accounts.google.com)")
@@ -336,5 +290,7 @@ func NewFlagSet() *pflag.FlagSet {
336290
337291 flagSet.String("user-id-claim", "email", "which claim contains the user ID")
338292
293+ flagSet.AddFlagSet(loggingFlagSet())
294+
339295 return flagSet
340296}
pkg/validation/logging.gonew file+62
@@ -0,0 +1,62 @@
1+package validation
2+
3+import (
4+ "os"
5+
6+ "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
7+ "github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
8+ "gopkg.in/natefinch/lumberjack.v2"
9+)
10+
11+// configureLogger is responsible for configuring the logger based on the options given
12+func configureLogger(o options.Logging, pingPath string, msgs []string) []string {
13+ // Setup the log file
14+ if len(o.File.Filename) > 0 {
15+ // Validate that the file/dir can be written
16+ file, err := os.OpenFile(o.File.Filename, os.O_WRONLY|os.O_CREATE, 0666)
17+ if err != nil {
18+ if os.IsPermission(err) {
19+ return append(msgs, "unable to write to log file: "+o.File.Filename)
20+ }
21+ }
22+ file.Close()
23+
24+ logger.Printf("Redirecting logging to file: %s", o.File.Filename)
25+
26+ logWriter := &lumberjack.Logger{
27+ Filename: o.File.Filename,
28+ MaxSize: o.File.MaxSize, // megabytes
29+ MaxAge: o.File.MaxAge, // days
30+ MaxBackups: o.File.MaxBackups,
31+ LocalTime: o.LocalTime,
32+ Compress: o.File.Compress,
33+ }
34+
35+ logger.SetOutput(logWriter)
36+ }
37+
38+ // Supply a sanity warning to the logger if all logging is disabled
39+ if !o.StandardEnabled && !o.AuthEnabled && !o.RequestEnabled {
40+ logger.Print("Warning: Logging disabled. No further logs will be shown.")
41+ }
42+
43+ // Pass configuration values to the standard logger
44+ logger.SetStandardEnabled(o.StandardEnabled)
45+ logger.SetAuthEnabled(o.AuthEnabled)
46+ logger.SetReqEnabled(o.RequestEnabled)
47+ logger.SetStandardTemplate(o.StandardFormat)
48+ logger.SetAuthTemplate(o.AuthFormat)
49+ logger.SetReqTemplate(o.RequestFormat)
50+
51+ excludePaths := o.ExcludePaths
52+ if o.SilencePing {
53+ excludePaths = append(excludePaths, pingPath)
54+ }
55+ logger.SetExcludePaths(excludePaths)
56+
57+ if !o.LocalTime {
58+ logger.SetFlags(logger.Flags() | logger.LUTC)
59+ }
60+
61+ return msgs
62+}
pkg/validation/options.go+6−59
@@ -23,7 +23,6 @@ import (
2323 "github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
2424 "github.com/oauth2-proxy/oauth2-proxy/pkg/sessions"
2525 "github.com/oauth2-proxy/oauth2-proxy/providers"
26− "gopkg.in/natefinch/lumberjack.v2"
2726)
2827
2928// Validate checks that required options are set and validates those that they
@@ -265,7 +264,7 @@ func Validate(o *options.Options) error {
265264
266265 msgs = parseSignatureKey(o, msgs)
267266 msgs = validateCookieName(o, msgs)
268− msgs = setupLogger(o, msgs)
267+ msgs = configureLogger(o.Logging, o.PingPath, msgs)
269268
270269 if o.ReverseProxy {
271270 parser, err := ip.GetRealClientIPParser(o.RealClientIPHeader)
@@ -273,6 +272,11 @@ func Validate(o *options.Options) error {
273272 msgs = append(msgs, fmt.Sprintf("real_client_ip_header (%s) not accepted parameter value: %v", o.RealClientIPHeader, err))
274273 }
275274 o.SetRealClientIPParser(parser)
275+
276+ // Allow the logger to get client IPs
277+ logger.SetGetClientFunc(func(r *http.Request) string {
278+ return ip.GetClientString(o.GetRealClientIPParser(), r, false)
279+ })
276280 }
277281
278282 if len(msgs) != 0 {
@@ -453,63 +457,6 @@ func validateCookieName(o *options.Options, msgs []string) []string {
453457 return msgs
454458}
455459
456−func setupLogger(o *options.Options, msgs []string) []string {
457− // Setup the log file
458− if len(o.LoggingFilename) > 0 {
459− // Validate that the file/dir can be written
460− file, err := os.OpenFile(o.LoggingFilename, os.O_WRONLY|os.O_CREATE, 0666)
461− if err != nil {
462− if os.IsPermission(err) {
463− return append(msgs, "unable to write to log file: "+o.LoggingFilename)
464− }
465− }
466− file.Close()
467−
468− logger.Printf("Redirecting logging to file: %s", o.LoggingFilename)
469−
470− logWriter := &lumberjack.Logger{
471− Filename: o.LoggingFilename,
472− MaxSize: o.LoggingMaxSize, // megabytes
473− MaxAge: o.LoggingMaxAge, // days
474− MaxBackups: o.LoggingMaxBackups,
475− LocalTime: o.LoggingLocalTime,
476− Compress: o.LoggingCompress,
477− }
478−
479− logger.SetOutput(logWriter)
480− }
481−
482− // Supply a sanity warning to the logger if all logging is disabled
483− if !o.StandardLogging && !o.AuthLogging && !o.RequestLogging {
484− logger.Print("Warning: Logging disabled. No further logs will be shown.")
485− }
486−
487− // Pass configuration values to the standard logger
488− logger.SetStandardEnabled(o.StandardLogging)
489− logger.SetAuthEnabled(o.AuthLogging)
490− logger.SetReqEnabled(o.RequestLogging)
491− logger.SetStandardTemplate(o.StandardLoggingFormat)
492− logger.SetAuthTemplate(o.AuthLoggingFormat)
493− logger.SetReqTemplate(o.RequestLoggingFormat)
494− logger.SetGetClientFunc(func(r *http.Request) string {
495− return ip.GetClientString(o.GetRealClientIPParser(), r, false)
496− })
497−
498− excludePaths := make([]string, 0)
499− excludePaths = append(excludePaths, strings.Split(o.ExcludeLoggingPaths, ",")...)
500− if o.SilencePingLogging {
501− excludePaths = append(excludePaths, o.PingPath)
502− }
503−
504− logger.SetExcludePaths(excludePaths)
505−
506− if !o.LoggingLocalTime {
507− logger.SetFlags(logger.Flags() | logger.LUTC)
508− }
509−
510− return msgs
511−}
512−
513460// jwtIssuer hold parsed JWT issuer info that's used to construct a verifier.
514461type jwtIssuer struct {
515462 issuerURI string