Skip to content

Commit

Permalink
add
Browse files Browse the repository at this point in the history
Signed-off-by: yaroslavborbat <[email protected]>
  • Loading branch information
yaroslavborbat committed Dec 10, 2024
1 parent fb2423c commit c3bcd08
Show file tree
Hide file tree
Showing 6 changed files with 260 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import (
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"

"github.com/deckhouse/deckhouse/pkg/log"

appconfig "github.com/deckhouse/virtualization-controller/pkg/config"
"github.com/deckhouse/virtualization-controller/pkg/controller/cvi"
"github.com/deckhouse/virtualization-controller/pkg/controller/indexer"
Expand All @@ -51,6 +52,7 @@ import (
"github.com/deckhouse/virtualization-controller/pkg/controller/vmop"
"github.com/deckhouse/virtualization-controller/pkg/controller/vmrestore"
"github.com/deckhouse/virtualization-controller/pkg/controller/vmsnapshot"
"github.com/deckhouse/virtualization-controller/pkg/controller/webhook"
"github.com/deckhouse/virtualization-controller/pkg/logger"
"github.com/deckhouse/virtualization/api/client/kubeclient"
virtv2alpha1 "github.com/deckhouse/virtualization/api/core/v1alpha2"
Expand Down Expand Up @@ -139,6 +141,11 @@ func main() {
viStorageClassSettings := appconfig.LoadVirtualImageStorageClassSettings()
vdStorageClassSettings := appconfig.LoadVirtualDiskStorageClassSettings()

serviceAccounts, err := appconfig.LoadServiceAccounts()
if err != nil {
log.Error(err.Error())
os.Exit(1)
}
// Get a config to talk to the apiserver
cfg, err := config.GetConfig()
if err != nil {
Expand Down Expand Up @@ -304,6 +311,8 @@ func main() {
os.Exit(1)
}

webhook.SetupHTTPHooks(mgr, serviceAccounts)

log.Info("Starting the Manager.")

// Start the Manager
Expand Down
128 changes: 128 additions & 0 deletions images/virtualization-artifact/pkg/config/load_sa.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package config

import (
"fmt"
"os"
)

const (
SACDIApiserver = "SA_CDI_APISERVER"
SACDICronjob = "SA_CDI_CRONJOB"
SACDIOperator = "SA_CDI_OPERATOR"
SACDISa = "SA_CDI_SA"
SACDIUploadProxy = "SA_CDI_UPLOAD_PROXY"
SAKubevirtApiserver = "SA_KUBEVIRT_APISERVER"
SAKubevirtController = "SA_KUBEVIRT_CONTROLLER"
SAKubevirtExportProxy = "SA_KUBEVIRT_EXPORT_PROXY"
SAKubevirtVirtHandler = "SA_KUBEVIRT_VIRT_HANDLER"
SAKubevirtOperator = "SA_KUBEVIRT_OPERATOR"
SAVirtualizationController = "SA_VIRTUALIZATION_CONTROLLER"
SAVirtualizationAPI = "SA_VIRTUALIZATION_API"
SAVirtualizationPpeDeleteHook = "SA_VIRTUALIZATION_PPE_DELETE_HOOK"
SAVmRouteForge = "SA_VM_ROUTE_FORGE"
)

type ServiceAccounts struct {
SACDIApiserver string
SACDICronjob string
SACDIOperator string
SACDISa string
SACDIUploadProxy string
SAKubevirtApiserver string
SAKubevirtController string
SAKubevirtExportProxy string
SAKubevirtVirtHandler string
SAKubevirtOperator string
SAVirtualizationController string
SAVirtualizationAPI string
SAVirtualizationPpeDeleteHook string
SAVmRouteForge string
}

func (s *ServiceAccounts) ToList() []string {
return []string{
s.SACDIApiserver,
s.SACDICronjob,
s.SACDIOperator,
s.SACDISa,
s.SACDIUploadProxy,
s.SAKubevirtApiserver,
s.SAKubevirtController,
s.SAKubevirtExportProxy,
s.SAKubevirtVirtHandler,
s.SAKubevirtOperator,
s.SAVirtualizationController,
s.SAVirtualizationAPI,
s.SAVirtualizationPpeDeleteHook,
s.SAVmRouteForge,
}
}

func (s *ServiceAccounts) Validate() error {
if s.SACDIApiserver == "" {
return fmt.Errorf("%q is required", SACDIApiserver)
}
if s.SACDICronjob == "" {
return fmt.Errorf("%q is required", SACDICronjob)
}
if s.SACDIOperator == "" {
return fmt.Errorf("%q is required", SACDIOperator)
}
if s.SACDISa == "" {
return fmt.Errorf("%q is required", SACDISa)
}
if s.SACDIUploadProxy == "" {
return fmt.Errorf("%q is required", SACDIUploadProxy)
}
if s.SAKubevirtApiserver == "" {
return fmt.Errorf("%q is required", SAKubevirtApiserver)
}
if s.SAKubevirtController == "" {
return fmt.Errorf("%q is required", SAKubevirtController)
}
if s.SAKubevirtExportProxy == "" {
return fmt.Errorf("%q is required", SAKubevirtExportProxy)
}
if s.SAKubevirtVirtHandler == "" {
return fmt.Errorf("%q is required", SAKubevirtVirtHandler)
}
if s.SAKubevirtOperator == "" {
return fmt.Errorf("%q is required", SAKubevirtOperator)
}
if s.SAVirtualizationController == "" {
return fmt.Errorf("%q is required", SAVirtualizationController)
}
if s.SAVirtualizationAPI == "" {
return fmt.Errorf("%q is required", SAVirtualizationAPI)
}
if s.SAVirtualizationPpeDeleteHook == "" {
return fmt.Errorf("%q is required", SAVirtualizationPpeDeleteHook)
}
if s.SAVmRouteForge == "" {
return fmt.Errorf("%q is required", SAVmRouteForge)
}
return nil
}

func LoadServiceAccounts() (ServiceAccounts, error) {
serviceAccounts := ServiceAccounts{
SACDIApiserver: os.Getenv(SACDIApiserver),
SACDICronjob: os.Getenv(SACDICronjob),
SACDIOperator: os.Getenv(SACDIOperator),
SACDISa: os.Getenv(SACDISa),
SACDIUploadProxy: os.Getenv(SACDIUploadProxy),
SAKubevirtApiserver: os.Getenv(SAKubevirtApiserver),
SAKubevirtController: os.Getenv(SAKubevirtController),
SAKubevirtExportProxy: os.Getenv(SAKubevirtExportProxy),
SAKubevirtVirtHandler: os.Getenv(SAKubevirtVirtHandler),
SAKubevirtOperator: os.Getenv(SAKubevirtOperator),
SAVirtualizationController: os.Getenv(SAVirtualizationController),
SAVirtualizationAPI: os.Getenv(SAVirtualizationAPI),
SAVirtualizationPpeDeleteHook: os.Getenv(SAVirtualizationPpeDeleteHook),
SAVmRouteForge: os.Getenv(SAVmRouteForge),
}
if err := serviceAccounts.Validate(); err != nil {
return ServiceAccounts{}, err
}
return serviceAccounts, nil
}
46 changes: 46 additions & 0 deletions images/virtualization-artifact/pkg/controller/webhook/protect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package webhook

import (
"context"
"slices"

admissionv1 "k8s.io/api/admission/v1"
virtcore "kubevirt.io/api/core"
cdicore "kubevirt.io/containerized-data-importer-api/pkg/apis/core"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

const ProtectResourcesPath = "/protect-resources"

var defaultProtectGroups = []string{
virtcore.GroupName,
cdicore.GroupName,
}

func newProtectHook(allowSA []string, groups []string) *protectHook {
return &protectHook{
allowSA: allowSA,
groups: groups,
operations: []admissionv1.Operation{
admissionv1.Create,
admissionv1.Update,
admissionv1.Delete,
},
}
}

type protectHook struct {
allowSA []string
groups []string
operations []admissionv1.Operation
}

func (p protectHook) Handle(_ context.Context, req admission.Request) admission.Response {
if slices.Contains(p.groups, req.Resource.Group) &&
!slices.Contains(p.allowSA, req.UserInfo.Username) &&
slices.Contains(p.operations, req.Operation) {
return admission.Denied("Operation forbidden for this service account.")
}

return admission.Allowed("")
}
24 changes: 24 additions & 0 deletions images/virtualization-artifact/pkg/controller/webhook/webhook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package webhook

import (
"net/http"

"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/webhook"

appconfig "github.com/deckhouse/virtualization-controller/pkg/config"
)

func SetupHTTPHooks(mgr manager.Manager, serviceAccounts appconfig.ServiceAccounts) {
saNames := serviceAccounts.ToList()

var hooks = map[string]http.Handler{
ProtectResourcesPath: &webhook.Admission{Handler: newProtectHook(saNames, defaultProtectGroups)},
}

ws := mgr.GetWebhookServer()

for path, hook := range hooks {
ws.Register(path, hook)
}
}
28 changes: 28 additions & 0 deletions templates/virtualization-controller/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,32 @@
- name: PPROF_BIND_ADDRESS
value: ":8081"
{{- end }}
- name: "SA_CDI_APISERVER"
value: "cdi-apiserver"
- name: "SA_CDI_CRONJOB"
value: "cdi-cronjob"
- name: "SA_CDI_OPERATOR"
value: "cdi-operator"
- name: "SA_CDI_SA"
value: "cdi-sa"
- name: "SA_CDI_UPLOAD_PROXY"
value: "cdi-uploadproxy"
- name: "SA_KUBEVIRT_APISERVER"
value: "kubevirt-internal-virtualization-apiserver"
- name: "SA_KUBEVIRT_CONTROLLER"
value: "kubevirt-internal-virtualization-controller"
- name: "SA_KUBEVIRT_EXPORT_PROXY"
value: "kubevirt-internal-virtualization-exportproxy"
- name: "SA_KUBEVIRT_VIRT_HANDLER"
value: "kubevirt-internal-virtualization-handler"
- name: "SA_KUBEVIRT_OPERATOR"
value: "kubevirt-operator"
- name: "SA_VIRTUALIZATION_CONTROLLER"
value: "virtualization-controller"
- name: "SA_VIRTUALIZATION_API"
value: "virtualization-api"
- name: "SA_VIRTUALIZATION_PPE_DELETE_HOOK"
value: "virtualization-pre-delete-hook"
- name: "SA_VM_ROUTE_FORGE"
value: "vm-route-forge"
{{- end }}
25 changes: 25 additions & 0 deletions templates/virtualization-controller/validation-webhook.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -207,3 +207,28 @@ webhooks:
{{ .Values.virtualization.internal.controller.cert.ca }}
admissionReviewVersions: ["v1"]
sideEffects: None
- name: "protect-resources.virtualization-controller.validate.d8-virtualization"
rules:
- apiGroups:
- "cdi.internal.virtualization.deckhouse.io"
- "clone.internal.virtualization.deckhouse.io"
- "export.internal.virtualization.deckhouse.io"
- "forklift.cdi.internal.virtualization.deckhouse.io"
- "instancetype.internal.virtualization.deckhouse.io"
- "internal.virtualization.deckhouse.io"
- "pool.internal.virtualization.deckhouse.io"
- "snapshot.internal.virtualization.deckhouse.io"
apiVersions: ["*"]
operations: ["CREATE", "UPDATE", "DELETE"]
resources: ["*"]
scope: "*"
clientConfig:
service:
namespace: d8-{{ .Chart.Name }}
name: virtualization-controller
path: "/protect-resources"
port: 443
caBundle: |
{{ .Values.virtualization.internal.controller.cert.ca }}
admissionReviewVersions: ["v1"]
sideEffects: None

0 comments on commit c3bcd08

Please sign in to comment.