Skip to content

Instantly share code, notes, and snippets.

@sttts
Created August 31, 2020 07:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sttts/3d858df53a5787d6b5304461d552e8dd to your computer and use it in GitHub Desktop.
Save sttts/3d858df53a5787d6b5304461d552e8dd to your computer and use it in GitHub Desktop.
diff --git a/openshift-kube-apiserver/admission/customresourcevalidation/customresourcevalidationregistration/cr_validation_registration.go b/openshift-kube-apiserver/admission/customresourcevalidation/customresourcevalidationregistration/cr_validation_registration.go
index 2495d4eb67b..07e98bf41d5 100644
--- a/openshift-kube-apiserver/admission/customresourcevalidation/customresourcevalidationregistration/cr_validation_registration.go
+++ b/openshift-kube-apiserver/admission/customresourcevalidation/customresourcevalidationregistration/cr_validation_registration.go
@@ -2,6 +2,7 @@ package customresourcevalidationregistration
import (
"k8s.io/apiserver/pkg/admission"
+ "k8s.io/kubernetes/openshift-kube-apiserver/admission/customresourcevalidation/proxy"
"k8s.io/kubernetes/openshift-kube-apiserver/admission/customresourcevalidation/apiserver"
"k8s.io/kubernetes/openshift-kube-apiserver/admission/customresourcevalidation/authentication"
@@ -27,6 +28,7 @@ var AllCustomResourceValidators = []string{
image.PluginName,
oauth.PluginName,
project.PluginName,
+ proxy.PluginName,
config.PluginName,
scheduler.PluginName,
clusterresourcequota.PluginName,
@@ -46,6 +48,7 @@ func RegisterCustomResourceValidation(plugins *admission.Plugins) {
image.Register(plugins)
oauth.Register(plugins)
project.Register(plugins)
+ proxy.Register(plugins)
config.Register(plugins)
scheduler.Register(plugins)
diff --git a/openshift-kube-apiserver/admission/customresourcevalidation/proxy/validate_proxy.go b/openshift-kube-apiserver/admission/customresourcevalidation/proxy/validate_proxy.go
new file mode 100644
index 00000000000..cad302d88de
--- /dev/null
+++ b/openshift-kube-apiserver/admission/customresourcevalidation/proxy/validate_proxy.go
@@ -0,0 +1,185 @@
+package proxy
+
+import (
+ "fmt"
+ "io"
+ "net"
+ "net/url"
+ "strings"
+
+ "k8s.io/apimachinery/pkg/api/validation"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/util/validation/field"
+ "k8s.io/apiserver/pkg/admission"
+
+ configv1 "github.com/openshift/api/config/v1"
+ "k8s.io/kubernetes/openshift-kube-apiserver/admission/customresourcevalidation"
+)
+
+const PluginName = "config.openshift.io/ValidateProxy"
+
+// Register registers a plugin
+func Register(plugins *admission.Plugins) {
+ plugins.Register(PluginName, func(config io.Reader) (admission.Interface, error) {
+ return customresourcevalidation.NewValidator(
+ map[schema.GroupResource]bool{
+ configv1.Resource("proxies"): true,
+ },
+ map[schema.GroupVersionKind]customresourcevalidation.ObjectValidator{
+ configv1.GroupVersion.WithKind("Proxy"): proxyAdmission{},
+ })
+ })
+}
+
+type proxyAdmission struct {
+}
+
+func toProxyV1(uncastObj runtime.Object) (*configv1.Proxy, field.ErrorList) {
+ if uncastObj == nil {
+ return nil, nil
+ }
+
+ allErrs := field.ErrorList{}
+
+ obj, ok := uncastObj.(*configv1.Proxy)
+ if !ok {
+ return nil, append(allErrs,
+ field.NotSupported(field.NewPath("kind"), fmt.Sprintf("%T", uncastObj), []string{"Proxy"}),
+ field.NotSupported(field.NewPath("apiVersion"), fmt.Sprintf("%T", uncastObj), []string{"config.openshift.io/v1"}))
+ }
+
+ return obj, nil
+}
+
+func (proxyAdmission) ValidateCreate(uncastObj runtime.Object) field.ErrorList {
+ obj, errs := toProxyV1(uncastObj)
+ if len(errs) > 0 {
+ return errs
+ }
+
+ errs = append(errs, validation.ValidateObjectMeta(&obj.ObjectMeta, false, customresourcevalidation.RequireNameCluster, field.NewPath("metadata"))...)
+ errs =append(errs, ValidateSpec(&obj.Spec, nil, field.NewPath("spec"))...)
+
+ return errs
+}
+
+func (proxyAdmission) ValidateUpdate(uncastObj runtime.Object, uncastOldObj runtime.Object) field.ErrorList {
+ obj, errs := toProxyV1(uncastObj)
+ if len(errs) > 0 {
+ return errs
+ }
+ oldObj, errs := toProxyV1(uncastOldObj)
+ if len(errs) > 0 {
+ return errs
+ }
+
+ errs = append(errs, validation.ValidateObjectMetaUpdate(&obj.ObjectMeta, &oldObj.ObjectMeta, field.NewPath("metadata"))...)
+
+ return errs
+}
+
+func (proxyAdmission) ValidateStatusUpdate(uncastObj runtime.Object, uncastOldObj runtime.Object) field.ErrorList {
+ obj, errs := toProxyV1(uncastObj)
+ if len(errs) > 0 {
+ return errs
+ }
+ oldObj, errs := toProxyV1(uncastOldObj)
+ if len(errs) > 0 {
+ return errs
+ }
+
+ errs = append(errs, validation.ValidateObjectMetaUpdate(&obj.ObjectMeta, &oldObj.ObjectMeta, field.NewPath("metadata"))...)
+
+ return errs
+}
+
+func ValidateSpec(obj, old *configv1.ProxySpec, fldPath *field.Path) field.ErrorList {
+ var errs field.ErrorList
+
+ if len(obj.HTTPProxy) > 0 && (old == nil || obj.HTTPProxy != old.HTTPProxy) {
+ err := validateURL(obj.HTTPProxy, "http://", fldPath.Child("httpProxy"))
+ if err != nil {
+ errs = append(errs, err)
+ }
+ }
+
+ if len(obj.HTTPSProxy) > 0 && (old == nil || obj.HTTPSProxy != old.HTTPSProxy) {
+ err := validateURL(obj.HTTPSProxy, "https://", fldPath.Child("httpsProxy"))
+ if err != nil {
+ errs = append(errs, err)
+ }
+ }
+
+ if len(obj.NoProxy) > 0 && (old ==nil || obj.NoProxy != old.NoProxy) {
+ for i, np := range(strings.Split(obj.NoProxy, ",")) {
+ _, _, err := net.ParseCIDR(np)
+ if err ==nil {
+ continue
+ }
+
+ u, err := url.Parse(np)
+ if err != nil || u.Hostname() != np {
+ errs = append(errs, field.Invalid(fldPath.Child("noProxy").Index(i), np, "must be a CIDR or a hostname"))
+ }
+ }
+ }
+
+ if len(obj.ReadinessEndpoints) > 0 && (old ==nil || obj.ReadinessEndpoints != old.ReadinessEndpoints) {
+ for i, np := range(strings.Split(obj.NoProxy, ",")) {
+ _, _, err := net.ParseCIDR(np)
+ if err ==nil {
+ continue
+ }
+
+ u, err := url.Parse(np)
+ if err != nil || u.Hostname() != np {
+ errs = append(errs, field.Invalid(fldPath.Child("noProxy").Index(i), np, "must be a CIDR or a hostname"))
+ }
+ }
+ }
+
+ // readinessEndpoints is a list of endpoints used to verify readiness of the proxy.
+ // +optional
+ ReadinessEndpoints []string `json:"readinessEndpoints,omitempty"`
+
+ // trustedCA is a reference to a ConfigMap containing a CA certificate bundle.
+ // The trustedCA field should only be consumed by a proxy validator. The
+ // validator is responsible for reading the certificate bundle from the required
+ // key "ca-bundle.crt", merging it with the system default trust bundle,
+ // and writing the merged trust bundle to a ConfigMap named "trusted-ca-bundle"
+ // in the "openshift-config-managed" namespace. Clients that expect to make
+ // proxy connections must use the trusted-ca-bundle for all HTTPS requests to
+ // the proxy, and may use the trusted-ca-bundle for non-proxy HTTPS requests as
+ // well.
+ //
+ // The namespace for the ConfigMap referenced by trustedCA is
+ // "openshift-config". Here is an example ConfigMap (in yaml):
+ //
+ // apiVersion: v1
+ // kind: ConfigMap
+ // metadata:
+ // name: user-ca-bundle
+ // namespace: openshift-config
+ // data:
+ // ca-bundle.crt: |
+ // -----BEGIN CERTIFICATE-----
+ // Custom CA certificate bundle.
+ // -----END CERTIFICATE-----
+ //
+ // +optional
+ TrustedCA ConfigMapNameReference `json:"trustedCA,omitempty"`
+}
+
+func validateURL(u string, schema string, fldPath *field.Path) *field.Error {
+ _, err := url.Parse(u)
+ if err != nil {
+ return field.Invalid(fldPath, u, err.Error())
+ }
+
+ if !strings.HasPrefix(u, schema) {
+ return field.Invalid(fldPath, u, fmt.Sprintf("must start with %s", schema))
+ }
+
+ return nil
+}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment