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 10a8187
Show file tree
Hide file tree
Showing 8 changed files with 31 additions and 33 deletions.
1 change: 1 addition & 0 deletions api/v1beta1/common_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ type GlanceAPITemplate struct {
APITimeout int `json:"apiTimeout,omitempty"`
}

// Storage -
type Storage struct {
// +kubebuilder:validation:Optional
// StorageClass -
Expand Down
2 changes: 1 addition & 1 deletion api/v1beta1/glance_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const (
APIEdge = "edge"
)

// GlanceSpec defines the desired state of Glance
// GlanceSpecCore defines the desired state of Glance
type GlanceSpecCore struct {
// +kubebuilder:validation:Optional
// +kubebuilder:default=glance
Expand Down
1 change: 1 addition & 0 deletions api/v1beta1/glance_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ func (r *GlanceSpec) ValidateUpdate(old GlanceSpec, basePath *field.Path) field.
return r.GlanceSpecCore.ValidateUpdate(old.GlanceSpecCore, basePath)
}

// ValidateUpdate -
func (r *GlanceSpecCore) ValidateUpdate(old GlanceSpecCore, basePath *field.Path) field.ErrorList {
var allErrs field.ErrorList

Expand Down
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
2 changes: 1 addition & 1 deletion pkg/glance/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const (
GlanceInternalPort int32 = 9292
// GlanceUID - https://github.com/openstack/kolla/blob/master/kolla/common/users.py
GlanceUID int64 = 42415
// GlanceGid - https://github.com/openstack/kolla/blob/master/kolla/common/users.py
// GlanceGID - https://github.com/openstack/kolla/blob/master/kolla/common/users.py
GlanceGID int64 = 42415
// DefaultsConfigFileName -
DefaultsConfigFileName = "00-config.conf"
Expand Down
36 changes: 14 additions & 22 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 @@ -13,19 +14,16 @@ func GetOwningGlanceName(instance client.Object) string {
return ownerRef.Name
}
}

return ""
}

// 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 +38,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 +57,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 +70,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
17 changes: 8 additions & 9 deletions pkg/glanceapi/cachejob.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,20 @@ limitations under the License.
package glanceapi

import (
"fmt"
glancev1 "github.com/openstack-k8s-operators/glance-operator/api/v1beta1"
"github.com/openstack-k8s-operators/glance-operator/pkg/glance"

"fmt"

batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"
)

// ImageCacheJob -
func ImageCacheJob(
instance *glancev1.GlanceAPI,
cronSpec glance.CronJobSpec,
) *batchv1.CronJob {
runAsUser := int64(0)
var config0644AccessMode int32 = 0644

cronCommand := fmt.Sprintf(
Expand Down Expand Up @@ -100,6 +98,9 @@ func ImageCacheJob(
Completions: &completions,
Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
SecurityContext: &corev1.PodSecurityContext{
FSGroup: ptr.To(glance.GlanceUID),
},
Affinity: GetGlanceAPIPodAffinity(instance),
Containers: []corev1.Container{
{
Expand All @@ -108,11 +109,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 10a8187

Please sign in to comment.