github.com/cilium/cilium@v1.16.2/pkg/policy/api/rule.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package api
     5  
     6  import (
     7  	"context"
     8  	"encoding/json"
     9  
    10  	"github.com/cilium/cilium/pkg/labels"
    11  )
    12  
    13  // AuthenticationMode is a string identifying a supported authentication type
    14  type AuthenticationMode string
    15  
    16  const (
    17  	AuthenticationModeDisabled   AuthenticationMode = "disabled" // Always succeeds
    18  	AuthenticationModeRequired   AuthenticationMode = "required" // Mutual TLS with SPIFFE as certificate provider by default
    19  	AuthenticationModeAlwaysFail AuthenticationMode = "test-always-fail"
    20  )
    21  
    22  // Authentication specifies the kind of cryptographic authentication required for the traffic to
    23  // be allowed.
    24  type Authentication struct {
    25  	// Mode is the required authentication mode for the allowed traffic, if any.
    26  	//
    27  	// +kubebuilder:validation:Enum=disabled;required;test-always-fail
    28  	// +kubebuilder:validation:Required
    29  	Mode AuthenticationMode `json:"mode"`
    30  }
    31  
    32  // DefaultDenyConfig expresses a policy's desired default mode for the subject
    33  // endpoints.
    34  type DefaultDenyConfig struct {
    35  	// Whether or not the endpoint should have a default-deny rule applied
    36  	// to ingress traffic.
    37  	//
    38  	// +kubebuilder:validation:Optional
    39  	Ingress *bool `json:"ingress,omitempty"`
    40  
    41  	// Whether or not the endpoint should have a default-deny rule applied
    42  	// to egress traffic.
    43  	//
    44  	// +kubebuilder:validation:Optional
    45  	Egress *bool `json:"egress,omitempty"`
    46  }
    47  
    48  // Rule is a policy rule which must be applied to all endpoints which match the
    49  // labels contained in the endpointSelector
    50  //
    51  // Each rule is split into an ingress section which contains all rules
    52  // applicable at ingress, and an egress section applicable at egress. For rule
    53  // types such as `L4Rule` and `CIDR` which can be applied at both ingress and
    54  // egress, both ingress and egress side have to either specifically allow the
    55  // connection or one side has to be omitted.
    56  //
    57  // Either ingress, egress, or both can be provided. If both ingress and egress
    58  // are omitted, the rule has no effect.
    59  //
    60  // +deepequal-gen:private-method=true
    61  type Rule struct {
    62  	// EndpointSelector selects all endpoints which should be subject to
    63  	// this rule. EndpointSelector and NodeSelector cannot be both empty and
    64  	// are mutually exclusive.
    65  	//
    66  	// +kubebuilder:validation:OneOf
    67  	EndpointSelector EndpointSelector `json:"endpointSelector,omitempty"`
    68  
    69  	// NodeSelector selects all nodes which should be subject to this rule.
    70  	// EndpointSelector and NodeSelector cannot be both empty and are mutually
    71  	// exclusive. Can only be used in CiliumClusterwideNetworkPolicies.
    72  	//
    73  	// +kubebuilder:validation:OneOf
    74  	NodeSelector EndpointSelector `json:"nodeSelector,omitempty"`
    75  
    76  	// Ingress is a list of IngressRule which are enforced at ingress.
    77  	// If omitted or empty, this rule does not apply at ingress.
    78  	//
    79  	// +kubebuilder:validation:Optional
    80  	Ingress []IngressRule `json:"ingress,omitempty"`
    81  
    82  	// IngressDeny is a list of IngressDenyRule which are enforced at ingress.
    83  	// Any rule inserted here will be denied regardless of the allowed ingress
    84  	// rules in the 'ingress' field.
    85  	// If omitted or empty, this rule does not apply at ingress.
    86  	//
    87  	// +kubebuilder:validation:Optional
    88  	IngressDeny []IngressDenyRule `json:"ingressDeny,omitempty"`
    89  
    90  	// Egress is a list of EgressRule which are enforced at egress.
    91  	// If omitted or empty, this rule does not apply at egress.
    92  	//
    93  	// +kubebuilder:validation:Optional
    94  	Egress []EgressRule `json:"egress,omitempty"`
    95  
    96  	// EgressDeny is a list of EgressDenyRule which are enforced at egress.
    97  	// Any rule inserted here will be denied regardless of the allowed egress
    98  	// rules in the 'egress' field.
    99  	// If omitted or empty, this rule does not apply at egress.
   100  	//
   101  	// +kubebuilder:validation:Optional
   102  	EgressDeny []EgressDenyRule `json:"egressDeny,omitempty"`
   103  
   104  	// Labels is a list of optional strings which can be used to
   105  	// re-identify the rule or to store metadata. It is possible to lookup
   106  	// or delete strings based on labels. Labels are not required to be
   107  	// unique, multiple rules can have overlapping or identical labels.
   108  	//
   109  	// +kubebuilder:validation:Optional
   110  	Labels labels.LabelArray `json:"labels,omitempty"`
   111  
   112  	// EnableDefaultDeny determines whether this policy configures the
   113  	// subject endpoint(s) to have a default deny mode. If enabled,
   114  	// this causes all traffic not explicitly allowed by a network policy
   115  	// to be dropped.
   116  	//
   117  	// If not specified, the default is true for each traffic direction
   118  	// that has rules, and false otherwise. For example, if a policy
   119  	// only has Ingress or IngressDeny rules, then the default for
   120  	// ingress is true and egress is false.
   121  	//
   122  	// If multiple policies apply to an endpoint, that endpoint's default deny
   123  	// will be enabled if any policy requests it.
   124  	//
   125  	// This is useful for creating broad-based network policies that will not
   126  	// cause endpoints to enter default-deny mode.
   127  	//
   128  	// +kubebuilder:validation:Optional
   129  	EnableDefaultDeny DefaultDenyConfig `json:"enableDefaultDeny,omitempty"`
   130  
   131  	// Description is a free form string, it can be used by the creator of
   132  	// the rule to store human readable explanation of the purpose of this
   133  	// rule. Rules cannot be identified by comment.
   134  	//
   135  	// +kubebuilder:validation:Optional
   136  	Description string `json:"description,omitempty"`
   137  }
   138  
   139  // MarshalJSON returns the JSON encoding of Rule r. We need to overwrite it to
   140  // enforce omitempty on the EndpointSelector nested structures.
   141  func (r *Rule) MarshalJSON() ([]byte, error) {
   142  	type common struct {
   143  		Ingress           []IngressRule     `json:"ingress,omitempty"`
   144  		IngressDeny       []IngressDenyRule `json:"ingressDeny,omitempty"`
   145  		Egress            []EgressRule      `json:"egress,omitempty"`
   146  		EgressDeny        []EgressDenyRule  `json:"egressDeny,omitempty"`
   147  		Labels            labels.LabelArray `json:"labels,omitempty"`
   148  		EnableDefaultDeny DefaultDenyConfig `json:"enableDefaultDeny,omitempty"`
   149  		Description       string            `json:"description,omitempty"`
   150  	}
   151  
   152  	var a interface{}
   153  	ruleCommon := common{
   154  		Ingress:           r.Ingress,
   155  		IngressDeny:       r.IngressDeny,
   156  		Egress:            r.Egress,
   157  		EgressDeny:        r.EgressDeny,
   158  		Labels:            r.Labels,
   159  		EnableDefaultDeny: r.EnableDefaultDeny,
   160  		Description:       r.Description,
   161  	}
   162  
   163  	// Only one of endpointSelector or nodeSelector is permitted.
   164  	switch {
   165  	case r.EndpointSelector.LabelSelector != nil:
   166  		a = struct {
   167  			EndpointSelector EndpointSelector `json:"endpointSelector,omitempty"`
   168  			common
   169  		}{
   170  			EndpointSelector: r.EndpointSelector,
   171  			common:           ruleCommon,
   172  		}
   173  	case r.NodeSelector.LabelSelector != nil:
   174  		a = struct {
   175  			NodeSelector EndpointSelector `json:"nodeSelector,omitempty"`
   176  			common
   177  		}{
   178  			NodeSelector: r.NodeSelector,
   179  			common:       ruleCommon,
   180  		}
   181  	}
   182  
   183  	return json.Marshal(a)
   184  }
   185  
   186  func (r *Rule) DeepEqual(o *Rule) bool {
   187  	switch {
   188  	case (r == nil) != (o == nil):
   189  		return false
   190  	case (r == nil) && (o == nil):
   191  		return true
   192  	}
   193  	return r.deepEqual(o)
   194  }
   195  
   196  // NewRule builds a new rule with no selector and no policy.
   197  func NewRule() *Rule {
   198  	return &Rule{}
   199  }
   200  
   201  // WithEndpointSelector configures the Rule with the specified selector.
   202  func (r *Rule) WithEndpointSelector(es EndpointSelector) *Rule {
   203  	r.EndpointSelector = es
   204  	return r
   205  }
   206  
   207  // WithIngressRules configures the Rule with the specified rules.
   208  func (r *Rule) WithIngressRules(rules []IngressRule) *Rule {
   209  	r.Ingress = rules
   210  	return r
   211  }
   212  
   213  // WithIngressDenyRules configures the Rule with the specified rules.
   214  func (r *Rule) WithIngressDenyRules(rules []IngressDenyRule) *Rule {
   215  	r.IngressDeny = rules
   216  	return r
   217  }
   218  
   219  // WithEgressRules configures the Rule with the specified rules.
   220  func (r *Rule) WithEgressRules(rules []EgressRule) *Rule {
   221  	r.Egress = rules
   222  	return r
   223  }
   224  
   225  // WithEgressDenyRules configures the Rule with the specified rules.
   226  func (r *Rule) WithEgressDenyRules(rules []EgressDenyRule) *Rule {
   227  	r.EgressDeny = rules
   228  	return r
   229  }
   230  
   231  // WithLabels configures the Rule with the specified labels metadata.
   232  func (r *Rule) WithLabels(labels labels.LabelArray) *Rule {
   233  	r.Labels = labels
   234  	return r
   235  }
   236  
   237  // WithDescription configures the Rule with the specified description metadata.
   238  func (r *Rule) WithDescription(desc string) *Rule {
   239  	r.Description = desc
   240  	return r
   241  }
   242  
   243  // RequiresDerivative it return true if the rule has a derivative rule.
   244  func (r *Rule) RequiresDerivative() bool {
   245  	for _, rule := range r.Egress {
   246  		if rule.RequiresDerivative() {
   247  			return true
   248  		}
   249  	}
   250  	for _, rule := range r.EgressDeny {
   251  		if rule.RequiresDerivative() {
   252  			return true
   253  		}
   254  	}
   255  	for _, rule := range r.Ingress {
   256  		if rule.RequiresDerivative() {
   257  			return true
   258  		}
   259  	}
   260  	for _, rule := range r.IngressDeny {
   261  		if rule.RequiresDerivative() {
   262  			return true
   263  		}
   264  	}
   265  	return false
   266  }
   267  
   268  // CreateDerivative will return a new Rule with the new data based gather
   269  // by the rules that autogenerated new Rule
   270  func (r *Rule) CreateDerivative(ctx context.Context) (*Rule, error) {
   271  	newRule := r.DeepCopy()
   272  	newRule.Egress = []EgressRule{}
   273  	newRule.EgressDeny = []EgressDenyRule{}
   274  	newRule.Ingress = []IngressRule{}
   275  	newRule.IngressDeny = []IngressDenyRule{}
   276  
   277  	for _, egressRule := range r.Egress {
   278  		derivativeEgressRule, err := egressRule.CreateDerivative(ctx)
   279  		if err != nil {
   280  			return newRule, err
   281  		}
   282  		newRule.Egress = append(newRule.Egress, *derivativeEgressRule)
   283  	}
   284  
   285  	for _, egressDenyRule := range r.EgressDeny {
   286  		derivativeEgressDenyRule, err := egressDenyRule.CreateDerivative(ctx)
   287  		if err != nil {
   288  			return newRule, err
   289  		}
   290  		newRule.EgressDeny = append(newRule.EgressDeny, *derivativeEgressDenyRule)
   291  	}
   292  
   293  	for _, ingressRule := range r.Ingress {
   294  		derivativeIngressRule, err := ingressRule.CreateDerivative(ctx)
   295  		if err != nil {
   296  			return newRule, err
   297  		}
   298  		newRule.Ingress = append(newRule.Ingress, *derivativeIngressRule)
   299  	}
   300  
   301  	for _, ingressDenyRule := range r.IngressDeny {
   302  		derivativeDenyIngressRule, err := ingressDenyRule.CreateDerivative(ctx)
   303  		if err != nil {
   304  			return newRule, err
   305  		}
   306  		newRule.IngressDeny = append(newRule.IngressDeny, *derivativeDenyIngressRule)
   307  	}
   308  	return newRule, nil
   309  }