pkg/appgw/redirects.go (65 lines of code) (raw):
// -------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// --------------------------------------------------------------------------------------------
package appgw
import (
"sort"
n "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-03-01/network"
"github.com/Azure/go-autorest/autorest/to"
"k8s.io/klog/v2"
"github.com/Azure/application-gateway-kubernetes-ingress/pkg/brownfield"
"github.com/Azure/application-gateway-kubernetes-ingress/pkg/sorter"
)
// getRedirectConfigurations creates App Gateway redirect configuration based on Ingress annotations.
func (c *appGwConfigBuilder) getRedirectConfigurations(cbCtx *ConfigBuilderContext) *[]n.ApplicationGatewayRedirectConfiguration {
if c.mem.redirectConfigs != nil {
return c.mem.redirectConfigs
}
redirectConfigs := []n.ApplicationGatewayRedirectConfiguration{}
// Iterate over all possible Listeners (generated from the K8s Ingress configurations)
httpListenersMap := c.groupListenersByListenerIdentifier(cbCtx)
for listenerID, listenerConfig := range c.getListenerConfigs(cbCtx) {
httpListener, exists := httpListenersMap[listenerID]
if !exists {
klog.Errorf("Redirect will not be created for target listener %+v as listener does not exist in listenerMap", listenerID)
continue
}
isHTTPS := listenerConfig.Protocol == n.ApplicationGatewayProtocolHTTPS
// What if multiple namespaces have a redirect configured?
hasSslRedirect := listenerConfig.SslRedirectConfigurationName != ""
// We will configure a Redirect only if the listener has TLS enabled (has a Certificate)
if isHTTPS && hasSslRedirect {
targetListener := resourceRef(*httpListener.ID)
redirectConfigs = append(redirectConfigs, c.newSSLRedirectConfig(listenerConfig, targetListener))
klog.Infof("Created redirection configuration %s for (%s,%d); not yet linked to a routing rule", listenerConfig.SslRedirectConfigurationName, listenerID.HostNames, listenerID.FrontendPort)
}
}
if cbCtx.EnvVariables.EnableBrownfieldDeployment {
er := brownfield.NewExistingResources(c.appGw, cbCtx.ProhibitedTargets, nil)
// Listeners we obtained from App Gateway - we segment them into ones AGIC is and is not allowed to change.
existingBlacklisted, existingNonBlacklisted := er.GetBlacklistedRedirects()
brownfield.LogRedirects(existingBlacklisted, existingNonBlacklisted, redirectConfigs)
// MergeRedirects would produce unique list of redirects based on Name. Blacklisted redirects,
// which have the same name as a managed redirects would be overwritten.
redirectConfigs = brownfield.MergeRedirects(existingBlacklisted, redirectConfigs)
}
sort.Sort(sorter.ByRedirectName(redirectConfigs))
c.mem.redirectConfigs = &redirectConfigs
return &redirectConfigs
}
// newSSLRedirectConfig creates a new Redirect in the form of a ApplicationGatewayRedirectConfiguration struct.
func (c *appGwConfigBuilder) newSSLRedirectConfig(listenerConfig listenerAzConfig, targetListener *n.SubResource) n.ApplicationGatewayRedirectConfiguration {
props := n.ApplicationGatewayRedirectConfigurationPropertiesFormat{
// RedirectType could be one of: 301/Permanent, 302/Found, 303/See Other, 307/Temporary
RedirectType: n.ApplicationGatewayRedirectTypePermanent,
// To what listener we are redirecting.
TargetListener: targetListener,
// Include the path in the redirected URL.
IncludePath: to.BoolPtr(true),
// Include the query string in the redirected URL.
IncludeQueryString: to.BoolPtr(true),
}
// To create a new redirect we need a
return n.ApplicationGatewayRedirectConfiguration{
Etag: to.StringPtr("*"),
Name: &listenerConfig.SslRedirectConfigurationName,
ID: to.StringPtr(c.appGwIdentifier.redirectConfigurationID(listenerConfig.SslRedirectConfigurationName)),
ApplicationGatewayRedirectConfigurationPropertiesFormat: &props,
}
}
func (c *appGwConfigBuilder) groupRedirectsByID(redirects *[]n.ApplicationGatewayRedirectConfiguration) *map[string]interface{} {
redirectsSet := make(map[string]interface{})
for _, redirect := range *redirects {
redirectsSet[*redirect.ID] = nil
}
return &redirectsSet
}
func (c *appGwConfigBuilder) getSslRedirectConfigResourceReference(targetListener listenerIdentifier) *n.SubResource {
configName := generateSSLRedirectConfigurationName(targetListener)
sslRedirectConfigID := c.appGwIdentifier.redirectConfigurationID(configName)
return resourceRef(sslRedirectConfigID)
}