Skip to content

Commit

Permalink
node-authorization-proposal
Browse files Browse the repository at this point in the history
  • Loading branch information
liggitt committed Apr 26, 2017
1 parent c359e8b commit 11b89bf
Showing 1 changed file with 119 additions and 0 deletions.
119 changes: 119 additions & 0 deletions contributors/design-proposals/kubelet-authorizer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Scoped Kubelet API Access

Author: Jordan Liggitt (jliggitt@redhat.com)

## Overview

Kubelets are responsible for:
* creating and updating status of their Node API object
* updating status of Pod API objects bound to their node
* creating/deleting "mirror pod" API objects for statically-defined pods running on their node
* reading Secret and ConfigMap objects referenced by pod specs bound to their node

Currently, kubelets have read/write access to all Node and Pod objects, and read access to all Secret and ConfigMap objects.
This means that compromising a node gives access to credentials with power to make escalating API calls that affect other nodes.

This proposal limits kubelets' API access using a new node authorizer and admission plugin:
* Node authorizer
* Authorizes requests from nodes using the existing policy rules developed for the `system:node` cluster role
* Further restricts secret and configmap requests to only authorize reading objects referenced by pods bound to the node
* Node admission
* Limits a node to mutating its own Node API object
* Limits a node to mutating pods bound to itself

## Node identification

The first step is to identify whether a particular API request is being made by
a node, and if so, from which node.

The proposed node authorizer and admission plugin will take a `NodeIdentifier` interface:

```go
type NodeIdentifier interface {
// IdentifyNode determines node information from the given user.Info.
// nodeName is the name of the Node API object associated with the user.Info,
// and may be empty if a specific node cannot be determined.
// isNode is true if the user.Info represents an identity issued to a node.
IdentifyNode(user.Info) (nodeName string, isNode bool)
}
```

The default `NodeIdentifier` implementation:
* `isNode` - true if the user groups contain the `system:nodes` group
* `nodeName` - populated if `isNode` is true, and the user name is in the format `system:node:<nodeName>`

## Node authorizer

A new node authorizer will be inserted into the authorization chain:
* API server authorizer (authorizes "loopback" API clients used by components within the API server)
* Node authorizer (new)
* User-configured authorizers... (e.g. ABAC, RBAC, Webhook)

The node authorizer is responsible for ensuring:
* The request is made by a node (`IdentifyNode()` returns isNode=true)
* The request is allowed by the rules contained in the default `system:node` cluster role

Requests that do not meet those conditions are forbidden by this authorizer.
Subsequent authorizers in the chain can run and choose to allow the request.

Requests from identifiable nodes (`IdentifyNode()` returns nodeName != "") for secrets and configmaps are further restricted:
* Requests for secrets are limited to `get`, and the requested secret must be related to the requesting node by one of the following relationships:
* node -> pod -> secret
* node -> pod -> pvc -> pv -> secret
* node -> pod -> pvc -> storageclass -> secret
* Requests for configmaps are limited to `get`, and the requested configmap must be related to the requesting node by one of the following relationships:
* node -> pod -> configmap

## Node admission

A new node admission plugin is made available that enforces the following:

Limits `create` of node resources by identifiable nodes:
* only allow the node object corresponding to the node making the API request

Limits `create` of pod resources by identifiable nodes:
* only allow pods with mirror pod annotations
* only allow pods with nodeName set to the node making the API request
* only allow pods with no secret references

Limits `update`,`patch`,`delete` of node and nodes/status resources by identifiable nodes:
* only allow modifying the node object corresponding to the node making the API request

Limits `update`,`patch`,`delete` of pod and pod/status resources by identifiable nodes:
* only allow modifying pods with nodeName set to the node making the API request (requires fetching the pod on delete)
* do not allow removing a mirror pod annotation

## API Changes

None

## RBAC Changes

Currently, the `system:node` cluster role is automatically bound to the `system:nodes` group.

Because the node authorizer accomplishes the same purpose, with the benefit of additional restrictions
on secret and configmap access, this binding is no longer needed, and will no longer be set up automatically.

The `system:node` cluster role will continue to be created, for compatibility with deployment
methods that bind other users or groups to that role.

## Migration considerations

### Kubelets outside the `system:nodes` group

Kubelets outside the `system:nodes` group would not be authorized by the node authorizer,
and would need to continue to be authorized via whatever mechanism currently authorizes them.
The node admission plugin would also ignore requests from these kubelets.

### Kubelets with undifferentiated usernames

In some deployments, kubelets have credentials that place them in the `system:nodes` group,
but do not identify the particular node they are associated with.
Those kubelets would be broadly authorized by the node authorizer, but would not have secret and configmap
requests restricted, since the specific node name would not be available.
The node admission plugin would ignore requests from these kubelets.

### Upgrades from previous versions

Versions prior to 1.7 that have the `system:node` cluster role bound to the `system:nodes` group would need to
remove that binding in order for the node authorizer restrictions on secret and configmap access to be effective.

0 comments on commit 11b89bf

Please sign in to comment.