Skip to content

Commit

Permalink
pb-6681: Add support for PSA in kdmp job
Browse files Browse the repository at this point in the history
- Added check and collected psa info from the namespace
- if psa enabled then extracted the uid and gid used by the POD.
  here the pod is choosen based on whichever PVC is used by that pod
- applied those uid and GID to all relevant job pod spec
- this is done only if the PSA mode enforced with "restricted" value
- for baseline and privilege mode no restriction on UID/GID and
  default setting of SElinux and secomp is adopted in the POD spec

Signed-off-by: Lalatendu Das <[email protected]>
  • Loading branch information
lalat-das committed May 28, 2024
1 parent 8461dc1 commit 93ae82b
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 2 deletions.
28 changes: 28 additions & 0 deletions pkg/controllers/dataexport/reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -1872,13 +1872,21 @@ func startTransferJob(
nfsServerAddr string
nfsExportPath string
nfsMountOption string
psaIsEnabled string
psaJobUid string
psaJobGid string
)

if backupLocation != nil {
nfsServerAddr = backupLocation.Location.NFSConfig.ServerAddr
nfsExportPath = backupLocation.Location.NFSConfig.SubPath
nfsMountOption = backupLocation.Location.NFSConfig.MountOptions
}
if dataExport != nil {
psaIsEnabled = getAnnotationValue(dataExport, utils.PsaEnabledKey)
psaJobUid = getAnnotationValue(dataExport, utils.PsaUIDKey)
psaJobGid = getAnnotationValue(dataExport, utils.PsaGIDKey)
}
switch drv.Name() {
case drivers.Rsync:
return drv.StartJob(
Expand Down Expand Up @@ -1927,6 +1935,9 @@ func startTransferJob(
drivers.WithNfsServer(nfsServerAddr),
drivers.WithNfsExportDir(nfsExportPath),
drivers.WithNfsMountOption(nfsMountOption),
drivers.WithPsaIsEnabled(psaIsEnabled),
drivers.WithPodUserId(psaJobUid),
drivers.WithPodGroupId(psaJobGid),
)
case drivers.KopiaRestore:
return drv.StartJob(
Expand All @@ -1945,6 +1956,9 @@ func startTransferJob(
drivers.WithJobConfigMapNs(jobConfigMapNs),
drivers.WithNfsServer(nfsServerAddr),
drivers.WithNfsExportDir(nfsExportPath),
drivers.WithPsaIsEnabled(psaIsEnabled),
drivers.WithPodUserId(psaJobUid),
drivers.WithPodGroupId(psaJobGid),
)
}

Expand Down Expand Up @@ -2353,6 +2367,17 @@ func startNfsCSIRestoreVolumeJob(
bl *storkapi.BackupLocation,
) (string, error) {

var (
psaIsEnabled string
psaJobUid string
psaJobGid string
)

if de != nil {
psaIsEnabled = getAnnotationValue(de, utils.PsaEnabledKey)
psaJobUid = getAnnotationValue(de, utils.PsaUIDKey)
psaJobGid = getAnnotationValue(de, utils.PsaGIDKey)
}
jobName := utils.GetCsiRestoreJobName(drivers.NFSCSIRestore, de.Name)
err := utils.CreateNfsSecret(utils.GetCredSecretName(jobName), bl, de.Namespace, nil)
if err != nil {
Expand All @@ -2371,6 +2396,9 @@ func startNfsCSIRestoreVolumeJob(
drivers.WithNfsExportDir(bl.Location.NFSConfig.SubPath),
drivers.WithNfsMountOption(bl.Location.NFSConfig.MountOptions),
drivers.WithNfsSubPath(bl.Location.Path),
drivers.WithPsaIsEnabled(psaIsEnabled),
drivers.WithPodUserId(psaJobUid),
drivers.WithPodGroupId(psaJobGid),
)
}
return "", fmt.Errorf("unknown driver for nfs csi volume restore: %s", drv.Name())
Expand Down
12 changes: 12 additions & 0 deletions pkg/controllers/resourceexport/reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ type updateResourceExportFields struct {
LargeResourceEnabled bool
}

func getAnnotationValue(re *kdmpapi.ResourceExport, key string) string {
var val string
if _, ok := re.Annotations[key]; ok {
val = re.Annotations[key]
}
return val
}

func (c *Controller) process(ctx context.Context, in *kdmpapi.ResourceExport) (bool, error) {
funct := "resourceExport.process"
if in == nil {
Expand Down Expand Up @@ -400,6 +408,8 @@ func startNfsResourceJob(
bl *storkapi.BackupLocation,
) (string, error) {

isPsaEnabled := getAnnotationValue(re, utils.PsaEnabledKey)

err := utils.CreateNfsSecret(utils.GetCredSecretName(re.Name), bl, re.Namespace, nil)
if err != nil {
logrus.Errorf("failed to create NFS cred secret: %v", err)
Expand All @@ -425,6 +435,7 @@ func startNfsResourceJob(
drivers.WithNfsExportDir(bl.Location.NFSConfig.SubPath),
drivers.WithJobConfigMap(jobConfigMap),
drivers.WithJobConfigMapNs(jobConfigMapNs),
drivers.WithPsaIsEnabled(isPsaEnabled),
)
case drivers.NFSRestore:
return drv.StartJob(
Expand All @@ -443,6 +454,7 @@ func startNfsResourceJob(
drivers.WithNfsExportDir(bl.Location.NFSConfig.SubPath),
drivers.WithJobConfigMap(jobConfigMap),
drivers.WithJobConfigMapNs(jobConfigMapNs),
drivers.WithPsaIsEnabled(isPsaEnabled),
)
}
return "", fmt.Errorf("unknown data transfer driver: %s", drv.Name())
Expand Down
8 changes: 8 additions & 0 deletions pkg/drivers/kopiabackup/kopiabackup.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ func jobFor(
logrus.Errorf("failed to get the toleration details: %v", err)
return nil, fmt.Errorf("failed to get the toleration details for job [%s/%s]", jobOption.Namespace, jobName)
}

job := &batchv1.Job{
ObjectMeta: metav1.ObjectMeta{
Name: jobName,
Expand Down Expand Up @@ -384,6 +385,13 @@ func jobFor(
},
},
}
// Add security Context only if the PSA is enabled.
if jobOption.PsaIsEnabled == "true" {
job, err = utils.AddSecurityContextToJob(job, jobOption.PodUserId, jobOption.PodGroupId)
if err != nil {
return nil, err
}
}

if len(nodeName) != 0 {
job.Spec.Template.Spec.NodeName = nodeName
Expand Down
9 changes: 8 additions & 1 deletion pkg/drivers/kopiarestore/kopiarestore.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ func jobFor(
logrus.Errorf("failed to get the toleration details: %v", err)
return nil, fmt.Errorf("failed to get the toleration details for job [%s/%s]", jobOption.Namespace, jobName)
}

job := &batchv1.Job{
ObjectMeta: metav1.ObjectMeta{
Name: jobName,
Expand Down Expand Up @@ -285,7 +286,13 @@ func jobFor(
},
},
}

// Add security Context only if the PSA is enabled.
if jobOption.PsaIsEnabled == "true" {
job, err = utils.AddSecurityContextToJob(job, jobOption.PodUserId, jobOption.PodGroupId)
if err != nil {
return nil, err
}
}
// Add the image secret in job spec only if it is present in the stork deployment.
if len(imageRegistrySecret) != 0 {
job.Spec.Template.Spec.ImagePullSecrets = utils.ToImagePullSecret(utils.GetImageSecretName(jobName))
Expand Down
14 changes: 13 additions & 1 deletion pkg/drivers/nfsbackup/nfsbackup.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,6 @@ func jobForBackupResource(
}, " ")

labels := addJobLabels(jobOption)

nfsExecutorImage, imageRegistrySecret, err := utils.GetExecutorImageAndSecret(drivers.NfsExecutorImage,
jobOption.NfsImageExecutorSource,
jobOption.NfsImageExecutorSourceNs,
Expand All @@ -216,6 +215,7 @@ func jobForBackupResource(
logrus.Errorf("failed to get the toleration details: %v", err)
return nil, fmt.Errorf("failed to get the toleration details for job [%s/%s]", jobOption.Namespace, jobOption.RestoreExportName)
}

job := &batchv1.Job{
ObjectMeta: metav1.ObjectMeta{
Name: jobOption.RestoreExportName,
Expand Down Expand Up @@ -270,6 +270,18 @@ func jobForBackupResource(
},
},
}

// Add security Context only if the PSA is enabled.
if jobOption.PsaIsEnabled == "true" {
// The Job is intended to backup resources to NFS backuplocation
// and it doesn't need a specific JOB uid/gid since it will be sqaushed at NFS server
// hence used a global hardcoded UID/GID.
job, err = utils.AddSecurityContextToJob(job, utils.KdmpJobUid, utils.KdmpJobGid)
if err != nil {
return nil, err
}
}

// Add the image secret in job spec only if it is present in the stork deployment.
if len(imageRegistrySecret) != 0 {
job.Spec.Template.Spec.ImagePullSecrets = utils.ToImagePullSecret(utils.GetImageSecretName(jobOption.RestoreExportName))
Expand Down
7 changes: 7 additions & 0 deletions pkg/drivers/nfscsirestore/nfscsirestore.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,13 @@ func jobForRestoreCSISnapshot(
},
},
}
// Add security Context only if the PSA is enabled.
if jobOption.PsaIsEnabled == "true" {
job, err = utils.AddSecurityContextToJob(job, jobOption.PodUserId, jobOption.PodGroupId)
if err != nil {
return nil, err
}
}
// Add the image secret in job spec only if it is present in the stork deployment.
if len(imageRegistrySecret) != 0 {
job.Spec.Template.Spec.ImagePullSecrets = utils.ToImagePullSecret(utils.GetImageSecretName(jobName))
Expand Down
9 changes: 9 additions & 0 deletions pkg/drivers/nfsrestore/nfsrestore.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,15 @@ func jobForRestoreResource(
},
},
}

// Add security Context only if the PSA is enabled.
if jobOption.PsaIsEnabled == "true" {
job, err = utils.AddSecurityContextToJob(job, utils.KdmpJobUid, utils.KdmpJobGid)
if err != nil {
return nil, err
}
}

// Add the image secret in job spec only if it is present in the stork deployment.
if len(imageRegistrySecret) != 0 {
job.Spec.Template.Spec.ImagePullSecrets = utils.ToImagePullSecret(utils.GetImageSecretName(jobOption.RestoreExportName))
Expand Down
28 changes: 28 additions & 0 deletions pkg/drivers/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ type JobOpts struct {
ResoureBackupName string
ResoureBackupNamespace string
S3DisableSSL bool
// psa specifc option to be used by job
PsaIsEnabled string
PodUserId string
PodGroupId string
}

// WithS3DisableSSL is job parameter
Expand Down Expand Up @@ -517,3 +521,27 @@ func WithNodeAffinity(l map[string]string) JobOption {
return nil
}
}

// WithpsaIsEnabled is job parameter.
func WithPsaIsEnabled(psaIsEnabled string) JobOption {
return func(opts *JobOpts) error {
opts.PsaIsEnabled = psaIsEnabled
return nil
}
}

// WithpsaIsEnabled is job parameter.
func WithPodUserId(podUserId string) JobOption {
return func(opts *JobOpts) error {
opts.PodUserId = podUserId
return nil
}
}

// WithpsaIsEnabled is job parameter.
func WithPodGroupId(PodGroupId string) JobOption {
return func(opts *JobOpts) error {
opts.PodGroupId = PodGroupId
return nil
}
}
44 changes: 44 additions & 0 deletions pkg/drivers/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/utils/ptr"
)

const (
Expand Down Expand Up @@ -67,6 +68,11 @@ const (
IstioInjectLabel = "sidecar.istio.io/inject"
// ProcessVMResourceSuccessMsg - vm resources processed successfully
ProcessVMResourceSuccessMsg = "vm resources processed successfully"
PsaEnabledKey = "portworx.io/psa-enabled"
PsaUIDKey = "portworx.io/psa-uid"
PsaGIDKey = "portworx.io/psa-gid"
KdmpJobUid = "1013"
KdmpJobGid = "1013"
)

var (
Expand Down Expand Up @@ -966,3 +972,41 @@ func GetShortUID(uid string) string {
}
return uid[:8]
}

// Add container security Context to job pod if the PSA is enabled.
// if static uids like kdmpJobUid or kdmpJobGid is used that means
// these are dummy UIDs used for backing up resources to backuplocation
// which doesn't need specific UID specific permission.
func AddSecurityContextToJob(job *batchv1.Job, podUserId, podGroupId string) (*batchv1.Job, error) {
if job == nil {
return job, fmt.Errorf("recieved a nil job object to add security context")
}
if podUserId != "" {
uid, err := strconv.ParseInt(podUserId, 10, 64)
if err != nil {
logrus.Errorf("failed to convert the UID to int: %v", err)
return nil, fmt.Errorf("failed to convert the UID to int: %v", err)
}
job.Spec.Template.Spec.SecurityContext.RunAsUser = &uid
}
if podGroupId != "" {
gid, err := strconv.ParseInt(podGroupId, 10, 64)
if err != nil {
logrus.Errorf("failed to convert the GID to int: %v", err)
return nil, fmt.Errorf("failed to convert the GID to int: %v", err)
}
job.Spec.Template.Spec.SecurityContext.RunAsGroup = &gid
}
// Add RunAsNonRoot to true and drop all capabilities and seccomp profile and allowPrivilegeEscalation to false
job.Spec.Template.Spec.Containers[0].SecurityContext.RunAsNonRoot = ptr.To(true)
job.Spec.Template.Spec.Containers[0].SecurityContext.AllowPrivilegeEscalation = ptr.To(false)
job.Spec.Template.Spec.Containers[0].SecurityContext.SeccompProfile = &corev1.SeccompProfile{
Type: "RuntimeDefault",
}
job.Spec.Template.Spec.Containers[0].SecurityContext.Capabilities = &corev1.Capabilities{
Drop: []corev1.Capability{
"ALL",
},
}
return job, nil
}

0 comments on commit 93ae82b

Please sign in to comment.