github.com/looshlee/beatles@v0.0.0-20220727174639-742810ab631c/pkg/identity/numericidentity.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 identity 16 17 import ( 18 "errors" 19 "fmt" 20 "strconv" 21 22 api "github.com/cilium/cilium/pkg/k8s/apis/cilium.io" 23 "github.com/cilium/cilium/pkg/labels" 24 "github.com/cilium/cilium/pkg/metrics" 25 "github.com/cilium/cilium/pkg/option" 26 ) 27 28 const ( 29 // ClusterIDShift specifies the number of bits the cluster ID will be 30 // shifted 31 ClusterIDShift = 16 32 33 // LocalIdentityFlag is the bit in the numeric identity that identifies 34 // a numeric identity to have local scope 35 LocalIdentityFlag = NumericIdentity(1 << 24) 36 37 // MinimalNumericIdentity represents the minimal numeric identity not 38 // used for reserved purposes. 39 MinimalNumericIdentity = NumericIdentity(256) 40 41 // MinimalAllocationIdentity is the minimum numeric identity handed out 42 // by the identity allocator. 43 MinimalAllocationIdentity = MinimalNumericIdentity 44 45 // MaximumAllocationIdentity is the maximum numeric identity handed out 46 // by the identity allocator 47 MaximumAllocationIdentity = NumericIdentity(^uint16(0)) 48 49 // UserReservedNumericIdentity represents the minimal numeric identity that 50 // can be used by users for reserved purposes. 51 UserReservedNumericIdentity = NumericIdentity(128) 52 53 // InvalidIdentity is the identity assigned if the identity is invalid 54 // or not determined yet 55 InvalidIdentity = NumericIdentity(0) 56 ) 57 58 const ( 59 // IdentityUnknown represents an unknown identity 60 IdentityUnknown NumericIdentity = iota 61 62 // ReservedIdentityHost represents the local host 63 ReservedIdentityHost 64 65 // ReservedIdentityWorld represents any endpoint outside of the cluster 66 ReservedIdentityWorld 67 68 // ReservedIdentityUnmanaged represents unmanaged endpoints. 69 ReservedIdentityUnmanaged 70 71 // ReservedIdentityHealth represents the local cilium-health endpoint 72 ReservedIdentityHealth 73 74 // ReservedIdentityInit is the identity given to endpoints that have not 75 // received any labels yet. 76 ReservedIdentityInit 77 78 // -------------------------------------------------------------- 79 // Special identities for well-known cluster components 80 81 // ReservedETCDOperator is the reserved identity used for the etcd-operator 82 // managed by Cilium. 83 ReservedETCDOperator NumericIdentity = 100 84 85 // ReservedCiliumKVStore is the reserved identity used for the kvstore 86 // managed by Cilium (etcd-operator). 87 ReservedCiliumKVStore NumericIdentity = 101 88 89 // ReservedKubeDNS is the reserved identity used for kube-dns. 90 ReservedKubeDNS NumericIdentity = 102 91 92 // ReservedEKSKubeDNS is the reserved identity used for kube-dns on EKS 93 ReservedEKSKubeDNS NumericIdentity = 103 94 95 // ReservedCoreDNS is the reserved identity used for CoreDNS 96 ReservedCoreDNS NumericIdentity = 104 97 98 // ReservedCiliumOperator is the reserved identity used for the Cilium operator 99 ReservedCiliumOperator NumericIdentity = 105 100 101 // ReservedEKSCoreDNS is the reserved identity used for CoreDNS on EKS 102 ReservedEKSCoreDNS NumericIdentity = 106 103 104 // ReservedCiliumEtcdOperator is the reserved identity used for the Cilium etcd operator 105 ReservedCiliumEtcdOperator NumericIdentity = 107 106 ) 107 108 type wellKnownIdentities map[NumericIdentity]wellKnownIdentity 109 110 // wellKnownIdentitity is an identity for well-known security labels for which 111 // a well-known numeric identity is reserved to avoid requiring a cluster wide 112 // setup. Examples of this include kube-dns and the etcd-operator. 113 type wellKnownIdentity struct { 114 identity *Identity 115 labelArray labels.LabelArray 116 } 117 118 func (w wellKnownIdentities) add(i NumericIdentity, lbls []string) { 119 labelMap := labels.NewLabelsFromModel(lbls) 120 identity := NewIdentity(i, labelMap) 121 w[i] = wellKnownIdentity{ 122 identity: NewIdentity(i, labelMap), 123 labelArray: labelMap.LabelArray(), 124 } 125 126 ReservedIdentityCache[i] = identity 127 metrics.IdentityCount.Inc() 128 } 129 130 func (w wellKnownIdentities) LookupByLabels(lbls labels.Labels) *Identity { 131 for _, i := range w { 132 if lbls.Equals(i.identity.Labels) { 133 return i.identity 134 } 135 } 136 137 return nil 138 } 139 140 func (w wellKnownIdentities) lookupByNumericIdentity(identity NumericIdentity) *Identity { 141 wki, ok := w[identity] 142 if !ok { 143 return nil 144 } 145 return wki.identity 146 } 147 148 // InitWellKnownIdentities establishes all well-known identities 149 func InitWellKnownIdentities() { 150 // Derive the namespace in which the Cilium components are running 151 namespace := option.Config.K8sNamespace 152 153 // etcd-operator labels 154 // k8s:io.cilium.k8s.policy.serviceaccount=cilium-etcd-sa 155 // k8s:io.kubernetes.pod.namespace=<NAMESPACE> 156 // k8s:io.cilium/app=etcd-operator 157 // k8s:io.cilium.k8s.policy.cluster=default 158 WellKnown.add(ReservedETCDOperator, []string{ 159 "k8s:io.cilium/app=etcd-operator", 160 fmt.Sprintf("k8s:%s=%s", api.PodNamespaceLabel, namespace), 161 fmt.Sprintf("k8s:%s=cilium-etcd-sa", api.PolicyLabelServiceAccount), 162 fmt.Sprintf("k8s:%s=%s", api.PolicyLabelCluster, option.Config.ClusterName), 163 }) 164 165 // cilium-etcd labels 166 // k8s:app=etcd 167 // k8s:io.cilium/app=etcd-operator 168 // k8s:etcd_cluster=cilium-etcd 169 // k8s:io.cilium.k8s.policy.serviceaccount=default 170 // k8s:io.kubernetes.pod.namespace=<NAMESPACE> 171 // k8s:io.cilium.k8s.policy.cluster=default 172 // these 2 labels are ignored by cilium-agent as they can change over time 173 // container:annotation.etcd.version=3.3.9 174 // k8s:etcd_node=cilium-etcd-6snk6vsjcm 175 WellKnown.add(ReservedCiliumKVStore, []string{ 176 "k8s:app=etcd", 177 "k8s:etcd_cluster=cilium-etcd", 178 "k8s:io.cilium/app=etcd-operator", 179 fmt.Sprintf("k8s:%s=%s", api.PodNamespaceLabel, namespace), 180 fmt.Sprintf("k8s:%s=default", api.PolicyLabelServiceAccount), 181 fmt.Sprintf("k8s:%s=%s", api.PolicyLabelCluster, option.Config.ClusterName), 182 }) 183 184 // kube-dns labels 185 // k8s:io.cilium.k8s.policy.serviceaccount=kube-dns 186 // k8s:io.kubernetes.pod.namespace=kube-system 187 // k8s:k8s-app=kube-dns 188 // k8s:io.cilium.k8s.policy.cluster=default 189 WellKnown.add(ReservedKubeDNS, []string{ 190 "k8s:k8s-app=kube-dns", 191 fmt.Sprintf("k8s:%s=kube-system", api.PodNamespaceLabel), 192 fmt.Sprintf("k8s:%s=kube-dns", api.PolicyLabelServiceAccount), 193 fmt.Sprintf("k8s:%s=%s", api.PolicyLabelCluster, option.Config.ClusterName), 194 }) 195 196 // kube-dns EKS labels 197 // k8s:io.cilium.k8s.policy.serviceaccount=kube-dns 198 // k8s:io.kubernetes.pod.namespace=kube-system 199 // k8s:k8s-app=kube-dns 200 // k8s:io.cilium.k8s.policy.cluster=default 201 // k8s:eks.amazonaws.com/component=kube-dns 202 WellKnown.add(ReservedEKSKubeDNS, []string{ 203 "k8s:k8s-app=kube-dns", 204 "k8s:eks.amazonaws.com/component=kube-dns", 205 fmt.Sprintf("k8s:%s=kube-system", api.PodNamespaceLabel), 206 fmt.Sprintf("k8s:%s=kube-dns", api.PolicyLabelServiceAccount), 207 fmt.Sprintf("k8s:%s=%s", api.PolicyLabelCluster, option.Config.ClusterName), 208 }) 209 210 // kube-dns EKS labels 211 // k8s:io.cilium.k8s.policy.serviceaccount=coredns 212 // k8s:io.kubernetes.pod.namespace=kube-system 213 // k8s:k8s-app=kube-dns 214 // k8s:io.cilium.k8s.policy.cluster=default 215 // k8s:eks.amazonaws.com/component=coredns 216 WellKnown.add(ReservedEKSCoreDNS, []string{ 217 "k8s:k8s-app=kube-dns", 218 "k8s:eks.amazonaws.com/component=coredns", 219 fmt.Sprintf("k8s:%s=kube-system", api.PodNamespaceLabel), 220 fmt.Sprintf("k8s:%s=coredns", api.PolicyLabelServiceAccount), 221 fmt.Sprintf("k8s:%s=%s", api.PolicyLabelCluster, option.Config.ClusterName), 222 }) 223 224 // CoreDNS labels 225 // k8s:io.cilium.k8s.policy.serviceaccount=coredns 226 // k8s:io.kubernetes.pod.namespace=kube-system 227 // k8s:k8s-app=kube-dns 228 // k8s:io.cilium.k8s.policy.cluster=default 229 WellKnown.add(ReservedCoreDNS, []string{ 230 "k8s:k8s-app=kube-dns", 231 fmt.Sprintf("k8s:%s=kube-system", api.PodNamespaceLabel), 232 fmt.Sprintf("k8s:%s=coredns", api.PolicyLabelServiceAccount), 233 fmt.Sprintf("k8s:%s=%s", api.PolicyLabelCluster, option.Config.ClusterName), 234 }) 235 236 // CiliumOperator labels 237 // k8s:io.cilium.k8s.policy.serviceaccount=cilium-operator 238 // k8s:io.kubernetes.pod.namespace=<NAMESPACE> 239 // k8s:name=cilium-operator 240 // k8s:io.cilium/app=operator 241 // k8s:io.cilium.k8s.policy.cluster=default 242 WellKnown.add(ReservedCiliumOperator, []string{ 243 "k8s:name=cilium-operator", 244 "k8s:io.cilium/app=operator", 245 fmt.Sprintf("k8s:%s=%s", api.PodNamespaceLabel, namespace), 246 fmt.Sprintf("k8s:%s=cilium-operator", api.PolicyLabelServiceAccount), 247 fmt.Sprintf("k8s:%s=%s", api.PolicyLabelCluster, option.Config.ClusterName), 248 }) 249 250 // cilium-etcd-operator labels 251 // k8s:io.cilium.k8s.policy.cluster=default 252 // k8s:io.cilium.k8s.policy.serviceaccount=cilium-etcd-operator 253 // k8s:io.cilium/app=etcd-operator 254 // k8s:io.kubernetes.pod.namespace=<NAMESPACE> 255 // k8s:name=cilium-etcd-operator 256 WellKnown.add(ReservedCiliumEtcdOperator, []string{ 257 "k8s:name=cilium-etcd-operator", 258 "k8s:io.cilium/app=etcd-operator", 259 fmt.Sprintf("k8s:%s=%s", api.PodNamespaceLabel, namespace), 260 fmt.Sprintf("k8s:%s=cilium-etcd-operator", api.PolicyLabelServiceAccount), 261 fmt.Sprintf("k8s:%s=%s", api.PolicyLabelCluster, option.Config.ClusterName), 262 }) 263 } 264 265 var ( 266 reservedIdentities = map[string]NumericIdentity{ 267 labels.IDNameHost: ReservedIdentityHost, 268 labels.IDNameWorld: ReservedIdentityWorld, 269 labels.IDNameUnmanaged: ReservedIdentityUnmanaged, 270 labels.IDNameHealth: ReservedIdentityHealth, 271 labels.IDNameInit: ReservedIdentityInit, 272 } 273 reservedIdentityNames = map[NumericIdentity]string{ 274 ReservedIdentityHost: labels.IDNameHost, 275 ReservedIdentityWorld: labels.IDNameWorld, 276 ReservedIdentityUnmanaged: labels.IDNameUnmanaged, 277 ReservedIdentityHealth: labels.IDNameHealth, 278 ReservedIdentityInit: labels.IDNameInit, 279 } 280 281 // WellKnown identities stores global state of all well-known identities. 282 WellKnown = wellKnownIdentities{} 283 284 // ErrNotUserIdentity is an error returned for an identity that is not user 285 // reserved. 286 ErrNotUserIdentity = errors.New("not a user reserved identity") 287 ) 288 289 // UpdateReservedIdentitiesMetrics updates identity metrics based on the reserved identities. 290 func UpdateReservedIdentitiesMetrics() { 291 metrics.IdentityCount.Add(float64(len(reservedIdentities))) 292 } 293 294 // IsUserReservedIdentity returns true if the given NumericIdentity belongs 295 // to the space reserved for users. 296 func IsUserReservedIdentity(id NumericIdentity) bool { 297 return id.Uint32() >= UserReservedNumericIdentity.Uint32() && 298 id.Uint32() < MinimalNumericIdentity.Uint32() 299 } 300 301 // AddUserDefinedNumericIdentity adds the given numeric identity and respective 302 // label to the list of reservedIdentities. If the numeric identity is not 303 // between UserReservedNumericIdentity and MinimalNumericIdentity it will return 304 // ErrNotUserIdentity. 305 // Is not safe for concurrent use. 306 func AddUserDefinedNumericIdentity(identity NumericIdentity, label string) error { 307 if !IsUserReservedIdentity(identity) { 308 return ErrNotUserIdentity 309 } 310 reservedIdentities[label] = identity 311 reservedIdentityNames[identity] = label 312 return nil 313 } 314 315 // DelReservedNumericIdentity deletes the given Numeric Identity from the list 316 // of reservedIdentities. If the numeric identity is not between 317 // UserReservedNumericIdentity and MinimalNumericIdentity it will return 318 // ErrNotUserIdentity. 319 // Is not safe for concurrent use. 320 func DelReservedNumericIdentity(identity NumericIdentity) error { 321 if !IsUserReservedIdentity(identity) { 322 return ErrNotUserIdentity 323 } 324 label, ok := reservedIdentityNames[identity] 325 if ok { 326 delete(reservedIdentities, label) 327 delete(reservedIdentityNames, identity) 328 } 329 return nil 330 } 331 332 // NumericIdentity is the numeric representation of a security identity. 333 // 334 // Bits: 335 // 0-15: identity identifier 336 // 16-23: cluster identifier 337 // 24: LocalIdentityFlag: Indicates that the identity has a local scope 338 type NumericIdentity uint32 339 340 func ParseNumericIdentity(id string) (NumericIdentity, error) { 341 nid, err := strconv.ParseUint(id, 0, 32) 342 if err != nil { 343 return NumericIdentity(0), err 344 } 345 return NumericIdentity(nid), nil 346 } 347 348 func (id NumericIdentity) StringID() string { 349 return strconv.FormatUint(uint64(id), 10) 350 } 351 352 func (id NumericIdentity) String() string { 353 if v, exists := reservedIdentityNames[id]; exists { 354 return v 355 } 356 357 return id.StringID() 358 } 359 360 // Uint32 normalizes the ID for use in BPF program. 361 func (id NumericIdentity) Uint32() uint32 { 362 return uint32(id) 363 } 364 365 func GetReservedID(name string) NumericIdentity { 366 if v, ok := reservedIdentities[name]; ok { 367 return v 368 } 369 return IdentityUnknown 370 } 371 372 // IsReservedIdentity returns whether id is one of the special reserved identities. 373 func (id NumericIdentity) IsReservedIdentity() bool { 374 _, isReservedIdentity := reservedIdentityNames[id] 375 return isReservedIdentity 376 } 377 378 // ClusterID returns the cluster ID associated with the identity 379 func (id NumericIdentity) ClusterID() int { 380 return int((uint32(id) >> 16) & 0xFF) 381 } 382 383 // GetAllReservedIdentities returns a list of all reserved numeric identities. 384 func GetAllReservedIdentities() []NumericIdentity { 385 identities := []NumericIdentity{} 386 for _, id := range reservedIdentities { 387 identities = append(identities, id) 388 } 389 return identities 390 } 391 392 // IterateReservedIdentities iterates over all reservedIdentities and executes 393 // the given function for each key, value pair in reservedIdentities. 394 func IterateReservedIdentities(f func(key string, value NumericIdentity)) { 395 for key, value := range reservedIdentities { 396 f(key, value) 397 } 398 } 399 400 // HasLocalScope returns true if the identity has a local scope 401 func (id NumericIdentity) HasLocalScope() bool { 402 return (id & LocalIdentityFlag) != 0 403 }