From 26eaa486bd1dd8f852ceb0d64ba5f2876e263707 Mon Sep 17 00:00:00 2001 From: pengbinbin1 Date: Fri, 20 Oct 2023 19:25:08 +0800 Subject: [PATCH] add webhook --- charts/ipamwrapper/templates/service.yaml | 69 ++++++++ charts/ipamwrapper/templates/tls.yaml | 195 ++++++++++++++++++++++ cmd/controller/main.go | 23 +-- pkg/k8s/api/v1/ippool_validate.go | 26 ++- pkg/k8s/api/v1/ippool_webhook.go | 3 +- 5 files changed, 302 insertions(+), 14 deletions(-) create mode 100644 charts/ipamwrapper/templates/service.yaml create mode 100644 charts/ipamwrapper/templates/tls.yaml diff --git a/charts/ipamwrapper/templates/service.yaml b/charts/ipamwrapper/templates/service.yaml new file mode 100644 index 0000000..3fa3502 --- /dev/null +++ b/charts/ipamwrapper/templates/service.yaml @@ -0,0 +1,69 @@ +{{- if .Values.ipamwrapperAgent.prometheus.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.ipamwrapperAgent.name | trunc 63 | trimSuffix "-" }} + namespace: {{ .Release.Namespace | quote }} + {{- if or .Values.global.commonAnnotations .Values.ipamwrapperAgent.service.annotations }} + annotations: + {{- if .Values.global.commonAnnotations }} + {{- include "tplvalues.render" ( dict "value" .Values.global.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.ipamwrapperAgent.service.annotations }} + {{- include "tplvalues.render" ( dict "value" .Values.ipamwrapperAgent.service.annotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} + labels: + {{- if .Values.global.commonLabels }} + {{- include "tplvalues.render" ( dict "value" .Values.global.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- include "ipamwrapper.ipamwrapperAgent.labels" . | nindent 4 }} +spec: + type: {{ .Values.ipamwrapperAgent.service.type }} + ports: + - name: metrics + port: {{ .Values.ipamwrapperAgent.prometheus.port }} + targetPort: metrics + protocol: TCP + selector: + {{- include "ipamwrapper.ipamwrapperAgent.selectorLabels" . | nindent 4 }} +{{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.ipamwrapperController.name | trunc 63 | trimSuffix "-" }} + namespace: {{ .Release.Namespace | quote }} + {{- if or .Values.global.commonAnnotations .Values.ipamwrapperController.service.annotations }} + annotations: + {{- if .Values.global.commonAnnotations }} + {{- include "tplvalues.render" ( dict "value" .Values.global.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.ipamwrapperController.service.annotations }} + {{- include "tplvalues.render" ( dict "value" .Values.ipamwrapperController.service.annotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} + labels: + {{- if .Values.global.commonLabels }} + {{- include "tplvalues.render" ( dict "value" .Values.global.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- include "ipamwrapper.ipamwrapperController.labels" . | nindent 4 }} +spec: + type: {{ .Values.ipamwrapperController.service.type }} + ports: + {{- if .Values.ipamwrapperController.prometheus.enabled }} + - name: metrics + port: {{ .Values.ipamwrapperController.prometheus.port }} + targetPort: metrics + protocol: TCP + {{- end }} + - name: webhook + port: {{ .Values.ipamwrapperController.webhookPort }} + targetPort: 9443 + protocol: TCP + - name: http + port: {{ .Values.ipamwrapperController.httpPort }} + targetPort: http + protocol: TCP + selector: + {{- include "ipamwrapper.ipamwrapperController.selectorLabels" . | nindent 4 }} diff --git a/charts/ipamwrapper/templates/tls.yaml b/charts/ipamwrapper/templates/tls.yaml new file mode 100644 index 0000000..0fec021 --- /dev/null +++ b/charts/ipamwrapper/templates/tls.yaml @@ -0,0 +1,195 @@ +{{- if (eq .Values.ipamwrapperController.tls.method "auto") }} +{{- $_ := include "generate-ca-certs" . }} +{{- end }} +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: {{ .Values.ipamwrapperController.name | trunc 63 | trimSuffix "-" }} + annotations: + {{- if (eq .Values.ipamwrapperController.tls.method "certmanager") }} + cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ .Values.ipamwrapperController.name | trunc 63 | trimSuffix "-" }}-server-certs + {{- end }} +webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: {{ .Values.ipamwrapperController.name | trunc 63 | trimSuffix "-" }} + namespace: {{ .Release.Namespace }} + path: /mutate-inspuripam-inspur-com-v1-ippool + port: {{ .Values.ipamwrapperController.webhookPort }} + {{- if (eq .Values.ipamwrapperController.tls.method "provided") }} + caBundle: {{ .Values.ipamwrapperController.tls.provided.tlsCa | required "missing ipamwrapperController.tls.provided.tlsCa" }} + {{- else if (eq .Values.ipamwrapperController.tls.method "auto") }} + caBundle: {{ .ca.Cert | b64enc }} + {{- end }} + failurePolicy: Fail + name: ippool.ipamwrapper.inspur.io + rules: + - apiGroups: + - inspuripam.inspur.com + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + - DELETE + resources: + - ippools + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: {{ .Values.ipamwrapperController.name | trunc 63 | trimSuffix "-" }} + namespace: {{ .Release.Namespace }} + path: /mutate-inspuripam-inspur-com-v1-ipamendpoint + port: {{ .Values.ipamwrapperController.webhookPort }} + {{- if (eq .Values.ipamwrapperController.tls.method "provided") }} + caBundle: {{ .Values.ipamwrapperController.tls.provided.tlsCa | required "missing ipamwrapperController.tls.provided.tlsCa" }} + {{- else if (eq .Values.ipamwrapperController.tls.method "auto") }} + caBundle: {{ .ca.Cert | b64enc }} + {{- end }} + failurePolicy: Fail + name: ipamendpoint.ipamwrapper.inspur.io + rules: + - apiGroups: + - inspuripam.inspur.com + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + - DELETE + resources: + - ipamendpoints + sideEffects: None +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + creationTimestamp: null + name: {{ .Values.ipamwrapperController.name | trunc 63 | trimSuffix "-" }} + annotations: + {{- if (eq .Values.ipamwrapperController.tls.method "certmanager") }} + cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ .Values.ipamwrapperController.name | trunc 63 | trimSuffix "-" }}-server-certs + {{- end }} +webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: {{ .Values.ipamwrapperController.name | trunc 63 | trimSuffix "-" }} + namespace: {{ .Release.Namespace }} + path: /validate-inspuripam-inspur-com-v1-ippool + port: {{ .Values.ipamwrapperController.webhookPort }} + {{- if (eq .Values.ipamwrapperController.tls.method "provided") }} + caBundle: {{ .Values.ipamwrapperController.tls.provided.tlsCa | required "missing ipamwrapperController.tls.provided.tlsCa" }} + {{- else if (eq .Values.ipamwrapperController.tls.method "auto") }} + caBundle: {{ .ca.Cert | b64enc }} + {{- end }} + failurePolicy: Fail + name: ippools.ipamwrapper.inspur.io + rules: + - apiGroups: + - inspuripam.inspur.com + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + - DELETE + resources: + - ippools + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: {{ .Values.ipamwrapperController.name | trunc 63 | trimSuffix "-" }} + namespace: {{ .Release.Namespace }} + path: /validate-inspuripam-inspur-com-v1-ipamendpoint + port: {{ .Values.ipamwrapperController.webhookPort }} + {{- if (eq .Values.ipamwrapperController.tls.method "provided") }} + caBundle: {{ .Values.ipamwrapperController.tls.provided.tlsCa | required "missing ipamwrapperController.tls.provided.tlsCa" }} + {{- else if (eq .Values.ipamwrapperController.tls.method "auto") }} + caBundle: {{ .ca.Cert | b64enc }} + {{- end }} + failurePolicy: Fail + name: ipamendpoint.ipamwrapper.inspur.io + rules: + - apiGroups: + - inspuripam.inspur.com + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + - DELETE + resources: + - ipamendpoints + sideEffects: None +{{- if eq .Values.ipamwrapperController.tls.method "certmanager" -}} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ .Values.ipamwrapperController.name | trunc 63 | trimSuffix "-" }}-server-certs + namespace: {{ .Release.Namespace }} +spec: + issuerRef: + name: {{ .Values.ipamwrapperController.tls.certmanager.issuerName | trunc 63 | trimSuffix "-" }} + secretName: {{ .Values.ipamwrapperController.tls.secretName | trunc 63 | trimSuffix "-" }} + commonName: {{ .Values.ipamwrapperController.name | trunc 63 | trimSuffix "-" }}.{{ .Release.Namespace }}.svc + dnsNames: + - {{ .Values.ipamwrapperController.name | trunc 63 | trimSuffix "-" }} + - {{ .Values.ipamwrapperController.name | trunc 63 | trimSuffix "-" }}.{{ .Release.Namespace }} + - {{ .Values.ipamwrapperController.name | trunc 63 | trimSuffix "-" }}.{{ .Release.Namespace }}.svc + - {{ .Values.ipamwrapperController.name | trunc 63 | trimSuffix "-" }}.{{ .Release.Namespace }}.svc.{{ .Values.global.clusterDnsDomain }} + {{- range $dns := .Values.ipamwrapperController.tls.certmanager.extraDnsNames }} + - {{ $dns | quote }} + {{- end }} + {{- if .Values.ipamwrapperController.tls.certmanager.extraIPAddresses }} + ipAddresses: + {{- range $ip := .Values.ipamwrapperController.tls.certmanager.extraIPAddresses }} + - {{ $ip | quote }} + {{- end }} + {{- end }} + duration: {{ printf "%dh" (mul .Values.ipamwrapperController.tls.certmanager.certValidityDuration 24) }} +{{- end }} +{{- if (eq .Values.ipamwrapperController.tls.method "provided") }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.ipamwrapperController.tls.secretName | trunc 63 | trimSuffix "-" }} + namespace: {{ .Release.Namespace }} +type: kubernetes.io/tls +data: + ca.crt: {{ .Values.ipamwrapperController.tls.provided.tlsCa | required "missing ipamwrapperController.tls.provided.tlsCa" }} + tls.crt: {{ .Values.ipamwrapperController.tls.provided.tlsCert | required "missing ipamwrapperController.tls.provided.tlsCert" }} + tls.key: {{ .Values.ipamwrapperController.tls.provided.tlsKey | required "missing ipamwrapperController.tls.provided.tlsKey" }} +{{- end }} +{{- if eq .Values.ipamwrapperController.tls.method "auto" }} +--- +{{- $cn := printf "inspur.io" }} +{{- $ip := .Values.ipamwrapperController.tls.auto.extraIpAddresses }} +{{- $dns1 := printf "%s.%s" .Values.ipamwrapperController.name .Release.Namespace }} +{{- $dns2 := printf "%s.%s.svc" .Values.ipamwrapperController.name .Release.Namespace }} +{{- $dns3 := printf "%s.%s.svc.%s" .Values.ipamwrapperController.name .Release.Namespace .Values.global.clusterDnsDomain }} +{{- $dns := prepend .Values.ipamwrapperController.tls.auto.extraDnsNames $dns1 }} +{{- $dns = prepend $dns $dns2 }} +{{- $dns = prepend $dns $dns3 }} +{{- $dns = prepend $dns $cn }} +{{- $cert := genSignedCert $cn $ip $dns (.Values.ipamwrapperController.tls.auto.certExpiration | int) .ca }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.ipamwrapperController.tls.secretName | trunc 63 | trimSuffix "-" }} + namespace: {{ .Release.Namespace }} +type: kubernetes.io/tls +data: + ca.crt: {{ .ca.Cert | b64enc }} + tls.crt: {{ $cert.Cert | b64enc }} + tls.key: {{ $cert.Key | b64enc }} +{{- end }} \ No newline at end of file diff --git a/cmd/controller/main.go b/cmd/controller/main.go index 1b26eb2..66ce5a0 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -100,6 +100,7 @@ func main() { // if you are doing or is intended to do any operation such as perform cleanups // after the manager stops then its usage might be unsafe. // LeaderElectionReleaseOnCancel: true, + CertDir: "/etc/tls", }) if err != nil { setupLog.Error(err, "unable to start manager") @@ -133,17 +134,17 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "IPAMEndpoint") os.Exit(1) } - /* - //webhook - if err = (&inspuripamv1.IPAMEndpoint{}).SetupWebhookWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create webhook", "webhook", "IPAMEndpoint") - os.Exit(1) - } - if err = (&inspuripamv1.IPPool{}).SetupWebhookWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create webhook", "webhook", "IPPool") - os.Exit(1) - } - */ + + //webhook + if err = (&inspuripamv1.IPAMEndpoint{}).SetupWebhookWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create webhook", "webhook", "IPAMEndpoint") + os.Exit(1) + } + if err = (&inspuripamv1.IPPool{}).SetupWebhookWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create webhook", "webhook", "IPPool") + os.Exit(1) + } + //+kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { diff --git a/pkg/k8s/api/v1/ippool_validate.go b/pkg/k8s/api/v1/ippool_validate.go index 0a8770f..65ff1c9 100644 --- a/pkg/k8s/api/v1/ippool_validate.go +++ b/pkg/k8s/api/v1/ippool_validate.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/Inspur-Data/ipamwrapper/pkg/constant" ipamwrapperip "github.com/Inspur-Data/ipamwrapper/pkg/ip" + "github.com/Inspur-Data/ipamwrapper/pkg/logging" "k8s.io/apimachinery/pkg/util/validation/field" "strconv" ) @@ -20,17 +21,20 @@ var ( func (r *IPPool) validCreate() field.ErrorList { //check ipversion if err := r.validIPversion(); err != nil { + logging.Errorf("ipversion is invalid, err: %v", err) return field.ErrorList{err} } //check CIDR ctx := context.Background() if err := r.validCIDR(ctx); err != nil { + logging.Errorf("CIDR is invalid, err: %v", err) return field.ErrorList{err} } //check available ip if err := r.validAvailableIPs(ctx); err != nil { + logging.Errorf("available ips is invalid, err: %v", err) return field.ErrorList{err} } @@ -45,7 +49,7 @@ func (r *IPPool) validIPversion() *field.Error { return field.Invalid( ipVersionField, version, - "is not generated correctly, 'spec.subnet' may be invalid", + "is not generated correctly, 'spec.ipVersion' may be invalid", ) } @@ -85,7 +89,14 @@ func (r *IPPool) validCIDR(ctx context.Context) *field.Error { } if pool.Spec.CIDR == r.Spec.CIDR { - continue + if r.isIPRangeOverlap(&pool) { + return field.Invalid( + ipsField, + r.Spec.IPs, + fmt.Sprintf("ips is overlaped with IPPool %s which 'spec.IPS' is %s", pool.Name, pool.Spec.IPs), + ) + } + } overlap, err := ipamwrapperip.IsCIDROverlap(*r.Spec.IPVersion, r.Spec.CIDR, pool.Spec.CIDR) @@ -106,6 +117,17 @@ func (r *IPPool) validCIDR(ctx context.Context) *field.Error { return nil } +func (r *IPPool) isIPRangeOverlap(pool *IPPool) bool { + for _, iprange := range r.Spec.IPs { + for _, subIpRange := range pool.Spec.IPs { + if overlaped, _ := ipamwrapperip.IsIPRangeOverlap(*r.Spec.IPVersion, iprange, subIpRange); overlaped { + return true + } + } + } + return false +} + // validAvailableIPs check the ippool's available ips func (r *IPPool) validAvailableIPs(ctx context.Context) *field.Error { //validate exclude ips diff --git a/pkg/k8s/api/v1/ippool_webhook.go b/pkg/k8s/api/v1/ippool_webhook.go index ab5c73b..52c87c4 100644 --- a/pkg/k8s/api/v1/ippool_webhook.go +++ b/pkg/k8s/api/v1/ippool_webhook.go @@ -20,6 +20,7 @@ import ( "fmt" "github.com/Inspur-Data/ipamwrapper/pkg/constant" ipamip "github.com/Inspur-Data/ipamwrapper/pkg/ip" + "github.com/Inspur-Data/ipamwrapper/pkg/logging" "github.com/Inspur-Data/ipamwrapper/pkg/types" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" @@ -65,7 +66,7 @@ var _ webhook.Validator = &IPPool{} // ValidateCreate implements webhook.Validator so a webhook will be registered for the type func (r *IPPool) ValidateCreate() (warnings admission.Warnings, err error) { - ippoollog.Info("validate create", "name", r.Name) + logging.Debugf("validate create", "name:%s", r.Name) errlist := r.validCreate() if len(errlist) != 0 { return nil, apierrors.NewInvalid(schema.GroupKind{Group: constant.APIGroup, Kind: constant.IPPOOL}, r.Name, errlist)