|
| 1 | +# Limiting Node Scope on the Node object |
| 2 | + |
| 3 | +### Author: Mike Danese, (@mikedanese) |
| 4 | + |
| 5 | +## Background |
| 6 | + |
| 7 | +Today the node client has total authority over its own Node object. This ability |
| 8 | +is incredibly useful for the node auto-registration flow. Some examples of |
| 9 | +fields the kubelet self-reports in the early node object are: |
| 10 | + |
| 11 | +1. Labels (provided by kubelet commandline) |
| 12 | +1. Taints (provided by kubelet commandline) |
| 13 | + |
| 14 | +As well as others. |
| 15 | + |
| 16 | +## Problem |
| 17 | + |
| 18 | +While this distributed method of registration is convenient and expedient, it |
| 19 | +has two problems that a centralized approach would not have. Minorly, it makes |
| 20 | +management difficult. Instead of configuring labels and taints in a centralized |
| 21 | +place, we must configure `N` kubelet command lines. More significantly, the |
| 22 | +approach greatly compromises security. Below are two straightforward escalations |
| 23 | +on an initially compromised node that exhibit the attack vector. |
| 24 | + |
| 25 | +### Capturing Dedicated Workloads |
| 26 | + |
| 27 | +Suppose company `foo` needs to run an application that deals with PII on |
| 28 | +dedicated nodes to comply with government regulation. A common mechanism for |
| 29 | +implementing dedicated nodes in Kubernetes today is to set a label or taint |
| 30 | +(e.g. `foo/dedicated=customer-info-app`) on the node and to select these |
| 31 | +dedicated nodes in the workload controller running `customer-info-app`. |
| 32 | + |
| 33 | +Since the nodes self reports labels upon registration, an intruder can easily |
| 34 | +register a compromised node with label `foo/dedicated=customer-info-app`. The |
| 35 | +scheduler will then bind `customer-info-app` to the compromised node potentially |
| 36 | +giving the intruder easy access to the PII. |
| 37 | + |
| 38 | +This attack also extends to secrets. Suppose company `foo` runs their outward |
| 39 | +facing nginx on dedicated nodes to reduce exposure to the company's publicly |
| 40 | +trusted server certificates. They use the secret mechanism to distribute the |
| 41 | +serving certificate key. An intruder captures the dedicated nginx workload in |
| 42 | +the same way and can now use the node certificate to read the company's serving |
| 43 | +certificate key. |
| 44 | + |
| 45 | +## Proposed Solution |
| 46 | + |
| 47 | +In many environments, we can improve the situation by centralizing reporting of |
| 48 | +sensitive node attributes to a more trusted source and disallowing reporting of |
| 49 | +these attributes from the kubelet. |
| 50 | + |
| 51 | +### Label And Taint Restriction |
| 52 | + |
| 53 | +An operator will configure a whitelist of taints and labels that nodes are |
| 54 | +allowed to set on themselves. This list should include the taints and labels |
| 55 | +that the kubelet is already setting on itself. |
| 56 | + |
| 57 | +Well known taint keys: |
| 58 | +``` |
| 59 | +node.cloudprovider.kubernetes.io/uninitialized |
| 60 | +``` |
| 61 | + |
| 62 | +Well known label keys: |
| 63 | + |
| 64 | +``` |
| 65 | +kubernetes.io/hostname |
| 66 | +failure-domain.beta.kubernetes.io/zone |
| 67 | +failure-domain.beta.kubernetes.io/region |
| 68 | +beta.kubernetes.io/instance-type |
| 69 | +beta.kubernetes.io/os |
| 70 | +beta.kubernetes.io/arch |
| 71 | +``` |
| 72 | + |
| 73 | +As well as any taints and labels that the operator is setting using: |
| 74 | + |
| 75 | +``` |
| 76 | + --register-with-taints |
| 77 | + --node-labels |
| 78 | +``` |
| 79 | + |
| 80 | +This whitelist is passed as a command line flag to the apiserver. |
| 81 | +NodeRestriction admission control will then prevent setting and modification by |
| 82 | +nodes of all taints and labels with keys not in the whitelist. |
| 83 | + |
| 84 | +### NodeRestriction Config |
| 85 | + |
| 86 | +A new configuration API group will be created for the NodeRestriction admission |
| 87 | +controller with the name `noderestriction.admission.k8s.io`. It will contain one |
| 88 | +config object: |
| 89 | + |
| 90 | +```golang |
| 91 | +type Configuration struct { |
| 92 | + // AllowedLabels is a list of label keys a node is allowed to set on itself. |
| 93 | + // The list also supports whitelisting all label keys with a specific prefix |
| 94 | + // by adding an entry of the form `<prefix>*`. |
| 95 | + AllowedLabels []string |
| 96 | + // AllowedTaints is a list of taint keys a node is allowed to set on itself. |
| 97 | + // The list also supports whitelisting all taint keys with a specific prefix |
| 98 | + // by adding an entry of the form `<prefix>*`. |
| 99 | + AllowedTaints []string |
| 100 | +} |
| 101 | +``` |
| 102 | + |
| 103 | +Labels and taints that are applied by the kubelet itself (and not by |
| 104 | +--register-with configurations) do not need to appear in this config. They are |
| 105 | +allowed implicitly. |
| 106 | + |
| 107 | +### NodeRestriction Config Examples |
| 108 | + |
| 109 | +A configuration that allows all labels and all taints with prefix `insecure.` |
| 110 | +and the `foo` taint: |
| 111 | + |
| 112 | +```yaml |
| 113 | +apiVersion: noderestriction.admission.k8s.io/v1 |
| 114 | +kind: Configuration |
| 115 | +allowedLabels: |
| 116 | +- * |
| 117 | +allowedTaints: |
| 118 | +- foo |
| 119 | +- insecure.* |
| 120 | +``` |
| 121 | +
|
| 122 | +A configuration that allows only labels for CSI plugins: |
| 123 | +
|
| 124 | +```yaml |
| 125 | +apiVersion: noderestriction.admission.k8s.io/v1 |
| 126 | +kind: Configuration |
| 127 | +allowedLabels: |
| 128 | +- csi.kubernetes.io.* |
| 129 | +``` |
| 130 | +
|
| 131 | +For backwards compatibility, the default config is equivalent to: |
| 132 | +
|
| 133 | +```yaml |
| 134 | +apiVersion: noderestriction.admission.k8s.io/v1 |
| 135 | +kind: Configuration |
| 136 | +allowedLabels: |
| 137 | +- * |
| 138 | +allowedTaints: |
| 139 | +- * |
| 140 | +``` |
| 141 | + |
| 142 | +### Removing self-delete from Node Permission |
| 143 | + |
| 144 | +Currently a node has permission to delete itself. A node will only delete itself |
| 145 | +when it's external name (inferred through the cloud provider) changes. This code |
| 146 | +path will never be executated on the majority of cloud providers and this |
| 147 | +capability undermines the usage of taints as a strong exclusion primitive. |
| 148 | + |
| 149 | +For example, suppose an operator sets a taint `compromised` on a node that they |
| 150 | +believe has been compromised. Currently, the compromised node could delete and |
| 151 | +recreate itself thereby removing the `compromised` taint. |
| 152 | + |
| 153 | +To prevent this, we will finish the removal of ExternalID which has been |
| 154 | +deprecated since 1.1. This will allow us to remove the self delete permission |
| 155 | +from the NodeAuthorizer. |
| 156 | + |
| 157 | +### Taints set by central controllers |
| 158 | + |
| 159 | +In many deployment environments, the sensitive attributes of a Node object |
| 160 | +discussed above ("labels", "taints") are discoverable by consulting a machine |
| 161 | +database (e.g. the GCE API). A centralized controller can register an |
| 162 | +initializer for the node object and build the sensitive fields by consulting the |
| 163 | +machine database. The `cloud-controller-manager` is an obvious candidate to |
| 164 | +house such a controller. |
0 commit comments