Add risk, flag for validation, tests
This commit is contained in:
parent
37e94edf50
commit
553c66d120
44 changed files with 331 additions and 8 deletions
|
@ -37,7 +37,7 @@ var aliasAnnotation = parser.Annotation{
|
||||||
serverAliasAnnotation: {
|
serverAliasAnnotation: {
|
||||||
Validator: parser.ValidateArrayOfServerName,
|
Validator: parser.ValidateArrayOfServerName,
|
||||||
Scope: parser.AnnotationScopeIngress,
|
Scope: parser.AnnotationScopeIngress,
|
||||||
Risk: parser.AnnotationRiskLow, // Low, as it allows regexes but on a very limited set
|
Risk: parser.AnnotationRiskHigh, // High as this allows regex chars
|
||||||
Documentation: `this annotation can be used to define additional server
|
Documentation: `this annotation can be used to define additional server
|
||||||
aliases for this Ingress`,
|
aliases for this Ingress`,
|
||||||
},
|
},
|
||||||
|
@ -86,3 +86,8 @@ func (a alias) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
|
|
||||||
return l, nil
|
return l, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a alias) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, aliasAnnotation.Annotations)
|
||||||
|
}
|
||||||
|
|
|
@ -180,6 +180,9 @@ func (e Extractor) Extract(ing *networking.Ingress) (*Ingress, error) {
|
||||||
|
|
||||||
data := make(map[string]interface{})
|
data := make(map[string]interface{})
|
||||||
for name, annotationParser := range e.annotations {
|
for name, annotationParser := range e.annotations {
|
||||||
|
if err := annotationParser.Validate(ing.GetAnnotations()); err != nil {
|
||||||
|
return nil, errors.NewRiskyAnnotations(name)
|
||||||
|
}
|
||||||
val, err := annotationParser.Parse(ing)
|
val, err := annotationParser.Parse(ing)
|
||||||
klog.V(5).InfoS("Parsing Ingress annotation", "name", name, "ingress", klog.KObj(ing), "value", val)
|
klog.V(5).InfoS("Parsing Ingress annotation", "name", name, "ingress", klog.KObj(ing), "value", val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -275,3 +275,8 @@ func dumpSecretAuthMap(filename string, secret *api.Secret) error {
|
||||||
func (a auth) GetDocumentation() parser.AnnotationFields {
|
func (a auth) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a auth) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, authSecretAnnotations.Annotations)
|
||||||
|
}
|
||||||
|
|
|
@ -502,3 +502,8 @@ func ParseStringToCacheDurations(input string) ([]string, error) {
|
||||||
func (a authReq) GetDocumentation() parser.AnnotationFields {
|
func (a authReq) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a authReq) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, authReqAnnotations.Annotations)
|
||||||
|
}
|
||||||
|
|
|
@ -67,3 +67,8 @@ func (a authReqGlobal) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (a authReqGlobal) GetDocumentation() parser.AnnotationFields {
|
func (a authReqGlobal) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a authReqGlobal) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, globalAuthAnnotations.Annotations)
|
||||||
|
}
|
|
@ -215,3 +215,8 @@ func (a authTLS) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (a authTLS) GetDocumentation() parser.AnnotationFields {
|
func (a authTLS) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a authTLS) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, authTLSAnnotations.Annotations)
|
||||||
|
}
|
|
@ -81,3 +81,8 @@ func (a backendProtocol) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
|
|
||||||
return proto, nil
|
return proto, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a backendProtocol) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, backendProtocolConfig.Annotations)
|
||||||
|
}
|
||||||
|
|
|
@ -188,3 +188,8 @@ func (c canary) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (c canary) GetDocumentation() parser.AnnotationFields {
|
func (c canary) GetDocumentation() parser.AnnotationFields {
|
||||||
return c.annotationConfig.Annotations
|
return c.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a canary) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, CanaryAnnotations.Annotations)
|
||||||
|
}
|
|
@ -64,3 +64,8 @@ func (cbbs clientBodyBufferSize) GetDocumentation() parser.AnnotationFields {
|
||||||
func (cbbs clientBodyBufferSize) Parse(ing *networking.Ingress) (interface{}, error) {
|
func (cbbs clientBodyBufferSize) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
return parser.GetStringAnnotation(clientBodyBufferSizeAnnotation, ing, cbbs.annotationConfig.Annotations)
|
return parser.GetStringAnnotation(clientBodyBufferSizeAnnotation, ing, cbbs.annotationConfig.Annotations)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a clientBodyBufferSize) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, clientBodyBufferSizeConfig.Annotations)
|
||||||
|
}
|
|
@ -100,3 +100,8 @@ func (r1 *Config) Equal(r2 *Config) bool {
|
||||||
func (a connection) GetDocumentation() parser.AnnotationFields {
|
func (a connection) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a connection) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, connectionHeadersAnnotations.Annotations)
|
||||||
|
}
|
|
@ -259,3 +259,8 @@ func (c cors) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (c cors) GetDocumentation() parser.AnnotationFields {
|
func (c cors) GetDocumentation() parser.AnnotationFields {
|
||||||
return c.annotationConfig.Annotations
|
return c.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a cors) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, corsAnnotation.Annotations)
|
||||||
|
}
|
|
@ -66,7 +66,7 @@ func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
||||||
// Parse parses the annotations contained in the ingress to use
|
// Parse parses the annotations contained in the ingress to use
|
||||||
// custom http errors
|
// custom http errors
|
||||||
func (e customhttperrors) Parse(ing *networking.Ingress) (interface{}, error) {
|
func (e customhttperrors) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
c, err := parser.GetStringAnnotation("custom-http-errors", ing, e.annotationConfig.Annotations)
|
c, err := parser.GetStringAnnotation(customHTTPErrorsAnnotation, ing, e.annotationConfig.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -87,3 +87,8 @@ func (e customhttperrors) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (e customhttperrors) GetDocumentation() parser.AnnotationFields {
|
func (e customhttperrors) GetDocumentation() parser.AnnotationFields {
|
||||||
return e.annotationConfig.Annotations
|
return e.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a customhttperrors) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, customHTTPErrorsAnnotations.Annotations)
|
||||||
|
}
|
||||||
|
|
|
@ -75,3 +75,8 @@ func (db backend) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (db backend) GetDocumentation() parser.AnnotationFields {
|
func (db backend) GetDocumentation() parser.AnnotationFields {
|
||||||
return db.annotationConfig.Annotations
|
return db.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a backend) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, defaultBackendAnnotations.Annotations)
|
||||||
|
}
|
|
@ -160,3 +160,8 @@ func (a fastcgi) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (a fastcgi) GetDocumentation() parser.AnnotationFields {
|
func (a fastcgi) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a fastcgi) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, fastCGIAnnotations.Annotations)
|
||||||
|
}
|
|
@ -173,3 +173,8 @@ func (a globalratelimit) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (a globalratelimit) GetDocumentation() parser.AnnotationFields {
|
func (a globalratelimit) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a globalratelimit) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, globalRateLimitAnnotationConfig.Annotations)
|
||||||
|
}
|
|
@ -61,3 +61,8 @@ func (h2pp http2PushPreload) Parse(ing *networking.Ingress) (interface{}, error)
|
||||||
func (h2pp http2PushPreload) GetDocumentation() parser.AnnotationFields {
|
func (h2pp http2PushPreload) GetDocumentation() parser.AnnotationFields {
|
||||||
return h2pp.annotationConfig.Annotations
|
return h2pp.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a http2PushPreload) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, http2PushPreloadAnnotations.Annotations)
|
||||||
|
}
|
|
@ -126,3 +126,8 @@ func (a ipallowlist) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (a ipallowlist) GetDocumentation() parser.AnnotationFields {
|
func (a ipallowlist) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a ipallowlist) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, allowlistAnnotations.Annotations)
|
||||||
|
}
|
|
@ -123,3 +123,8 @@ func (a ipdenylist) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (a ipdenylist) GetDocumentation() parser.AnnotationFields {
|
func (a ipdenylist) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a ipdenylist) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, denylistAnnotations.Annotations)
|
||||||
|
}
|
|
@ -67,3 +67,8 @@ func (a loadbalancing) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (a loadbalancing) GetDocumentation() parser.AnnotationFields {
|
func (a loadbalancing) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a loadbalancing) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, loadBalanceAnnotations.Annotations)
|
||||||
|
}
|
|
@ -100,3 +100,8 @@ func (l log) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (l log) GetDocumentation() parser.AnnotationFields {
|
func (l log) GetDocumentation() parser.AnnotationFields {
|
||||||
return l.annotationConfig.Annotations
|
return l.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a log) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, logAnnotations.Annotations)
|
||||||
|
}
|
|
@ -161,3 +161,8 @@ func (a mirror) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (a mirror) GetDocumentation() parser.AnnotationFields {
|
func (a mirror) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a mirror) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, mirrorAnnotation.Annotations)
|
||||||
|
}
|
|
@ -153,3 +153,8 @@ func (a modSecurity) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (a modSecurity) GetDocumentation() parser.AnnotationFields {
|
func (a modSecurity) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a modSecurity) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, modsecurityAnnotation.Annotations)
|
||||||
|
}
|
|
@ -149,3 +149,8 @@ func (c opentelemetry) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (c opentelemetry) GetDocumentation() parser.AnnotationFields {
|
func (c opentelemetry) GetDocumentation() parser.AnnotationFields {
|
||||||
return c.annotationConfig.Annotations
|
return c.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a opentelemetry) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, otelAnnotations.Annotations)
|
||||||
|
}
|
|
@ -106,3 +106,8 @@ func (s opentracing) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (s opentracing) GetDocumentation() parser.AnnotationFields {
|
func (s opentracing) GetDocumentation() parser.AnnotationFields {
|
||||||
return s.annotationConfig.Annotations
|
return s.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a opentracing) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, opentracingAnnotations.Annotations)
|
||||||
|
}
|
|
@ -30,12 +30,15 @@ import (
|
||||||
|
|
||||||
// DefaultAnnotationsPrefix defines the common prefix used in the nginx ingress controller
|
// DefaultAnnotationsPrefix defines the common prefix used in the nginx ingress controller
|
||||||
const (
|
const (
|
||||||
DefaultAnnotationsPrefix = "nginx.ingress.kubernetes.io"
|
DefaultAnnotationsPrefix = "nginx.ingress.kubernetes.io"
|
||||||
|
DefaultDisableAnnotationValidation = true
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// AnnotationsPrefix is the mutable attribute that the controller explicitly refers to
|
// AnnotationsPrefix is the mutable attribute that the controller explicitly refers to
|
||||||
AnnotationsPrefix = DefaultAnnotationsPrefix
|
AnnotationsPrefix = DefaultAnnotationsPrefix
|
||||||
|
// DisableAnnotationValidation is the mutable attribute for enabling or disabling the validation functions
|
||||||
|
DisableAnnotationValidation = DefaultDisableAnnotationValidation
|
||||||
)
|
)
|
||||||
|
|
||||||
// AnnotationGroup defines the group that this annotation may belong
|
// AnnotationGroup defines the group that this annotation may belong
|
||||||
|
@ -92,6 +95,7 @@ type Annotation struct {
|
||||||
type IngressAnnotation interface {
|
type IngressAnnotation interface {
|
||||||
Parse(ing *networking.Ingress) (interface{}, error)
|
Parse(ing *networking.Ingress) (interface{}, error)
|
||||||
GetDocumentation() AnnotationFields
|
GetDocumentation() AnnotationFields
|
||||||
|
Validate(anns map[string]string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type ingAnnotations map[string]string
|
type ingAnnotations map[string]string
|
||||||
|
@ -189,6 +193,23 @@ func GetAnnotationWithPrefix(suffix string) string {
|
||||||
return fmt.Sprintf("%v/%v", AnnotationsPrefix, suffix)
|
return fmt.Sprintf("%v/%v", AnnotationsPrefix, suffix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TrimAnnotationPrefix(annotation string) string {
|
||||||
|
return strings.TrimPrefix(annotation, AnnotationsPrefix+"/")
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringRiskToRisk(risk string) AnnotationRisk {
|
||||||
|
switch strings.ToLower(risk) {
|
||||||
|
case "critical":
|
||||||
|
return AnnotationRiskCritical
|
||||||
|
case "high":
|
||||||
|
return AnnotationRiskHigh
|
||||||
|
case "medium":
|
||||||
|
return AnnotationRiskMedium
|
||||||
|
default:
|
||||||
|
return AnnotationRiskLow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func normalizeString(input string) string {
|
func normalizeString(input string) string {
|
||||||
trimmedContent := []string{}
|
trimmedContent := []string{}
|
||||||
for _, line := range strings.Split(input, "\n") {
|
for _, line := range strings.Split(input, "\n") {
|
||||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||||
package parser
|
package parser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -25,7 +26,7 @@ import (
|
||||||
|
|
||||||
networking "k8s.io/api/networking/v1"
|
networking "k8s.io/api/networking/v1"
|
||||||
machineryvalidation "k8s.io/apimachinery/pkg/api/validation"
|
machineryvalidation "k8s.io/apimachinery/pkg/api/validation"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/errors"
|
ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
|
||||||
"k8s.io/ingress-nginx/internal/net"
|
"k8s.io/ingress-nginx/internal/net"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
)
|
)
|
||||||
|
@ -189,12 +190,12 @@ func checkAnnotation(name string, ing *networking.Ingress, fields AnnotationFiel
|
||||||
}
|
}
|
||||||
|
|
||||||
if ing == nil || len(ing.GetAnnotations()) == 0 {
|
if ing == nil || len(ing.GetAnnotations()) == 0 {
|
||||||
return "", errors.ErrMissingAnnotations
|
return "", ing_errors.ErrMissingAnnotations
|
||||||
}
|
}
|
||||||
|
|
||||||
annotationFullName := GetAnnotationWithPrefix(name)
|
annotationFullName := GetAnnotationWithPrefix(name)
|
||||||
if annotationFullName == "" {
|
if annotationFullName == "" {
|
||||||
return "", errors.ErrInvalidAnnotationName
|
return "", ing_errors.ErrInvalidAnnotationName
|
||||||
}
|
}
|
||||||
|
|
||||||
annotationValue := ing.GetAnnotations()[annotationFullName]
|
annotationValue := ing.GetAnnotations()[annotationFullName]
|
||||||
|
@ -213,13 +214,24 @@ func checkAnnotation(name string, ing *networking.Ingress, fields AnnotationFiel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We don't run validation against empty values
|
// We don't run validation against empty values
|
||||||
if annotationValue != "" {
|
if annotationValue != "" && !DisableAnnotationValidation {
|
||||||
if err := validateFunc(annotationValue); err != nil {
|
if err := validateFunc(annotationValue); err != nil {
|
||||||
klog.Warningf("validation error on ingress %s/%s: annotation %s contains invalid value %s", ing.GetNamespace(), ing.GetName(), name, annotationValue)
|
klog.Warningf("validation error on ingress %s/%s: annotation %s contains invalid value %s", ing.GetNamespace(), ing.GetName(), name, annotationValue)
|
||||||
return "", errors.NewValidationError(annotationFullName)
|
return "", ing_errors.NewValidationError(annotationFullName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return annotationFullName, nil
|
return annotationFullName, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CheckAnnotationRisk(annotations map[string]string, maxrisk AnnotationRisk, config AnnotationFields) error {
|
||||||
|
var err error
|
||||||
|
for annotation := range annotations {
|
||||||
|
annPure := TrimAnnotationPrefix(annotation)
|
||||||
|
if cfg, ok := config[annPure]; ok && cfg.Risk > maxrisk {
|
||||||
|
err = errors.Join(err, fmt.Errorf("annotation %s is too risky for environment", annotation))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
@ -221,3 +221,90 @@ func Test_checkAnnotation(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCheckAnnotationRisk(t *testing.T) {
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
annotations map[string]string
|
||||||
|
maxrisk AnnotationRisk
|
||||||
|
config AnnotationFields
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "high risk should not be accepted with maximum medium",
|
||||||
|
maxrisk: AnnotationRiskMedium,
|
||||||
|
annotations: map[string]string{
|
||||||
|
"nginx.ingress.kubernetes.io/bla": "blo",
|
||||||
|
"nginx.ingress.kubernetes.io/bli": "bl3",
|
||||||
|
},
|
||||||
|
config: AnnotationFields{
|
||||||
|
"bla": {
|
||||||
|
Risk: AnnotationRiskHigh,
|
||||||
|
},
|
||||||
|
"bli": {
|
||||||
|
Risk: AnnotationRiskMedium,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "high risk should be accepted with maximum critical",
|
||||||
|
maxrisk: AnnotationRiskCritical,
|
||||||
|
annotations: map[string]string{
|
||||||
|
"nginx.ingress.kubernetes.io/bla": "blo",
|
||||||
|
"nginx.ingress.kubernetes.io/bli": "bl3",
|
||||||
|
},
|
||||||
|
config: AnnotationFields{
|
||||||
|
"bla": {
|
||||||
|
Risk: AnnotationRiskHigh,
|
||||||
|
},
|
||||||
|
"bli": {
|
||||||
|
Risk: AnnotationRiskMedium,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "low risk should be accepted with maximum low",
|
||||||
|
maxrisk: AnnotationRiskLow,
|
||||||
|
annotations: map[string]string{
|
||||||
|
"nginx.ingress.kubernetes.io/bla": "blo",
|
||||||
|
"nginx.ingress.kubernetes.io/bli": "bl3",
|
||||||
|
},
|
||||||
|
config: AnnotationFields{
|
||||||
|
"bla": {
|
||||||
|
Risk: AnnotationRiskLow,
|
||||||
|
},
|
||||||
|
"bli": {
|
||||||
|
Risk: AnnotationRiskLow,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "critical risk should be accepted with maximum critical",
|
||||||
|
maxrisk: AnnotationRiskCritical,
|
||||||
|
annotations: map[string]string{
|
||||||
|
"nginx.ingress.kubernetes.io/bla": "blo",
|
||||||
|
"nginx.ingress.kubernetes.io/bli": "bl3",
|
||||||
|
},
|
||||||
|
config: AnnotationFields{
|
||||||
|
"bla": {
|
||||||
|
Risk: AnnotationRiskCritical,
|
||||||
|
},
|
||||||
|
"bli": {
|
||||||
|
Risk: AnnotationRiskCritical,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if err := CheckAnnotationRisk(tt.annotations, tt.maxrisk, tt.config); (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("CheckAnnotationRisk() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -66,3 +66,8 @@ func (a portInRedirect) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (a portInRedirect) GetDocumentation() parser.AnnotationFields {
|
func (a portInRedirect) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a portInRedirect) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, portsInRedirectAnnotations.Annotations)
|
||||||
|
}
|
|
@ -357,3 +357,8 @@ func (a proxy) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (a proxy) GetDocumentation() parser.AnnotationFields {
|
func (a proxy) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a proxy) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, proxyAnnotations.Annotations)
|
||||||
|
}
|
|
@ -259,3 +259,8 @@ func (p proxySSL) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (p proxySSL) GetDocumentation() parser.AnnotationFields {
|
func (p proxySSL) GetDocumentation() parser.AnnotationFields {
|
||||||
return p.annotationConfig.Annotations
|
return p.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a proxySSL) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, proxySSLAnnotation.Annotations)
|
||||||
|
}
|
|
@ -294,3 +294,8 @@ func encode(s string) string {
|
||||||
func (a ratelimit) GetDocumentation() parser.AnnotationFields {
|
func (a ratelimit) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a ratelimit) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, rateLimitAnnotations.Annotations)
|
||||||
|
}
|
|
@ -177,3 +177,8 @@ func isValidURL(s string) error {
|
||||||
func (a redirect) GetDocumentation() parser.AnnotationFields {
|
func (a redirect) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a redirect) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, redirectAnnotations.Annotations)
|
||||||
|
}
|
|
@ -208,3 +208,8 @@ func (a rewrite) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (a rewrite) GetDocumentation() parser.AnnotationFields {
|
func (a rewrite) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a rewrite) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, rewriteAnnotations.Annotations)
|
||||||
|
}
|
|
@ -68,3 +68,8 @@ func (s satisfy) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (s satisfy) GetDocumentation() parser.AnnotationFields {
|
func (s satisfy) GetDocumentation() parser.AnnotationFields {
|
||||||
return s.annotationConfig.Annotations
|
return s.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a satisfy) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, satisfyAnnotations.Annotations)
|
||||||
|
}
|
|
@ -62,3 +62,8 @@ func (a serverSnippet) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (a serverSnippet) GetDocumentation() parser.AnnotationFields {
|
func (a serverSnippet) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a serverSnippet) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, serverSnippetAnnotations.Annotations)
|
||||||
|
}
|
|
@ -68,3 +68,8 @@ func (s serviceUpstream) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (s serviceUpstream) GetDocumentation() parser.AnnotationFields {
|
func (s serviceUpstream) GetDocumentation() parser.AnnotationFields {
|
||||||
return s.annotationConfig.Annotations
|
return s.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a serviceUpstream) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, serviceUpstreamAnnotations.Annotations)
|
||||||
|
}
|
|
@ -297,3 +297,8 @@ func (a affinity) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (a affinity) GetDocumentation() parser.AnnotationFields {
|
func (a affinity) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a affinity) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, sessionAffinityAnnotations.Annotations)
|
||||||
|
}
|
|
@ -62,3 +62,8 @@ func (a snippet) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (a snippet) GetDocumentation() parser.AnnotationFields {
|
func (a snippet) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a snippet) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, configurationSnippetAnnotations.Annotations)
|
||||||
|
}
|
|
@ -103,3 +103,8 @@ func (sc sslCipher) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (sc sslCipher) GetDocumentation() parser.AnnotationFields {
|
func (sc sslCipher) GetDocumentation() parser.AnnotationFields {
|
||||||
return sc.annotationConfig.Annotations
|
return sc.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a sslCipher) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, sslCipherAnnotations.Annotations)
|
||||||
|
}
|
|
@ -65,3 +65,8 @@ func (a sslpt) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (a sslpt) GetDocumentation() parser.AnnotationFields {
|
func (a sslpt) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a sslpt) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, sslPassthroughAnnotations.Annotations)
|
||||||
|
}
|
|
@ -62,3 +62,8 @@ func (a streamSnippet) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (a streamSnippet) GetDocumentation() parser.AnnotationFields {
|
func (a streamSnippet) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a streamSnippet) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, streamSnippetAnnotations.Annotations)
|
||||||
|
}
|
|
@ -107,3 +107,8 @@ func (a upstreamhashby) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (a upstreamhashby) GetDocumentation() parser.AnnotationFields {
|
func (a upstreamhashby) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a upstreamhashby) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, upstreamHashByAnnotations.Annotations)
|
||||||
|
}
|
|
@ -63,3 +63,8 @@ func (a upstreamVhost) Parse(ing *networking.Ingress) (interface{}, error) {
|
||||||
func (a upstreamVhost) GetDocumentation() parser.AnnotationFields {
|
func (a upstreamVhost) GetDocumentation() parser.AnnotationFields {
|
||||||
return a.annotationConfig.Annotations
|
return a.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a upstreamVhost) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, upstreamVhostAnnotations.Annotations)
|
||||||
|
}
|
|
@ -61,3 +61,8 @@ func (cbbs xforwardedprefix) Parse(ing *networking.Ingress) (interface{}, error)
|
||||||
func (cbbs xforwardedprefix) GetDocumentation() parser.AnnotationFields {
|
func (cbbs xforwardedprefix) GetDocumentation() parser.AnnotationFields {
|
||||||
return cbbs.annotationConfig.Annotations
|
return cbbs.annotationConfig.Annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a xforwardedprefix) Validate(anns map[string]string) error {
|
||||||
|
maxrisk := parser.StringRiskToRisk(a.r.GetSecurityConfiguration().AnnotationsRisk)
|
||||||
|
return parser.CheckAnnotationRisk(anns, maxrisk, xForwardedForAnnotations.Annotations)
|
||||||
|
}
|
Loading…
Reference in a new issue