diff --git a/cluster-sync/clean.sh b/cluster-sync/clean.sh index 72e949cb1e..01da49a79c 100755 --- a/cluster-sync/clean.sh +++ b/cluster-sync/clean.sh @@ -16,10 +16,6 @@ OPERATOR_MANIFEST=./_out/manifests/release/cdi-operator.yaml LABELS=("operator.cdi.kubevirt.io" "cdi.kubevirt.io" "prometheus.cdi.kubevirt.io") NAMESPACES=(default kube-system cdi) -set +e -_kubectl patch cdi ${CR_NAME} --type=json -p '[{ "op": "remove", "path": "/metadata/finalizers" }]' -set -e - _kubectl get ot --all-namespaces -o=custom-columns=NAME:.metadata.name,NAMESPACE:.metadata.namespace,FINALIZERS:.metadata.finalizers --no-headers | grep objectTransfer | while read p; do arr=($p) name="${arr[0]}" @@ -52,10 +48,14 @@ if [ -f "${OPERATOR_CR_MANIFEST}" ]; then echo "Cleaning CR object ..." if _kubectl get crd cdis.cdi.kubevirt.io ; then _kubectl delete --ignore-not-found -f "${OPERATOR_CR_MANIFEST}" - _kubectl wait cdis.cdi.kubevirt.io/${CR_NAME} --for=delete | echo "this is fine" + _kubectl wait cdis.cdi.kubevirt.io/${CR_NAME} --for=delete --timeout=30s | echo "this is fine" fi fi +set +e +_kubectl patch cdi ${CR_NAME} --type=json -p '[{ "op": "remove", "path": "/metadata/finalizers" }]' | echo "this is fine" +set -e + if [ "${CDI_CLEAN}" == "all" ] && [ -f "${OPERATOR_MANIFEST}" ]; then echo "Deleting operator ..." _kubectl delete --ignore-not-found -f "${OPERATOR_MANIFEST}" diff --git a/cmd/cdi-cloner/BUILD.bazel b/cmd/cdi-cloner/BUILD.bazel index be84a112e7..098bff0a10 100644 --- a/cmd/cdi-cloner/BUILD.bazel +++ b/cmd/cdi-cloner/BUILD.bazel @@ -52,5 +52,6 @@ container_image( ":cdi-cloner", ":cloner_startup.sh", ], + user = "1001", visibility = ["//visibility:public"], ) diff --git a/cmd/cdi-cloner/clone-source.go b/cmd/cdi-cloner/clone-source.go index 9dfba4f798..67e14416e1 100644 --- a/cmd/cdi-cloner/clone-source.go +++ b/cmd/cdi-cloner/clone-source.go @@ -146,12 +146,29 @@ func validateMount() { } func newTarReader(preallocation bool) (io.ReadCloser, error) { - args := "cv" + excludeMap := map[string]struct{}{ + "lost+found": struct{}{}, + } + + args := []string{"cv"} if !preallocation { // -S is used to handle sparse files. It can only be used when preallocation is not requested - args = "S" + args + args = append(args, "-S") + } + + files, err := os.ReadDir(mountPoint) + if err != nil { + return nil, err } - cmd := exec.Command("/usr/bin/tar", args, ".") + + for _, f := range files { + if _, ok := excludeMap[f.Name()]; ok { + continue + } + args = append(args, f.Name()) + } + + cmd := exec.Command("/usr/bin/tar", args...) cmd.Dir = mountPoint stdout, err := cmd.StdoutPipe() diff --git a/cmd/cdi-importer/BUILD.bazel b/cmd/cdi-importer/BUILD.bazel index 17fdc86be0..dd62712b3e 100644 --- a/cmd/cdi-importer/BUILD.bazel +++ b/cmd/cdi-importer/BUILD.bazel @@ -49,6 +49,7 @@ container_image( "//tools/cdi-image-size-detection", "//tools/cdi-source-update-poller", ], + user = "1001", visibility = ["//visibility:public"], ) diff --git a/cmd/cdi-uploadserver/BUILD.bazel b/cmd/cdi-uploadserver/BUILD.bazel index 7093c5b498..ac257d2aa9 100755 --- a/cmd/cdi-uploadserver/BUILD.bazel +++ b/cmd/cdi-uploadserver/BUILD.bazel @@ -39,6 +39,7 @@ container_image( "-alsologtostderr", ], files = [":cdi-uploadserver"], + user = "1001", visibility = ["//visibility:public"], ) diff --git a/pkg/controller/clone-controller.go b/pkg/controller/clone-controller.go index 66bf9817c9..4c89046476 100644 --- a/pkg/controller/clone-controller.go +++ b/pkg/controller/clone-controller.go @@ -23,7 +23,6 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/record" - "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/handler" @@ -573,7 +572,7 @@ func MakeCloneSourcePodSpec(sourceVolumeMode corev1.PersistentVolumeMode, image, } } - preallocationRequested, _ := targetPvc.Annotations[AnnPreallocationRequested] + preallocationRequested := targetPvc.Annotations[AnnPreallocationRequested] pod := &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ @@ -644,14 +643,6 @@ func MakeCloneSourcePodSpec(sourceVolumeMode corev1.PersistentVolumeMode, image, Protocol: corev1.ProtocolTCP, }, }, - SecurityContext: &corev1.SecurityContext{ - Capabilities: &corev1.Capabilities{ - Drop: []corev1.Capability{ - "ALL", - }, - }, - AllowPrivilegeEscalation: pointer.BoolPtr(false), - }, }, }, RestartPolicy: corev1.RestartPolicyOnFailure, @@ -740,6 +731,7 @@ func MakeCloneSourcePodSpec(sourceVolumeMode corev1.PersistentVolumeMode, image, pod.Spec.Containers[0].Env = append(pod.Spec.Containers[0].Env, addVars...) SetPodPvcAnnotations(pod, targetPvc) + SetRestrictedSecurityContext(&pod.Spec) return pod } diff --git a/pkg/controller/dataimportcron-controller.go b/pkg/controller/dataimportcron-controller.go index a1533fa4bd..39c77c6bf2 100644 --- a/pkg/controller/dataimportcron-controller.go +++ b/pkg/controller/dataimportcron-controller.go @@ -41,7 +41,6 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/validation" "k8s.io/client-go/tools/record" - "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/event" @@ -752,14 +751,6 @@ func (r *DataImportCronReconciler) newCronJob(cron *cdiv1.DataImportCron) (*batc return nil, err } container := corev1.Container{ - SecurityContext: &corev1.SecurityContext{ - Capabilities: &corev1.Capabilities{ - Drop: []corev1.Capability{ - "ALL", - }, - }, - AllowPrivilegeEscalation: pointer.BoolPtr(false), - }, Name: "cdi-source-update-poller", Image: r.image, Command: []string{ @@ -873,6 +864,7 @@ func (r *DataImportCronReconciler) newCronJob(cron *cdiv1.DataImportCron) (*batc if err := sdk.SetLastAppliedConfiguration(cronJob, AnnLastAppliedConfig); err != nil { return nil, err } + SetRestrictedSecurityContext(&cronJob.Spec.JobTemplate.Spec.Template.Spec) return cronJob, nil } diff --git a/pkg/controller/datavolume-controller.go b/pkg/controller/datavolume-controller.go index 87d11a2ce2..9d8b4fcc73 100644 --- a/pkg/controller/datavolume-controller.go +++ b/pkg/controller/datavolume-controller.go @@ -47,7 +47,6 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/record" - "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -1630,14 +1629,6 @@ func (r *DatavolumeReconciler) createExpansionPod(pvc *corev1.PersistentVolumeCl ImagePullPolicy: corev1.PullPolicy(r.pullPolicy), Command: []string{"/bin/bash"}, Args: []string{"-c", "echo", "'hello cdi'"}, - SecurityContext: &corev1.SecurityContext{ - Capabilities: &corev1.Capabilities{ - Drop: []corev1.Capability{ - "ALL", - }, - }, - AllowPrivilegeEscalation: pointer.BoolPtr(false), - }, }, }, RestartPolicy: corev1.RestartPolicyOnFailure, @@ -1677,6 +1668,8 @@ func (r *DatavolumeReconciler) createExpansionPod(pvc *corev1.PersistentVolumeCl return nil, err } + SetRestrictedSecurityContext(&pod.Spec) + if err := r.client.Create(context.TODO(), pod); err != nil { if !k8serrors.IsAlreadyExists(err) { return nil, err @@ -3149,6 +3142,8 @@ func (r *DatavolumeReconciler) makeSizeDetectionPodSpec( }, } + SetRestrictedSecurityContext(&pod.Spec) + return pod } @@ -3185,14 +3180,6 @@ func (r *DatavolumeReconciler) makeSizeDetectionContainerSpec(volName string) *c Name: volName, }, }, - SecurityContext: &corev1.SecurityContext{ - Capabilities: &corev1.Capabilities{ - Drop: []corev1.Capability{ - "ALL", - }, - }, - AllowPrivilegeEscalation: pointer.BoolPtr(false), - }, } // Get and assign container's default resource requirements diff --git a/pkg/controller/import-controller.go b/pkg/controller/import-controller.go index fafb90aa1d..389548dd47 100644 --- a/pkg/controller/import-controller.go +++ b/pkg/controller/import-controller.go @@ -19,7 +19,6 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/tools/record" - "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/handler" @@ -943,7 +942,7 @@ func createImporterPod(log logr.Logger, client client.Client, args *importerPodA // makeNodeImporterPodSpec creates and returns the node docker cache based importer pod spec based on the passed-in importImage and pvc. func makeNodeImporterPodSpec(args *importerPodArgs) *corev1.Pod { // importer pod name contains the pvc name - podName, _ := args.pvc.Annotations[AnnImportPod] + podName := args.pvc.Annotations[AnnImportPod] volumes := []corev1.Volume{ { @@ -995,14 +994,6 @@ func makeNodeImporterPodSpec(args *importerPodArgs) *corev1.Pod { Name: "shared-volume", }, }, - SecurityContext: &corev1.SecurityContext{ - Capabilities: &corev1.Capabilities{ - Drop: []corev1.Capability{ - "ALL", - }, - }, - AllowPrivilegeEscalation: pointer.BoolPtr(false), - }, }, }, Containers: []corev1.Container{ @@ -1018,14 +1009,6 @@ func makeNodeImporterPodSpec(args *importerPodArgs) *corev1.Pod { Name: "shared-volume", }, }, - SecurityContext: &corev1.SecurityContext{ - Capabilities: &corev1.Capabilities{ - Drop: []corev1.Capability{ - "ALL", - }, - }, - AllowPrivilegeEscalation: pointer.BoolPtr(false), - }, }, }, RestartPolicy: corev1.RestartPolicyOnFailure, @@ -1072,13 +1055,15 @@ func makeNodeImporterPodSpec(args *importerPodArgs) *corev1.Pod { Name: "shared-volume", }) + SetRestrictedSecurityContext(&pod.Spec) + return pod } // makeImporterPodSpec creates and return the importer pod spec based on the passed-in endpoint, secret and pvc. func makeImporterPodSpec(args *importerPodArgs) *corev1.Pod { // importer pod name contains the pvc name - podName, _ := args.pvc.Annotations[AnnImportPod] + podName := args.pvc.Annotations[AnnImportPod] blockOwnerDeletion := true isController := true @@ -1230,6 +1215,8 @@ func makeImporterPodSpec(args *importerPodArgs) *corev1.Pod { pod.Spec.Volumes = append(pod.Spec.Volumes, vol) } + SetRestrictedSecurityContext(&pod.Spec) + return pod } @@ -1253,14 +1240,6 @@ func setImporterPodCommons(pod *corev1.Pod, podEnvVar *importPodEnvVar, pvc *cor pod.Spec.Containers[0].Env = makeImportEnv(podEnvVar, ownerUID) - if podEnvVar.contentType == string(cdiv1.DataVolumeKubeVirt) { - // Set the fsGroup on the security context to the QemuSubGid - if pod.Spec.SecurityContext == nil { - pod.Spec.SecurityContext = &corev1.PodSecurityContext{} - } - fsGroup := common.QemuSubGid - pod.Spec.SecurityContext.FSGroup = &fsGroup - } SetPodPvcAnnotations(pod, pvc) } @@ -1277,14 +1256,6 @@ func makeImporterContainerSpec(image, verbose, pullPolicy string) *corev1.Contai Protocol: corev1.ProtocolTCP, }, }, - SecurityContext: &corev1.SecurityContext{ - Capabilities: &corev1.Capabilities{ - Drop: []corev1.Capability{ - "ALL", - }, - }, - AllowPrivilegeEscalation: pointer.BoolPtr(false), - }, } } diff --git a/pkg/controller/import-controller_test.go b/pkg/controller/import-controller_test.go index f174d06ecb..abfc8486cc 100644 --- a/pkg/controller/import-controller_test.go +++ b/pkg/controller/import-controller_test.go @@ -260,8 +260,6 @@ var _ = Describe("ImportConfig Controller reconcile loop", func() { } } Expect(foundEndPoint).To(BeTrue()) - By("Verifying the fsGroup of the pod is the qemu user") - Expect(*pod.Spec.SecurityContext.FSGroup).To(Equal(int64(107))) }) It("Should create a POD with node placement", func() { @@ -332,8 +330,6 @@ var _ = Describe("ImportConfig Controller reconcile loop", func() { } } Expect(foundEndPoint).To(BeTrue()) - By("Verifying the fsGroup of the pod is the qemu user") - Expect(*pod.Spec.SecurityContext.FSGroup).To(Equal(int64(107))) By("Verifying the pod is annotated correctly") Expect(pod.GetAnnotations()[AnnPodNetwork]).To(Equal("net1")) Expect(pod.GetAnnotations()[AnnPodSidecarInjection]).To(Equal(AnnPodSidecarInjectionDefault)) @@ -360,27 +356,6 @@ var _ = Describe("ImportConfig Controller reconcile loop", func() { Expect(pod.GetAnnotations()["annot1"]).ToNot(Equal("value1")) }) - It("Should create a POD if a bound PVC with all needed annotations is passed, but not set fsgroup if not kubevirt contenttype", func() { - pvc := createPvc("testPvc1", "default", map[string]string{AnnEndpoint: testEndPoint, AnnImportPod: "importer-testPvc1", AnnContentType: string(cdiv1.DataVolumeArchive)}, nil) - pvc.Status.Phase = v1.ClaimBound - reconciler = createImportReconciler(pvc) - _, err := reconciler.Reconcile(context.TODO(), reconcile.Request{NamespacedName: types.NamespacedName{Name: "testPvc1", Namespace: "default"}}) - Expect(err).ToNot(HaveOccurred()) - pod := &corev1.Pod{} - err = reconciler.client.Get(context.TODO(), types.NamespacedName{Name: "importer-testPvc1", Namespace: "default"}, pod) - Expect(err).ToNot(HaveOccurred()) - foundEndPoint := false - for _, envVar := range pod.Spec.Containers[0].Env { - if envVar.Name == common.ImporterEndpoint { - foundEndPoint = true - Expect(envVar.Value).To(Equal(testEndPoint)) - } - } - Expect(foundEndPoint).To(BeTrue()) - By("Verifying the fsGroupis not set") - Expect(pod.Spec.SecurityContext).To(BeNil()) - }) - It("Should error if a POD with the same name exists, but is not owned by the PVC, if a PVC with all needed annotations is passed", func() { pod := &corev1.Pod{ TypeMeta: metav1.TypeMeta{ diff --git a/pkg/controller/upload-controller.go b/pkg/controller/upload-controller.go index fc1346810c..284c8f30b5 100644 --- a/pkg/controller/upload-controller.go +++ b/pkg/controller/upload-controller.go @@ -38,7 +38,6 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/tools/record" - "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/handler" @@ -720,7 +719,6 @@ func createUploadServiceNameFromPvcName(pvc string) string { func (r *UploadReconciler) makeUploadPodSpec(args UploadPodArgs, resourceRequirements *v1.ResourceRequirements, workloadNodePlacement *sdkapi.NodePlacement) *v1.Pod { requestImageSize, _ := getRequestedImageSize(args.PVC) serviceName := naming.GetServiceNameFromResourceName(args.Name) - fsGroup := common.QemuSubGid pod := &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: args.Name, @@ -810,14 +808,6 @@ func (r *UploadReconciler) makeUploadPodSpec(args UploadPodArgs, resourceRequire InitialDelaySeconds: 2, PeriodSeconds: 5, }, - SecurityContext: &corev1.SecurityContext{ - Capabilities: &corev1.Capabilities{ - Drop: []corev1.Capability{ - "ALL", - }, - }, - AllowPrivilegeEscalation: pointer.BoolPtr(false), - }, }, }, RestartPolicy: v1.RestartPolicyOnFailure, @@ -839,13 +829,6 @@ func (r *UploadReconciler) makeUploadPodSpec(args UploadPodArgs, resourceRequire }, } - if !checkPVC(args.PVC, AnnCloneRequest, r.log.WithValues("Name", args.PVC.Name, "Namspace", args.PVC.Namespace)) { - if pod.Spec.SecurityContext == nil { - pod.Spec.SecurityContext = &v1.PodSecurityContext{} - } - pod.Spec.SecurityContext.FSGroup = &fsGroup - } - if resourceRequirements != nil { pod.Spec.Containers[0].Resources = *resourceRequirements } @@ -887,5 +870,6 @@ func (r *UploadReconciler) makeUploadPodSpec(args UploadPodArgs, resourceRequire }) } SetPodPvcAnnotations(pod, args.PVC) + SetRestrictedSecurityContext(&pod.Spec) return pod } diff --git a/pkg/controller/util.go b/pkg/controller/util.go index 4ea0af3029..649f2aacb2 100644 --- a/pkg/controller/util.go +++ b/pkg/controller/util.go @@ -13,6 +13,7 @@ import ( snapshotv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1" ocpconfigv1 "github.com/openshift/api/config/v1" "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1" storagev1 "k8s.io/api/storage/v1" extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -23,6 +24,8 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/tools/record" "k8s.io/klog/v2" + "k8s.io/utils/pointer" + cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1" cdiv1utils "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1/utils" "kubevirt.io/containerized-data-importer/pkg/common" @@ -1244,3 +1247,36 @@ func isPVCComplete(pvc *v1.PersistentVolumeClaim) bool { func isPodComplete(pod *v1.Pod) bool { return pod != nil && pod.Status.Phase == v1.PodSucceeded } + +func SetRestrictedSecurityContext(podSpec *v1.PodSpec) { + hasVolumeMounts := false + for _, containers := range [][]v1.Container{podSpec.InitContainers, podSpec.Containers} { + for i := range containers { + container := &containers[i] + if container.SecurityContext == nil { + container.SecurityContext = &v1.SecurityContext{} + } + container.SecurityContext.Capabilities = &corev1.Capabilities{ + Drop: []corev1.Capability{ + "ALL", + }, + } + container.SecurityContext.SeccompProfile = &v1.SeccompProfile{ + Type: v1.SeccompProfileTypeRuntimeDefault, + } + container.SecurityContext.AllowPrivilegeEscalation = pointer.BoolPtr(false) + container.SecurityContext.RunAsNonRoot = pointer.BoolPtr(true) + container.SecurityContext.RunAsUser = pointer.Int64(common.QemuSubGid) + if len(container.VolumeMounts) > 0 { + hasVolumeMounts = true + } + } + } + + if hasVolumeMounts { + if podSpec.SecurityContext == nil { + podSpec.SecurityContext = &v1.PodSecurityContext{} + } + podSpec.SecurityContext.FSGroup = pointer.Int64(common.QemuSubGid) + } +} diff --git a/pkg/importer/data-processor.go b/pkg/importer/data-processor.go index 973c99eb33..0524ebe739 100644 --- a/pkg/importer/data-processor.go +++ b/pkg/importer/data-processor.go @@ -332,7 +332,7 @@ func (dp *DataProcessor) resize() (ProcessingPhase, error) { } dp.preallocationApplied = dp.preallocation } - if dp.dataFile != "" { + if dp.dataFile != "" && !isBlockDev { // Change permissions to 0660 err := os.Chmod(dp.dataFile, 0660) if err != nil { diff --git a/pkg/importer/http-datasource.go b/pkg/importer/http-datasource.go index 1c6b0efd96..e12936672e 100644 --- a/pkg/importer/http-datasource.go +++ b/pkg/importer/http-datasource.go @@ -46,8 +46,8 @@ import ( const ( tempFile = "tmpimage" - nbdkitPid = "/var/run/nbdkit.pid" - nbdkitSocket = "/var/run/nbdkit.sock" + nbdkitPid = "/tmp/nbdkit.pid" + nbdkitSocket = "/tmp/nbdkit.sock" defaultUserAgent = "cdi-golang-importer" ) diff --git a/pkg/importer/http-datasource_test.go b/pkg/importer/http-datasource_test.go index 858c110bf1..70696dc18a 100644 --- a/pkg/importer/http-datasource_test.go +++ b/pkg/importer/http-datasource_test.go @@ -96,7 +96,7 @@ var _ = Describe("Http data source", func() { Expect(err).NotTo(HaveOccurred()) Expect(expectedPhase).To(Equal(newPhase)) if newPhase == ProcessingPhaseConvert { - expectURL, err := url.Parse("nbd+unix:///?socket=/var/run/nbdkit.sock") + expectURL, err := url.Parse("nbd+unix:///?socket=/tmp/nbdkit.sock") Expect(err).NotTo(HaveOccurred()) Expect(expectURL).To(Equal(dp.GetURL())) } diff --git a/pkg/importer/registry-datasource.go b/pkg/importer/registry-datasource.go index 3ff1d1f48d..d2bef876ff 100644 --- a/pkg/importer/registry-datasource.go +++ b/pkg/importer/registry-datasource.go @@ -165,7 +165,7 @@ func getImageFileName(dir string) (string, error) { } func createCertificateDir(registryCertDir string) (string, error) { - allCerts := "/var/local/all_certs" + allCerts := "/tmp/all_certs" err := os.MkdirAll(allCerts, 0700) if err != nil { return allCerts, err diff --git a/pkg/importer/vddk-datasource_amd64.go b/pkg/importer/vddk-datasource_amd64.go index 6349598017..cb4dcfbce1 100644 --- a/pkg/importer/vddk-datasource_amd64.go +++ b/pkg/importer/vddk-datasource_amd64.go @@ -64,8 +64,8 @@ var newNbdKitLogWatcher = createNbdKitLogWatcher /* Section: nbdkit */ const ( - nbdUnixSocket = "/var/run/nbd.sock" - nbdPidFile = "/var/run/nbd.pid" + nbdUnixSocket = "/tmp/nbd.sock" + nbdPidFile = "/tmp/nbd.pid" maxLogLines = 30 ) diff --git a/pkg/operator/controller/BUILD.bazel b/pkg/operator/controller/BUILD.bazel index ad51ef0cef..016a698fd2 100644 --- a/pkg/operator/controller/BUILD.bazel +++ b/pkg/operator/controller/BUILD.bazel @@ -46,6 +46,7 @@ go_library( "//vendor/k8s.io/api/rbac/v1:go_default_library", "//vendor/k8s.io/api/scheduling/v1:go_default_library", "//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/operator/controller/callbacks.go b/pkg/operator/controller/callbacks.go index b4dbe0dd53..eeb7364290 100644 --- a/pkg/operator/controller/callbacks.go +++ b/pkg/operator/controller/callbacks.go @@ -45,7 +45,7 @@ func addReconcileCallbacks(r *ReconcileCDI) { r.reconciler.AddCallback(&corev1.ServiceAccount{}, reconcileServiceAccountRead) r.reconciler.AddCallback(&corev1.ServiceAccount{}, reconcileServiceAccounts) r.reconciler.AddCallback(&corev1.ServiceAccount{}, reconcileCreateSCC) - r.reconciler.AddCallback(&corev1.ServiceAccount{}, reconcileSELinuxPerms) + r.reconciler.AddCallback(&corev1.ServiceAccount{}, reconcileSCC) r.reconciler.AddCallback(&appsv1.Deployment{}, reconcileCreateRoute) r.reconciler.AddCallback(&appsv1.Deployment{}, reconcileCreatePrometheusInfra) r.reconciler.AddCallback(&appsv1.Deployment{}, reconcileRemainingRelationshipLabels) diff --git a/pkg/operator/controller/cruft.go b/pkg/operator/controller/cruft.go index 2fb2a32f17..aa1c5ae5fe 100644 --- a/pkg/operator/controller/cruft.go +++ b/pkg/operator/controller/cruft.go @@ -22,26 +22,25 @@ import ( "fmt" "reflect" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - - cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1" - "kubevirt.io/containerized-data-importer/pkg/apiserver" - "kubevirt.io/containerized-data-importer/pkg/common" - "kubevirt.io/containerized-data-importer/pkg/operator" - "kubevirt.io/containerized-data-importer/pkg/util" - "kubevirt.io/controller-lifecycle-operator-sdk/pkg/sdk/callbacks" - routev1 "github.com/openshift/api/route/v1" secv1 "github.com/openshift/api/security/v1" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + apiequality "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client" + cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1" + "kubevirt.io/containerized-data-importer/pkg/apiserver" + "kubevirt.io/containerized-data-importer/pkg/common" + "kubevirt.io/containerized-data-importer/pkg/operator" + "kubevirt.io/containerized-data-importer/pkg/util" sdk "kubevirt.io/controller-lifecycle-operator-sdk/pkg/sdk" + "kubevirt.io/controller-lifecycle-operator-sdk/pkg/sdk/callbacks" ) const ( @@ -200,8 +199,7 @@ func reconcileInitializeCRD(args *callbacks.ReconcileCallbackArgs) error { return nil } -// delete when we no longer support <= 1.27.0 -func reconcileSELinuxPerms(args *callbacks.ReconcileCallbackArgs) error { +func reconcileSCC(args *callbacks.ReconcileCallbackArgs) error { if args.State != callbacks.ReconcileStatePostRead { return nil } @@ -221,10 +219,33 @@ func reconcileSELinuxPerms(args *callbacks.ReconcileCallbackArgs) error { return err } - if scc.SELinuxContext.Type != secv1.SELinuxStrategyRunAsAny { - scc.SELinuxContext.Type = secv1.SELinuxStrategyRunAsAny + newSCC := scc.DeepCopy() + + newSCC.Priority = &[]int32{10}[0] + newSCC.RequiredDropCapabilities = nil + newSCC.RunAsUser = secv1.RunAsUserStrategyOptions{ + Type: secv1.RunAsUserStrategyMustRunAsNonRoot, + } + newSCC.SELinuxContext = secv1.SELinuxContextStrategyOptions{ + Type: secv1.SELinuxStrategyMustRunAs, + } + newSCC.SupplementalGroups = secv1.SupplementalGroupsStrategyOptions{ + Type: secv1.SupplementalGroupsStrategyMustRunAs, + } + newSCC.SeccompProfiles = []string{ + "*", + } + newSCC.Volumes = []secv1.FSType{ + secv1.FSTypeConfigMap, + secv1.FSTypeDownwardAPI, + secv1.FSTypeEmptyDir, + secv1.FSTypePersistentVolumeClaim, + secv1.FSProjected, + secv1.FSTypeSecret, + } - if err = args.Client.Update(context.TODO(), scc); err != nil { + if !apiequality.Semantic.DeepEqual(newSCC, scc) { + if err = args.Client.Update(context.TODO(), newSCC); err != nil { return err } } diff --git a/pkg/operator/controller/scc.go b/pkg/operator/controller/scc.go index 211ed2368e..6b965793c4 100644 --- a/pkg/operator/controller/scc.go +++ b/pkg/operator/controller/scc.go @@ -22,7 +22,6 @@ import ( "github.com/go-logr/logr" secv1 "github.com/openshift/api/security/v1" - corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -67,17 +66,17 @@ func ensureSCCExists(logger logr.Logger, c client.Client, saNamespace, saName st FSGroup: secv1.FSGroupStrategyOptions{ Type: secv1.FSGroupStrategyRunAsAny, }, - RequiredDropCapabilities: []corev1.Capability{ - "MKNOD", - }, RunAsUser: secv1.RunAsUserStrategyOptions{ - Type: secv1.RunAsUserStrategyRunAsAny, + Type: secv1.RunAsUserStrategyMustRunAsNonRoot, }, SELinuxContext: secv1.SELinuxContextStrategyOptions{ - Type: secv1.SELinuxStrategyRunAsAny, + Type: secv1.SELinuxStrategyMustRunAs, }, SupplementalGroups: secv1.SupplementalGroupsStrategyOptions{ - Type: secv1.SupplementalGroupsStrategyRunAsAny, + Type: secv1.SupplementalGroupsStrategyMustRunAs, + }, + SeccompProfiles: []string{ + "*", }, Volumes: []secv1.FSType{ secv1.FSTypeConfigMap, diff --git a/pkg/operator/resources/utils/BUILD.bazel b/pkg/operator/resources/utils/BUILD.bazel index 0ca324ebd8..7d1f0f2a09 100644 --- a/pkg/operator/resources/utils/BUILD.bazel +++ b/pkg/operator/resources/utils/BUILD.bazel @@ -10,6 +10,7 @@ go_library( "//pkg/util:go_default_library", "//vendor/k8s.io/api/apps/v1:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library", + "//vendor/k8s.io/utils/pointer:go_default_library", "//vendor/kubevirt.io/controller-lifecycle-operator-sdk/api:go_default_library", "//vendor/kubevirt.io/controller-lifecycle-operator-sdk/pkg/sdk/resources:go_default_library", ], diff --git a/pkg/operator/resources/utils/common.go b/pkg/operator/resources/utils/common.go index 80067759b3..0fe71d1b91 100644 --- a/pkg/operator/resources/utils/common.go +++ b/pkg/operator/resources/utils/common.go @@ -19,6 +19,7 @@ package utils import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + "k8s.io/utils/pointer" "kubevirt.io/containerized-data-importer/pkg/common" "kubevirt.io/containerized-data-importer/pkg/util" @@ -52,12 +53,37 @@ func CreateContainer(name, image, verbosity, pullPolicy string) corev1.Container container.TerminationMessagePolicy = corev1.TerminationMessageReadFile container.TerminationMessagePath = corev1.TerminationMessagePathDefault container.Args = []string{"-v=" + verbosity} + container.SecurityContext = &corev1.SecurityContext{ + Capabilities: &corev1.Capabilities{ + Drop: []corev1.Capability{ + "ALL", + }, + }, + SeccompProfile: &corev1.SeccompProfile{ + Type: corev1.SeccompProfileTypeRuntimeDefault, + }, + AllowPrivilegeEscalation: pointer.BoolPtr(false), + RunAsNonRoot: pointer.BoolPtr(true), + } return *container } // CreatePortsContainer creates container with ports func CreatePortsContainer(name, image, pullPolicy string, ports []corev1.ContainerPort) corev1.Container { - return *ResourceBuilder.CreatePortsContainer(name, image, pullPolicy, ports) + container := ResourceBuilder.CreatePortsContainer(name, image, pullPolicy, ports) + container.SecurityContext = &corev1.SecurityContext{ + Capabilities: &corev1.Capabilities{ + Drop: []corev1.Capability{ + "ALL", + }, + }, + SeccompProfile: &corev1.SeccompProfile{ + Type: corev1.SeccompProfileTypeRuntimeDefault, + }, + AllowPrivilegeEscalation: pointer.BoolPtr(false), + RunAsNonRoot: pointer.BoolPtr(true), + } + return *container } // CreateDeployment creates deployment diff --git a/pkg/util/util.go b/pkg/util/util.go index 5ee4ee89c2..897524730c 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -201,19 +201,12 @@ func StreamDataToFile(r io.Reader, fileName string) error { // UnArchiveTar unarchives a tar file and streams its files // using the specified io.Reader to the specified destination. -func UnArchiveTar(reader io.Reader, destDir string, arg ...string) error { +func UnArchiveTar(reader io.Reader, destDir string) error { klog.V(1).Infof("begin untar to %s...\n", destDir) - - var tarOptions string - var args = arg - if len(arg) > 0 { - tarOptions = arg[0] - args = arg[1:] - } - options := fmt.Sprintf("-%s%s", tarOptions, "xvC") - untar := exec.Command("/usr/bin/tar", "--no-same-owner", options, destDir, strings.Join(args, "")) + untar := exec.Command("/usr/bin/tar", "--no-same-owner", "-xvC", destDir) untar.Stdin = reader - var errBuf bytes.Buffer + var outBuf, errBuf bytes.Buffer + untar.Stdout = &outBuf untar.Stderr = &errBuf err := untar.Start() if err != nil { @@ -221,7 +214,8 @@ func UnArchiveTar(reader io.Reader, destDir string, arg ...string) error { } err = untar.Wait() if err != nil { - klog.V(3).Infof("%s\n", errBuf.String()) + klog.V(3).Infof("STDOUT\n%s\n", outBuf.String()) + klog.V(3).Infof("STDERR\n%s\n", errBuf.String()) klog.Errorf("%s\n", err.Error()) return err } diff --git a/tests/framework/BUILD.bazel b/tests/framework/BUILD.bazel index be270d9fc7..d4cad8d2fd 100644 --- a/tests/framework/BUILD.bazel +++ b/tests/framework/BUILD.bazel @@ -19,6 +19,7 @@ go_library( deps = [ "//pkg/client/clientset/versioned:go_default_library", "//pkg/common:go_default_library", + "//pkg/controller:go_default_library", "//pkg/feature-gates:go_default_library", "//pkg/image:go_default_library", "//pkg/util/naming:go_default_library", diff --git a/tests/framework/framework.go b/tests/framework/framework.go index 302847ef82..aa5d3516a8 100644 --- a/tests/framework/framework.go +++ b/tests/framework/framework.go @@ -218,6 +218,12 @@ func (f *Framework) AfterEach() { // CreateNamespace instantiates a new namespace object with a unique name and the passed-in label(s). func (f *Framework) CreateNamespace(prefix string, labels map[string]string) (*v1.Namespace, error) { + if labels == nil { + labels = make(map[string]string) + } + // pod-security.kubernetes.io/: + labels["pod-security.kubernetes.io/enforce"] = "restricted" + ns := &v1.Namespace{ ObjectMeta: metav1.ObjectMeta{ GenerateName: fmt.Sprintf("cdi-e2e-tests-%s-", prefix), diff --git a/tests/framework/pvc.go b/tests/framework/pvc.go index da97cf932a..3e7e4b8afc 100644 --- a/tests/framework/pvc.go +++ b/tests/framework/pvc.go @@ -19,10 +19,9 @@ import ( "k8s.io/klog/v2" cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1" - "kubevirt.io/containerized-data-importer/pkg/util/naming" - - "kubevirt.io/containerized-data-importer/pkg/common" + "kubevirt.io/containerized-data-importer/pkg/controller" "kubevirt.io/containerized-data-importer/pkg/image" + "kubevirt.io/containerized-data-importer/pkg/util/naming" "kubevirt.io/containerized-data-importer/tests/utils" ) @@ -172,7 +171,7 @@ func (f *Framework) GetMD5(namespace *k8sv1.Namespace, pvc *k8sv1.PersistentVolu cmd := "md5sum " + fileName if numBytes > 0 { - cmd = fmt.Sprintf("head -c %d %s 1> null && head -c %d %s | md5sum", numBytes, fileName, numBytes, fileName) + cmd = fmt.Sprintf("head -c %d %s 1> /dev/null && head -c %d %s | md5sum", numBytes, fileName, numBytes, fileName) } var output, stderr string @@ -350,7 +349,6 @@ func (f *Framework) RunCommandAndCaptureOutput(pvc *k8sv1.PersistentVolumeClaim, func (f *Framework) NewPodWithPVC(podName, cmd string, pvc *k8sv1.PersistentVolumeClaim) *k8sv1.Pod { var importerImage string volumeName := naming.GetLabelNameFromResourceName(pvc.GetName()) - fsGroup := common.QemuSubGid for _, e := range f.ControllerPod.Spec.Containers[0].Env { if e.Name == "IMPORTER_IMAGE" { importerImage = e.Value @@ -392,9 +390,6 @@ func (f *Framework) NewPodWithPVC(podName, cmd string, pvc *k8sv1.PersistentVolu }, }, }, - SecurityContext: &k8sv1.PodSecurityContext{ - FSGroup: &fsGroup, - }, }, } @@ -404,6 +399,9 @@ func (f *Framework) NewPodWithPVC(podName, cmd string, pvc *k8sv1.PersistentVolu } else { pod.Spec.Containers[0].VolumeMounts = addVolumeMounts(pvc, volumeName) } + + controller.SetRestrictedSecurityContext(&pod.Spec) + return pod } diff --git a/tools/vddk-test/BUILD.bazel b/tools/vddk-test/BUILD.bazel index eacd6e1b7c..8a7f9c7c77 100644 --- a/tools/vddk-test/BUILD.bazel +++ b/tools/vddk-test/BUILD.bazel @@ -16,7 +16,7 @@ container_image( container_image( name = "vddk-test-image", - entrypoint = "mkdir -p /opt/testing && cp -f /libvddk-test-plugin.so /opt/testing/libvddk-test-plugin.so && mv /cirros.raw /opt/testing/nbdtest.img", + entrypoint = "mkdir -p /opt/testing && cp -f /libvddk-test-plugin.so /opt/testing/libvddk-test-plugin.so && cp -f /cirros.raw /opt/testing/nbdtest.img", files = [ ":vddk-test-plugin", "//tests:images/cirros.raw", @@ -29,6 +29,7 @@ container_image( "//rpm:testimage_x86_64", ], }), + user = "1001", visibility = ["//visibility:public"], )