pkg/appgw/certificates.go (109 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 (
"encoding/base64"
"fmt"
"sort"
n "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-03-01/network"
"github.com/Azure/go-autorest/autorest/to"
v1 "k8s.io/api/core/v1"
networking "k8s.io/api/networking/v1"
"github.com/Azure/application-gateway-kubernetes-ingress/pkg/brownfield"
"github.com/Azure/application-gateway-kubernetes-ingress/pkg/events"
"github.com/Azure/application-gateway-kubernetes-ingress/pkg/sorter"
)
// getSslCertificates obtains all SSL Certificates for the given Ingress object.
func (c *appGwConfigBuilder) getSslCertificates(cbCtx *ConfigBuilderContext) *[]n.ApplicationGatewaySslCertificate {
if c.mem.certs != nil {
return c.mem.certs
}
secretIDCertificateMap := make(map[secretIdentifier]*string)
for _, ingress := range cbCtx.IngressList {
for k, v := range c.getSecretToCertificateMap(ingress) {
secretIDCertificateMap[k] = v
}
}
sslCertificates := []n.ApplicationGatewaySslCertificate{}
for secretID, cert := range secretIDCertificateMap {
sslCertificates = append(sslCertificates, c.newCert(secretID, cert))
}
// Merge certs from k8s ingress with existing appgw certs
if c.appGw.SslCertificates != nil {
// MergePools would produce unique list of pools based on Name. Blacklisted pools, which have the same name
// as a managed pool would be overwritten.
sslCertificates = brownfield.MergeCerts(*c.appGw.SslCertificates, sslCertificates)
}
sort.Sort(sorter.ByCertificateName(sslCertificates))
c.mem.certs = &sslCertificates
return &sslCertificates
}
func (c *appGwConfigBuilder) getSecretToCertificateMap(ingress *networking.Ingress) map[secretIdentifier]*string {
secretIDCertificateMap := make(map[secretIdentifier]*string)
for _, tls := range ingress.Spec.TLS {
if len(tls.SecretName) == 0 {
continue
}
tlsSecret := secretIdentifier{
Name: tls.SecretName,
Namespace: ingress.Namespace,
}
// add hostname-tlsSecret mapping to a per-ingress map
if cert := c.k8sContext.CertificateSecretStore.GetPfxCertificate(tlsSecret.secretKey()); cert != nil {
secretIDCertificateMap[tlsSecret] = to.StringPtr(base64.StdEncoding.EncodeToString(cert))
} else {
logLine := fmt.Sprintf("Unable to find the secret associated to secretId: [%s]", tlsSecret.secretKey())
c.recorder.Event(ingress, v1.EventTypeWarning, events.ReasonSecretNotFound, logLine)
}
}
return secretIDCertificateMap
}
func (c *appGwConfigBuilder) getCertificate(ingress *networking.Ingress, hostname string, hostnameSecretIDMap map[string]secretIdentifier) (*string, *secretIdentifier) {
if hostnameSecretIDMap == nil {
return nil, nil
}
secID, exists := hostnameSecretIDMap[hostname]
if !exists {
// check if wildcard exists
secID, exists = hostnameSecretIDMap[""]
}
if !exists {
// no wildcard or matched certificate
return nil, nil
}
cert, exists := c.getSecretToCertificateMap(ingress)[secID]
if !exists {
// secret referred does not correspond to a certificate
return nil, nil
}
return cert, &secID
}
func (c *appGwConfigBuilder) newHostToSecretMap(ingress *networking.Ingress) map[string]secretIdentifier {
hostToSecretMap := make(map[string]secretIdentifier)
for _, tls := range ingress.Spec.TLS {
if len(tls.SecretName) == 0 {
continue
}
tlsSecret := secretIdentifier{
Name: tls.SecretName,
Namespace: ingress.Namespace,
}
// add hostname-tlsSecret mapping to a per-ingress map
cert := c.k8sContext.CertificateSecretStore.GetPfxCertificate(tlsSecret.secretKey())
if cert == nil {
continue
}
// default secret
if len(tls.Hosts) == 0 {
hostToSecretMap[""] = tlsSecret
}
for _, hostname := range tls.Hosts {
// default secret
if len(hostname) == 0 {
hostToSecretMap[""] = tlsSecret
} else {
hostToSecretMap[hostname] = tlsSecret
}
}
}
return hostToSecretMap
}
func (c *appGwConfigBuilder) newCert(secretID secretIdentifier, cert *string) n.ApplicationGatewaySslCertificate {
sslCertName := secretID.secretFullName()
return n.ApplicationGatewaySslCertificate{
Etag: to.StringPtr("*"),
Name: to.StringPtr(sslCertName),
ID: to.StringPtr(c.appGwIdentifier.sslCertificateID(sslCertName)),
ApplicationGatewaySslCertificatePropertiesFormat: &n.ApplicationGatewaySslCertificatePropertiesFormat{
Data: cert,
Password: to.StringPtr("msazure"),
},
}
}