Change:
Reported by It's possible to turn the master into a proxy to localhost or the GCE metadata server by adding a new endpoint that points to the service. To reproduce, add a new endpoint by posting to http://apiserver/api/v1beta3/endpoints with a description like: If you then go to http://apiserver/api/v1beta3/proxy/namespaces/default/services/myendpoint/ you can interact with the master's metadata server. We can't validate that Endpoints are within the cluster CIDR because we deliberately allow importing of external addresses -- that was the original purpose of allowing users to post Endpoints. I wouldn't disallow link-local and localhost addresses in Endpoints, either, since that might be useful in the future. I'd prefer to just disallow proxying to such addresses. Obviously we'd need to resolve DNS names before checking. See also cc
I think it would be simpler to disallow 169.254.0.0/16 as endpoints, document why and move on. The alternatives are more complicated and difficult to internalize and debug. , Robert Bailey wrote:
The user would either get an error when trying to post the Endpoints, or when trying to access the proxy. The latter is unlikely, IMO, except in malicious circumstances. The former would prevent using services to do something like publish a local metadata service (say, similar to the ) on a link-local address. But I'm ok with that approach for now, since it seems easy to change later.
Yeah, we can open it up as real requirements emerge, was my feeling. , Brian Grant wrote:
I agree w/ fix. Also we should block any similar range that AWS uses, etc.
Or resolve "metadata" and block just that.

Discussion:
return allErrs } <ins> var linkLocalNet *net.IPNet </ins> func validateEndpointAddress(address *api.EndpointAddress) errs.ValidationErrorList { <ins> if linkLocalNet == nil { var err error _, linkLocalNet, err = net.ParseCIDR("169.254.0.0/16") if err != nil { glog.Errorf("Failed to parse link-local CIDR: %v", err) } } </ins> allErrs := errs.ValidationErrorList{} if !util.IsValidIPv4(address.IP) { allErrs = append(allErrs, errs.NewFieldInvalid("ip", address.IP, "invalid IPv4 address")) } <ins> if linkLocalNet.Contains(net.ParseIP(address.IP)) { allErrs = append(allErrs, errs.NewFieldInvalid("ip", address.IP, "may not be in the link-local range (169.254.0.0/16)")) } </ins> return allErrs }

}, errorType: "FieldValueRequired", }, <ins> "Address is link-local": { endpoints: api.Endpoints{ ObjectMeta: api.ObjectMeta{Name: "mysvc", Namespace: "namespace"}, Subsets: []api.EndpointSubset{ { Addresses: []api.EndpointAddress{{IP: "169.254.169.254"}}, Ports:     []api.EndpointPort{{Name: "p", Port: 93, Protocol: "TCP"}}, }, }, }, errorType:   "FieldValueInvalid", errorDetail: "link-local", }, </ins> } for k, v := range errorCases { <del> if errs := ValidateEndpoints(&v.endpoints); len(errs) == 0 || errs[0].(*errors.ValidationError).Type != v.errorType || errs[0].(*errors.ValidationError).Detail != v.errorDetail { </del> <ins> if errs := ValidateEndpoints(&v.endpoints); len(errs) == 0 || errs[0].(*errors.ValidationError).Type != v.errorType || !strings.Contains(errs[0].(*errors.ValidationError).Detail, v.errorDetail) { </ins> t.Errorf("Expected error type %s with detail %s for %s, got %v", v.errorType, v.errorDetail, k, errs) } }