mirror of https://github.com/k3s-io/k3s
Merge pull request #29204 from aledbf/ingress-wildcard-hosts
Automatic merge from submit-queue Allow leading * in ingress hostname fixes #29043pull/6/head
commit
0410c33995
|
@ -323,6 +323,20 @@ func validateIngressTLS(spec *extensions.IngressSpec, fldPath *field.Path) field
|
||||||
allErrs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
// TODO: Perform a more thorough validation of spec.TLS.Hosts that takes
|
// TODO: Perform a more thorough validation of spec.TLS.Hosts that takes
|
||||||
// the wildcard spec from RFC 6125 into account.
|
// the wildcard spec from RFC 6125 into account.
|
||||||
|
for _, itls := range spec.TLS {
|
||||||
|
for i, host := range itls.Hosts {
|
||||||
|
if strings.Contains(host, "*") {
|
||||||
|
for _, msg := range validation.IsWildcardDNS1123Subdomain(host) {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("hosts"), host, msg))
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, msg := range validation.IsDNS1123Subdomain(host) {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("hosts"), host, msg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,21 +372,27 @@ func ValidateIngressStatusUpdate(ingress, oldIngress *extensions.Ingress) field.
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateIngressRules(IngressRules []extensions.IngressRule, fldPath *field.Path) field.ErrorList {
|
func validateIngressRules(ingressRules []extensions.IngressRule, fldPath *field.Path) field.ErrorList {
|
||||||
allErrs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
if len(IngressRules) == 0 {
|
if len(ingressRules) == 0 {
|
||||||
return append(allErrs, field.Required(fldPath, ""))
|
return append(allErrs, field.Required(fldPath, ""))
|
||||||
}
|
}
|
||||||
for i, ih := range IngressRules {
|
for i, ih := range ingressRules {
|
||||||
if len(ih.Host) > 0 {
|
if len(ih.Host) > 0 {
|
||||||
// TODO: Ports and ips are allowed in the host part of a url
|
|
||||||
// according to RFC 3986, consider allowing them.
|
|
||||||
for _, msg := range validation.IsDNS1123Subdomain(ih.Host) {
|
|
||||||
allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("host"), ih.Host, msg))
|
|
||||||
}
|
|
||||||
if isIP := (net.ParseIP(ih.Host) != nil); isIP {
|
if isIP := (net.ParseIP(ih.Host) != nil); isIP {
|
||||||
allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("host"), ih.Host, "must be a DNS name, not an IP address"))
|
allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("host"), ih.Host, "must be a DNS name, not an IP address"))
|
||||||
}
|
}
|
||||||
|
// TODO: Ports and ips are allowed in the host part of a url
|
||||||
|
// according to RFC 3986, consider allowing them.
|
||||||
|
if strings.Contains(ih.Host, "*") {
|
||||||
|
for _, msg := range validation.IsWildcardDNS1123Subdomain(ih.Host) {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("host"), ih.Host, msg))
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, msg := range validation.IsDNS1123Subdomain(ih.Host) {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("host"), ih.Host, msg))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
allErrs = append(allErrs, validateIngressRuleValue(&ih.IngressRuleValue, fldPath.Index(0))...)
|
allErrs = append(allErrs, validateIngressRuleValue(&ih.IngressRuleValue, fldPath.Index(0))...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -796,6 +796,82 @@ func TestValidateIngress(t *testing.T) {
|
||||||
errorCases[badPathErr] = badRegexPath
|
errorCases[badPathErr] = badRegexPath
|
||||||
errorCases[badHostIPErr] = badHostIP
|
errorCases[badHostIPErr] = badHostIP
|
||||||
|
|
||||||
|
wildcardHost := "foo.*.bar.com"
|
||||||
|
badWildcard := newValid()
|
||||||
|
badWildcard.Spec.Rules[0].Host = wildcardHost
|
||||||
|
badWildcardErr := fmt.Sprintf("spec.rules[0].host: Invalid value: '%v'", wildcardHost)
|
||||||
|
errorCases[badWildcardErr] = badWildcard
|
||||||
|
|
||||||
|
for k, v := range errorCases {
|
||||||
|
errs := ValidateIngress(&v)
|
||||||
|
if len(errs) == 0 {
|
||||||
|
t.Errorf("expected failure for %q", k)
|
||||||
|
} else {
|
||||||
|
s := strings.Split(k, ":")
|
||||||
|
err := errs[0]
|
||||||
|
if err.Field != s[0] || !strings.Contains(err.Error(), s[1]) {
|
||||||
|
t.Errorf("unexpected error: %q, expected: %q", err, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateIngressTLS(t *testing.T) {
|
||||||
|
defaultBackend := extensions.IngressBackend{
|
||||||
|
ServiceName: "default-backend",
|
||||||
|
ServicePort: intstr.FromInt(80),
|
||||||
|
}
|
||||||
|
|
||||||
|
newValid := func() extensions.Ingress {
|
||||||
|
return extensions.Ingress{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Namespace: api.NamespaceDefault,
|
||||||
|
},
|
||||||
|
Spec: extensions.IngressSpec{
|
||||||
|
Backend: &extensions.IngressBackend{
|
||||||
|
ServiceName: "default-backend",
|
||||||
|
ServicePort: intstr.FromInt(80),
|
||||||
|
},
|
||||||
|
Rules: []extensions.IngressRule{
|
||||||
|
{
|
||||||
|
Host: "foo.bar.com",
|
||||||
|
IngressRuleValue: extensions.IngressRuleValue{
|
||||||
|
HTTP: &extensions.HTTPIngressRuleValue{
|
||||||
|
Paths: []extensions.HTTPIngressPath{
|
||||||
|
{
|
||||||
|
Path: "/foo",
|
||||||
|
Backend: defaultBackend,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Status: extensions.IngressStatus{
|
||||||
|
LoadBalancer: api.LoadBalancerStatus{
|
||||||
|
Ingress: []api.LoadBalancerIngress{
|
||||||
|
{IP: "127.0.0.1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errorCases := map[string]extensions.Ingress{}
|
||||||
|
|
||||||
|
wildcardHost := "foo.*.bar.com"
|
||||||
|
badWildcardTLS := newValid()
|
||||||
|
badWildcardTLS.Spec.Rules[0].Host = "*.foo.bar.com"
|
||||||
|
badWildcardTLS.Spec.TLS = []extensions.IngressTLS{
|
||||||
|
{
|
||||||
|
Hosts: []string{wildcardHost},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
badWildcardTLSErr := fmt.Sprintf("spec.tls[0].hosts: Invalid value: '%v'", wildcardHost)
|
||||||
|
errorCases[badWildcardTLSErr] = badWildcardTLS
|
||||||
|
|
||||||
for k, v := range errorCases {
|
for k, v := range errorCases {
|
||||||
errs := ValidateIngress(&v)
|
errs := ValidateIngress(&v)
|
||||||
if len(errs) == 0 {
|
if len(errs) == 0 {
|
||||||
|
|
|
@ -139,6 +139,27 @@ func IsDNS1035Label(value string) []string {
|
||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wildcard definition - RFC 1034 section 4.3.3.
|
||||||
|
// examples:
|
||||||
|
// - valid: *.bar.com, *.foo.bar.com
|
||||||
|
// - invalid: *.*.bar.com, *.foo.*.com, *bar.com, f*.bar.com, *
|
||||||
|
const wildcardDNF1123SubdomainFmt = "\\*\\." + dns1123SubdomainFmt
|
||||||
|
|
||||||
|
// IsWildcardDNS1123Subdomain tests for a string that conforms to the definition of a
|
||||||
|
// wildcard subdomain in DNS (RFC 1034 section 4.3.3).
|
||||||
|
func IsWildcardDNS1123Subdomain(value string) []string {
|
||||||
|
wildcardDNS1123SubdomainRegexp := regexp.MustCompile("^\\*\\." + dns1123SubdomainFmt + "$")
|
||||||
|
|
||||||
|
var errs []string
|
||||||
|
if len(value) > DNS1123SubdomainMaxLength {
|
||||||
|
errs = append(errs, MaxLenError(DNS1123SubdomainMaxLength))
|
||||||
|
}
|
||||||
|
if !wildcardDNS1123SubdomainRegexp.MatchString(value) {
|
||||||
|
errs = append(errs, RegexError(wildcardDNF1123SubdomainFmt, "*.example.com"))
|
||||||
|
}
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
const cIdentifierFmt string = "[A-Za-z_][A-Za-z0-9_]*"
|
const cIdentifierFmt string = "[A-Za-z_][A-Za-z0-9_]*"
|
||||||
|
|
||||||
var cIdentifierRegexp = regexp.MustCompile("^" + cIdentifierFmt + "$")
|
var cIdentifierRegexp = regexp.MustCompile("^" + cIdentifierFmt + "$")
|
||||||
|
|
|
@ -407,3 +407,29 @@ func TestIsConfigMapKey(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsWildcardDNS1123Subdomain(t *testing.T) {
|
||||||
|
goodValues := []string{
|
||||||
|
"*.example.com",
|
||||||
|
"*.bar.com",
|
||||||
|
"*.foo.bar.com",
|
||||||
|
}
|
||||||
|
for _, val := range goodValues {
|
||||||
|
if errs := IsWildcardDNS1123Subdomain(val); len(errs) != 0 {
|
||||||
|
t.Errorf("expected no errors for %q: %v", val, errs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
badValues := []string{
|
||||||
|
"*.*.bar.com",
|
||||||
|
"*.foo.*.com",
|
||||||
|
"*bar.com",
|
||||||
|
"f*.bar.com",
|
||||||
|
"*",
|
||||||
|
}
|
||||||
|
for _, val := range badValues {
|
||||||
|
if errs := IsWildcardDNS1123Subdomain(val); len(errs) == 0 {
|
||||||
|
t.Errorf("expected errors for %q", val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue