sigs.k8s.io/gateway-api@v1.0.0/geps/gep-726.md (about) 1 # GEP-726: Add Path Redirects and Rewrites 2 3 * Issue: [#726](https://github.com/kubernetes-sigs/gateway-api/issues/726) 4 * Status: Standard 5 6 ## TLDR 7 8 This GEP proposes adding support for path redirects and rewrites in addition to 9 host rewrites. This would augment the existing host redirection capabilities. 10 11 ## Goals 12 13 * Implement path redirects. 14 * Implement the most portable and simple forms of path rewrites. 15 * Describe how more advanced rewrite and redirect and redirect capabilities 16 could be added in the future. 17 18 ## API 19 20 Although many implementations support very advanced rewrite and redirect 21 capabilities, the following are the most [portable](#portability) concepts that 22 are not already supported by the Gateway API: 23 24 * Path redirects 25 * Path prefix redirects 26 * Path prefix rewrites 27 * Host rewrites 28 29 Although regular expression based redirects and rewrites are commonly supported, 30 there is significantly more variation in both if and how they are implemented. 31 Given the wide support for this concept, it is important to design the API in a 32 way that would make it easy to add this capability in the future. 33 34 ### Path Modifiers 35 36 Both redirects and rewrites would share the same `PathModifier` types: 37 38 ```go 39 // HTTPPathModifierType defines the type of path redirect. 40 type HTTPPathModifierType string 41 42 const ( 43 // This type of modifier indicates that the complete path will be replaced by 44 // the path redirect value. 45 AbsoluteHTTPPathModifier HTTPPathModifierType = "Absolute" 46 47 // This type of modifier indicates that any prefix path matches will be 48 // replaced by the substitution value. For example, a path with a prefix match 49 // of "/foo" and a ReplacePrefixMatch substitution of "/bar" will have the 50 // "/foo" prefix replaced with "/bar" in matching requests. 51 PrefixMatchHTTPPathModifier HTTPPathModifierType = "ReplacePrefixMatch" 52 ) 53 54 // HTTPPathModifier defines configuration for path modifiers. 55 type HTTPPathModifier struct { 56 // Type defines the type of path modifier. 57 // 58 // +kubebuilder:validation:Enum=Absolute;ReplacePrefixMatch 59 Type HTTPPathModifierType `json:"type"` 60 61 // Substitution defines the HTTP path value to substitute. An empty value ("") 62 // indicates that the portion of the path to be changed should be removed from 63 // the resulting path. For example, a request to "/foo/bar" with a prefix 64 // match of "/foo" would be modified to "/bar". 65 // 66 // +kubebuilder:validation:MaxLength=1024 67 Substitution string `json:"substitution"` 68 } 69 ``` 70 71 ### Redirects 72 73 The existing `RequestRedirect` filter can be expanded to support path redirects. 74 In the following example, a request to `/foo/abc` would be redirected to 75 `/bar/abc`. 76 77 ```yaml 78 kind: HTTPRoute 79 apiVersion: gateway.networking.k8s.io/v1alpha2 80 metadata: 81 name: http-filter-1 82 spec: 83 rules: 84 - matches: 85 - path: 86 type: Prefix 87 value: /foo 88 filters: 89 - type: RequestRedirect 90 requestRedirect: 91 hostname: foo.com 92 path: 93 type: ReplacePrefixMatch 94 value: /bar 95 ``` 96 97 This would be represented with the following API addition to the existing 98 HTTPRequestRedirect filter: 99 ```go 100 // HTTPRequestRedirect defines a filter that redirects a request. At most one of 101 // these filters may be used on a Route rule. This may not be used on the same 102 // Route rule as a HTTPRequestRewrite filter. 103 // 104 // Support: Extended 105 type HTTPRequestRedirect struct { 106 // Path defines a path redirect. 107 // 108 // Support: Extended 109 // 110 // +optional 111 Path *HTTPPathModifier `json:"path,omitempty"` 112 // ... 113 } 114 ``` 115 116 ### Rewrites 117 118 A new `URLRewrite` filter can be added to support rewrites. In the following 119 example, a request to `example.com/foo/abc` would be rewritten to 120 `example.net/bar/abc`. 121 122 ```yaml 123 kind: HTTPRoute 124 apiVersion: gateway.networking.k8s.io/v1alpha2 125 metadata: 126 name: http-filter-1 127 spec: 128 hostnames: 129 - example.com 130 rules: 131 - matches: 132 - path: 133 type: Prefix 134 value: /foo 135 filters: 136 - type: URLRewrite 137 requestRewrite: 138 hostname: example.net 139 path: 140 type: ReplacePrefixMatch 141 substitution: /bar 142 ``` 143 144 This would be represent with the following API additions: 145 ```go 146 // HTTPURLRewrite defines a filter that modifies a request during forwarding. 147 // At most one of these filters may be used on a Route rule. This may not be 148 // used on the same Route rule as a HTTPRequestRedirect filter. 149 // 150 // Support: Extended 151 type HTTPURLRewrite struct { 152 // Hostname is the value to be used to replace the Host header value during 153 // forwarding. 154 // 155 // Support: Extended 156 // 157 // +optional 158 // +kubebuilder:validation:MaxLength=255 159 Hostname *string `json:"hostname,omitempty"` 160 161 // Path defines a path rewrite. 162 // 163 // Support: Extended 164 // 165 // +optional 166 Path *HTTPPathModifier `json:"path,omitempty"` 167 } 168 ``` 169 170 Note: `RequestRewrite` was originally considered as a name for this filter. 171 `URLRewrite` was chosen as it more clearly represented the capabilities of the 172 filter and would not be confused with header or query param modification. 173 174 ## Portability 175 176 When considering what should be possible in the API, it's worth evaluating what 177 common tooling is capable of. This is by no means a complete list, but this 178 provides a high level overview of how this is configured across different 179 implementations. 180 181 Although not all of these implementations directly support prefix rewrites or 182 redirects, the ones that don't include regular expression support which can be 183 used to implement prefix rewrites and redirects. 184 185 Note: This section intentionally excludes the redirect capabilities already 186 contained in the API. 187 188 ### Envoy 189 Envoy supports the following relevant capabilities 190 ([reference](https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto)): 191 192 * path_redirect (redirect only) 193 * prefix_rewrite (redirect and forwarding) 194 * regex_rewrite (redirect and forwarding) 195 * host_rewrite_literal (forwarding only) 196 * strip_query (redirect only) 197 198 Note that path rewrite relies on the prefix match for the route, there is not 199 a way to differentiate between the prefix used for matching and rewriting. 200 201 ### Google Cloud 202 Google Cloud URL Maps support the following relevant capabilities 203 ([reference](https://cloud.google.com/compute/docs/reference/rest/v1/urlMaps)): 204 205 * pathPrefixRewrite (forwarding only) 206 * hostRewrite (forwarding only) 207 * pathRedirect (redirect only) 208 * prefixRedirect (redirect only) 209 * stripQuery (redirect only) 210 211 Note that path rewrite relies on the prefix match for the route, there is not 212 a way to differentiate between the prefix used for matching and rewriting. 213 214 ### HAProxy 215 HAProxy supports the following relevant capabilities 216 ([reference](https://cbonte.github.io/haproxy-dconv/2.5/configuration.html)): 217 218 * http-request set-path (advanced path rewrite capabilities) 219 * http-request replace-path (rewrites entire path) 220 * http-request replace-pathq (rewrites entire path + query string) 221 * http-request replace-uri (URI rewrite based on input regex) 222 * redirect location (advanced redirect capabilities) 223 224 ### NGINX 225 The NGINX rewrite module contains the following relevant capabilities 226 ([reference](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html)): 227 228 * PCRE regex based rewrites 229 * Rewrite directive can be used during forwarding or redirects 230 * Rewrite directive can affect host, path, or both 231 * Rewrite directive can be chained 232 233 ## Future Extension 234 There are two relatively common types of path rewrite/redirect that are not 235 covered by this proposal: 236 237 1. Replace a path prefix separate from the match 238 2. Replace with a Regular Expression substitution 239 240 Both of the following can be represented by adding a new field new types. For 241 example, this config would result in a request to `/foo/baz` to be rewritten to 242 `/bar/baz`: 243 244 ```yaml 245 filters: 246 - type: RequestRewrite 247 requestRewrite: 248 path: 249 type: ReplacePrefix 250 pattern: /foo 251 substitution: /bar 252 ``` 253 254 Similarly, this config would result in a request to `/foo/bar/baz` being 255 rewritten to `/foo/other/baz`. 256 ```yaml 257 filters: 258 - type: RequestRewrite 259 requestRewrite: 260 path: 261 type: RegularExpression 262 pattern: /foo/(.*)/baz 263 substitution: other 264 ``` 265 266 Although both of the above are natural extensions of the API, they are not quite 267 as broadly supported. For that reason, this GEP proposes omitting these types 268 from the initial implementation. 269 270 ## Alternatives 271 272 ### 1. Generic Path Match Replacement 273 Instead of the `ReplacePrefixMatch` option proposed above, we could have a 274 `ReplacePathMatch` option. This would provide significantly more flexibility and 275 room for growth than prefix replacement. 276 277 Unfortunately it would be difficult to represent conformance and support levels. 278 It also would have limited value. Replacing "Exact" match types would be nearly 279 identical to the "Absolute" match type, and replacing "RegularExpression" match 280 types would likely not yield the desired result. In most cases, RegEx rewrites 281 are implemented separately from RegEx path matching. So a user may want to match 282 all paths matching one RegEx, but use a separate RegEx + substitution value for 283 rewrites. 284 285 It is theoretically possible that future patch match types could be useful as a 286 rewrite source, but the common proxies described above seem to be limited to the 287 rewrite types described above. 288 289 ### 2. Top Level Rewrite Fields 290 Although a small difference, we could restructure how the path rewrites and 291 redirects were configured. One example would be adding top level fields in the 292 filters for each kind of path rewrite or redirect. That would result in a change 293 like this: 294 295 **Before:** 296 ```yaml 297 requestRewrite: 298 hostname: foo.com 299 path: 300 type: Prefix 301 substitution: /bar 302 ``` 303 304 **After:** 305 ```yaml 306 requestRewrite: 307 hostname: foo.com 308 pathPrefix: /bar 309 ``` 310 311 Although simpler for the initial use cases, it may become more difficult to 312 maintain and validate as additional types of rewrites and redirects were added. 313 314 315 ## References 316 317 Issues: 318 319 - [#200: Add support for configurable HTTP redirects](https://github.com/kubernetes-sigs/gateway-api/issues/200) 320 - [#678: Add support for HTTP rewrites](https://github.com/kubernetes-sigs/gateway-api/issues/678)