Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 70 additions & 11 deletions pkg/controller/kibana/driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ func TestDriverDeploymentParams(t *testing.T) {
kb: kibanaFixture,
initialObjects: defaultInitialObjects,
},
want: expectedDeploymentParams(),
want: pre710(expectedDeploymentParams()),
wantErr: false,
},
{
Expand All @@ -233,7 +233,7 @@ func TestDriverDeploymentParams(t *testing.T) {
initialObjects: defaultInitialObjects,
policyAnnotations: map[string]string{"policy.k8s.elastic.co/kibana-config-hash": "2123345"},
},
want: expectedDeploymentWithPolicyAnnotations(map[string]string{"policy.k8s.elastic.co/kibana-config-hash": "2123345"}),
want: pre710(expectedDeploymentWithPolicyAnnotations(map[string]string{"policy.k8s.elastic.co/kibana-config-hash": "2123345"})),
wantErr: false,
},
{
Expand All @@ -249,7 +249,7 @@ func TestDriverDeploymentParams(t *testing.T) {
initialObjects: defaultInitialObjects,
},
want: func() deployment.Params {
params := expectedDeploymentParams()
params := pre710(expectedDeploymentParams())
params.PodTemplateSpec.Spec.Volumes = params.PodTemplateSpec.Spec.Volumes[1:]
params.PodTemplateSpec.Spec.InitContainers[0].VolumeMounts = params.PodTemplateSpec.Spec.InitContainers[0].VolumeMounts[1:]
params.PodTemplateSpec.Spec.Containers[0].VolumeMounts = params.PodTemplateSpec.Spec.Containers[0].VolumeMounts[1:]
Expand All @@ -266,7 +266,7 @@ func TestDriverDeploymentParams(t *testing.T) {
initialObjects: defaultInitialObjects,
},
want: func() deployment.Params {
p := expectedDeploymentParams()
p := pre710(expectedDeploymentParams())
p.PodTemplateSpec.Labels["mylabel"] = "value"
for i, c := range p.PodTemplateSpec.Spec.Containers {
if c.Name == kbv1.KibanaContainerName {
Expand Down Expand Up @@ -323,7 +323,7 @@ func TestDriverDeploymentParams(t *testing.T) {
},
},
want: func() deployment.Params {
p := expectedDeploymentParams()
p := pre710(expectedDeploymentParams())
p.PodTemplateSpec.Annotations["kibana.k8s.elastic.co/config-hash"] = "2368465874"
return p
}(),
Expand All @@ -340,7 +340,7 @@ func TestDriverDeploymentParams(t *testing.T) {
initialObjects: defaultInitialObjects,
},
want: func() deployment.Params {
p := expectedDeploymentParams()
p := pre710(expectedDeploymentParams())
p.PodTemplateSpec.Labels["kibana.k8s.elastic.co/version"] = "6.8.0"
return p
}(),
Expand All @@ -357,12 +357,29 @@ func TestDriverDeploymentParams(t *testing.T) {
initialObjects: defaultInitialObjects,
},
want: func() deployment.Params {
p := expectedDeploymentParams()
p := pre710(expectedDeploymentParams())
p.PodTemplateSpec.Labels["kibana.k8s.elastic.co/version"] = "6.8.0"
return p
}(),
wantErr: false,
},
{
name: "7.10+ contains security contexts",
args: args{
kb: func() *kbv1.Kibana {
kb := kibanaFixture()
kb.Spec.Version = "7.10.0"
return kb
},
initialObjects: defaultInitialObjects,
},
want: func() deployment.Params {
p := expectedDeploymentParams()
p.PodTemplateSpec.Labels["kibana.k8s.elastic.co/version"] = "7.10.0"
return p
}(),
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -490,15 +507,25 @@ func expectedDeploymentParams() deployment.Params {
EmptyDir: &corev1.EmptyDirVolumeSource{},
},
},
{
Name: "kibana-plugins",
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
},
},
{
Name: "temp-volume",
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
},
},
},
InitContainers: []corev1.Container{{
Name: "elastic-internal-init-config",
ImagePullPolicy: corev1.PullIfNotPresent,
Image: "my-image",
Command: []string{"/usr/bin/env", "bash", "-c", InitConfigScript},
SecurityContext: &corev1.SecurityContext{
Privileged: &falseVal,
},
SecurityContext: &defaultSecurityContext,
Env: []corev1.EnvVar{
{Name: settings.EnvPodIP, Value: "", ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{APIVersion: "v1", FieldPath: "status.podIP"},
Expand Down Expand Up @@ -535,6 +562,16 @@ func expectedDeploymentParams() deployment.Params {
ReadOnly: falseVal,
MountPath: DataVolumeMountPath,
},
{
Name: "kibana-plugins",
ReadOnly: falseVal,
MountPath: "/usr/share/kibana/plugins",
},
{
Name: "temp-volume",
ReadOnly: falseVal,
MountPath: "/tmp",
},
},
Resources: corev1.ResourceRequirements{
Requests: map[corev1.ResourceName]resource.Quantity{
Expand Down Expand Up @@ -571,6 +608,16 @@ func expectedDeploymentParams() deployment.Params {
ReadOnly: falseVal,
MountPath: DataVolumeMountPath,
},
{
Name: "kibana-plugins",
ReadOnly: falseVal,
MountPath: "/usr/share/kibana/plugins",
},
{
Name: "temp-volume",
ReadOnly: falseVal,
MountPath: "/tmp",
},
},
Image: "my-image",
Name: kbv1.KibanaContainerName,
Expand All @@ -591,9 +638,11 @@ func expectedDeploymentParams() deployment.Params {
},
},
},
Resources: DefaultResources,
Resources: DefaultResources,
SecurityContext: &defaultSecurityContext,
}},
AutomountServiceAccountToken: &falseVal,
SecurityContext: &defaultPodSecurityContext,
},
},
}
Expand All @@ -608,6 +657,16 @@ func expectedDeploymentWithPolicyAnnotations(policyAnnotations map[string]string
return deploymentParams
}

func pre710(params deployment.Params) deployment.Params {
params.PodTemplateSpec.Spec.Containers[0].SecurityContext = nil
params.PodTemplateSpec.Spec.InitContainers[0].SecurityContext = nil
params.PodTemplateSpec.Spec.SecurityContext = nil
params.PodTemplateSpec.Spec.Volumes = params.PodTemplateSpec.Spec.Volumes[:5]
params.PodTemplateSpec.Spec.InitContainers[0].VolumeMounts = params.PodTemplateSpec.Spec.InitContainers[0].VolumeMounts[:5]
params.PodTemplateSpec.Spec.Containers[0].VolumeMounts = params.PodTemplateSpec.Spec.Containers[0].VolumeMounts[:5]
return params
}

func kibanaFixture() *kbv1.Kibana {
kbFixture := &kbv1.Kibana{
ObjectMeta: metav1.ObjectMeta{
Expand Down
7 changes: 1 addition & 6 deletions pkg/controller/kibana/init_configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,11 @@ echo "Kibana configuration successfully prepared."
// The script creates symbolic links from the generated configuration files in /mnt/elastic-internal/kibana-config/ to
// an empty directory later mounted in /use/share/kibana/config
func initConfigContainer(kb kbv1.Kibana) corev1.Container {
privileged := false

return corev1.Container{
// Image will be inherited from pod template defaults
ImagePullPolicy: corev1.PullIfNotPresent,
Name: InitConfigContainerName,
SecurityContext: &corev1.SecurityContext{
Privileged: &privileged,
},
Command: []string{"/usr/bin/env", "bash", "-c", InitConfigScript},
Command: []string{"/usr/bin/env", "bash", "-c", InitConfigScript},
VolumeMounts: []corev1.VolumeMount{
ConfigSharedVolume.InitContainerVolumeMount(),
ConfigVolume(kb).VolumeMount(),
Expand Down
25 changes: 25 additions & 0 deletions pkg/controller/kibana/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ import (
const (
DataVolumeName = "kibana-data"
DataVolumeMountPath = "/usr/share/kibana/data"
PluginsVolumeName = "kibana-plugins"
PluginsVolumeMountPath = "/usr/share/kibana/plugins"
TempVolumeName = "temp-volume"
TempVolumeMountPath = "/tmp"
KibanaBasePathEnvName = "SERVER_BASEPATH"
KibanaRewriteBasePathEnvName = "SERVER_REWRITEBASEPATH"
)
Expand All @@ -43,6 +47,14 @@ var (
// Since Kibana is stateless and the keystore is created on pod start, an EmptyDir is fine here.
DataVolume = volume.NewEmptyDirVolume(DataVolumeName, DataVolumeMountPath)

// PluginsVolume can be used to persist plugins after installation via an init container when
// the Kibana pod has readOnlyRootFilesystem set to true.
PluginsVolume = volume.NewEmptyDirVolume(PluginsVolumeName, PluginsVolumeMountPath)

// TempVolume can be used for some reporting features when the Kibana pod has
// readOnlyRootFilesystem set to true.
TempVolume = volume.NewEmptyDirVolume(TempVolumeName, TempVolumeMountPath)

DefaultMemoryLimits = resource.MustParse("1Gi")
DefaultResources = corev1.ResourceRequirements{
Requests: map[corev1.ResourceName]resource.Quantity{
Expand Down Expand Up @@ -116,6 +128,19 @@ func NewPodTemplateSpec(ctx context.Context, client k8sclient.Client, kb kbv1.Ki
builder.WithVolumes(volume.Volume()).WithVolumeMounts(volume.VolumeMount())
}

// Kibana 7.5.0 and above support running with a read-only root filesystem,
// but require a temporary volume to be mounted at /tmp for some reporting features
// and a plugin volume mounted at /usr/share/kibana/plugins.
// Limiting to 7.10.0 here as there was a bug in previous versions causing rebuilding
// of browser bundles to happen on plugin install, which would attempt a write to the
// root filesystem on restart.
if v.GTE(version.From(7, 10, 0)) {
builder.WithPodSecurityContext(defaultPodSecurityContext).
WithContainersSecurityContext(defaultSecurityContext).
WithVolumes(TempVolume.Volume()).WithVolumeMounts(TempVolume.VolumeMount()).
WithVolumes(PluginsVolume.Volume()).WithVolumeMounts(PluginsVolume.VolumeMount())
}

if keystore != nil {
builder.WithVolumes(keystore.Volume).
WithInitContainers(keystore.InitContainer)
Expand Down
14 changes: 9 additions & 5 deletions pkg/controller/kibana/pod_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ func TestNewPodTemplateSpec(t *testing.T) {
},
},
{
name: "with user-provided labels",
name: "with user-provided labels, and 7.4.x shouldn't have security contexts set",
keystore: nil,
kb: kbv1.Kibana{
ObjectMeta: metav1.ObjectMeta{
Expand All @@ -165,6 +165,8 @@ func TestNewPodTemplateSpec(t *testing.T) {
labels["label2"] = "value2"
labels[kblabel.KibanaNameLabelName] = "overridden-kibana-name"
assert.Equal(t, labels, pod.Labels)
assert.Nil(t, pod.Spec.SecurityContext)
assert.Nil(t, GetKibanaContainer(pod.Spec).SecurityContext)
},
},
{
Expand Down Expand Up @@ -192,7 +194,7 @@ func TestNewPodTemplateSpec(t *testing.T) {
},
},
{
name: "with user-provided volumes and volume mounts",
name: "with user-provided volumes and 8.x should have volume mounts including /tmp and plugins volumes and security contexts",
kb: kbv1.Kibana{Spec: kbv1.KibanaSpec{
PodTemplate: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
Expand All @@ -217,9 +219,11 @@ func TestNewPodTemplateSpec(t *testing.T) {
}},
assertions: func(pod corev1.PodTemplateSpec) {
assert.Len(t, pod.Spec.InitContainers, 1)
assert.Len(t, pod.Spec.InitContainers[0].VolumeMounts, 3)
assert.Len(t, pod.Spec.Volumes, 1)
assert.Len(t, GetKibanaContainer(pod.Spec).VolumeMounts, 1)
assert.Len(t, pod.Spec.InitContainers[0].VolumeMounts, 5)
assert.Len(t, pod.Spec.Volumes, 3)
assert.Len(t, GetKibanaContainer(pod.Spec).VolumeMounts, 3)
assert.Equal(t, pod.Spec.SecurityContext, &defaultPodSecurityContext)
assert.Equal(t, GetKibanaContainer(pod.Spec).SecurityContext, &defaultSecurityContext)
},
},
{
Expand Down
28 changes: 28 additions & 0 deletions pkg/controller/kibana/securitycontext.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License 2.0;
// you may not use this file except in compliance with the Elastic License 2.0.

package kibana

import (
corev1 "k8s.io/api/core/v1"
"k8s.io/utils/ptr"
)

var (
defaultSecurityContext = corev1.SecurityContext{
AllowPrivilegeEscalation: ptr.To(bool(false)),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{
corev1.Capability("ALL"),
},
},
Privileged: ptr.To(bool(false)),
ReadOnlyRootFilesystem: ptr.To(bool(true)),
RunAsUser: ptr.To(int64(1000)),
RunAsGroup: ptr.To(int64(1000)),
}
defaultPodSecurityContext = corev1.PodSecurityContext{
FSGroup: ptr.To(int64(1000)),
}
)