2016-11-10 22:56:29 +00:00
/ *
Copyright 2016 The Kubernetes Authors .
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package proxy
import (
2023-07-22 03:32:07 +00:00
"regexp"
2021-08-21 20:42:00 +00:00
networking "k8s.io/api/networking/v1"
2016-11-10 22:56:29 +00:00
2017-11-07 22:02:12 +00:00
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/resolver"
2016-11-10 22:56:29 +00:00
)
2023-07-22 03:32:07 +00:00
const (
proxyConnectTimeoutAnnotation = "proxy-connect-timeout"
proxySendTimeoutAnnotation = "proxy-send-timeout"
proxyReadTimeoutAnnotation = "proxy-read-timeout"
proxyBuffersNumberAnnotation = "proxy-buffers-number"
proxyBufferSizeAnnotation = "proxy-buffer-size"
2024-12-05 18:10:00 +00:00
proxyBusyBuffersSizeAnnotation = "proxy-busy-buffers-size"
2023-07-22 03:32:07 +00:00
proxyCookiePathAnnotation = "proxy-cookie-path"
proxyCookieDomainAnnotation = "proxy-cookie-domain"
proxyBodySizeAnnotation = "proxy-body-size"
proxyNextUpstreamAnnotation = "proxy-next-upstream"
proxyNextUpstreamTimeoutAnnotation = "proxy-next-upstream-timeout"
proxyNextUpstreamTriesAnnotation = "proxy-next-upstream-tries"
proxyRequestBufferingAnnotation = "proxy-request-buffering"
proxyRedirectFromAnnotation = "proxy-redirect-from"
proxyRedirectToAnnotation = "proxy-redirect-to"
proxyBufferingAnnotation = "proxy-buffering"
proxyHTTPVersionAnnotation = "proxy-http-version"
2023-09-11 03:02:10 +00:00
proxyMaxTempFileSizeAnnotation = "proxy-max-temp-file-size" //#nosec G101
2023-07-22 03:32:07 +00:00
)
2023-08-31 07:36:48 +00:00
var validUpstreamAnnotation = regexp . MustCompile ( ` ^((error|timeout|invalid_header|http_500|http_502|http_503|http_504|http_403|http_404|http_429|non_idempotent|off)\s?)+$ ` )
2023-07-22 03:32:07 +00:00
var proxyAnnotations = parser . Annotation {
Group : "backend" ,
Annotations : parser . AnnotationFields {
proxyConnectTimeoutAnnotation : {
Validator : parser . ValidateInt ,
Scope : parser . AnnotationScopeLocation ,
Risk : parser . AnnotationRiskLow ,
Documentation : ` This annotation allows setting the timeout in seconds of the connect operation to the backend. ` ,
} ,
proxySendTimeoutAnnotation : {
Validator : parser . ValidateInt ,
Scope : parser . AnnotationScopeLocation ,
Risk : parser . AnnotationRiskLow ,
Documentation : ` This annotation allows setting the timeout in seconds of the send operation to the backend. ` ,
} ,
proxyReadTimeoutAnnotation : {
Validator : parser . ValidateInt ,
Scope : parser . AnnotationScopeLocation ,
Risk : parser . AnnotationRiskLow ,
Documentation : ` This annotation allows setting the timeout in seconds of the read operation to the backend. ` ,
} ,
proxyBuffersNumberAnnotation : {
Validator : parser . ValidateInt ,
Scope : parser . AnnotationScopeLocation ,
Risk : parser . AnnotationRiskLow ,
Documentation : ` This annotation sets the number of the buffers in proxy_buffers used for reading the first part of the response received from the proxied server .
By default proxy buffers number is set as 4 ` ,
} ,
proxyBufferSizeAnnotation : {
2023-08-31 07:36:48 +00:00
Validator : parser . ValidateRegex ( parser . SizeRegex , true ) ,
2023-07-22 03:32:07 +00:00
Scope : parser . AnnotationScopeLocation ,
Risk : parser . AnnotationRiskLow ,
Documentation : ` This annotation sets the size of the buffer proxy_buffer_size used for reading the first part of the response received from the proxied server .
By default proxy buffer size is set as "4k" . ` ,
} ,
2024-12-05 18:10:00 +00:00
proxyBusyBuffersSizeAnnotation : {
Validator : parser . ValidateRegex ( parser . SizeRegex , true ) ,
Scope : parser . AnnotationScopeLocation ,
Risk : parser . AnnotationRiskLow ,
Documentation : ` This annotation limits the total size of buffers that can be busy sending a response to the client while the response is not yet fully read. By default proxy busy buffers size is set as "8k". ` ,
} ,
2023-07-22 03:32:07 +00:00
proxyCookiePathAnnotation : {
2023-08-31 07:36:48 +00:00
Validator : parser . ValidateRegex ( parser . URLIsValidRegex , true ) ,
2023-07-22 03:32:07 +00:00
Scope : parser . AnnotationScopeLocation ,
Risk : parser . AnnotationRiskMedium ,
Documentation : ` This annotation sets a text that should be changed in the path attribute of the "Set-Cookie" header fields of a proxied server response. ` ,
} ,
proxyCookieDomainAnnotation : {
2023-08-31 07:36:48 +00:00
Validator : parser . ValidateRegex ( parser . BasicCharsRegex , true ) ,
2023-07-22 03:32:07 +00:00
Scope : parser . AnnotationScopeLocation ,
Risk : parser . AnnotationRiskMedium ,
Documentation : ` This annotation ets a text that should be changed in the domain attribute of the "Set-Cookie" header fields of a proxied server response. ` ,
} ,
proxyBodySizeAnnotation : {
2023-08-31 07:36:48 +00:00
Validator : parser . ValidateRegex ( parser . SizeRegex , true ) ,
2023-07-22 03:32:07 +00:00
Scope : parser . AnnotationScopeLocation ,
Risk : parser . AnnotationRiskMedium ,
Documentation : ` This annotation allows setting the maximum allowed size of a client request body. ` ,
} ,
proxyNextUpstreamAnnotation : {
2023-08-31 07:36:48 +00:00
Validator : parser . ValidateRegex ( validUpstreamAnnotation , false ) ,
2023-07-22 03:32:07 +00:00
Scope : parser . AnnotationScopeLocation ,
Risk : parser . AnnotationRiskMedium ,
Documentation : ` This annotation defines when the next upstream should be used .
This annotation reflect the directive https : //nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream
and only the allowed values on upstream are allowed here . ` ,
} ,
proxyNextUpstreamTimeoutAnnotation : {
Validator : parser . ValidateInt ,
Scope : parser . AnnotationScopeLocation ,
Risk : parser . AnnotationRiskLow ,
Documentation : ` This annotation limits the time during which a request can be passed to the next server ` ,
} ,
proxyNextUpstreamTriesAnnotation : {
Validator : parser . ValidateInt ,
Scope : parser . AnnotationScopeLocation ,
Risk : parser . AnnotationRiskLow ,
Documentation : ` This annotation limits the number of possible tries for passing a request to the next server ` ,
} ,
proxyRequestBufferingAnnotation : {
Validator : parser . ValidateOptions ( [ ] string { "on" , "off" } , true , true ) ,
Scope : parser . AnnotationScopeLocation ,
Risk : parser . AnnotationRiskLow ,
Documentation : ` This annotation enables or disables buffering of a client request body. ` ,
} ,
proxyRedirectFromAnnotation : {
2023-08-31 07:36:48 +00:00
Validator : parser . ValidateRegex ( parser . URLIsValidRegex , true ) ,
2023-07-22 03:32:07 +00:00
Scope : parser . AnnotationScopeLocation ,
Risk : parser . AnnotationRiskMedium ,
Documentation : ` The annotations proxy-redirect-from and proxy-redirect-to will set the first and second parameters of NGINX's proxy_redirect directive respectively ` ,
} ,
proxyRedirectToAnnotation : {
2023-08-31 07:36:48 +00:00
Validator : parser . ValidateRegex ( parser . URLIsValidRegex , true ) ,
2023-07-22 03:32:07 +00:00
Scope : parser . AnnotationScopeLocation ,
Risk : parser . AnnotationRiskMedium ,
Documentation : ` The annotations proxy-redirect-from and proxy-redirect-to will set the first and second parameters of NGINX's proxy_redirect directive respectively ` ,
} ,
proxyBufferingAnnotation : {
Validator : parser . ValidateOptions ( [ ] string { "on" , "off" } , true , true ) ,
Scope : parser . AnnotationScopeLocation ,
Risk : parser . AnnotationRiskLow ,
Documentation : ` This annotation enables or disables buffering of responses from the proxied server. It can be "on" or "off" ` ,
} ,
proxyHTTPVersionAnnotation : {
Validator : parser . ValidateOptions ( [ ] string { "1.0" , "1.1" } , true , true ) ,
Scope : parser . AnnotationScopeLocation ,
Risk : parser . AnnotationRiskLow ,
Documentation : ` This annotations sets the HTTP protocol version for proxying. Can be "1.0" or "1.1". ` ,
} ,
proxyMaxTempFileSizeAnnotation : {
2023-08-31 07:36:48 +00:00
Validator : parser . ValidateRegex ( parser . SizeRegex , true ) ,
2023-07-22 03:32:07 +00:00
Scope : parser . AnnotationScopeLocation ,
Risk : parser . AnnotationRiskLow ,
Documentation : ` This annotation defines the maximum size of a temporary file when buffering responses. ` ,
} ,
} ,
}
2017-11-07 16:36:51 +00:00
// Config returns the proxy timeout to use in the upstream server/s
type Config struct {
2019-08-12 17:27:05 +00:00
BodySize string ` json:"bodySize" `
ConnectTimeout int ` json:"connectTimeout" `
SendTimeout int ` json:"sendTimeout" `
ReadTimeout int ` json:"readTimeout" `
BuffersNumber int ` json:"buffersNumber" `
BufferSize string ` json:"bufferSize" `
2024-12-05 18:10:00 +00:00
BusyBuffersSize string ` json:"busyBuffersSize" `
2019-08-12 17:27:05 +00:00
CookieDomain string ` json:"cookieDomain" `
CookiePath string ` json:"cookiePath" `
NextUpstream string ` json:"nextUpstream" `
NextUpstreamTimeout int ` json:"nextUpstreamTimeout" `
NextUpstreamTries int ` json:"nextUpstreamTries" `
ProxyRedirectFrom string ` json:"proxyRedirectFrom" `
ProxyRedirectTo string ` json:"proxyRedirectTo" `
RequestBuffering string ` json:"requestBuffering" `
ProxyBuffering string ` json:"proxyBuffering" `
ProxyHTTPVersion string ` json:"proxyHTTPVersion" `
ProxyMaxTempFileSize string ` json:"proxyMaxTempFileSize" `
2016-11-10 22:56:29 +00:00
}
2017-07-27 03:07:59 +00:00
// Equal tests for equality between two Configuration types
2017-11-07 16:36:51 +00:00
func ( l1 * Config ) Equal ( l2 * Config ) bool {
2017-06-14 21:33:12 +00:00
if l1 == l2 {
return true
}
if l1 == nil || l2 == nil {
return false
}
if l1 . BodySize != l2 . BodySize {
return false
}
if l1 . ConnectTimeout != l2 . ConnectTimeout {
return false
}
if l1 . SendTimeout != l2 . SendTimeout {
return false
}
if l1 . ReadTimeout != l2 . ReadTimeout {
return false
}
2019-02-22 02:21:17 +00:00
if l1 . BuffersNumber != l2 . BuffersNumber {
2019-02-20 10:05:09 +00:00
return false
}
2017-06-14 21:33:12 +00:00
if l1 . BufferSize != l2 . BufferSize {
return false
}
2024-12-05 18:10:00 +00:00
if l1 . BusyBuffersSize != l2 . BusyBuffersSize {
return false
}
2017-06-14 21:33:12 +00:00
if l1 . CookieDomain != l2 . CookieDomain {
return false
}
if l1 . CookiePath != l2 . CookiePath {
return false
}
2017-08-31 13:09:23 +00:00
if l1 . NextUpstream != l2 . NextUpstream {
return false
}
2019-04-15 15:08:57 +00:00
if l1 . NextUpstreamTimeout != l2 . NextUpstreamTimeout {
return false
}
2018-03-22 11:12:36 +00:00
if l1 . NextUpstreamTries != l2 . NextUpstreamTries {
return false
}
2017-09-01 15:43:11 +00:00
if l1 . RequestBuffering != l2 . RequestBuffering {
return false
}
2017-11-13 22:57:41 +00:00
if l1 . ProxyRedirectFrom != l2 . ProxyRedirectFrom {
return false
}
if l1 . ProxyRedirectTo != l2 . ProxyRedirectTo {
return false
}
2018-01-29 14:43:55 +00:00
if l1 . ProxyBuffering != l2 . ProxyBuffering {
return false
}
2019-07-08 18:32:00 +00:00
if l1 . ProxyHTTPVersion != l2 . ProxyHTTPVersion {
return false
}
2017-09-01 15:43:11 +00:00
2019-08-12 17:27:05 +00:00
if l1 . ProxyMaxTempFileSize != l2 . ProxyMaxTempFileSize {
return false
}
2017-06-14 21:33:12 +00:00
return true
}
2016-12-29 20:02:06 +00:00
type proxy struct {
2023-07-22 03:32:07 +00:00
r resolver . Resolver
annotationConfig parser . Annotation
2016-12-29 20:02:06 +00:00
}
// NewParser creates a new reverse proxy configuration annotation parser
2017-11-08 20:58:57 +00:00
func NewParser ( r resolver . Resolver ) parser . IngressAnnotation {
2023-08-31 07:36:48 +00:00
return proxy {
r : r ,
2023-07-22 03:32:07 +00:00
annotationConfig : proxyAnnotations ,
}
2016-12-29 20:02:06 +00:00
}
2016-11-10 22:56:29 +00:00
// ParseAnnotations parses the annotations contained in the ingress
// rule used to configure upstream check parameters
2019-06-09 22:49:59 +00:00
func ( a proxy ) Parse ( ing * networking . Ingress ) ( interface { } , error ) {
2017-11-08 20:58:57 +00:00
defBackend := a . r . GetDefaultBackend ( )
2018-11-30 22:56:11 +00:00
config := & Config { }
var err error
2023-07-22 03:32:07 +00:00
config . ConnectTimeout , err = parser . GetIntAnnotation ( proxyConnectTimeoutAnnotation , ing , a . annotationConfig . Annotations )
2016-11-10 22:56:29 +00:00
if err != nil {
2018-11-30 22:56:11 +00:00
config . ConnectTimeout = defBackend . ProxyConnectTimeout
2016-11-10 22:56:29 +00:00
}
2023-07-22 03:32:07 +00:00
config . SendTimeout , err = parser . GetIntAnnotation ( proxySendTimeoutAnnotation , ing , a . annotationConfig . Annotations )
2016-11-10 22:56:29 +00:00
if err != nil {
2018-11-30 22:56:11 +00:00
config . SendTimeout = defBackend . ProxySendTimeout
2016-11-10 22:56:29 +00:00
}
2023-07-22 03:32:07 +00:00
config . ReadTimeout , err = parser . GetIntAnnotation ( proxyReadTimeoutAnnotation , ing , a . annotationConfig . Annotations )
2016-11-10 22:56:29 +00:00
if err != nil {
2018-11-30 22:56:11 +00:00
config . ReadTimeout = defBackend . ProxyReadTimeout
2016-11-10 22:56:29 +00:00
}
2023-07-22 03:32:07 +00:00
config . BuffersNumber , err = parser . GetIntAnnotation ( proxyBuffersNumberAnnotation , ing , a . annotationConfig . Annotations )
2019-02-20 10:05:09 +00:00
if err != nil {
2019-02-22 02:21:17 +00:00
config . BuffersNumber = defBackend . ProxyBuffersNumber
2019-02-20 10:05:09 +00:00
}
2023-07-22 03:32:07 +00:00
config . BufferSize , err = parser . GetStringAnnotation ( proxyBufferSizeAnnotation , ing , a . annotationConfig . Annotations )
2018-11-30 22:56:11 +00:00
if err != nil {
config . BufferSize = defBackend . ProxyBufferSize
2017-01-20 21:53:32 +00:00
}
2024-12-05 18:10:00 +00:00
config . BusyBuffersSize , err = parser . GetStringAnnotation ( proxyBusyBuffersSizeAnnotation , ing , a . annotationConfig . Annotations )
if err != nil {
config . BusyBuffersSize = defBackend . ProxyBusyBuffersSize
}
2023-07-22 03:32:07 +00:00
config . CookiePath , err = parser . GetStringAnnotation ( proxyCookiePathAnnotation , ing , a . annotationConfig . Annotations )
2018-11-30 22:56:11 +00:00
if err != nil {
config . CookiePath = defBackend . ProxyCookiePath
2016-12-27 09:52:04 +00:00
}
2023-07-22 03:32:07 +00:00
config . CookieDomain , err = parser . GetStringAnnotation ( proxyCookieDomainAnnotation , ing , a . annotationConfig . Annotations )
2018-11-30 22:56:11 +00:00
if err != nil {
config . CookieDomain = defBackend . ProxyCookieDomain
2016-12-27 09:52:04 +00:00
}
2023-07-22 03:32:07 +00:00
config . BodySize , err = parser . GetStringAnnotation ( proxyBodySizeAnnotation , ing , a . annotationConfig . Annotations )
2018-11-30 22:56:11 +00:00
if err != nil {
config . BodySize = defBackend . ProxyBodySize
2016-11-10 22:56:29 +00:00
}
2023-07-22 03:32:07 +00:00
config . NextUpstream , err = parser . GetStringAnnotation ( proxyNextUpstreamAnnotation , ing , a . annotationConfig . Annotations )
2018-11-30 22:56:11 +00:00
if err != nil {
config . NextUpstream = defBackend . ProxyNextUpstream
2017-06-26 19:39:24 +00:00
}
2023-07-22 03:32:07 +00:00
config . NextUpstreamTimeout , err = parser . GetIntAnnotation ( proxyNextUpstreamTimeoutAnnotation , ing , a . annotationConfig . Annotations )
2019-04-15 15:08:57 +00:00
if err != nil {
config . NextUpstreamTimeout = defBackend . ProxyNextUpstreamTimeout
}
2023-07-22 03:32:07 +00:00
config . NextUpstreamTries , err = parser . GetIntAnnotation ( proxyNextUpstreamTriesAnnotation , ing , a . annotationConfig . Annotations )
2018-03-22 11:12:36 +00:00
if err != nil {
2018-11-30 22:56:11 +00:00
config . NextUpstreamTries = defBackend . ProxyNextUpstreamTries
2018-03-22 11:12:36 +00:00
}
2023-07-22 03:32:07 +00:00
config . RequestBuffering , err = parser . GetStringAnnotation ( proxyRequestBufferingAnnotation , ing , a . annotationConfig . Annotations )
2018-11-30 22:56:11 +00:00
if err != nil {
config . RequestBuffering = defBackend . ProxyRequestBuffering
2017-09-01 15:43:11 +00:00
}
2023-07-22 03:32:07 +00:00
config . ProxyRedirectFrom , err = parser . GetStringAnnotation ( proxyRedirectFromAnnotation , ing , a . annotationConfig . Annotations )
2018-11-30 22:56:11 +00:00
if err != nil {
config . ProxyRedirectFrom = defBackend . ProxyRedirectFrom
2017-11-13 22:57:41 +00:00
}
2023-07-22 03:32:07 +00:00
config . ProxyRedirectTo , err = parser . GetStringAnnotation ( proxyRedirectToAnnotation , ing , a . annotationConfig . Annotations )
2018-11-30 22:56:11 +00:00
if err != nil {
config . ProxyRedirectTo = defBackend . ProxyRedirectTo
2017-11-13 22:57:41 +00:00
}
2023-07-22 03:32:07 +00:00
config . ProxyBuffering , err = parser . GetStringAnnotation ( proxyBufferingAnnotation , ing , a . annotationConfig . Annotations )
2018-11-30 22:56:11 +00:00
if err != nil {
config . ProxyBuffering = defBackend . ProxyBuffering
2018-01-29 14:43:55 +00:00
}
2023-07-22 03:32:07 +00:00
config . ProxyHTTPVersion , err = parser . GetStringAnnotation ( proxyHTTPVersionAnnotation , ing , a . annotationConfig . Annotations )
2019-07-08 18:32:00 +00:00
if err != nil {
config . ProxyHTTPVersion = defBackend . ProxyHTTPVersion
}
2023-07-22 03:32:07 +00:00
config . ProxyMaxTempFileSize , err = parser . GetStringAnnotation ( proxyMaxTempFileSizeAnnotation , ing , a . annotationConfig . Annotations )
2019-08-12 17:27:05 +00:00
if err != nil {
config . ProxyMaxTempFileSize = defBackend . ProxyMaxTempFileSize
}
2018-11-30 22:56:11 +00:00
return config , nil
2016-11-10 22:56:29 +00:00
}
2023-07-22 03:32:07 +00:00
func ( a proxy ) GetDocumentation ( ) parser . AnnotationFields {
return a . annotationConfig . Annotations
}
func ( a proxy ) Validate ( anns map [ string ] string ) error {
maxrisk := parser . StringRiskToRisk ( a . r . GetSecurityConfiguration ( ) . AnnotationsRiskLevel )
return parser . CheckAnnotationRisk ( anns , maxrisk , proxyAnnotations . Annotations )
}