Implement annotation validation (#9673)

* Add validation to all annotations

* Add annotation validation for fcgi

* Fix reviews and fcgi e2e

* Add flag to disable cross namespace validation

* Add risk, flag for validation, tests

* Add missing formating

* Enable validation by default on tests

* Test validation flag

* remove ajp from list

* Finalize validation changes

* Add validations to CI

* Update helm docs

* Fix code review

* Use a better name for annotation risk
This commit is contained in:
Ricardo Katz 2023-07-22 00:32:07 -03:00 committed by GitHub
parent 86c00a2310
commit c5f348ea2e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
109 changed files with 4320 additions and 586 deletions

View file

@ -37,13 +37,56 @@ type Config struct {
FromToWWW bool `json:"fromToWWW"`
}
const (
fromToWWWRedirAnnotation = "from-to-www-redirect"
temporalRedirectAnnotation = "temporal-redirect"
permanentRedirectAnnotation = "permanent-redirect"
permanentRedirectAnnotationCode = "permanent-redirect-code"
)
var redirectAnnotations = parser.Annotation{
Group: "redirect",
Annotations: parser.AnnotationFields{
fromToWWWRedirAnnotation: {
Validator: parser.ValidateBool,
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskLow, // Low, as it allows just a set of options
Documentation: `In some scenarios is required to redirect from www.domain.com to domain.com or vice versa. To enable this feature use this annotation.`,
},
temporalRedirectAnnotation: {
Validator: parser.ValidateRegex(*parser.URLIsValidRegex, false),
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskMedium, // Medium, as it allows arbitrary URLs that needs to be validated
Documentation: `This annotation allows you to return a temporal redirect (Return Code 302) instead of sending data to the upstream.
For example setting this annotation to https://www.google.com would redirect everything to Google with a Return Code of 302 (Moved Temporarily).`,
},
permanentRedirectAnnotation: {
Validator: parser.ValidateRegex(*parser.URLIsValidRegex, false),
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskMedium, // Medium, as it allows arbitrary URLs that needs to be validated
Documentation: `This annotation allows to return a permanent redirect (Return Code 301) instead of sending data to the upstream.
For example setting this annotation https://www.google.com would redirect everything to Google with a code 301`,
},
permanentRedirectAnnotationCode: {
Validator: parser.ValidateInt,
Scope: parser.AnnotationScopeLocation,
Risk: parser.AnnotationRiskLow, // Low, as it allows just a set of options
Documentation: `This annotation allows you to modify the status code used for permanent redirects.`,
},
},
}
type redirect struct {
r resolver.Resolver
r resolver.Resolver
annotationConfig parser.Annotation
}
// NewParser creates a new redirect annotation parser
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
return redirect{r}
return redirect{
r: r,
annotationConfig: redirectAnnotations,
}
}
// Parse parses the annotations contained in the ingress
@ -51,9 +94,12 @@ func NewParser(r resolver.Resolver) parser.IngressAnnotation {
// If the Ingress contains both annotations the execution order is
// temporal and then permanent
func (r redirect) Parse(ing *networking.Ingress) (interface{}, error) {
r3w, _ := parser.GetBoolAnnotation("from-to-www-redirect", ing)
r3w, err := parser.GetBoolAnnotation(fromToWWWRedirAnnotation, ing, r.annotationConfig.Annotations)
if err != nil && !errors.IsMissingAnnotations(err) {
return nil, err
}
tr, err := parser.GetStringAnnotation("temporal-redirect", ing)
tr, err := parser.GetStringAnnotation(temporalRedirectAnnotation, ing, r.annotationConfig.Annotations)
if err != nil && !errors.IsMissingAnnotations(err) {
return nil, err
}
@ -70,12 +116,12 @@ func (r redirect) Parse(ing *networking.Ingress) (interface{}, error) {
}, nil
}
pr, err := parser.GetStringAnnotation("permanent-redirect", ing)
pr, err := parser.GetStringAnnotation(permanentRedirectAnnotation, ing, r.annotationConfig.Annotations)
if err != nil && !errors.IsMissingAnnotations(err) {
return nil, err
}
prc, err := parser.GetIntAnnotation("permanent-redirect-code", ing)
prc, err := parser.GetIntAnnotation(permanentRedirectAnnotationCode, ing, r.annotationConfig.Annotations)
if err != nil && !errors.IsMissingAnnotations(err) {
return nil, err
}
@ -127,3 +173,12 @@ func isValidURL(s string) error {
return nil
}
func (a redirect) GetDocumentation() parser.AnnotationFields {
return a.annotationConfig.Annotations
}
func (a redirect) Validate(anns map[string]string) error {
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
return parser.CheckAnnotationRisk(anns, maxrisk, redirectAnnotations.Annotations)
}

View file

@ -43,7 +43,7 @@ func TestPermanentRedirectWithDefaultCode(t *testing.T) {
ing := new(networking.Ingress)
data := make(map[string]string, 1)
data[parser.GetAnnotationWithPrefix("permanent-redirect")] = defRedirectURL
data[parser.GetAnnotationWithPrefix(permanentRedirectAnnotation)] = defRedirectURL
ing.SetAnnotations(data)
i, err := rp.Parse(ing)
@ -81,8 +81,8 @@ func TestPermanentRedirectWithCustomCode(t *testing.T) {
ing := new(networking.Ingress)
data := make(map[string]string, 2)
data[parser.GetAnnotationWithPrefix("permanent-redirect")] = defRedirectURL
data[parser.GetAnnotationWithPrefix("permanent-redirect-code")] = strconv.Itoa(tc.input)
data[parser.GetAnnotationWithPrefix(permanentRedirectAnnotation)] = defRedirectURL
data[parser.GetAnnotationWithPrefix(permanentRedirectAnnotationCode)] = strconv.Itoa(tc.input)
ing.SetAnnotations(data)
i, err := rp.Parse(ing)
@ -112,8 +112,8 @@ func TestTemporalRedirect(t *testing.T) {
ing := new(networking.Ingress)
data := make(map[string]string, 1)
data[parser.GetAnnotationWithPrefix("from-to-www-redirect")] = "true"
data[parser.GetAnnotationWithPrefix("temporal-redirect")] = defRedirectURL
data[parser.GetAnnotationWithPrefix(fromToWWWRedirAnnotation)] = "true"
data[parser.GetAnnotationWithPrefix(temporalRedirectAnnotation)] = defRedirectURL
ing.SetAnnotations(data)
i, err := rp.Parse(ing)