-
Notifications
You must be signed in to change notification settings - Fork 28
/
Copy pathvirtual_service_processor.go
142 lines (117 loc) · 4.8 KB
/
virtual_service_processor.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package istio
import (
"fmt"
gatewayv1beta1 "github.com/kyma-project/api-gateway/apis/gateway/v1beta1"
"github.com/kyma-project/api-gateway/internal/builders"
"github.com/kyma-project/api-gateway/internal/helpers"
"github.com/kyma-project/api-gateway/internal/processing"
"github.com/kyma-project/api-gateway/internal/processing/default_domain"
"github.com/kyma-project/api-gateway/internal/processing/processors"
networkingv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
)
// Newv1beta1VirtualServiceProcessor returns a VirtualServiceProcessor with the desired state handling specific for the Istio handler.
func Newv1beta1VirtualServiceProcessor(config processing.ReconciliationConfig, api *gatewayv1beta1.APIRule) processors.VirtualServiceProcessor {
return processors.VirtualServiceProcessor{
ApiRule: api,
Creator: virtualServiceCreator{
oathkeeperSvc: config.OathkeeperSvc,
oathkeeperSvcPort: config.OathkeeperSvcPort,
corsConfig: config.CorsConfig,
defaultDomainName: config.DefaultDomainName,
},
}
}
type virtualServiceCreator struct {
oathkeeperSvc string
oathkeeperSvcPort uint32
corsConfig *processing.CorsConfig
defaultDomainName string
}
// Create returns the Virtual Service using the configuration of the APIRule.
func (r virtualServiceCreator) Create(api *gatewayv1beta1.APIRule) (*networkingv1beta1.VirtualService, error) {
virtualServiceNamePrefix := fmt.Sprintf("%s-", api.ObjectMeta.Name)
vsSpecBuilder := builders.VirtualServiceSpec()
vsSpecBuilder.AddHost(default_domain.GetHostWithDomain(*api.Spec.Host, r.defaultDomainName))
vsSpecBuilder.Gateway(*api.Spec.Gateway)
filteredRules := processing.FilterDuplicatePaths(api.Spec.Rules)
for _, rule := range filteredRules {
httpRouteBuilder := builders.HTTPRoute()
serviceNamespace := helpers.FindServiceNamespace(api, &rule)
routeDirectlyToService := false
if !processing.IsSecuredByOathkeeper(rule) {
routeDirectlyToService = true
} else if processing.IsJwtSecured(rule) {
routeDirectlyToService = true
}
var host string
var port uint32
if routeDirectlyToService {
// Use rule level service if it exists
if rule.Service != nil {
host = default_domain.GetHostLocalDomain(*rule.Service.Name, serviceNamespace)
port = *rule.Service.Port
} else {
// Otherwise use service defined on APIRule spec level
host = default_domain.GetHostLocalDomain(*api.Spec.Service.Name, serviceNamespace)
port = *api.Spec.Service.Port
}
} else {
host = r.oathkeeperSvc
port = r.oathkeeperSvcPort
}
httpRouteBuilder.Route(builders.RouteDestination().Host(host).Port(port))
matchBuilder := builders.MatchRequest()
if restrictsExposedMethods(rule) {
matchBuilder.MethodRegEx(rule.Methods...)
}
if rule.Path == "/*" {
matchBuilder.Uri().Prefix("/")
} else {
matchBuilder.Uri().Regex(rule.Path)
}
httpRouteBuilder.Match(matchBuilder)
if api.Spec.CorsPolicy == nil {
httpRouteBuilder.CorsPolicy(builders.CorsPolicy().
AllowOrigins(r.corsConfig.AllowOrigins...).
AllowMethods(r.corsConfig.AllowMethods...).
AllowHeaders(r.corsConfig.AllowHeaders...))
}
httpRouteBuilder.Timeout(processors.GetVirtualServiceHttpTimeout(api.Spec, rule))
headersBuilder := builders.NewHttpRouteHeadersBuilder().
SetHostHeader(default_domain.GetHostWithDomain(*api.Spec.Host, r.defaultDomainName))
if api.Spec.CorsPolicy != nil {
httpRouteBuilder.CorsPolicy(builders.CorsPolicy().FromApiRuleCorsPolicy(*api.Spec.CorsPolicy))
headersBuilder.RemoveUpstreamCORSPolicyHeaders()
}
// We need to add mutators only for JWT secured rules, since "noop" and "oauth2_introspection" access strategies
// create access rules and therefore use ory mutators. The "allow" access strategy does not support mutators at all.
if processing.IsJwtSecured(rule) {
cookieMutator, err := rule.GetCookieMutator()
if err != nil {
return nil, err
}
if cookieMutator.HasCookies() {
headersBuilder.SetRequestCookies(cookieMutator.Cookies)
}
headerMutator, err := rule.GetHeaderMutator()
if err != nil {
return nil, err
}
if headerMutator.HasHeaders() {
headersBuilder.SetRequestHeaders(headerMutator.Headers)
}
}
httpRouteBuilder.Headers(headersBuilder.Get())
vsSpecBuilder.HTTP(httpRouteBuilder)
}
vsBuilder := builders.VirtualService().
GenerateName(virtualServiceNamePrefix).
Namespace(api.ObjectMeta.Namespace).
Label(processing.OwnerLabel, fmt.Sprintf("%s.%s", api.ObjectMeta.Name, api.ObjectMeta.Namespace))
vsBuilder.Spec(vsSpecBuilder)
return vsBuilder.Get(), nil
}
// restrictsExposedMethods checks if the rule has only access strategies defined that restrict access to specific HTTP methods.
func restrictsExposedMethods(rule gatewayv1beta1.Rule) bool {
return !rule.ContainsAccessStrategy(gatewayv1beta1.AccessStrategyAllow)
}