Skip to content

Commit 2156efa

Browse files
committed
Make Node authorizer's index authoritative for unauthorized calls
1 parent 1dbf083 commit 2156efa

File tree

4 files changed

+674
-28
lines changed

4 files changed

+674
-28
lines changed

plugin/pkg/auth/authorizer/node/graph.go

Lines changed: 60 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package node
1818

1919
import (
20+
"fmt"
2021
"sync"
2122
"time"
2223

@@ -79,7 +80,8 @@ func (e *destinationEdge) DestinationID() int { return e.Destination.ID() }
7980
// pvc <- pv
8081
// pv <- secret
8182
type Graph struct {
82-
lock sync.RWMutex
83+
lock sync.RWMutex
84+
// Calling graph.SetEdge is restricted to the addEdgeLocked method of Graph.
8385
graph *simple.DirectedAcyclicGraph
8486
// vertices is a map of type -> namespace -> name -> vertex
8587
vertices map[vertexType]namespaceVertexMapping
@@ -138,6 +140,20 @@ var vertexTypes = map[vertexType]string{
138140
serviceAccountVertexType: "serviceAccount",
139141
}
140142

143+
// vertexTypeWithAuthoritativeIndex indicates which types of vertices can hold
144+
// a destination edge index that is authoritative i.e. if the index exists,
145+
// then it always stores all of the Nodes that are reachable from that vertex
146+
// in the graph.
147+
var vertexTypeWithAuthoritativeIndex = map[vertexType]bool{
148+
configMapVertexType: true,
149+
sliceVertexType: true,
150+
podVertexType: true,
151+
pvcVertexType: true,
152+
resourceClaimVertexType: true,
153+
vaVertexType: true,
154+
serviceAccountVertexType: true,
155+
}
156+
141157
// must be called under a write lock
142158
func (g *Graph) getOrCreateVertexLocked(vertexType vertexType, namespace, name string) *namedVertex {
143159
if vertex, exists := g.getVertexRLocked(vertexType, namespace, name); exists {
@@ -348,7 +364,8 @@ func (g *Graph) AddPod(pod *corev1.Pod) {
348364
g.deleteVertexLocked(podVertexType, pod.Namespace, pod.Name)
349365
podVertex := g.getOrCreateVertexLocked(podVertexType, pod.Namespace, pod.Name)
350366
nodeVertex := g.getOrCreateVertexLocked(nodeVertexType, "", pod.Spec.NodeName)
351-
g.graph.SetEdge(newDestinationEdge(podVertex, nodeVertex, nodeVertex))
367+
// Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
368+
g.addEdgeLocked(podVertex, nodeVertex, nodeVertex)
352369

353370
// Short-circuit adding edges to other resources for mirror pods.
354371
// A node must never be able to create a pod that grants them permissions on other API objects.
@@ -363,24 +380,21 @@ func (g *Graph) AddPod(pod *corev1.Pod) {
363380
// ref https://github.com/kubernetes/kubernetes/issues/58790
364381
if len(pod.Spec.ServiceAccountName) > 0 {
365382
serviceAccountVertex := g.getOrCreateVertexLocked(serviceAccountVertexType, pod.Namespace, pod.Spec.ServiceAccountName)
366-
e := newDestinationEdge(serviceAccountVertex, podVertex, nodeVertex)
367-
g.graph.SetEdge(e)
368-
g.addEdgeToDestinationIndexLocked(e)
383+
// Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
384+
g.addEdgeLocked(serviceAccountVertex, podVertex, nodeVertex)
369385
}
370386

371387
podutil.VisitPodSecretNames(pod, func(secret string) bool {
372388
secretVertex := g.getOrCreateVertexLocked(secretVertexType, pod.Namespace, secret)
373-
e := newDestinationEdge(secretVertex, podVertex, nodeVertex)
374-
g.graph.SetEdge(e)
375-
g.addEdgeToDestinationIndexLocked(e)
389+
// Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
390+
g.addEdgeLocked(secretVertex, podVertex, nodeVertex)
376391
return true
377392
})
378393

379394
podutil.VisitPodConfigmapNames(pod, func(configmap string) bool {
380395
configmapVertex := g.getOrCreateVertexLocked(configMapVertexType, pod.Namespace, configmap)
381-
e := newDestinationEdge(configmapVertex, podVertex, nodeVertex)
382-
g.graph.SetEdge(e)
383-
g.addEdgeToDestinationIndexLocked(e)
396+
// Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
397+
g.addEdgeLocked(configmapVertex, podVertex, nodeVertex)
384398
return true
385399
})
386400

@@ -393,9 +407,8 @@ func (g *Graph) AddPod(pod *corev1.Pod) {
393407
}
394408
if claimName != "" {
395409
pvcVertex := g.getOrCreateVertexLocked(pvcVertexType, pod.Namespace, claimName)
396-
e := newDestinationEdge(pvcVertex, podVertex, nodeVertex)
397-
g.graph.SetEdge(e)
398-
g.addEdgeToDestinationIndexLocked(e)
410+
// Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
411+
g.addEdgeLocked(pvcVertex, podVertex, nodeVertex)
399412
}
400413
}
401414

@@ -407,12 +420,34 @@ func (g *Graph) AddPod(pod *corev1.Pod) {
407420
// was created and never will be because it isn't needed.
408421
if err == nil && claimName != nil {
409422
claimVertex := g.getOrCreateVertexLocked(resourceClaimVertexType, pod.Namespace, *claimName)
410-
e := newDestinationEdge(claimVertex, podVertex, nodeVertex)
411-
g.graph.SetEdge(e)
412-
g.addEdgeToDestinationIndexLocked(e)
423+
// Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
424+
g.addEdgeLocked(claimVertex, podVertex, nodeVertex)
413425
}
414426
}
415427
}
428+
429+
// Must be called under a write lock.
430+
// All edge adds must be handled by that method rather than by calling
431+
// g.graph.SetEdge directly.
432+
// Note: if "from" belongs to vertexTypeWithAuthoritativeIndex, then
433+
// "destination" must be non-nil.
434+
func (g *Graph) addEdgeLocked(from, to, destination *namedVertex) {
435+
if destination != nil {
436+
e := newDestinationEdge(from, to, destination)
437+
g.graph.SetEdge(e)
438+
g.addEdgeToDestinationIndexLocked(e)
439+
return
440+
}
441+
442+
// We must not create edges without a Node label from a vertex that is
443+
// supposed to hold authoritative destination edge index only.
444+
// Entering this branch would mean there's a bug in the Node authorizer.
445+
if vertexTypeWithAuthoritativeIndex[from.vertexType] {
446+
panic(fmt.Sprintf("vertex of type %q must have destination edges only", vertexTypes[from.vertexType]))
447+
}
448+
g.graph.SetEdge(simple.Edge{F: from, T: to})
449+
}
450+
416451
func (g *Graph) DeletePod(name, namespace string) {
417452
start := time.Now()
418453
defer func() {
@@ -444,11 +479,13 @@ func (g *Graph) AddPV(pv *corev1.PersistentVolume) {
444479
pvVertex := g.getOrCreateVertexLocked(pvVertexType, "", pv.Name)
445480

446481
// since we don't know the other end of the pvc -> pod -> node chain (or it may not even exist yet), we can't decorate these edges with kubernetes node info
447-
g.graph.SetEdge(simple.Edge{F: pvVertex, T: g.getOrCreateVertexLocked(pvcVertexType, pv.Spec.ClaimRef.Namespace, pv.Spec.ClaimRef.Name)})
482+
// Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
483+
g.addEdgeLocked(pvVertex, g.getOrCreateVertexLocked(pvcVertexType, pv.Spec.ClaimRef.Namespace, pv.Spec.ClaimRef.Name), nil)
448484
pvutil.VisitPVSecretNames(pv, func(namespace, secret string, kubeletVisible bool) bool {
449485
// This grants access to the named secret in the same namespace as the bound PVC
450486
if kubeletVisible {
451-
g.graph.SetEdge(simple.Edge{F: g.getOrCreateVertexLocked(secretVertexType, namespace, secret), T: pvVertex})
487+
// Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
488+
g.addEdgeLocked(g.getOrCreateVertexLocked(secretVertexType, namespace, secret), pvVertex, nil)
452489
}
453490
return true
454491
})
@@ -482,7 +519,8 @@ func (g *Graph) AddVolumeAttachment(attachmentName, nodeName string) {
482519
if len(nodeName) > 0 {
483520
vaVertex := g.getOrCreateVertexLocked(vaVertexType, "", attachmentName)
484521
nodeVertex := g.getOrCreateVertexLocked(nodeVertexType, "", nodeName)
485-
g.graph.SetEdge(newDestinationEdge(vaVertex, nodeVertex, nodeVertex))
522+
// Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
523+
g.addEdgeLocked(vaVertex, nodeVertex, nodeVertex)
486524
}
487525
}
488526
func (g *Graph) DeleteVolumeAttachment(name string) {
@@ -513,7 +551,8 @@ func (g *Graph) AddResourceSlice(sliceName, nodeName string) {
513551
if len(nodeName) > 0 {
514552
sliceVertex := g.getOrCreateVertexLocked(sliceVertexType, "", sliceName)
515553
nodeVertex := g.getOrCreateVertexLocked(nodeVertexType, "", nodeName)
516-
g.graph.SetEdge(newDestinationEdge(sliceVertex, nodeVertex, nodeVertex))
554+
// Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
555+
g.addEdgeLocked(sliceVertex, nodeVertex, nodeVertex)
517556
}
518557
}
519558
func (g *Graph) DeleteResourceSlice(sliceName string) {

0 commit comments

Comments
 (0)