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:
parent
86c00a2310
commit
c5f348ea2e
109 changed files with 4320 additions and 586 deletions
|
|
@ -19,17 +19,49 @@ package fastcgi
|
|||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
|
||||
networking "k8s.io/api/networking/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||
ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
|
||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||
)
|
||||
|
||||
const (
|
||||
fastCGIIndexAnnotation = "fastcgi-index"
|
||||
fastCGIParamsAnnotation = "fastcgi-params-configmap"
|
||||
)
|
||||
|
||||
var (
|
||||
// fast-cgi valid parameters is just a single file name (like index.php)
|
||||
regexValidIndexAnnotationAndKey = regexp.MustCompile(`^[A-Za-z0-9\.\-\_]+$`)
|
||||
)
|
||||
|
||||
var fastCGIAnnotations = parser.Annotation{
|
||||
Group: "fastcgi",
|
||||
Annotations: parser.AnnotationFields{
|
||||
fastCGIIndexAnnotation: {
|
||||
Validator: parser.ValidateRegex(*regexValidIndexAnnotationAndKey, true),
|
||||
Scope: parser.AnnotationScopeLocation,
|
||||
Risk: parser.AnnotationRiskMedium,
|
||||
Documentation: `This annotation can be used to specify an index file`,
|
||||
},
|
||||
fastCGIParamsAnnotation: {
|
||||
Validator: parser.ValidateRegex(*parser.BasicCharsRegex, true),
|
||||
Scope: parser.AnnotationScopeLocation,
|
||||
Risk: parser.AnnotationRiskMedium,
|
||||
Documentation: `This annotation can be used to specify a ConfigMap containing the fastcgi parameters as a key/value.
|
||||
Only ConfigMaps on the same namespace of ingress can be used. They key and value from ConfigMap are validated for unauthorized characters.`,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type fastcgi struct {
|
||||
r resolver.Resolver
|
||||
r resolver.Resolver
|
||||
annotationConfig parser.Annotation
|
||||
}
|
||||
|
||||
// Config describes the per location fastcgi config
|
||||
|
|
@ -57,7 +89,10 @@ func (l1 *Config) Equal(l2 *Config) bool {
|
|||
|
||||
// NewParser creates a new fastcgiConfig protocol annotation parser
|
||||
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
||||
return fastcgi{r}
|
||||
return fastcgi{
|
||||
r: r,
|
||||
annotationConfig: fastCGIAnnotations,
|
||||
}
|
||||
}
|
||||
|
||||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
|
|
@ -70,14 +105,21 @@ func (a fastcgi) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
return fcgiConfig, nil
|
||||
}
|
||||
|
||||
index, err := parser.GetStringAnnotation("fastcgi-index", ing)
|
||||
index, err := parser.GetStringAnnotation(fastCGIIndexAnnotation, ing, a.annotationConfig.Annotations)
|
||||
if err != nil {
|
||||
if ing_errors.IsValidationError(err) {
|
||||
return fcgiConfig, err
|
||||
}
|
||||
index = ""
|
||||
}
|
||||
|
||||
fcgiConfig.Index = index
|
||||
|
||||
cm, err := parser.GetStringAnnotation("fastcgi-params-configmap", ing)
|
||||
cm, err := parser.GetStringAnnotation(fastCGIParamsAnnotation, ing, a.annotationConfig.Annotations)
|
||||
if err != nil {
|
||||
if ing_errors.IsValidationError(err) {
|
||||
return fcgiConfig, err
|
||||
}
|
||||
return fcgiConfig, nil
|
||||
}
|
||||
|
||||
|
|
@ -87,8 +129,10 @@ func (a fastcgi) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
Reason: fmt.Errorf("error reading configmap name from annotation: %w", err),
|
||||
}
|
||||
}
|
||||
secCfg := a.r.GetSecurityConfiguration()
|
||||
|
||||
if cmns != "" && cmns != ing.Namespace {
|
||||
// We don't accept different namespaces for secrets.
|
||||
if cmns != "" && !secCfg.AllowCrossNamespaceResources && cmns != ing.Namespace {
|
||||
return fcgiConfig, fmt.Errorf("different namespace is not supported on fast_cgi param configmap")
|
||||
}
|
||||
|
||||
|
|
@ -100,7 +144,24 @@ func (a fastcgi) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
}
|
||||
}
|
||||
|
||||
for k, v := range cmap.Data {
|
||||
if !regexValidIndexAnnotationAndKey.MatchString(k) || !parser.NGINXVariable.MatchString(v) {
|
||||
klog.ErrorS(fmt.Errorf("fcgi contains invalid key or value"), "fcgi annotation error", "configmap", cmap.Name, "namespace", cmap.Namespace, "key", k, "value", v)
|
||||
return fcgiConfig, ing_errors.NewValidationError(fastCGIParamsAnnotation)
|
||||
}
|
||||
}
|
||||
|
||||
fcgiConfig.Index = index
|
||||
fcgiConfig.Params = cmap.Data
|
||||
|
||||
return fcgiConfig, nil
|
||||
}
|
||||
|
||||
func (a fastcgi) GetDocumentation() parser.AnnotationFields {
|
||||
return a.annotationConfig.Annotations
|
||||
}
|
||||
|
||||
func (a fastcgi) Validate(anns map[string]string) error {
|
||||
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRiskLevel)
|
||||
return parser.CheckAnnotationRisk(anns, maxrisk, fastCGIAnnotations.Annotations)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue