From f6cf9babb1008cbaae8a804bfd254d06ff3439a8 Mon Sep 17 00:00:00 2001 From: Rohith Date: Mon, 28 Aug 2017 18:48:11 +0100 Subject: [PATCH] HTTP Server and Upstream Timeouts Related to issue [263](https://github.com/gambol99/keycloak-proxy/issues/263). Permitting the users to set varioues timeouts on the http.Server and upstream proxy --- CHANGELOG.md | 1 + README.md | 154 ++++++++++++++++++++++++++------------------------- config.go | 26 +++++---- doc.go | 17 +++++- server.go | 31 +++++++---- 5 files changed, 133 insertions(+), 96 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2065b44..f9076c47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ FEATURES * moved to use zap for the logging [#PR237](https://github.com/gambol99/keycloak-proxy/pull/237) * making the X-Auth-Token optional in the upstream headers via the --enable-token-header [#PR247](https://github.com/gambol99/keycloak-proxy/pull/247) * adding the ability to load a CA authority to provide trust on upstream endpoint [#PR248](https://github.com/gambol99/keycloak-proxy/pull/248) +* adding the ability to set various http server and upstream timeout [#PR268](https://github.com/gambol99/keycloak-proxy/pull/268) BREAKING CHANGES: * the proxy no longer uses prefixes for resources, if you wish to use wildcard urls you need diff --git a/README.md b/README.md index 63ecb084..50365812 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ USAGE: keycloak-proxy [options] VERSION: - v2.1.0-rc2 (git+sha: 6782490-dirty, built: 06-07-2017) + v2.1.0-rc3 (git+sha: 920a0a6-dirty, built: 28-08-2017) AUTHOR: Rohith @@ -43,79 +43,85 @@ COMMANDS: help, h Shows a list of commands or help for one command GLOBAL OPTIONS: - --config value path the a configuration file [$PROXY_CONFIG_FILE] - --listen value the interface the service should be listening on [$PROXY_LISTEN] - --listen-http value interface we should be listening [$PROXY_LISTEN_HTTP] - --discovery-url value discovery url to retrieve the openid configuration [$PROXY_DISCOVERY_URL] - --client-id value client id used to authenticate to the oauth service [$PROXY_CLIENT_ID] - --client-secret value client secret used to authenticate to the oauth service [$PROXY_CLIENT_SECRET] - --redirection-url value redirection url for the oauth callback url, defaults to host header is absent [$PROXY_REDIRECTION_URL] - --revocation-url value url for the revocation endpoint to revoke refresh token [$PROXY_REVOCATION_URL] - --skip-openid-provider-tls-verify skip the verification of any TLS communication with the openid provider (default: false) - --scopes value list of scopes requested when authenticating the user - --upstream-url value url for the upstream endpoint you wish to proxy [$PROXY_UPSTREAM_URL] - --upstream-ca value the path to a file container a CA certificate to validate the upstream tls endpoint - --resources value list of resources 'uri=/admin|methods=GET,PUT|roles=role1,role2' - --headers value custom headers to the upstream request, key=value - --enable-token-header enables the token authentication header X-Auth-Token to upstream (default: true) - --enable-encrypted-token enable encryption for the access tokens (default: false) - --enable-logging enable http logging of the requests (default: false) - --enable-json-logging switch on json logging rather than text (default: false) - --enable-forwarding enables the forwarding proxy mode, signing outbound request (default: false) - --enable-security-filter enables the security filter handler (default: false) - --enable-refresh-tokens nables the handling of the refresh tokens (default: false) [$PROXY_ENABLE_SECURITY_FILTER] - --enable-login-handler enables the handling of the refresh tokens (default: false) [$PROXY_ENABLE_LOGIN_HANDLER] - --enable-authorization-header adds the authorization header to the proxy request (default: true) - --enable-https-redirection enable the http to https redirection on the http service (default: false) - --enable-profiling switching on the golang profiling via pprof on /debug/pprof, /debug/pprof/heap etc (default: false) - --enable-metrics enable the prometheus metrics collector on /oauth/metrics (default: false) - --filter-browser-xss enable the adds the X-XSS-Protection header with mode=block (default: false) - --filter-content-nosniff adds the X-Content-Type-Options header with the value nosniff (default: false) - --filter-frame-deny enable to the frame deny header (default: false) - --content-security-policy value specify the content security policy - --localhost-metrics enforces the metrics page can only been requested from 127.0.0.1 (default: false) - --access-token-duration value fallback cookie duration for the access token when using refresh tokens (default: 720h0m0s) - --cookie-domain value domain the access cookie is available to, defaults host header - --cookie-access-name value name of the cookie use to hold the access token (default: "kc-access") - --cookie-refresh-name value name of the cookie used to hold the encrypted refresh token (default: "kc-state") - --secure-cookie enforces the cookie to be secure (default: true) - --http-only-cookie enforces the cookie is in http only mode (default: false) - --match-claims value keypair values for matching access token claims e.g. aud=myapp, iss=http://example.* - --add-claims value extra claims from the token and inject into headers, e.g given_name -> X-Auth-Given-Name - --tls-cert value path to ths TLS certificate - --tls-private-key value path to the private key for TLS - --tls-ca-certificate value path to the ca certificate used for signing requests - --tls-ca-key value path the ca private key, used by the forward signing proxy - --tls-client-certificate value path to the client certificate for outbound connections in reverse and forwarding proxy modes - --skip-upstream-tls-verify skip the verification of any upstream TLS (default: true) - --skip-client-id skip the check on the client token (default: false) - --cors-origins value origins to add to the CORE origins control (Access-Control-Allow-Origin) - --cors-methods value methods permitted in the access control (Access-Control-Allow-Methods) - --cors-headers value set of headers to add to the CORS access control (Access-Control-Allow-Headers) - --cors-exposed-headers value expose cors headers access control (Access-Control-Expose-Headers) - --cors-credentials credentials access control header (Access-Control-Allow-Credentials) (default: false) - --cors-max-age value max age applied to cors headers (Access-Control-Max-Age) (default: 0s) - --hostnames value list of hostnames the service will respond to - --store-url value url for the storage subsystem, e.g redis://127.0.0.1:6379, file:///etc/tokens.file - --encryption-key value encryption key used to encryption the session state [$PROXY_ENCRYPTION_KEY] - --no-redirects do not have back redirects when no authentication is present, 401 them (default: false) - --skip-token-verification TESTING ONLY; bypass token verification, only expiration and roles enforced (default: false) - --upstream-keepalives enables or disables the keepalive connections for upstream endpoint (default: false) - --upstream-timeout value maximum amount of time a dial will wait for a connect to complete (default: 10s) - --upstream-keepalive-timeout value specifies the keep-alive period for an active network connection (default: 10s) - --verbose switch on debug / verbose logging (default: false) - --enabled-proxy-protocol enable proxy protocol (default: false) - --use-letsencrypt use letsencrypt for certificates (default: false) - --letsencrypt-cache-dir value path where cached letsencrypt certificates are stored (default: "./cache/") - --sign-in-page value path to custom template displayed for signin - --forbidden-page value path to custom template used for access forbidden - --tags value keypairs passed to the templates at render,e.g title=Page - --forwarding-username value username to use when logging into the openid provider - --forwarding-password value password to use when logging into the openid provider - --forwarding-domains value list of domains which should be signed; everything else is relayed unsigned - --disable-all-logging disables all logging to stdout and stderr (default: false) - --help, -h show help - --version, -v print the version + --config value path the a configuration file [$PROXY_CONFIG_FILE] + --listen value the interface the service should be listening on [$PROXY_LISTEN] + --listen-http value interface we should be listening [$PROXY_LISTEN_HTTP] + --discovery-url value discovery url to retrieve the openid configuration [$PROXY_DISCOVERY_URL] + --client-id value client id used to authenticate to the oauth service [$PROXY_CLIENT_ID] + --client-secret value client secret used to authenticate to the oauth service [$PROXY_CLIENT_SECRET] + --redirection-url value redirection url for the oauth callback url, defaults to host header is absent [$PROXY_REDIRECTION_URL] + --revocation-url value url for the revocation endpoint to revoke refresh token [$PROXY_REVOCATION_URL] + --skip-openid-provider-tls-verify skip the verification of any TLS communication with the openid provider (default: false) + --scopes value list of scopes requested when authenticating the user + --upstream-url value url for the upstream endpoint you wish to proxy [$PROXY_UPSTREAM_URL] + --upstream-ca value the path to a file container a CA certificate to validate the upstream tls endpoint + --resources value list of resources 'uri=/admin|methods=GET,PUT|roles=role1,role2' + --headers value custom headers to the upstream request, key=value + --enable-token-header enables the token authentication header X-Auth-Token to upstream (default: true) + --enable-encrypted-token enable encryption for the access tokens (default: false) + --enable-logging enable http logging of the requests (default: false) + --enable-json-logging switch on json logging rather than text (default: false) + --enable-forwarding enables the forwarding proxy mode, signing outbound request (default: false) + --enable-security-filter enables the security filter handler (default: false) + --enable-refresh-tokens nables the handling of the refresh tokens (default: false) [$PROXY_ENABLE_SECURITY_FILTER] + --enable-login-handler enables the handling of the refresh tokens (default: false) [$PROXY_ENABLE_LOGIN_HANDLER] + --enable-authorization-header adds the authorization header to the proxy request (default: true) + --enable-https-redirection enable the http to https redirection on the http service (default: false) + --enable-profiling switching on the golang profiling via pprof on /debug/pprof, /debug/pprof/heap etc (default: false) + --enable-metrics enable the prometheus metrics collector on /oauth/metrics (default: false) + --filter-browser-xss enable the adds the X-XSS-Protection header with mode=block (default: false) + --filter-content-nosniff adds the X-Content-Type-Options header with the value nosniff (default: false) + --filter-frame-deny enable to the frame deny header (default: false) + --content-security-policy value specify the content security policy + --localhost-metrics enforces the metrics page can only been requested from 127.0.0.1 (default: false) + --access-token-duration value fallback cookie duration for the access token when using refresh tokens (default: 720h0m0s) + --cookie-domain value domain the access cookie is available to, defaults host header + --cookie-access-name value name of the cookie use to hold the access token (default: "kc-access") + --cookie-refresh-name value name of the cookie used to hold the encrypted refresh token (default: "kc-state") + --secure-cookie enforces the cookie to be secure (default: true) + --http-only-cookie enforces the cookie is in http only mode (default: false) + --match-claims value keypair values for matching access token claims e.g. aud=myapp, iss=http://example.* + --add-claims value extra claims from the token and inject into headers, e.g given_name -> X-Auth-Given-Name + --tls-cert value path to ths TLS certificate + --tls-private-key value path to the private key for TLS + --tls-ca-certificate value path to the ca certificate used for signing requests + --tls-ca-key value path the ca private key, used by the forward signing proxy + --tls-client-certificate value path to the client certificate for outbound connections in reverse and forwarding proxy modes + --skip-upstream-tls-verify skip the verification of any upstream TLS (default: true) + --skip-client-id skip the check on the client token (default: false) + --cors-origins value origins to add to the CORE origins control (Access-Control-Allow-Origin) + --cors-methods value methods permitted in the access control (Access-Control-Allow-Methods) + --cors-headers value set of headers to add to the CORS access control (Access-Control-Allow-Headers) + --cors-exposed-headers value expose cors headers access control (Access-Control-Expose-Headers) + --cors-credentials credentials access control header (Access-Control-Allow-Credentials) (default: false) + --cors-max-age value max age applied to cors headers (Access-Control-Max-Age) (default: 0s) + --hostnames value list of hostnames the service will respond to + --store-url value url for the storage subsystem, e.g redis://127.0.0.1:6379, file:///etc/tokens.file + --encryption-key value encryption key used to encryption the session state [$PROXY_ENCRYPTION_KEY] + --no-redirects do not have back redirects when no authentication is present, 401 them (default: false) + --skip-token-verification TESTING ONLY; bypass token verification, only expiration and roles enforced (default: false) + --upstream-keepalives enables or disables the keepalive connections for upstream endpoint (default: false) + --upstream-timeout value maximum amount of time a dial will wait for a connect to complete (default: 10s) + --upstream-keepalive-timeout value specifies the keep-alive period for an active network connection (default: 10s) + --upstream-tls-handshake-timeout value the timeout placed on the tls handshake for upstream (default: 10s) + --upstream-response-header-timeout value the timeout placed on the response header for upstream (default: 1s) + --upstream-expect-continue-timeout value the timeout placed on the expect continue for upstream (default: 10s) + --verbose switch on debug / verbose logging (default: false) + --enabled-proxy-protocol enable proxy protocol (default: false) + --server-read-timeout value the server read timeout on the http server (default: 5s) + --server-write-timeout value the server write timeout on the http server (default: 10s) + --server-idle-timeout value the server idle timeout on the http server (default: 2m0s) + --use-letsencrypt use letsencrypt for certificates (default: false) + --letsencrypt-cache-dir value path where cached letsencrypt certificates are stored (default: "./cache/") + --sign-in-page value path to custom template displayed for signin + --forbidden-page value path to custom template used for access forbidden + --tags value keypairs passed to the templates at render,e.g title=Page + --forwarding-username value username to use when logging into the openid provider + --forwarding-password value password to use when logging into the openid provider + --forwarding-domains value list of domains which should be signed; everything else is relayed unsigned + --disable-all-logging disables all logging to stdout and stderr (default: false) + --help, -h show help + --version, -v print the version ``` #### **Building** diff --git a/config.go b/config.go index c98c0edd..927d8793 100644 --- a/config.go +++ b/config.go @@ -28,20 +28,26 @@ import ( func newDefaultConfig() *Config { return &Config{ AccessTokenDuration: time.Duration(720) * time.Hour, - Tags: make(map[string]string), - MatchClaims: make(map[string]string), - Headers: make(map[string]string), - UpstreamTimeout: time.Duration(10) * time.Second, - UpstreamKeepaliveTimeout: time.Duration(10) * time.Second, - EnableAuthorizationHeader: true, - EnableTokenHeader: true, CookieAccessName: "kc-access", CookieRefreshName: "kc-state", + EnableAuthorizationHeader: true, + EnableTokenHeader: true, + Headers: make(map[string]string), + LetsEncryptCacheDir: "./cache/", + MatchClaims: make(map[string]string), SecureCookie: true, - SkipUpstreamTLSVerify: true, + ServerIdleTimeout: 120 * time.Second, + ServerReadTimeout: 5 * time.Second, + ServerWriteTimeout: 10 * time.Second, SkipOpenIDProviderTLSVerify: false, - UseLetsEncrypt: false, - LetsEncryptCacheDir: "./cache/", + SkipUpstreamTLSVerify: true, + Tags: make(map[string]string, 0), + UpstreamExpectContinueTimeout: 10 * time.Second, + UpstreamKeepaliveTimeout: 10 * time.Second, + UpstreamResponseHeaderTimeout: 1 * time.Second, + UpstreamTLSHandshakeTimeout: 10 * time.Second, + UpstreamTimeout: 10 * time.Second, + UseLetsEncrypt: false, } } diff --git a/doc.go b/doc.go index fe25325e..94385254 100644 --- a/doc.go +++ b/doc.go @@ -26,7 +26,7 @@ import ( ) var ( - release = "v2.1.0-rc3" + release = "v2.1.0-rc4" gitsha = "no gitsha provided" compiled = "0" version = "" @@ -229,12 +229,25 @@ type Config struct { UpstreamKeepalives bool `json:"upstream-keepalives" yaml:"upstream-keepalives" usage:"enables or disables the keepalive connections for upstream endpoint"` // UpstreamTimeout is the maximum amount of time a dial will wait for a connect to complete UpstreamTimeout time.Duration `json:"upstream-timeout" yaml:"upstream-timeout" usage:"maximum amount of time a dial will wait for a connect to complete"` - // UpstreamKeepaliveTimeout + // UpstreamKeepaliveTimeout is the upstream keepalive timeout UpstreamKeepaliveTimeout time.Duration `json:"upstream-keepalive-timeout" yaml:"upstream-keepalive-timeout" usage:"specifies the keep-alive period for an active network connection"` + // UpstreamTLSHandshakeTimeout is the timeout for upstream to tls handshake + UpstreamTLSHandshakeTimeout time.Duration `json:"upstream-tls-handshake-timeout" yaml:"upstream-tls-handshake-timeout" usage:"the timeout placed on the tls handshake for upstream"` + // UpstreamResponseHeaderTimeout is the timeout for upstream header response + UpstreamResponseHeaderTimeout time.Duration `json:"upstream-response-header-timeout" yaml:"upstream-response-header-timeout" usage:"the timeout placed on the response header for upstream"` + // UpstreamExpectContinueTimeout is the timeout expect continue for upstream + UpstreamExpectContinueTimeout time.Duration `json:"upstream-expect-continue-timeout" yaml:"upstream-expect-continue-timeout" usage:"the timeout placed on the expect continue for upstream"` + // Verbose switches on debug logging Verbose bool `json:"verbose" yaml:"verbose" usage:"switch on debug / verbose logging"` // EnableProxyProtocol controls the proxy protocol EnableProxyProtocol bool `json:"enabled-proxy-protocol" yaml:"enabled-proxy-protocol" usage:"enable proxy protocol"` + // ServerReadTimeout is the read timeout on the http server + ServerReadTimeout time.Duration `json:"server-read-timeout" yaml:"server-read-timeout" usage:"the server read timeout on the http server"` + // ServerWriteTimeout is the write timeout on the http server + ServerWriteTimeout time.Duration `json:"server-write-timeout" yaml:"server-write-timeout" usage:"the server write timeout on the http server"` + // ServerIdleTimeout is the idle timeout on the http server + ServerIdleTimeout time.Duration `json:"server-idle-timeout" yaml:"server-idle-timeout" usage:"the server idle timeout on the http server"` // UseLetsEncrypt controls if we should use letsencrypt to retrieve certificates UseLetsEncrypt bool `json:"use-letsencrypt" yaml:"use-letsencrypt" usage:"use letsencrypt for certificates"` diff --git a/server.go b/server.go index fddd051b..80fac533 100644 --- a/server.go +++ b/server.go @@ -334,9 +334,11 @@ func (r *oauthProxy) Run() error { } // step: create the http server server := &http.Server{ - Addr: r.config.Listen, - Handler: r.router, - IdleTimeout: 120 * time.Second, + Addr: r.config.Listen, + Handler: r.router, + ReadTimeout: r.config.ServerReadTimeout, + WriteTimeout: r.config.ServerWriteTimeout, + IdleTimeout: r.config.ServerIdleTimeout, } r.server = server r.listener = listener @@ -361,8 +363,11 @@ func (r *oauthProxy) Run() error { return err } httpsvc := &http.Server{ - Addr: r.config.ListenHTTP, - Handler: r.router, + Addr: r.config.ListenHTTP, + Handler: r.router, + ReadTimeout: r.config.ServerReadTimeout, + WriteTimeout: r.config.ServerWriteTimeout, + IdleTimeout: r.config.ServerIdleTimeout, } go func() { if err := httpsvc.Serve(httpListener); err != nil { @@ -548,13 +553,19 @@ func (r *oauthProxy) createUpstreamProxy(upstream *url.URL) error { proxy.Logger = httplog.New(ioutil.Discard, "", 0) r.upstream = proxy - // update the tls configuration of the reverse proxy - r.upstream.(*goproxy.ProxyHttpServer).Tr = &http.Transport{ - Dial: dialer, - TLSClientConfig: tlsConfig, - DisableKeepAlives: !r.config.UpstreamKeepalives, + // create the http transport + tp := &http.Transport{ + Dial: dialer, + DisableKeepAlives: !r.config.UpstreamKeepalives, + ExpectContinueTimeout: r.config.UpstreamExpectContinueTimeout, + ResponseHeaderTimeout: r.config.UpstreamResponseHeaderTimeout, + TLSClientConfig: tlsConfig, + TLSHandshakeTimeout: r.config.UpstreamTLSHandshakeTimeout, } + // update the tls configuration of the reverse proxy + r.upstream.(*goproxy.ProxyHttpServer).Tr = tp + return nil }