mirror of
https://github.com/rancher/dynamiclistener.git
synced 2025-08-14 11:35:21 +00:00
Add support for wildcard SANs
This commit is contained in:
parent
0a2d8dff62
commit
c83dcf47ef
@ -12,7 +12,6 @@ import (
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@ -28,10 +27,6 @@ const (
|
||||
fingerprint = "listener.cattle.io/fingerprint"
|
||||
)
|
||||
|
||||
var (
|
||||
cnRegexp = regexp.MustCompile("^([A-Za-z0-9:][-A-Za-z0-9_.:]*)?[A-Za-z0-9:]$")
|
||||
)
|
||||
|
||||
type TLS struct {
|
||||
CACert []*x509.Certificate
|
||||
CAKey crypto.Signer
|
||||
@ -244,7 +239,7 @@ func populateCN(secret *v1.Secret, cn ...string) *v1.Secret {
|
||||
secret.Annotations = map[string]string{}
|
||||
}
|
||||
for _, cn := range cn {
|
||||
if cnRegexp.MatchString(cn) {
|
||||
if validHostnamePattern(cn) {
|
||||
secret.Annotations[getAnnotationKey(cn)] = cn
|
||||
} else {
|
||||
logrus.Errorf("dropping invalid CN: %s", cn)
|
||||
@ -272,7 +267,7 @@ func NeedsUpdate(maxSANs int, secret *v1.Secret, cn ...string) bool {
|
||||
}
|
||||
|
||||
for _, cn := range cn {
|
||||
if secret.Annotations[getAnnotationKey(cn)] == "" {
|
||||
if secret.Annotations[getAnnotationKey(cn)] == "" && secret.Annotations[getAnnotationKey(getWildcardSAN(cn))] == "" {
|
||||
if maxSANs > 0 && len(cns(secret)) >= maxSANs {
|
||||
return false
|
||||
}
|
||||
@ -344,13 +339,82 @@ func NewPrivateKey() (crypto.Signer, error) {
|
||||
func getAnnotationKey(cn string) string {
|
||||
cn = cnPrefix + cn
|
||||
cnLen := len(cn)
|
||||
if cnLen < 64 && !strings.ContainsRune(cn, ':') {
|
||||
if cnLen < 64 && !strings.ContainsRune(cn, ':') && !strings.ContainsRune(cn, '*') {
|
||||
return cn
|
||||
}
|
||||
digest := sha256.Sum256([]byte(cn))
|
||||
// : only resides in IPv6 addresses
|
||||
cn = strings.ReplaceAll(cn, ":", "_")
|
||||
// * only resides in domain name wildcards, so it cannot coexit with : in annotation keys
|
||||
cn = strings.ReplaceAll(cn, "*", "_")
|
||||
if cnLen > 56 {
|
||||
cnLen = 56
|
||||
}
|
||||
return cn[0:cnLen] + "-" + hex.EncodeToString(digest[0:])[0:6]
|
||||
}
|
||||
|
||||
// get wildcard SAN for a given CN
|
||||
// e.g. *.example.com for k3s.example.com
|
||||
func getWildcardSAN(cn string) string {
|
||||
if strings.Contains(cn, ".") {
|
||||
return "*." + strings.SplitN(cn, ".", 2)[1]
|
||||
}
|
||||
return cn
|
||||
}
|
||||
|
||||
// from https://github.com/golang/go/blob/master/src/crypto/x509/verify.go
|
||||
func validHostnamePattern(host string) bool { return validHostname(host, true) }
|
||||
|
||||
// adapted from https://github.com/golang/go/blob/master/src/crypto/x509/verify.go
|
||||
// DIFFERENT WITH Go codebase: added support of IPv6 address (:)
|
||||
//
|
||||
// validHostname reports whether host is a valid hostname that can be matched or
|
||||
// matched against according to RFC 6125 2.2, with some leniency to accommodate
|
||||
// legacy values.
|
||||
func validHostname(host string, isPattern bool) bool {
|
||||
if !isPattern {
|
||||
host = strings.TrimSuffix(host, ".")
|
||||
}
|
||||
if len(host) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for i, part := range strings.Split(host, ".") {
|
||||
if part == "" {
|
||||
// Empty label.
|
||||
return false
|
||||
}
|
||||
if isPattern && i == 0 && part == "*" {
|
||||
// Only allow full left-most wildcards, as those are the only ones
|
||||
// we match, and matching literal '*' characters is probably never
|
||||
// the expected behavior.
|
||||
continue
|
||||
}
|
||||
for j, c := range part {
|
||||
if 'a' <= c && c <= 'z' {
|
||||
continue
|
||||
}
|
||||
if '0' <= c && c <= '9' {
|
||||
continue
|
||||
}
|
||||
if 'A' <= c && c <= 'Z' {
|
||||
continue
|
||||
}
|
||||
if c == '-' && j != 0 {
|
||||
continue
|
||||
}
|
||||
if c == '_' {
|
||||
// Not a valid character in hostnames, but commonly
|
||||
// found in deployments outside the WebPKI.
|
||||
continue
|
||||
}
|
||||
if c == ':' {
|
||||
// IPv6 support added in dynamiclistener
|
||||
continue
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user