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 }