github.com/imran-kn/cilium-fork@v1.6.9/pkg/policy/api/egress.go (about)

     1  // Copyright 2016-2019 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package api
    16  
    17  import (
    18  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    19  )
    20  
    21  // EgressRule contains all rule types which can be applied at egress, i.e.
    22  // network traffic that originates inside the endpoint and exits the endpoint
    23  // selected by the endpointSelector.
    24  //
    25  // - All members of this structure are optional. If omitted or empty, the
    26  //   member will have no effect on the rule.
    27  //
    28  // - For now, combining ToPorts and ToCIDR in the same rule is not supported
    29  //   and such rules will be rejected. In the future, this will be supported and
    30  //   if if multiple members of the structure are specified, then all members
    31  //   must match in order for the rule to take effect.
    32  type EgressRule struct {
    33  	// ToEndpoints is a list of endpoints identified by an EndpointSelector to
    34  	// which the endpoints subject to the rule are allowed to communicate.
    35  	//
    36  	// Example:
    37  	// Any endpoint with the label "role=frontend" can communicate with any
    38  	// endpoint carrying the label "role=backend".
    39  	//
    40  	// +optional
    41  	ToEndpoints []EndpointSelector `json:"toEndpoints,omitempty"`
    42  
    43  	// ToRequires is a list of additional constraints which must be met
    44  	// in order for the selected endpoints to be able to connect to other
    45  	// endpoints. These additional constraints do no by itself grant access
    46  	// privileges and must always be accompanied with at least one matching
    47  	// ToEndpoints.
    48  	//
    49  	// Example:
    50  	// Any Endpoint with the label "team=A" requires any endpoint to which it
    51  	// communicates to also carry the label "team=A".
    52  	//
    53  	// +optional
    54  	ToRequires []EndpointSelector `json:"toRequires,omitempty"`
    55  
    56  	// ToPorts is a list of destination ports identified by port number and
    57  	// protocol which the endpoint subject to the rule is allowed to
    58  	// connect to.
    59  	//
    60  	// Example:
    61  	// Any endpoint with the label "role=frontend" is allowed to initiate
    62  	// connections to destination port 8080/tcp
    63  	//
    64  	// +optional
    65  	ToPorts []PortRule `json:"toPorts,omitempty"`
    66  
    67  	// ToCIDR is a list of IP blocks which the endpoint subject to the rule
    68  	// is allowed to initiate connections. Only connections destined for
    69  	// outside of the cluster and not targeting the host will be subject
    70  	// to CIDR rules.  This will match on the destination IP address of
    71  	// outgoing connections. Adding a prefix into ToCIDR or into ToCIDRSet
    72  	// with no ExcludeCIDRs is equivalent. Overlaps are allowed between
    73  	// ToCIDR and ToCIDRSet.
    74  	//
    75  	// Example:
    76  	// Any endpoint with the label "app=database-proxy" is allowed to
    77  	// initiate connections to 10.2.3.0/24
    78  	//
    79  	// +optional
    80  	ToCIDR CIDRSlice `json:"toCIDR,omitempty"`
    81  
    82  	// ToCIDRSet is a list of IP blocks which the endpoint subject to the rule
    83  	// is allowed to initiate connections to in addition to connections
    84  	// which are allowed via ToEndpoints, along with a list of subnets contained
    85  	// within their corresponding IP block to which traffic should not be
    86  	// allowed. This will match on the destination IP address of outgoing
    87  	// connections. Adding a prefix into ToCIDR or into ToCIDRSet with no
    88  	// ExcludeCIDRs is equivalent. Overlaps are allowed between ToCIDR and
    89  	// ToCIDRSet.
    90  	//
    91  	// Example:
    92  	// Any endpoint with the label "app=database-proxy" is allowed to
    93  	// initiate connections to 10.2.3.0/24 except from IPs in subnet 10.2.3.0/28.
    94  	//
    95  	// +optional
    96  	ToCIDRSet CIDRRuleSlice `json:"toCIDRSet,omitempty"`
    97  
    98  	// ToEntities is a list of special entities to which the endpoint subject
    99  	// to the rule is allowed to initiate connections. Supported entities are
   100  	// `world`, `cluster` and `host`
   101  	//
   102  	// +optional
   103  	ToEntities EntitySlice `json:"toEntities,omitempty"`
   104  
   105  	// ToServices is a list of services to which the endpoint subject
   106  	// to the rule is allowed to initiate connections.
   107  	//
   108  	// Example:
   109  	// Any endpoint with the label "app=backend-app" is allowed to
   110  	// initiate connections to all cidrs backing the "external-service" service
   111  	// + optional
   112  	ToServices []Service `json:"toServices,omitempty"`
   113  
   114  	// ToFQDN allows whitelisting DNS names in place of IPs. The IPs that result
   115  	// from DNS resolution of `ToFQDN.MatchName`s are added to the same
   116  	// EgressRule object as ToCIDRSet entries, and behave accordingly. Any L4 and
   117  	// L7 rules within this EgressRule will also apply to these IPs.
   118  	// The DNS -> IP mapping is re-resolved periodically from within the
   119  	// cilium-agent, and the IPs in the DNS response are effected in the policy
   120  	// for selected pods as-is (i.e. the list of IPs is not modified in any way).
   121  	// Note: An explicit rule to allow for DNS traffic is needed for the pods, as
   122  	// ToFQDN counts as an egress rule and will enforce egress policy when
   123  	// PolicyEnforcment=default.
   124  	// Note: If the resolved IPs are IPs within the kubernetes cluster, the
   125  	// ToFQDN rule will not apply to that IP.
   126  	// Note: ToFQDN cannot occur in the same policy as other To* rules.
   127  	//
   128  	// The current implementation has a number of limitations:
   129  	// - The DNS resolution originates from cilium-agent, and not from the pods.
   130  	// Differences between the responses seen by cilium agent and a particular
   131  	// pod will whitelist the incorrect IP.
   132  	// - DNS TTLs are ignored, and cilium-agent will repoll on a short interval
   133  	// (5 seconds). Each change to the DNS data will trigger a policy
   134  	// regeneration. This may result in delayed updates to the policy for an
   135  	// endpoint when the data changes often or the system is under load.
   136  	//
   137  	// +optional
   138  	ToFQDNs FQDNSelectorSlice `json:"toFQDNs,omitempty"`
   139  
   140  	// ToGroups is a directive that allows the integration with multiple outside
   141  	// providers. Currently, only AWS is supported, and the rule can select by
   142  	// multiple sub directives:
   143  	//
   144  	// Example:
   145  	// toGroups:
   146  	// - aws:
   147  	//     securityGroupsIds:
   148  	//     - 'sg-XXXXXXXXXXXXX'
   149  	// +optional
   150  	ToGroups []ToGroups `json:"toGroups,omitempty"`
   151  
   152  	// TODO: Move this to the policy package (https://github.com/cilium/cilium/issues/8353)
   153  	aggregatedSelectors EndpointSelectorSlice
   154  }
   155  
   156  // SetAggregatedSelectors creates a single slice containing all of the following
   157  // fields within the EgressRule, converted to EndpointSelector, to be stored
   158  // within the EgressRule for easy lookup while performing policy evaluation
   159  // for the rule:
   160  // * ToEntities
   161  // * ToCIDR
   162  // * ToCIDRSet
   163  // * ToFQDNs
   164  //
   165  // ToEndpoints is not aggregated due to requirement folding in
   166  // GetDestinationEndpointSelectorsWithRequirements()
   167  func (e *EgressRule) SetAggregatedSelectors() {
   168  	res := make(EndpointSelectorSlice, 0, len(e.ToEntities)+len(e.ToCIDR)+len(e.ToCIDRSet)+len(e.ToFQDNs))
   169  	res = append(res, e.ToEntities.GetAsEndpointSelectors()...)
   170  	res = append(res, e.ToCIDR.GetAsEndpointSelectors()...)
   171  	res = append(res, e.ToCIDRSet.GetAsEndpointSelectors()...)
   172  	res = append(res, e.ToFQDNs.GetAsEndpointSelectors()...)
   173  	// Goroutines can race setting this, but they will all compute
   174  	// the same result, so it does not matter.
   175  	e.aggregatedSelectors = res
   176  }
   177  
   178  // GetDestinationEndpointSelectorsWithRequirements returns a slice of endpoints selectors covering
   179  // all L3 source selectors of the ingress rule
   180  func (e *EgressRule) GetDestinationEndpointSelectorsWithRequirements(requirements []metav1.LabelSelectorRequirement) EndpointSelectorSlice {
   181  	if e.aggregatedSelectors == nil {
   182  		e.SetAggregatedSelectors()
   183  	}
   184  	res := make(EndpointSelectorSlice, 0, len(e.ToEndpoints)+len(e.aggregatedSelectors))
   185  
   186  	if len(requirements) > 0 && len(e.ToEndpoints) > 0 {
   187  		for idx := range e.ToEndpoints {
   188  			sel := *e.ToEndpoints[idx].DeepCopy()
   189  			sel.MatchExpressions = append(sel.MatchExpressions, requirements...)
   190  			sel.SyncRequirementsWithLabelSelector()
   191  			// Even though this string is deep copied, we need to override it
   192  			// because we are updating the contents of the MatchExpressions.
   193  			sel.cachedLabelSelectorString = sel.LabelSelector.String()
   194  			res = append(res, sel)
   195  		}
   196  	} else {
   197  		res = append(res, e.ToEndpoints...)
   198  	}
   199  	return append(res, e.aggregatedSelectors...)
   200  }
   201  
   202  // IsLabelBased returns true whether the L3 destination endpoints are selected
   203  // based on labels, i.e. either by setting ToEndpoints or ToEntities, or not
   204  // setting any To field.
   205  func (e *EgressRule) IsLabelBased() bool {
   206  	return len(e.ToRequires)+len(e.ToServices)+len(e.ToFQDNs) == 0
   207  }
   208  
   209  // RequiresDerivative returns true when the EgressRule contains sections that
   210  // need a derivative policy created in order to be enforced (e.g. ToGroups).
   211  func (e *EgressRule) RequiresDerivative() bool {
   212  	return len(e.ToGroups) > 0
   213  }
   214  
   215  // CreateDerivative will return a new rule based on the data gathered by the
   216  // rules that creates a new derivative policy.
   217  // In the case of ToGroups will call outside using the groups callback and this
   218  // function can take a bit of time.
   219  func (e *EgressRule) CreateDerivative() (*EgressRule, error) {
   220  	newRule := e.DeepCopy()
   221  	if !e.RequiresDerivative() {
   222  		return newRule, nil
   223  	}
   224  	newRule.ToCIDRSet = CIDRRuleSlice{}
   225  	for _, group := range e.ToGroups {
   226  		cidrSet, err := group.GetCidrSet()
   227  		if err != nil {
   228  			return &EgressRule{}, err
   229  		}
   230  		if len(cidrSet) == 0 {
   231  			return &EgressRule{}, nil
   232  		}
   233  		newRule.ToCIDRSet = append(e.ToCIDRSet, cidrSet...)
   234  	}
   235  	newRule.ToGroups = nil
   236  	e.SetAggregatedSelectors()
   237  	return newRule, nil
   238  }