github.com/nginxinc/kubernetes-ingress@v1.12.5/internal/k8s/appprotect/app_protect_resources.go (about)

     1  package appprotect
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"regexp"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    11  )
    12  
    13  var appProtectPolicyRequiredFields = [][]string{
    14  	{"spec", "policy"},
    15  }
    16  
    17  var appProtectLogConfRequiredFields = [][]string{
    18  	{"spec", "content"},
    19  	{"spec", "filter"},
    20  }
    21  
    22  var appProtectUserSigRequiredSlices = [][]string{
    23  	{"spec", "signatures"},
    24  }
    25  
    26  func validateRequiredFields(obj *unstructured.Unstructured, fieldsList [][]string) error {
    27  	for _, fields := range fieldsList {
    28  		field, found, err := unstructured.NestedMap(obj.Object, fields...)
    29  		if err != nil {
    30  			return fmt.Errorf("Error checking for required field %v: %w", field, err)
    31  		}
    32  		if !found {
    33  			return fmt.Errorf("Required field %v not found", field)
    34  		}
    35  	}
    36  	return nil
    37  }
    38  
    39  func validateRequiredSlices(obj *unstructured.Unstructured, fieldsList [][]string) error {
    40  	for _, fields := range fieldsList {
    41  		field, found, err := unstructured.NestedSlice(obj.Object, fields...)
    42  		if err != nil {
    43  			return fmt.Errorf("Error checking for required field %v: %w", field, err)
    44  		}
    45  		if !found {
    46  			return fmt.Errorf("Required field %v not found", field)
    47  		}
    48  	}
    49  	return nil
    50  }
    51  
    52  // validateAppProtectPolicy validates Policy resource
    53  func validateAppProtectPolicy(policy *unstructured.Unstructured) error {
    54  	polName := policy.GetName()
    55  
    56  	err := validateRequiredFields(policy, appProtectPolicyRequiredFields)
    57  	if err != nil {
    58  		return fmt.Errorf("Error validating App Protect Policy %v: %w", polName, err)
    59  	}
    60  
    61  	return nil
    62  }
    63  
    64  // validateAppProtectLogConf validates LogConfiguration resource
    65  func validateAppProtectLogConf(logConf *unstructured.Unstructured) error {
    66  	lcName := logConf.GetName()
    67  	err := validateRequiredFields(logConf, appProtectLogConfRequiredFields)
    68  	if err != nil {
    69  		return fmt.Errorf("Error validating App Protect Log Configuration %v: %w", lcName, err)
    70  	}
    71  
    72  	return nil
    73  }
    74  
    75  var (
    76  	logDstEx     = regexp.MustCompile(`(?:syslog:server=((?:\d{1,3}\.){3}\d{1,3}|localhost):\d{1,5})|stderr|(?:\/[\S]+)+`)
    77  	logDstFileEx = regexp.MustCompile(`(?:\/[\S]+)+`)
    78  )
    79  
    80  // ValidateAppProtectLogDestination validates destination for log configuration
    81  func ValidateAppProtectLogDestination(dstAntn string) error {
    82  	errormsg := "Error parsing App Protect Log config: Destination must follow format: syslog:server=<ip-address | localhost>:<port> or stderr or absolute path to file"
    83  	if !logDstEx.MatchString(dstAntn) {
    84  		return fmt.Errorf("%s Log Destination did not follow format", errormsg)
    85  	}
    86  	if dstAntn == "stderr" {
    87  		return nil
    88  	}
    89  
    90  	if logDstFileEx.MatchString(dstAntn) {
    91  		return nil
    92  	}
    93  
    94  	dstchunks := strings.Split(dstAntn, ":")
    95  
    96  	// This error can be ignored since the regex check ensures this string will be parsable
    97  	port, _ := strconv.Atoi(dstchunks[2])
    98  
    99  	if port > 65535 || port < 1 {
   100  		return fmt.Errorf("Error parsing port: %v not a valid port number", port)
   101  	}
   102  
   103  	ipstr := strings.Split(dstchunks[1], "=")[1]
   104  	if ipstr == "localhost" {
   105  		return nil
   106  	}
   107  
   108  	if net.ParseIP(ipstr) == nil {
   109  		return fmt.Errorf("Error parsing host: %v is not a valid ip address", ipstr)
   110  	}
   111  
   112  	return nil
   113  }
   114  
   115  // ParseResourceReferenceAnnotation returns a namespace/name string
   116  func ParseResourceReferenceAnnotation(ns, antn string) string {
   117  	if !strings.Contains(antn, "/") {
   118  		return ns + "/" + antn
   119  	}
   120  	return antn
   121  }
   122  
   123  // ParseResourceReferenceAnnotationList returns a slice of ns/names strings
   124  func ParseResourceReferenceAnnotationList(ns, annotations string) []string {
   125  	var out []string
   126  	for _, antn := range strings.Split(annotations, ",") {
   127  		out = append(out, ParseResourceReferenceAnnotation(ns, antn))
   128  	}
   129  	return out
   130  }
   131  
   132  func validateAppProtectUserSig(userSig *unstructured.Unstructured) error {
   133  	sigName := userSig.GetName()
   134  	err := validateRequiredSlices(userSig, appProtectUserSigRequiredSlices)
   135  	if err != nil {
   136  		return fmt.Errorf("Error validating App Protect User Signature %v: %w", sigName, err)
   137  	}
   138  
   139  	return nil
   140  }
   141  
   142  // GetNsName gets the key of a resource in the format: "resNamespace/resName"
   143  func GetNsName(obj *unstructured.Unstructured) string {
   144  	return obj.GetNamespace() + "/" + obj.GetName()
   145  }