Skip to content

Commit

Permalink
Run glance-api as privileged container when image cache is enabled
Browse files Browse the repository at this point in the history
ImageCache currently uses two different cronJobs associated to each
glance-api instance (-cleaner and -pruner cronJobs). They mount
/var/lib/glance/image-cache, a RWO Pvc, and execute a glance utility
on the filestem owned by glance kolla user/group. Without glance-api
being privileged, after the cronJob execution the Glance Pod is not
able to access the image-cache path anymore, resulting in a Permission
denied error.
This patch defines a FSGroup that should be set at Pod level to make
sure we always have the right privileges on the container fs, and,
in addition, it runs glance-api as a privileged container when Cache
is enabled.

Jira: https://issues.redhat.com/browse/OSPRH-9842

Signed-off-by: Francesco Pantano <[email protected]>
  • Loading branch information
fmount committed Sep 19, 2024
1 parent 4f61b6b commit 3c4ebc1
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 27 deletions.
2 changes: 2 additions & 0 deletions controllers/glanceapi_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,8 @@ func (r *GlanceAPIReconciler) reconcileNormal(

// This is currently required because cleaner and pruner cronJobs
// mount the same pvc to clean data present in /var/lib/glance/image-cache
// TODO (fpantano) reference a Glance spec/proposal to move to a different
// approach
if len(instance.Spec.ImageCache.Size) > 0 {
privileged = true
}
Expand Down
35 changes: 14 additions & 21 deletions pkg/glance/funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package glance

import (
corev1 "k8s.io/api/core/v1"
"k8s.io/utils/ptr"
"sigs.k8s.io/controller-runtime/pkg/client"
)

Expand All @@ -20,12 +21,10 @@ func GetOwningGlanceName(instance client.Object) string {
// dbSyncSecurityContext - currently used to make sure we don't run db-sync as
// root user
func dbSyncSecurityContext() *corev1.SecurityContext {
runAsUser := int64(GlanceUID)
runAsGroup := int64(GlanceGID)

return &corev1.SecurityContext{
RunAsUser: &runAsUser,
RunAsGroup: &runAsGroup,
RunAsUser: ptr.To(GlanceUID),
RunAsGroup: ptr.To(GlanceGID),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{
"MKNOD",
Expand All @@ -40,16 +39,12 @@ func dbSyncSecurityContext() *corev1.SecurityContext {
// BaseSecurityContext - currently used to make sure we don't run cronJob and Log
// Pods as root user, and we drop privileges and Capabilities we don't need
func BaseSecurityContext() *corev1.SecurityContext {
falseVal := false
trueVal := true
runAsUser := int64(GlanceUID)
runAsGroup := int64(GlanceGID)

return &corev1.SecurityContext{
RunAsUser: &runAsUser,
RunAsGroup: &runAsGroup,
RunAsNonRoot: &trueVal,
AllowPrivilegeEscalation: &falseVal,
RunAsUser: ptr.To(GlanceUID),
RunAsGroup: ptr.To(GlanceGID),
RunAsNonRoot: ptr.To(true),
AllowPrivilegeEscalation: ptr.To(false),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{
"ALL",
Expand All @@ -63,11 +58,10 @@ func BaseSecurityContext() *corev1.SecurityContext {

// APISecurityContext -
func APISecurityContext(userID int64, privileged bool) *corev1.SecurityContext {
runAsUser := int64(userID)
trueVal := true

return &corev1.SecurityContext{
AllowPrivilegeEscalation: &trueVal,
RunAsUser: &runAsUser,
AllowPrivilegeEscalation: ptr.To(true),
RunAsUser: ptr.To(userID),
Privileged: &privileged,
SeccompProfile: &corev1.SeccompProfile{
Type: corev1.SeccompProfileTypeRuntimeDefault,
Expand All @@ -77,16 +71,15 @@ func APISecurityContext(userID int64, privileged bool) *corev1.SecurityContext {

// HttpdSecurityContext -
func HttpdSecurityContext() *corev1.SecurityContext {
runAsUser := int64(0)
falseVal := false

return &corev1.SecurityContext{
AllowPrivilegeEscalation: &falseVal,
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{
"ALL",
"MKNOD",
},
},
RunAsUser: &runAsUser,
RunAsUser: ptr.To(GlanceUID),
RunAsGroup: ptr.To(GlanceGID),
SeccompProfile: &corev1.SeccompProfile{
Type: corev1.SeccompProfileTypeRuntimeDefault,
},
Expand Down
13 changes: 7 additions & 6 deletions pkg/glanceapi/cachejob.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func ImageCacheJob(
instance *glancev1.GlanceAPI,
cronSpec glance.CronJobSpec,
) *batchv1.CronJob {
runAsUser := int64(0)
userID := glance.GlanceUID
var config0644AccessMode int32 = 0644

cronCommand := fmt.Sprintf(
Expand Down Expand Up @@ -100,6 +100,9 @@ func ImageCacheJob(
Completions: &completions,
Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
SecurityContext: &corev1.PodSecurityContext{
FSGroup: &userID,
},
Affinity: GetGlanceAPIPodAffinity(instance),
Containers: []corev1.Container{
{
Expand All @@ -108,11 +111,9 @@ func ImageCacheJob(
Command: []string{
"/bin/bash",
},
Args: args,
VolumeMounts: cronJobVolumeMounts,
SecurityContext: &corev1.SecurityContext{
RunAsUser: &runAsUser,
},
Args: args,
VolumeMounts: cronJobVolumeMounts,
SecurityContext: glance.BaseSecurityContext(),
},
},
Volumes: cronJobVolume,
Expand Down
3 changes: 3 additions & 0 deletions pkg/glanceapi/statefulset.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ func StatefulSet(
Labels: labels,
},
Spec: corev1.PodSpec{
SecurityContext: &corev1.PodSecurityContext{
FSGroup: &userID,
},
ServiceAccountName: instance.Spec.ServiceAccount,
// When using Cinder we run as privileged, but also some
// commands need to be run on the host using nsenter (eg:
Expand Down

0 comments on commit 3c4ebc1

Please sign in to comment.