Files
capsule/pkg/runtime/cert/san.go
T
3d1158ed23 fix: correct tls reconciler and add tenantowners (#1946)
* fix(controller): decode old object for delete requests

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: modernize golang

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: modernize golang

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: modernize golang

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* fix: tls controller

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* feat: add tenantowner tenant status reference

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* fix: tlsreconciler only patches cabundles

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* chore: refactor logger usage

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix: tlsreconciler only patches cabundles

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* fix: tlsreconciler only patches cabundles

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

---------

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>
Signed-off-by: Oliver Baehler <oliver@sudo-i.net>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-03 16:02:17 +02:00

162 lines
3.1 KiB
Go

// Copyright 2020-2026 Project Capsule Authors
// SPDX-License-Identifier: Apache-2.0
package cert
import (
"crypto/x509"
"fmt"
"net"
"net/url"
"sort"
"strings"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
)
type CertificateSANs struct {
DNSNames []string
IPAddrs []net.IP
}
func (s CertificateSANs) Empty() bool {
return len(s.DNSNames) == 0 && len(s.IPAddrs) == 0
}
func (s CertificateSANs) Normalize() CertificateSANs {
dnsSet := make(map[string]struct{}, len(s.DNSNames))
dnsNames := make([]string, 0, len(s.DNSNames))
for _, name := range s.DNSNames {
name = strings.TrimSpace(strings.ToLower(name))
if name == "" {
continue
}
if _, ok := dnsSet[name]; ok {
continue
}
dnsSet[name] = struct{}{}
dnsNames = append(dnsNames, name)
}
ipSet := make(map[string]struct{}, len(s.IPAddrs))
ipAddrs := make([]net.IP, 0, len(s.IPAddrs))
for _, ip := range s.IPAddrs {
if ip == nil {
continue
}
normalized := ip.String()
if _, ok := ipSet[normalized]; ok {
continue
}
ipSet[normalized] = struct{}{}
ipAddrs = append(ipAddrs, ip)
}
sort.Strings(dnsNames)
sort.Slice(ipAddrs, func(i, j int) bool {
return ipAddrs[i].String() < ipAddrs[j].String()
})
return CertificateSANs{
DNSNames: dnsNames,
IPAddrs: ipAddrs,
}
}
func (s *CertificateSANs) AddDNSNames(names ...string) {
s.DNSNames = append(s.DNSNames, names...)
}
func (s *CertificateSANs) AddIPAddrs(ips ...net.IP) {
s.IPAddrs = append(s.IPAddrs, ips...)
}
func (s *CertificateSANs) AddServiceReference(
service *admissionregistrationv1.ServiceReference,
defaultNamespace string,
) {
if service == nil || service.Name == "" {
return
}
namespace := service.Namespace
if namespace == "" {
namespace = defaultNamespace
}
s.AddDNSNames(
service.Name,
fmt.Sprintf("%s.%s", service.Name, namespace),
fmt.Sprintf("%s.%s.svc", service.Name, namespace),
fmt.Sprintf("%s.%s.svc.cluster.local", service.Name, namespace),
)
}
func (s *CertificateSANs) AddURL(rawURL *string) error {
if rawURL == nil || strings.TrimSpace(*rawURL) == "" {
return nil
}
parsed, err := url.Parse(*rawURL)
if err != nil {
return fmt.Errorf("parse webhook URL %q: %w", *rawURL, err)
}
host := parsed.Hostname()
if host == "" {
return fmt.Errorf("webhook URL %q has empty host", *rawURL)
}
if ip := net.ParseIP(host); ip != nil {
s.AddIPAddrs(ip)
return nil
}
s.AddDNSNames(host)
return nil
}
func (s CertificateSANs) MatchesCertificate(certificate *x509.Certificate) bool {
if certificate == nil {
return false
}
desired := s.Normalize()
actual := CertificateSANs{
DNSNames: append([]string(nil), certificate.DNSNames...),
IPAddrs: append([]net.IP(nil), certificate.IPAddresses...),
}.Normalize()
if len(desired.DNSNames) != len(actual.DNSNames) {
return false
}
for i := range desired.DNSNames {
if desired.DNSNames[i] != actual.DNSNames[i] {
return false
}
}
if len(desired.IPAddrs) != len(actual.IPAddrs) {
return false
}
for i := range desired.IPAddrs {
if desired.IPAddrs[i].String() != actual.IPAddrs[i].String() {
return false
}
}
return true
}