github.com/nginxinc/kubernetes-ingress@v1.12.5/internal/configs/ingress.go (about) 1 package configs 2 3 import ( 4 "fmt" 5 "sort" 6 "strings" 7 8 "github.com/golang/glog" 9 "github.com/nginxinc/kubernetes-ingress/internal/k8s/secrets" 10 api_v1 "k8s.io/api/core/v1" 11 networking "k8s.io/api/networking/v1beta1" 12 "k8s.io/apimachinery/pkg/runtime" 13 14 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 15 16 "github.com/nginxinc/kubernetes-ingress/internal/configs/version1" 17 ) 18 19 const emptyHost = "" 20 21 // AppProtectResources holds namespace names of App Protect resources relavant to an Ingress 22 type AppProtectResources struct { 23 AppProtectPolicy string 24 AppProtectLogconfs []string 25 } 26 27 // AppProtectLog holds a single pair of log config and log destination 28 type AppProtectLog struct { 29 LogConf *unstructured.Unstructured 30 Dest string 31 } 32 33 // IngressEx holds an Ingress along with the resources that are referenced in this Ingress. 34 type IngressEx struct { 35 Ingress *networking.Ingress 36 Endpoints map[string][]string 37 HealthChecks map[string]*api_v1.Probe 38 ExternalNameSvcs map[string]bool 39 PodsByIP map[string]PodInfo 40 ValidHosts map[string]bool 41 ValidMinionPaths map[string]bool 42 AppProtectPolicy *unstructured.Unstructured 43 AppProtectLogs []AppProtectLog 44 SecretRefs map[string]*secrets.SecretReference 45 } 46 47 // JWTKey represents a secret that holds JSON Web Key. 48 type JWTKey struct { 49 Name string 50 Secret *api_v1.Secret 51 } 52 53 func (ingEx *IngressEx) String() string { 54 if ingEx.Ingress == nil { 55 return "IngressEx has no Ingress" 56 } 57 58 return fmt.Sprintf("%v/%v", ingEx.Ingress.Namespace, ingEx.Ingress.Name) 59 } 60 61 // MergeableIngresses is a mergeable ingress of a master and minions. 62 type MergeableIngresses struct { 63 Master *IngressEx 64 Minions []*IngressEx 65 } 66 67 func generateNginxCfg(ingEx *IngressEx, apResources AppProtectResources, isMinion bool, baseCfgParams *ConfigParams, isPlus bool, 68 isResolverConfigured bool, staticParams *StaticConfigParams, isWildcardEnabled bool) (version1.IngressNginxConfig, Warnings) { 69 hasAppProtect := staticParams.MainAppProtectLoadModule 70 cfgParams := parseAnnotations(ingEx, baseCfgParams, isPlus, hasAppProtect, staticParams.EnableInternalRoutes) 71 72 wsServices := getWebsocketServices(ingEx) 73 spServices := getSessionPersistenceServices(ingEx) 74 rewrites := getRewrites(ingEx) 75 sslServices := getSSLServices(ingEx) 76 grpcServices := getGrpcServices(ingEx) 77 78 upstreams := make(map[string]version1.Upstream) 79 healthChecks := make(map[string]version1.HealthCheck) 80 81 // HTTP2 is required for gRPC to function 82 if len(grpcServices) > 0 && !cfgParams.HTTP2 { 83 glog.Errorf("Ingress %s/%s: annotation nginx.org/grpc-services requires HTTP2, ignoring", ingEx.Ingress.Namespace, ingEx.Ingress.Name) 84 grpcServices = make(map[string]bool) 85 } 86 87 if ingEx.Ingress.Spec.Backend != nil { 88 name := getNameForUpstream(ingEx.Ingress, emptyHost, ingEx.Ingress.Spec.Backend) 89 upstream := createUpstream(ingEx, name, ingEx.Ingress.Spec.Backend, spServices[ingEx.Ingress.Spec.Backend.ServiceName], &cfgParams, 90 isPlus, isResolverConfigured, staticParams.EnableLatencyMetrics) 91 upstreams[name] = upstream 92 93 if cfgParams.HealthCheckEnabled { 94 if hc, exists := ingEx.HealthChecks[ingEx.Ingress.Spec.Backend.ServiceName+ingEx.Ingress.Spec.Backend.ServicePort.String()]; exists { 95 healthChecks[name] = createHealthCheck(hc, name, &cfgParams) 96 } 97 } 98 } 99 100 allWarnings := newWarnings() 101 102 var servers []version1.Server 103 104 for _, rule := range ingEx.Ingress.Spec.Rules { 105 // skipping invalid hosts 106 if !ingEx.ValidHosts[rule.Host] { 107 continue 108 } 109 110 httpIngressRuleValue := rule.HTTP 111 112 if httpIngressRuleValue == nil { 113 // the code in this loop expects non-nil 114 httpIngressRuleValue = &networking.HTTPIngressRuleValue{} 115 } 116 117 serverName := rule.Host 118 119 statusZone := rule.Host 120 121 server := version1.Server{ 122 Name: serverName, 123 ServerTokens: cfgParams.ServerTokens, 124 HTTP2: cfgParams.HTTP2, 125 RedirectToHTTPS: cfgParams.RedirectToHTTPS, 126 SSLRedirect: cfgParams.SSLRedirect, 127 ProxyProtocol: cfgParams.ProxyProtocol, 128 HSTS: cfgParams.HSTS, 129 HSTSMaxAge: cfgParams.HSTSMaxAge, 130 HSTSIncludeSubdomains: cfgParams.HSTSIncludeSubdomains, 131 HSTSBehindProxy: cfgParams.HSTSBehindProxy, 132 StatusZone: statusZone, 133 RealIPHeader: cfgParams.RealIPHeader, 134 SetRealIPFrom: cfgParams.SetRealIPFrom, 135 RealIPRecursive: cfgParams.RealIPRecursive, 136 ProxyHideHeaders: cfgParams.ProxyHideHeaders, 137 ProxyPassHeaders: cfgParams.ProxyPassHeaders, 138 ServerSnippets: cfgParams.ServerSnippets, 139 Ports: cfgParams.Ports, 140 SSLPorts: cfgParams.SSLPorts, 141 TLSPassthrough: staticParams.TLSPassthrough, 142 AppProtectEnable: cfgParams.AppProtectEnable, 143 AppProtectLogEnable: cfgParams.AppProtectLogEnable, 144 SpiffeCerts: cfgParams.SpiffeServerCerts, 145 } 146 147 warnings := addSSLConfig(&server, ingEx.Ingress, rule.Host, ingEx.Ingress.Spec.TLS, ingEx.SecretRefs, isWildcardEnabled) 148 allWarnings.Add(warnings) 149 150 if hasAppProtect { 151 server.AppProtectPolicy = apResources.AppProtectPolicy 152 server.AppProtectLogConfs = apResources.AppProtectLogconfs 153 } 154 155 if !isMinion && cfgParams.JWTKey != "" { 156 jwtAuth, redirectLoc, warnings := generateJWTConfig(ingEx.Ingress, ingEx.SecretRefs, &cfgParams, getNameForRedirectLocation(ingEx.Ingress)) 157 server.JWTAuth = jwtAuth 158 if redirectLoc != nil { 159 server.JWTRedirectLocations = append(server.JWTRedirectLocations, *redirectLoc) 160 } 161 allWarnings.Add(warnings) 162 } 163 164 var locations []version1.Location 165 healthChecks := make(map[string]version1.HealthCheck) 166 167 rootLocation := false 168 169 grpcOnly := true 170 if len(grpcServices) > 0 { 171 for _, path := range httpIngressRuleValue.Paths { 172 if _, exists := grpcServices[path.Backend.ServiceName]; !exists { 173 grpcOnly = false 174 break 175 } 176 } 177 } else { 178 grpcOnly = false 179 } 180 181 for _, path := range httpIngressRuleValue.Paths { 182 // skip invalid paths for minions 183 if isMinion && !ingEx.ValidMinionPaths[path.Path] { 184 continue 185 } 186 187 upsName := getNameForUpstream(ingEx.Ingress, rule.Host, &path.Backend) 188 189 if cfgParams.HealthCheckEnabled { 190 if hc, exists := ingEx.HealthChecks[path.Backend.ServiceName+path.Backend.ServicePort.String()]; exists { 191 healthChecks[upsName] = createHealthCheck(hc, upsName, &cfgParams) 192 } 193 } 194 195 if _, exists := upstreams[upsName]; !exists { 196 upstream := createUpstream(ingEx, upsName, &path.Backend, spServices[path.Backend.ServiceName], &cfgParams, isPlus, isResolverConfigured, staticParams.EnableLatencyMetrics) 197 upstreams[upsName] = upstream 198 } 199 200 ssl := isSSLEnabled(sslServices[path.Backend.ServiceName], cfgParams, staticParams) 201 proxySSLName := generateProxySSLName(path.Backend.ServiceName, ingEx.Ingress.Namespace) 202 loc := createLocation(pathOrDefault(path.Path), upstreams[upsName], &cfgParams, wsServices[path.Backend.ServiceName], rewrites[path.Backend.ServiceName], 203 ssl, grpcServices[path.Backend.ServiceName], proxySSLName, path.PathType, path.Backend.ServiceName) 204 205 if isMinion && cfgParams.JWTKey != "" { 206 jwtAuth, redirectLoc, warnings := generateJWTConfig(ingEx.Ingress, ingEx.SecretRefs, &cfgParams, getNameForRedirectLocation(ingEx.Ingress)) 207 loc.JWTAuth = jwtAuth 208 if redirectLoc != nil { 209 server.JWTRedirectLocations = append(server.JWTRedirectLocations, *redirectLoc) 210 } 211 allWarnings.Add(warnings) 212 } 213 214 locations = append(locations, loc) 215 216 if loc.Path == "/" { 217 rootLocation = true 218 } 219 } 220 221 if !rootLocation && ingEx.Ingress.Spec.Backend != nil { 222 upsName := getNameForUpstream(ingEx.Ingress, emptyHost, ingEx.Ingress.Spec.Backend) 223 ssl := isSSLEnabled(sslServices[ingEx.Ingress.Spec.Backend.ServiceName], cfgParams, staticParams) 224 proxySSLName := generateProxySSLName(ingEx.Ingress.Spec.Backend.ServiceName, ingEx.Ingress.Namespace) 225 pathtype := networking.PathTypePrefix 226 227 loc := createLocation(pathOrDefault("/"), upstreams[upsName], &cfgParams, wsServices[ingEx.Ingress.Spec.Backend.ServiceName], rewrites[ingEx.Ingress.Spec.Backend.ServiceName], 228 ssl, grpcServices[ingEx.Ingress.Spec.Backend.ServiceName], proxySSLName, &pathtype, ingEx.Ingress.Spec.Backend.ServiceName) 229 locations = append(locations, loc) 230 231 if cfgParams.HealthCheckEnabled { 232 if hc, exists := ingEx.HealthChecks[ingEx.Ingress.Spec.Backend.ServiceName+ingEx.Ingress.Spec.Backend.ServicePort.String()]; exists { 233 healthChecks[upsName] = createHealthCheck(hc, upsName, &cfgParams) 234 } 235 } 236 237 if _, exists := grpcServices[ingEx.Ingress.Spec.Backend.ServiceName]; !exists { 238 grpcOnly = false 239 } 240 } 241 242 server.Locations = locations 243 server.HealthChecks = healthChecks 244 server.GRPCOnly = grpcOnly 245 246 servers = append(servers, server) 247 } 248 249 var keepalive string 250 if cfgParams.Keepalive > 0 { 251 keepalive = fmt.Sprint(cfgParams.Keepalive) 252 } 253 254 return version1.IngressNginxConfig{ 255 Upstreams: upstreamMapToSlice(upstreams), 256 Servers: servers, 257 Keepalive: keepalive, 258 Ingress: version1.Ingress{ 259 Name: ingEx.Ingress.Name, 260 Namespace: ingEx.Ingress.Namespace, 261 Annotations: ingEx.Ingress.Annotations, 262 }, 263 SpiffeClientCerts: staticParams.NginxServiceMesh && !cfgParams.SpiffeServerCerts, 264 }, allWarnings 265 } 266 267 func generateJWTConfig(owner runtime.Object, secretRefs map[string]*secrets.SecretReference, cfgParams *ConfigParams, 268 redirectLocationName string) (*version1.JWTAuth, *version1.JWTRedirectLocation, Warnings) { 269 warnings := newWarnings() 270 271 secretRef := secretRefs[cfgParams.JWTKey] 272 var secretType api_v1.SecretType 273 if secretRef.Secret != nil { 274 secretType = secretRef.Secret.Type 275 } 276 if secretType != "" && secretType != secrets.SecretTypeJWK { 277 warnings.AddWarningf(owner, "JWK secret %s is of a wrong type '%s', must be '%s'", cfgParams.JWTKey, secretType, secrets.SecretTypeJWK) 278 } else if secretRef.Error != nil { 279 warnings.AddWarningf(owner, "JWK secret %s is invalid: %v", cfgParams.JWTKey, secretRef.Error) 280 } 281 282 // Key is configured for all cases, including when the secret is (1) invalid or (2) of a wrong type. 283 // For (1) and (2), NGINX Plus will reject such a key at runtime and return 500 to clients. 284 jwtAuth := &version1.JWTAuth{ 285 Key: secretRef.Path, 286 Realm: cfgParams.JWTRealm, 287 Token: cfgParams.JWTToken, 288 } 289 290 var redirectLocation *version1.JWTRedirectLocation 291 292 if cfgParams.JWTLoginURL != "" { 293 jwtAuth.RedirectLocationName = redirectLocationName 294 redirectLocation = &version1.JWTRedirectLocation{ 295 Name: redirectLocationName, 296 LoginURL: cfgParams.JWTLoginURL, 297 } 298 } 299 300 return jwtAuth, redirectLocation, warnings 301 } 302 303 func addSSLConfig(server *version1.Server, owner runtime.Object, host string, ingressTLS []networking.IngressTLS, 304 secretRefs map[string]*secrets.SecretReference, isWildcardEnabled bool) Warnings { 305 warnings := newWarnings() 306 307 var tlsEnabled bool 308 var tlsSecret string 309 310 for _, tls := range ingressTLS { 311 for _, h := range tls.Hosts { 312 if h == host { 313 tlsEnabled = true 314 tlsSecret = tls.SecretName 315 break 316 } 317 } 318 } 319 320 if !tlsEnabled { 321 return warnings 322 } 323 324 var pemFile string 325 var rejectHandshake bool 326 327 if tlsSecret != "" { 328 secretRef := secretRefs[tlsSecret] 329 var secretType api_v1.SecretType 330 if secretRef.Secret != nil { 331 secretType = secretRef.Secret.Type 332 } 333 if secretType != "" && secretType != api_v1.SecretTypeTLS { 334 rejectHandshake = true 335 warnings.AddWarningf(owner, "TLS secret %s is of a wrong type '%s', must be '%s'", tlsSecret, secretType, api_v1.SecretTypeTLS) 336 } else if secretRef.Error != nil { 337 rejectHandshake = true 338 warnings.AddWarningf(owner, "TLS secret %s is invalid: %v", tlsSecret, secretRef.Error) 339 } else { 340 pemFile = secretRef.Path 341 } 342 } else if isWildcardEnabled { 343 pemFile = pemFileNameForWildcardTLSSecret 344 } else { 345 rejectHandshake = true 346 warnings.AddWarningf(owner, "TLS termination for host '%s' requires specifying a TLS secret or configuring a global wildcard TLS secret", host) 347 } 348 349 server.SSL = true 350 server.SSLCertificate = pemFile 351 server.SSLCertificateKey = pemFile 352 server.SSLRejectHandshake = rejectHandshake 353 354 return warnings 355 } 356 357 func generateIngressPath(path string, pathType *networking.PathType) string { 358 if pathType == nil { 359 return path 360 } 361 if *pathType == networking.PathTypeExact { 362 path = "= " + path 363 } 364 365 return path 366 } 367 368 func createLocation(path string, upstream version1.Upstream, cfg *ConfigParams, websocket bool, rewrite string, ssl bool, grpc bool, proxySSLName string, pathType *networking.PathType, serviceName string) version1.Location { 369 loc := version1.Location{ 370 Path: generateIngressPath(path, pathType), 371 Upstream: upstream, 372 ProxyConnectTimeout: cfg.ProxyConnectTimeout, 373 ProxyReadTimeout: cfg.ProxyReadTimeout, 374 ProxySendTimeout: cfg.ProxySendTimeout, 375 ClientMaxBodySize: cfg.ClientMaxBodySize, 376 Websocket: websocket, 377 Rewrite: rewrite, 378 SSL: ssl, 379 GRPC: grpc, 380 ProxyBuffering: cfg.ProxyBuffering, 381 ProxyBuffers: cfg.ProxyBuffers, 382 ProxyBufferSize: cfg.ProxyBufferSize, 383 ProxyMaxTempFileSize: cfg.ProxyMaxTempFileSize, 384 ProxySSLName: proxySSLName, 385 LocationSnippets: cfg.LocationSnippets, 386 ServiceName: serviceName, 387 } 388 389 return loc 390 } 391 392 // upstreamRequiresQueue checks if the upstream requires a queue. 393 // Mandatory Health Checks can cause nginx to return errors on reload, since all Upstreams start 394 // Unhealthy. By adding a queue to the Upstream we can avoid returning errors, at the cost of a short delay. 395 func upstreamRequiresQueue(name string, ingEx *IngressEx, cfg *ConfigParams) (n int64, timeout int64) { 396 if cfg.HealthCheckEnabled && cfg.HealthCheckMandatory && cfg.HealthCheckMandatoryQueue > 0 { 397 if hc, exists := ingEx.HealthChecks[name]; exists { 398 return cfg.HealthCheckMandatoryQueue, int64(hc.TimeoutSeconds) 399 } 400 } 401 return 0, 0 402 } 403 404 func createUpstream(ingEx *IngressEx, name string, backend *networking.IngressBackend, stickyCookie string, cfg *ConfigParams, 405 isPlus bool, isResolverConfigured bool, isLatencyMetricsEnabled bool) version1.Upstream { 406 var ups version1.Upstream 407 labels := version1.UpstreamLabels{ 408 Service: backend.ServiceName, 409 ResourceType: "ingress", 410 ResourceName: ingEx.Ingress.Name, 411 ResourceNamespace: ingEx.Ingress.Namespace, 412 } 413 if isPlus { 414 queue, timeout := upstreamRequiresQueue(backend.ServiceName+backend.ServicePort.String(), ingEx, cfg) 415 ups = version1.Upstream{Name: name, StickyCookie: stickyCookie, Queue: queue, QueueTimeout: timeout, UpstreamLabels: labels} 416 } else { 417 ups = version1.NewUpstreamWithDefaultServer(name) 418 if isLatencyMetricsEnabled { 419 ups.UpstreamLabels = labels 420 } 421 } 422 423 endps, exists := ingEx.Endpoints[backend.ServiceName+backend.ServicePort.String()] 424 if exists { 425 var upsServers []version1.UpstreamServer 426 // Always false for NGINX OSS 427 _, isExternalNameSvc := ingEx.ExternalNameSvcs[backend.ServiceName] 428 if isExternalNameSvc && !isResolverConfigured { 429 glog.Warningf("A resolver must be configured for Type ExternalName service %s, no upstream servers will be created", backend.ServiceName) 430 endps = []string{} 431 } 432 433 for _, endp := range endps { 434 addressport := strings.Split(endp, ":") 435 upsServers = append(upsServers, version1.UpstreamServer{ 436 Address: addressport[0], 437 Port: addressport[1], 438 MaxFails: cfg.MaxFails, 439 MaxConns: cfg.MaxConns, 440 FailTimeout: cfg.FailTimeout, 441 SlowStart: cfg.SlowStart, 442 Resolve: isExternalNameSvc, 443 }) 444 } 445 if len(upsServers) > 0 { 446 ups.UpstreamServers = upsServers 447 } 448 } 449 450 ups.LBMethod = cfg.LBMethod 451 ups.UpstreamZoneSize = cfg.UpstreamZoneSize 452 return ups 453 } 454 455 func createHealthCheck(hc *api_v1.Probe, upstreamName string, cfg *ConfigParams) version1.HealthCheck { 456 return version1.HealthCheck{ 457 UpstreamName: upstreamName, 458 Fails: hc.FailureThreshold, 459 Interval: hc.PeriodSeconds, 460 Passes: hc.SuccessThreshold, 461 URI: hc.HTTPGet.Path, 462 Scheme: strings.ToLower(string(hc.HTTPGet.Scheme)), 463 Mandatory: cfg.HealthCheckMandatory, 464 Headers: headersToString(hc.HTTPGet.HTTPHeaders), 465 TimeoutSeconds: int64(hc.TimeoutSeconds), 466 } 467 } 468 469 func headersToString(headers []api_v1.HTTPHeader) map[string]string { 470 m := make(map[string]string) 471 for _, header := range headers { 472 m[header.Name] = header.Value 473 } 474 return m 475 } 476 477 func pathOrDefault(path string) string { 478 if path == "" { 479 return "/" 480 } 481 return path 482 } 483 484 func getNameForUpstream(ing *networking.Ingress, host string, backend *networking.IngressBackend) string { 485 return fmt.Sprintf("%v-%v-%v-%v-%v", ing.Namespace, ing.Name, host, backend.ServiceName, backend.ServicePort.String()) 486 } 487 488 func getNameForRedirectLocation(ing *networking.Ingress) string { 489 return fmt.Sprintf("@login_url_%v-%v", ing.Namespace, ing.Name) 490 } 491 492 func upstreamMapToSlice(upstreams map[string]version1.Upstream) []version1.Upstream { 493 keys := make([]string, 0, len(upstreams)) 494 for k := range upstreams { 495 keys = append(keys, k) 496 } 497 498 // this ensures that the slice 'result' is sorted, which preserves the order of upstream servers 499 // in the generated configuration file from one version to another and is also required for repeatable 500 // Unit test results 501 sort.Strings(keys) 502 503 result := make([]version1.Upstream, 0, len(upstreams)) 504 505 for _, k := range keys { 506 result = append(result, upstreams[k]) 507 } 508 509 return result 510 } 511 512 func generateNginxCfgForMergeableIngresses(mergeableIngs *MergeableIngresses, masterApResources AppProtectResources, 513 baseCfgParams *ConfigParams, isPlus bool, isResolverConfigured bool, staticParams *StaticConfigParams, 514 isWildcardEnabled bool) (version1.IngressNginxConfig, Warnings) { 515 516 var masterServer version1.Server 517 var locations []version1.Location 518 var upstreams []version1.Upstream 519 healthChecks := make(map[string]version1.HealthCheck) 520 var keepalive string 521 522 // replace master with a deepcopy because we will modify it 523 originalMaster := mergeableIngs.Master.Ingress 524 mergeableIngs.Master.Ingress = mergeableIngs.Master.Ingress.DeepCopy() 525 526 removedAnnotations := filterMasterAnnotations(mergeableIngs.Master.Ingress.Annotations) 527 if len(removedAnnotations) != 0 { 528 glog.Errorf("Ingress Resource %v/%v with the annotation 'nginx.org/mergeable-ingress-type' set to 'master' cannot contain the '%v' annotation(s). They will be ignored", 529 mergeableIngs.Master.Ingress.Namespace, mergeableIngs.Master.Ingress.Name, strings.Join(removedAnnotations, ",")) 530 } 531 isMinion := false 532 533 masterNginxCfg, warnings := generateNginxCfg(mergeableIngs.Master, masterApResources, isMinion, baseCfgParams, isPlus, isResolverConfigured, staticParams, isWildcardEnabled) 534 535 // because mergeableIngs.Master.Ingress is a deepcopy of the original master 536 // we need to change the key in the warnings to the original master 537 if _, exists := warnings[mergeableIngs.Master.Ingress]; exists { 538 warnings[originalMaster] = warnings[mergeableIngs.Master.Ingress] 539 delete(warnings, mergeableIngs.Master.Ingress) 540 } 541 542 masterServer = masterNginxCfg.Servers[0] 543 masterServer.Locations = []version1.Location{} 544 545 upstreams = append(upstreams, masterNginxCfg.Upstreams...) 546 547 if masterNginxCfg.Keepalive != "" { 548 keepalive = masterNginxCfg.Keepalive 549 } 550 551 minions := mergeableIngs.Minions 552 for _, minion := range minions { 553 // replace minion with a deepcopy because we will modify it 554 originalMinion := minion.Ingress 555 minion.Ingress = minion.Ingress.DeepCopy() 556 557 // Remove the default backend so that "/" will not be generated 558 minion.Ingress.Spec.Backend = nil 559 560 // Add acceptable master annotations to minion 561 mergeMasterAnnotationsIntoMinion(minion.Ingress.Annotations, mergeableIngs.Master.Ingress.Annotations) 562 563 removedAnnotations = filterMinionAnnotations(minion.Ingress.Annotations) 564 if len(removedAnnotations) != 0 { 565 glog.Errorf("Ingress Resource %v/%v with the annotation 'nginx.org/mergeable-ingress-type' set to 'minion' cannot contain the %v annotation(s). They will be ignored", 566 minion.Ingress.Namespace, minion.Ingress.Name, strings.Join(removedAnnotations, ",")) 567 } 568 569 isMinion := true 570 // App Protect Resources not allowed in minions - pass empty struct 571 dummyApResources := AppProtectResources{} 572 nginxCfg, minionWarnings := generateNginxCfg(minion, dummyApResources, isMinion, baseCfgParams, isPlus, isResolverConfigured, staticParams, isWildcardEnabled) 573 warnings.Add(minionWarnings) 574 575 // because minion.Ingress is a deepcopy of the original minion 576 // we need to change the key in the warnings to the original minion 577 if _, exists := warnings[minion.Ingress]; exists { 578 warnings[originalMinion] = warnings[minion.Ingress] 579 delete(warnings, minion.Ingress) 580 } 581 582 for _, server := range nginxCfg.Servers { 583 for _, loc := range server.Locations { 584 loc.MinionIngress = &nginxCfg.Ingress 585 locations = append(locations, loc) 586 } 587 for hcName, healthCheck := range server.HealthChecks { 588 healthChecks[hcName] = healthCheck 589 } 590 masterServer.JWTRedirectLocations = append(masterServer.JWTRedirectLocations, server.JWTRedirectLocations...) 591 } 592 593 upstreams = append(upstreams, nginxCfg.Upstreams...) 594 } 595 596 masterServer.HealthChecks = healthChecks 597 masterServer.Locations = locations 598 599 return version1.IngressNginxConfig{ 600 Servers: []version1.Server{masterServer}, 601 Upstreams: upstreams, 602 Keepalive: keepalive, 603 Ingress: masterNginxCfg.Ingress, 604 SpiffeClientCerts: staticParams.NginxServiceMesh && !baseCfgParams.SpiffeServerCerts, 605 }, warnings 606 } 607 608 func isSSLEnabled(isSSLService bool, cfgParams ConfigParams, staticCfgParams *StaticConfigParams) bool { 609 return isSSLService || staticCfgParams.NginxServiceMesh && !cfgParams.SpiffeServerCerts 610 }