...
1
16
17 package denyserviceexternalips
18
19 import (
20 "context"
21 "fmt"
22 "io"
23
24 "k8s.io/apimachinery/pkg/api/errors"
25 "k8s.io/apiserver/pkg/admission"
26 "k8s.io/klog/v2"
27 "k8s.io/kubernetes/pkg/apis/core"
28 )
29
30 const (
31
32 PluginName = "DenyServiceExternalIPs"
33 )
34
35
36 func Register(plugins *admission.Plugins) {
37 plugins.Register(PluginName, func(config io.Reader) (admission.Interface, error) {
38 plugin := newPlugin()
39 return plugin, nil
40 })
41 }
42
43
44 type externalIPsDenierPlugin struct {
45 *admission.Handler
46 }
47
48 var _ admission.Interface = &externalIPsDenierPlugin{}
49 var _ admission.ValidationInterface = &externalIPsDenierPlugin{}
50
51
52 func newPlugin() *externalIPsDenierPlugin {
53 return &externalIPsDenierPlugin{
54 Handler: admission.NewHandler(admission.Create, admission.Update),
55 }
56 }
57
58
59
60 func (plug *externalIPsDenierPlugin) Validate(ctx context.Context, attr admission.Attributes, o admission.ObjectInterfaces) error {
61 if attr.GetResource().GroupResource() != core.Resource("services") {
62 return nil
63 }
64
65 if len(attr.GetSubresource()) != 0 {
66 return nil
67 }
68
69
70 newSvc, ok := attr.GetObject().(*core.Service)
71 if !ok {
72 klog.V(3).Infof("Expected Service resource, got: %v", attr.GetKind())
73 return errors.NewInternalError(fmt.Errorf("Expected Service resource, got: %v", attr.GetKind()))
74 }
75
76 var oldSvc *core.Service
77 if old := attr.GetOldObject(); old != nil {
78 tmp, ok := old.(*core.Service)
79 if !ok {
80 klog.V(3).Infof("Expected Service resource, got: %v", attr.GetKind())
81 return errors.NewInternalError(fmt.Errorf("Expected Service resource, got: %v", attr.GetKind()))
82 }
83 oldSvc = tmp
84 }
85
86 if isSubset(newSvc, oldSvc) {
87 return nil
88 }
89
90 klog.V(4).Infof("Denying new use of ExternalIPs on Service %s/%s", newSvc.Namespace, newSvc.Name)
91 return admission.NewForbidden(attr, fmt.Errorf("Use of external IPs is denied by admission control"))
92 }
93
94 func isSubset(newSvc, oldSvc *core.Service) bool {
95
96 if len(newSvc.Spec.ExternalIPs) == 0 {
97 return true
98 }
99
100 if oldSvc == nil {
101 return false
102 }
103 oldIPs := map[string]bool{}
104 for _, ip := range oldSvc.Spec.ExternalIPs {
105 oldIPs[ip] = true
106 }
107
108 for _, ip := range newSvc.Spec.ExternalIPs {
109 if oldIPs[ip] == false {
110 return false
111 }
112 }
113 return true
114 }
115
View as plain text