Skip to content

Commit

Permalink
UPSTREAM: <carry>: Make RestrictedEndpointsAdmission check NotReadyAd…
Browse files Browse the repository at this point in the history
…dresses

UPSTREAM: <carry>: Make RestrictedEndpointsAdmission restrict EndpointSlices as well

openshift-rebase(v1.24):source=819a64c501a
  • Loading branch information
danwinship authored and soltysh committed Aug 22, 2022
1 parent 5e646cf commit bd8e25f
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/klog/v2"
kapi "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/discovery"
netutils "k8s.io/utils/net"

"github.com/openshift/library-go/pkg/config/helpers"
"k8s.io/kubernetes/openshift-kube-apiserver/admission/network/apis/restrictedendpoints"
Expand Down Expand Up @@ -70,7 +72,7 @@ var _ = admission.ValidationInterface(&restrictedEndpointsAdmission{})
// ParseSimpleCIDRRules parses a list of CIDR strings
func ParseSimpleCIDRRules(rules []string) (networks []*net.IPNet, err error) {
for _, s := range rules {
_, cidr, err := net.ParseCIDR(s)
_, cidr, err := netutils.ParseCIDRSloppy(s)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -106,41 +108,60 @@ var (
}
defaultRestrictedNetworks = []*net.IPNet{
// IPv4 link-local range 169.254.0.0/16 (including cloud metadata IP)
{IP: net.ParseIP("169.254.0.0"), Mask: net.CIDRMask(16, 32)},
{IP: netutils.ParseIPSloppy("169.254.0.0"), Mask: net.CIDRMask(16, 32)},
}
)

func (r *restrictedEndpointsAdmission) findRestrictedIP(ep *kapi.Endpoints, restricted []*net.IPNet) error {
func checkRestrictedIP(ipString string, restricted []*net.IPNet) error {
ip := netutils.ParseIPSloppy(ipString)
if ip == nil {
return nil
}
for _, net := range restricted {
if net.Contains(ip) {
return fmt.Errorf("endpoint address %s is not allowed", ipString)
}
}
return nil
}

func checkRestrictedPort(protocol kapi.Protocol, port int32, restricted []kapi.EndpointPort) error {
for _, rport := range restricted {
if protocol == rport.Protocol && port == rport.Port {
return fmt.Errorf("endpoint port %s:%d is not allowed", protocol, port)
}
}
return nil
}

func (r *restrictedEndpointsAdmission) endpointsFindRestrictedIP(ep *kapi.Endpoints, restricted []*net.IPNet) error {
for _, subset := range ep.Subsets {
for _, addr := range subset.Addresses {
ip := net.ParseIP(addr.IP)
if ip == nil {
continue
if err := checkRestrictedIP(addr.IP, restricted); err != nil {
return err
}
for _, net := range restricted {
if net.Contains(ip) {
return fmt.Errorf("endpoint address %s is not allowed", addr.IP)
}
}
for _, addr := range subset.NotReadyAddresses {
if err := checkRestrictedIP(addr.IP, restricted); err != nil {
return err
}
}
}
return nil
}

func (r *restrictedEndpointsAdmission) findRestrictedPort(ep *kapi.Endpoints, restricted []kapi.EndpointPort) error {
func (r *restrictedEndpointsAdmission) endpointsFindRestrictedPort(ep *kapi.Endpoints, restricted []kapi.EndpointPort) error {
for _, subset := range ep.Subsets {
for _, port := range subset.Ports {
for _, restricted := range restricted {
if port.Protocol == restricted.Protocol && port.Port == restricted.Port {
return fmt.Errorf("endpoint port %s:%d is not allowed", string(port.Protocol), port.Port)
}
if err := checkRestrictedPort(port.Protocol, port.Port, restricted); err != nil {
return err
}
}
}
return nil
}

func (r *restrictedEndpointsAdmission) checkAccess(ctx context.Context, attr admission.Attributes) (bool, error) {
func (r *restrictedEndpointsAdmission) endpointsCheckAccess(ctx context.Context, attr admission.Attributes) (bool, error) {
authzAttr := authorizer.AttributesRecord{
User: attr.GetUserInfo(),
Verb: "create",
Expand All @@ -155,11 +176,7 @@ func (r *restrictedEndpointsAdmission) checkAccess(ctx context.Context, attr adm
return authorized == authorizer.DecisionAllow, err
}

// Admit determines if the endpoints object should be admitted
func (r *restrictedEndpointsAdmission) Validate(ctx context.Context, a admission.Attributes, _ admission.ObjectInterfaces) error {
if a.GetResource().GroupResource() != kapi.Resource("endpoints") {
return nil
}
func (r *restrictedEndpointsAdmission) endpointsValidate(ctx context.Context, a admission.Attributes) error {
ep, ok := a.GetObject().(*kapi.Endpoints)
if !ok {
return nil
Expand All @@ -169,18 +186,18 @@ func (r *restrictedEndpointsAdmission) Validate(ctx context.Context, a admission
return nil
}

restrictedErr := r.findRestrictedIP(ep, r.restrictedNetworks)
restrictedErr := r.endpointsFindRestrictedIP(ep, r.restrictedNetworks)
if restrictedErr == nil {
restrictedErr = r.findRestrictedIP(ep, defaultRestrictedNetworks)
restrictedErr = r.endpointsFindRestrictedIP(ep, defaultRestrictedNetworks)
}
if restrictedErr == nil {
restrictedErr = r.findRestrictedPort(ep, defaultRestrictedPorts)
restrictedErr = r.endpointsFindRestrictedPort(ep, defaultRestrictedPorts)
}
if restrictedErr == nil {
return nil
}

allow, err := r.checkAccess(ctx, a)
allow, err := r.endpointsCheckAccess(ctx, a)
if err != nil {
return err
}
Expand All @@ -189,3 +206,87 @@ func (r *restrictedEndpointsAdmission) Validate(ctx context.Context, a admission
}
return nil
}

func (r *restrictedEndpointsAdmission) sliceFindRestrictedIP(slice *discovery.EndpointSlice, restricted []*net.IPNet) error {
for _, endpoint := range slice.Endpoints {
for _, addr := range endpoint.Addresses {
if err := checkRestrictedIP(addr, restricted); err != nil {
return err
}
}
}
return nil
}

func (r *restrictedEndpointsAdmission) sliceFindRestrictedPort(slice *discovery.EndpointSlice, restricted []kapi.EndpointPort) error {
for _, port := range slice.Ports {
if port.Port == nil {
continue
}
sliceProtocol := kapi.ProtocolTCP
if port.Protocol != nil {
sliceProtocol = *port.Protocol
}
if err := checkRestrictedPort(sliceProtocol, *port.Port, restricted); err != nil {
return err
}
}
return nil
}

func (r *restrictedEndpointsAdmission) sliceCheckAccess(ctx context.Context, attr admission.Attributes) (bool, error) {
authzAttr := authorizer.AttributesRecord{
User: attr.GetUserInfo(),
Verb: "create",
Namespace: attr.GetNamespace(),
Resource: "endpointslices",
Subresource: "restricted",
APIGroup: discovery.GroupName,
Name: attr.GetName(),
ResourceRequest: true,
}
authorized, _, err := r.authorizer.Authorize(ctx, authzAttr)
return authorized == authorizer.DecisionAllow, err
}

func (r *restrictedEndpointsAdmission) sliceValidate(ctx context.Context, a admission.Attributes) error {
slice, ok := a.GetObject().(*discovery.EndpointSlice)
if !ok {
return nil
}
old, ok := a.GetOldObject().(*discovery.EndpointSlice)
if ok && reflect.DeepEqual(slice.Endpoints, old.Endpoints) && reflect.DeepEqual(slice.Ports, old.Ports) {
return nil
}

restrictedErr := r.sliceFindRestrictedIP(slice, r.restrictedNetworks)
if restrictedErr == nil {
restrictedErr = r.sliceFindRestrictedIP(slice, defaultRestrictedNetworks)
}
if restrictedErr == nil {
restrictedErr = r.sliceFindRestrictedPort(slice, defaultRestrictedPorts)
}
if restrictedErr == nil {
return nil
}

allow, err := r.sliceCheckAccess(ctx, a)
if err != nil {
return err
}
if !allow {
return admission.NewForbidden(a, restrictedErr)
}
return nil
}

// Validate determines if the endpoints or endpointslice object should be admitted
func (r *restrictedEndpointsAdmission) Validate(ctx context.Context, a admission.Attributes, _ admission.ObjectInterfaces) error {
if a.GetResource().GroupResource() == kapi.Resource("endpoints") {
return r.endpointsValidate(ctx, a)
} else if a.GetResource().GroupResource() == discovery.Resource("endpointslices") {
return r.sliceValidate(ctx, a)
} else {
return nil
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ func buildControllerRoles() ([]rbacv1.ClusterRole, []rbacv1.ClusterRoleBinding)
// resource that is owned by the service and sets blockOwnerDeletion=true in its ownerRef.
rbacv1helpers.NewRule("update").Groups(legacyGroup).Resources("services/finalizers").RuleOrDie(),
rbacv1helpers.NewRule("get", "list", "create", "update", "delete").Groups(discoveryGroup).Resources("endpointslices").RuleOrDie(),
rbacv1helpers.NewRule("create").Groups(discoveryGroup).Resources("endpointslices/restricted").RuleOrDie(),
eventsRule(),
},
})
Expand All @@ -171,6 +172,7 @@ func buildControllerRoles() ([]rbacv1.ClusterRole, []rbacv1.ClusterRoleBinding)
// see https://github.com/openshift/kubernetes/blob/8691466059314c3f7d6dcffcbb76d14596ca716c/pkg/controller/endpointslicemirroring/utils.go#L87-L88
rbacv1helpers.NewRule("update").Groups(legacyGroup).Resources("endpoints/finalizers").RuleOrDie(),
rbacv1helpers.NewRule("get", "list", "create", "update", "delete").Groups(discoveryGroup).Resources("endpointslices").RuleOrDie(),
rbacv1helpers.NewRule("create").Groups(discoveryGroup).Resources("endpointslices/restricted").RuleOrDie(),
eventsRule(),
},
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,12 @@ items:
- get
- list
- update
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices/restricted
verbs:
- create
- apiGroups:
- ""
- events.k8s.io
Expand Down Expand Up @@ -560,6 +566,12 @@ items:
- get
- list
- update
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices/restricted
verbs:
- create
- apiGroups:
- ""
- events.k8s.io
Expand Down

0 comments on commit bd8e25f

Please sign in to comment.