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  }