From 92cd8165afed95eed690f0b0fb9bb8fc8e147cce Mon Sep 17 00:00:00 2001 From: Gerard Vanloo Date: Thu, 30 Jun 2022 09:56:12 -0400 Subject: [PATCH] operator: Making all pods and containers compliant with restricted policy (#6514) --- operator/CHANGELOG.md | 1 + operator/Makefile | 4 + .../apis/config/v1/projectconfig_types.go | 1 + ...-operator-manager-config_v1_configmap.yaml | 1 + .../loki-operator.clusterserviceversion.yaml | 10 ++ operator/cmd/loki-broker/main.go | 2 + operator/config/manager/manager.yaml | 5 + .../controller_manager_config.yaml | 1 + .../overlays/development/kustomization.yaml | 1 + .../manager_security_context_patch.yaml | 10 ++ .../openshift/controller_manager_config.yaml | 1 + .../openshift/manager_auth_proxy_patch.yaml | 7 + .../production/controller_manager_config.yaml | 1 + .../production/manager_auth_proxy_patch.yaml | 7 + operator/hack/addons_dev.yaml | 87 ++++-------- operator/hack/addons_ocp.yaml | 59 ++++---- operator/internal/manifests/build_test.go | 133 ++++++++++++++++++ operator/internal/manifests/compactor.go | 2 + operator/internal/manifests/distributor.go | 2 + operator/internal/manifests/gateway.go | 13 ++ operator/internal/manifests/indexgateway.go | 2 + operator/internal/manifests/ingester.go | 2 + operator/internal/manifests/options.go | 2 + operator/internal/manifests/querier.go | 2 + operator/internal/manifests/query-frontend.go | 2 + operator/internal/manifests/ruler.go | 2 + operator/internal/manifests/var.go | 24 ++++ operator/main.go | 1 + 28 files changed, 295 insertions(+), 90 deletions(-) create mode 100644 operator/config/overlays/development/manager_security_context_patch.yaml diff --git a/operator/CHANGELOG.md b/operator/CHANGELOG.md index 1571fb7eba..932d7e7bc7 100644 --- a/operator/CHANGELOG.md +++ b/operator/CHANGELOG.md @@ -1,5 +1,6 @@ ## Main +- [6514](https://github.com/grafana/loki/pull/6514) **Red-GV** Update all pods and containers to be compliant with restricted Pod Security Standard - [6531](https://github.com/grafana/loki/pull/6531) **periklis**: Use default interface_names for lokistack clusters (IPv6 Support) - [6411](https://github.com/grafana/loki/pull/6478) **aminesnow**: Support TLS enabled lokistack-gateway for vanilla kubernetes deployments - [6504](https://github.com/grafana/loki/pull/6504) **periklis**: Disable usage report on OpenShift diff --git a/operator/Makefile b/operator/Makefile index 3400bf999d..777424e447 100644 --- a/operator/Makefile +++ b/operator/Makefile @@ -194,6 +194,10 @@ quickstart: oci-build oci-push $(KIND) @./quickstart.sh $(filter-out $@,$(MAKECMDGOALS)) endif +.PHONY: quickstart-cleanup +quickstart-cleanup: $(KIND) ## Cleanup for quickstart set up + $(KIND) delete cluster + .PHONY: run run: generate manifests ## Run against the configured Kubernetes cluster in ~/.kube/config go run ./main.go diff --git a/operator/apis/config/v1/projectconfig_types.go b/operator/apis/config/v1/projectconfig_types.go index 234522509c..876426b991 100644 --- a/operator/apis/config/v1/projectconfig_types.go +++ b/operator/apis/config/v1/projectconfig_types.go @@ -19,6 +19,7 @@ type FeatureFlags struct { EnableLokiStackWebhook bool `json:"enableLokiStackWebhook,omitempty"` EnableAlertingRuleWebhook bool `json:"enableAlertingRuleWebhook,omitempty"` EnableRecordingRuleWebhook bool `json:"enableRecordingRuleWebhook,omitempty"` + EnableRuntimeSeccompProfile bool `json:"enableRuntimeSeccompProfile,omitempty"` } //+kubebuilder:object:root=true diff --git a/operator/bundle/manifests/loki-operator-manager-config_v1_configmap.yaml b/operator/bundle/manifests/loki-operator-manager-config_v1_configmap.yaml index 97a91f5dbb..920963fb0f 100644 --- a/operator/bundle/manifests/loki-operator-manager-config_v1_configmap.yaml +++ b/operator/bundle/manifests/loki-operator-manager-config_v1_configmap.yaml @@ -27,6 +27,7 @@ data: enableLokiStackWebhook: true enableAlertingRuleWebhook: true enableRecordingRuleWebhook: true + enableRuntimeSeccompProfile: false kind: ConfigMap metadata: labels: diff --git a/operator/bundle/manifests/loki-operator.clusterserviceversion.yaml b/operator/bundle/manifests/loki-operator.clusterserviceversion.yaml index f136d718bf..a21aa324d5 100644 --- a/operator/bundle/manifests/loki-operator.clusterserviceversion.yaml +++ b/operator/bundle/manifests/loki-operator.clusterserviceversion.yaml @@ -1210,6 +1210,9 @@ spec: resources: {} securityContext: allowPrivilegeEscalation: false + capabilities: + drop: + - ALL volumeMounts: - mountPath: /tmp/k8s-webhook-server/serving-certs name: webhook-cert @@ -1230,11 +1233,18 @@ spec: - containerPort: 8443 name: https resources: {} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL volumeMounts: - mountPath: /var/run/secrets/serving-cert name: loki-operator-metrics-cert nodeSelector: kubernetes.io/os: linux + securityContext: + runAsNonRoot: true terminationGracePeriodSeconds: 10 volumes: - name: webhook-cert diff --git a/operator/cmd/loki-broker/main.go b/operator/cmd/loki-broker/main.go index 0e5f6e8e93..b875c44e31 100644 --- a/operator/cmd/loki-broker/main.go +++ b/operator/cmd/loki-broker/main.go @@ -42,6 +42,8 @@ func (c *config) registerFlags(f *flag.FlagSet) { f.BoolVar(&c.featureFlags.EnableTLSServiceMonitorConfig, "with-tls-service-monitors", false, "Enable TLS endpoint for service monitors.") f.BoolVar(&c.featureFlags.EnablePrometheusAlerts, "with-prometheus-alerts", false, "Enables prometheus alerts") f.BoolVar(&c.featureFlags.EnableGateway, "with-lokistack-gateway", false, "Enables the manifest creation for the entire lokistack-gateway.") + f.BoolVar(&c.featureFlags.EnableRuntimeSeccompProfile, "with-runtime-seccomp-profile", false, "Enables the usage of the runtime/default seccomp profile for pods and containers.") + // Object storage options c.objectStorage = storage.Options{ S3: &storage.S3StorageConfig{}, diff --git a/operator/config/manager/manager.yaml b/operator/config/manager/manager.yaml index 1ec47d9d71..7d2b43f5af 100644 --- a/operator/config/manager/manager.yaml +++ b/operator/config/manager/manager.yaml @@ -27,6 +27,9 @@ spec: name: metrics securityContext: allowPrivilegeEscalation: false + capabilities: + drop: + - ALL livenessProbe: httpGet: path: /healthz @@ -42,3 +45,5 @@ spec: nodeSelector: kubernetes.io/os: linux terminationGracePeriodSeconds: 10 + securityContext: + runAsNonRoot: true diff --git a/operator/config/overlays/development/controller_manager_config.yaml b/operator/config/overlays/development/controller_manager_config.yaml index 382d99d53e..93ee5ad0a5 100644 --- a/operator/config/overlays/development/controller_manager_config.yaml +++ b/operator/config/overlays/development/controller_manager_config.yaml @@ -15,3 +15,4 @@ featureFlags: enableLokiStackWebhook: false enableAlertingRuleWebhook: false enableRecordingRuleWebhook: false + enableRuntimeSeccompProfile: true diff --git a/operator/config/overlays/development/kustomization.yaml b/operator/config/overlays/development/kustomization.yaml index eb1d25809e..ea84383259 100644 --- a/operator/config/overlays/development/kustomization.yaml +++ b/operator/config/overlays/development/kustomization.yaml @@ -29,3 +29,4 @@ patchesStrategicMerge: - manager_run_flags_patch.yaml - manager_related_image_patch.yaml - manager_image_pull_policy_patch.yaml +- manager_security_context_patch.yaml diff --git a/operator/config/overlays/development/manager_security_context_patch.yaml b/operator/config/overlays/development/manager_security_context_patch.yaml new file mode 100644 index 0000000000..47d3977209 --- /dev/null +++ b/operator/config/overlays/development/manager_security_context_patch.yaml @@ -0,0 +1,10 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager +spec: + template: + spec: + securityContext: + seccompProfile: + type: RuntimeDefault diff --git a/operator/config/overlays/openshift/controller_manager_config.yaml b/operator/config/overlays/openshift/controller_manager_config.yaml index b4148d7806..0b284b5902 100644 --- a/operator/config/overlays/openshift/controller_manager_config.yaml +++ b/operator/config/overlays/openshift/controller_manager_config.yaml @@ -24,3 +24,4 @@ featureFlags: enableLokiStackWebhook: true enableAlertingRuleWebhook: true enableRecordingRuleWebhook: true + enableRuntimeSeccompProfile: false diff --git a/operator/config/overlays/openshift/manager_auth_proxy_patch.yaml b/operator/config/overlays/openshift/manager_auth_proxy_patch.yaml index 6d1e5c29c7..261cbfd4cc 100644 --- a/operator/config/overlays/openshift/manager_auth_proxy_patch.yaml +++ b/operator/config/overlays/openshift/manager_auth_proxy_patch.yaml @@ -21,9 +21,16 @@ spec: volumeMounts: - mountPath: /var/run/secrets/serving-cert name: loki-operator-metrics-cert + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL volumes: - name: loki-operator-metrics-cert secret: defaultMode: 420 optional: true secretName: loki-operator-metrics + securityContext: + runAsNonRoot: true diff --git a/operator/config/overlays/production/controller_manager_config.yaml b/operator/config/overlays/production/controller_manager_config.yaml index 7cc35fd57c..80acb5ef5e 100644 --- a/operator/config/overlays/production/controller_manager_config.yaml +++ b/operator/config/overlays/production/controller_manager_config.yaml @@ -11,3 +11,4 @@ leaderElection: resourceName: e3716011.grafana.com featureFlags: enableLokiStackGateway: true + enableRuntimeSeccompProfile: false diff --git a/operator/config/overlays/production/manager_auth_proxy_patch.yaml b/operator/config/overlays/production/manager_auth_proxy_patch.yaml index ce4d09b9f2..c5349edb67 100644 --- a/operator/config/overlays/production/manager_auth_proxy_patch.yaml +++ b/operator/config/overlays/production/manager_auth_proxy_patch.yaml @@ -23,9 +23,16 @@ spec: volumeMounts: - mountPath: /var/run/secrets/serving-cert name: loki-operator-metrics-cert + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL volumes: - name: loki-operator-metrics-cert secret: defaultMode: 420 optional: true secretName: loki-operator-metrics + securityContext: + runAsNonRoot: true diff --git a/operator/hack/addons_dev.yaml b/operator/hack/addons_dev.yaml index e50f5ebffe..a07cfec582 100644 --- a/operator/hack/addons_dev.yaml +++ b/operator/hack/addons_dev.yaml @@ -29,7 +29,7 @@ spec: spec: containers: - name: logcli - image: docker.io/grafana/logcli:2.4.2-amd64 + image: docker.io/grafana/logcli:2.5.0-amd64 imagePullPolicy: IfNotPresent command: - /bin/sh @@ -43,7 +43,16 @@ spec: args: - -c - while true; do logcli query '{job="systemd-journal"}'; sleep 30; done + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL serviceAccountName: lokistack-dev-addons-logcli + securityContext: + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault --- apiVersion: apps/v1 kind: DaemonSet @@ -63,7 +72,7 @@ spec: spec: containers: - name: promtail - image: docker.io/grafana/promtail:2.4.2 + image: docker.io/grafana/promtail:2.5.0 args: - -config.file=/etc/promtail/promtail.yaml - -log.level=info @@ -84,31 +93,33 @@ spec: name: journal readOnly: true securityContext: - privileged: true - readOnlyRootFilesystem: true - runAsGroup: 0 - runAsUser: 0 + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL serviceAccountName: lokistack-dev-addons-promtail + securityContext: + runAsNonRoot: true volumes: - configMap: defaultMode: 420 name: lokistack-dev-addons-promtail name: config - - hostPath: - path: /run/promtail - type: "" + - emptyDir: + medium: "" + sizeLimit: 10G name: run - - hostPath: - path: /var/lib/docker/containers - type: "" + - emptyDir: + medium: "" + sizeLimit: 10G name: docker - - hostPath: - path: /var/log/pods - type: "" + - emptyDir: + medium: "" + sizeLimit: 10G name: pods - - hostPath: - path: /var/log/journal - type: "" + - emptyDir: + medium: "" + sizeLimit: 10G name: journal --- apiVersion: v1 @@ -397,46 +408,6 @@ data: - __meta_kubernetes_pod_container_name target_label: __path__ --- -apiVersion: policy/v1beta1 -kind: PodSecurityPolicy -metadata: - name: lokistack-dev-addons-policy -spec: - allowPrivilegeEscalation: false - fsGroup: - rule: RunAsAny - hostIPC: false - hostNetwork: false - hostPID: false - privileged: false - readOnlyRootFilesystem: true - requiredDropCapabilities: - - ALL - runAsUser: - rule: RunAsAny - seLinux: - rule: RunAsAny - supplementalGroups: - rule: RunAsAny - volumes: - - secret - - configMap - - hostPath ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: lokistack-dev-addons-writer -rules: -- apiGroups: - - extensions - resourceNames: - - lokistack-dev-addons-policy - resources: - - podsecuritypolicies - verbs: - - use ---- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: diff --git a/operator/hack/addons_ocp.yaml b/operator/hack/addons_ocp.yaml index 312deee33a..bdd6769d4e 100644 --- a/operator/hack/addons_ocp.yaml +++ b/operator/hack/addons_ocp.yaml @@ -29,7 +29,7 @@ spec: spec: containers: - name: logcli - image: docker.io/grafana/logcli:2.4.2-amd64 + image: docker.io/grafana/logcli:2.5.0-amd64 imagePullPolicy: IfNotPresent command: - /bin/sh @@ -43,7 +43,14 @@ spec: args: - -c - while true; do logcli --ca-cert="/var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt" query '{job="systemd-journal"}'; sleep 30; done + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL serviceAccountName: lokistack-dev-addons-logcli + securityContext: + runAsNonRoot: true --- apiVersion: apps/v1 kind: DaemonSet @@ -63,7 +70,7 @@ spec: spec: containers: - name: promtail - image: docker.io/grafana/promtail:2.4.2 + image: docker.io/grafana/promtail:2.5.0 args: - -config.file=/etc/promtail/promtail.yaml - -log.level=info @@ -84,31 +91,33 @@ spec: name: journal readOnly: true securityContext: - privileged: true - readOnlyRootFilesystem: true - runAsGroup: 0 - runAsUser: 0 + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL serviceAccountName: lokistack-dev-addons-promtail + securityContext: + runAsNonRoot: true volumes: - configMap: defaultMode: 420 name: lokistack-dev-addons-promtail name: config - - hostPath: - path: /run/promtail - type: "" + - emptyDir: + medium: "" + sizeLimit: 10G name: run - - hostPath: - path: /var/lib/docker/containers - type: "" + - emptyDir: + medium: "" + sizeLimit: 10G name: docker - - hostPath: - path: /var/log/pods - type: "" + - emptyDir: + medium: "" + sizeLimit: 10G name: pods - - hostPath: - path: /var/log/journal - type: "" + - emptyDir: + medium: "" + sizeLimit: 10G name: journal --- apiVersion: v1 @@ -400,20 +409,6 @@ data: target_label: __path__ --- apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: lokistack-dev-addons-writer -rules: -- apiGroups: - - security.openshift.io - resourceNames: - - privileged - resources: - - securitycontextconstraints - verbs: - - use ---- -apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: lokistack-dev-addons-writer diff --git a/operator/internal/manifests/build_test.go b/operator/internal/manifests/build_test.go index 8b3fa7496c..8bf585dcbd 100644 --- a/operator/internal/manifests/build_test.go +++ b/operator/internal/manifests/build_test.go @@ -539,6 +539,139 @@ func TestBuildAll_WithFeatureFlags_EnableTLSGRPCServices(t *testing.T) { } } +func TestBuildAll_WithFeatureFlags_EnableRuntimeSeccompProfile(t *testing.T) { + type test struct { + desc string + BuildOptions Options + } + + table := []test{ + { + desc: "disabled default/runtime seccomp profile", + BuildOptions: Options{ + Name: "test", + Namespace: "test", + Stack: lokiv1beta1.LokiStackSpec{ + Size: lokiv1beta1.SizeOneXSmall, + Rules: &lokiv1beta1.RulesSpec{ + Enabled: true, + }, + Template: &lokiv1beta1.LokiTemplateSpec{ + Compactor: &lokiv1beta1.LokiComponentSpec{ + Replicas: 1, + }, + Distributor: &lokiv1beta1.LokiComponentSpec{ + Replicas: 1, + }, + Ingester: &lokiv1beta1.LokiComponentSpec{ + Replicas: 1, + }, + Querier: &lokiv1beta1.LokiComponentSpec{ + Replicas: 1, + }, + QueryFrontend: &lokiv1beta1.LokiComponentSpec{ + Replicas: 1, + }, + Gateway: &lokiv1beta1.LokiComponentSpec{ + Replicas: 1, + }, + IndexGateway: &lokiv1beta1.LokiComponentSpec{ + Replicas: 1, + }, + Ruler: &lokiv1beta1.LokiComponentSpec{ + Replicas: 1, + }, + }, + }, + Flags: FeatureFlags{ + EnableRuntimeSeccompProfile: false, + }, + }, + }, + { + desc: "enabled default/runtime seccomp profile", + BuildOptions: Options{ + Name: "test", + Namespace: "test", + Stack: lokiv1beta1.LokiStackSpec{ + Size: lokiv1beta1.SizeOneXSmall, + Rules: &lokiv1beta1.RulesSpec{ + Enabled: true, + }, + Template: &lokiv1beta1.LokiTemplateSpec{ + Compactor: &lokiv1beta1.LokiComponentSpec{ + Replicas: 1, + }, + Distributor: &lokiv1beta1.LokiComponentSpec{ + Replicas: 1, + }, + Ingester: &lokiv1beta1.LokiComponentSpec{ + Replicas: 1, + }, + Querier: &lokiv1beta1.LokiComponentSpec{ + Replicas: 1, + }, + QueryFrontend: &lokiv1beta1.LokiComponentSpec{ + Replicas: 1, + }, + Gateway: &lokiv1beta1.LokiComponentSpec{ + Replicas: 1, + }, + IndexGateway: &lokiv1beta1.LokiComponentSpec{ + Replicas: 1, + }, + Ruler: &lokiv1beta1.LokiComponentSpec{ + Replicas: 1, + }, + }, + }, + Flags: FeatureFlags{ + EnableRuntimeSeccompProfile: true, + }, + }, + }, + } + + for _, tst := range table { + tst := tst + t.Run(tst.desc, func(t *testing.T) { + t.Parallel() + + err := ApplyDefaultSettings(&tst.BuildOptions) + require.NoError(t, err) + + objs, err := BuildAll(tst.BuildOptions) + require.NoError(t, err) + + for _, o := range objs { + var ( + name string + spec *corev1.PodSpec + ) + switch obj := o.(type) { + case *appsv1.Deployment: + name = obj.Name + spec = &obj.Spec.Template.Spec + case *appsv1.StatefulSet: + name = obj.Name + spec = &obj.Spec.Template.Spec + default: + continue + } + + t.Run(name, func(t *testing.T) { + if tst.BuildOptions.Flags.EnableRuntimeSeccompProfile { + require.NotNil(t, spec.SecurityContext.SeccompProfile) + require.Equal(t, spec.SecurityContext.SeccompProfile.Type, corev1.SeccompProfileTypeRuntimeDefault) + } else { + require.Nil(t, spec.SecurityContext.SeccompProfile) + } + }) + } + }) + } +} + func TestBuildAll_WithFeatureFlags_EnableGateway(t *testing.T) { type test struct { desc string diff --git a/operator/internal/manifests/compactor.go b/operator/internal/manifests/compactor.go index 25334ec5d6..9220393e2b 100644 --- a/operator/internal/manifests/compactor.go +++ b/operator/internal/manifests/compactor.go @@ -101,8 +101,10 @@ func NewCompactorStatefulSet(opts Options) *appsv1.StatefulSet { TerminationMessagePath: "/dev/termination-log", TerminationMessagePolicy: "File", ImagePullPolicy: "IfNotPresent", + SecurityContext: containerSecurityContext(), }, }, + SecurityContext: podSecurityContext(opts.Flags.EnableRuntimeSeccompProfile), } if opts.Stack.Template != nil && opts.Stack.Template.Compactor != nil { diff --git a/operator/internal/manifests/distributor.go b/operator/internal/manifests/distributor.go index 0fa7f4c6fd..e41f60c407 100644 --- a/operator/internal/manifests/distributor.go +++ b/operator/internal/manifests/distributor.go @@ -96,8 +96,10 @@ func NewDistributorDeployment(opts Options) *appsv1.Deployment { TerminationMessagePath: "/dev/termination-log", TerminationMessagePolicy: "File", ImagePullPolicy: "IfNotPresent", + SecurityContext: containerSecurityContext(), }, }, + SecurityContext: podSecurityContext(opts.Flags.EnableRuntimeSeccompProfile), } if opts.Stack.Template != nil && opts.Stack.Template.Distributor != nil { diff --git a/operator/internal/manifests/gateway.go b/operator/internal/manifests/gateway.go index 38cc884aa7..d01702c196 100644 --- a/operator/internal/manifests/gateway.go +++ b/operator/internal/manifests/gateway.go @@ -60,6 +60,8 @@ func BuildGateway(opts Options) ([]client.Object, error) { objs = configureGatewayObjsForMode(objs, opts) } + configureDeploymentForRestrictedPolicy(dpl, opts.Flags) + return objs, nil } @@ -407,3 +409,14 @@ func configureGatewayMetricsPKI(podSpec *corev1.PodSpec, serviceName string) err return nil } + +func configureDeploymentForRestrictedPolicy(d *appsv1.Deployment, flags FeatureFlags) { + podSpec := d.Spec.Template.Spec + + podSpec.SecurityContext = podSecurityContext(flags.EnableRuntimeSeccompProfile) + for i := range podSpec.Containers { + podSpec.Containers[i].SecurityContext = containerSecurityContext() + } + + d.Spec.Template.Spec = podSpec +} diff --git a/operator/internal/manifests/indexgateway.go b/operator/internal/manifests/indexgateway.go index 439f90ad44..77a7cb4b29 100644 --- a/operator/internal/manifests/indexgateway.go +++ b/operator/internal/manifests/indexgateway.go @@ -100,8 +100,10 @@ func NewIndexGatewayStatefulSet(opts Options) *appsv1.StatefulSet { TerminationMessagePath: "/dev/termination-log", TerminationMessagePolicy: "File", ImagePullPolicy: "IfNotPresent", + SecurityContext: containerSecurityContext(), }, }, + SecurityContext: podSecurityContext(opts.Flags.EnableRuntimeSeccompProfile), } if opts.Stack.Template != nil && opts.Stack.Template.IndexGateway != nil { diff --git a/operator/internal/manifests/ingester.go b/operator/internal/manifests/ingester.go index 4394913516..fc918a1c7e 100644 --- a/operator/internal/manifests/ingester.go +++ b/operator/internal/manifests/ingester.go @@ -114,8 +114,10 @@ func NewIngesterStatefulSet(opts Options) *appsv1.StatefulSet { TerminationMessagePath: "/dev/termination-log", TerminationMessagePolicy: "File", ImagePullPolicy: "IfNotPresent", + SecurityContext: containerSecurityContext(), }, }, + SecurityContext: podSecurityContext(opts.Flags.EnableRuntimeSeccompProfile), } if opts.Stack.Template != nil && opts.Stack.Template.Ingester != nil { diff --git a/operator/internal/manifests/options.go b/operator/internal/manifests/options.go index 2c29b1b527..8c03a610c5 100644 --- a/operator/internal/manifests/options.go +++ b/operator/internal/manifests/options.go @@ -44,6 +44,8 @@ type FeatureFlags struct { EnableGateway bool EnableGatewayRoute bool EnableGrafanaLabsStats bool + EnableRuntimeSeccompProfile bool + EnableNonRootUser bool } // Tenants contains the configuration per tenant and secrets for authn/authz. diff --git a/operator/internal/manifests/querier.go b/operator/internal/manifests/querier.go index d917dadf5c..6af2f94598 100644 --- a/operator/internal/manifests/querier.go +++ b/operator/internal/manifests/querier.go @@ -102,8 +102,10 @@ func NewQuerierDeployment(opts Options) *appsv1.Deployment { TerminationMessagePath: "/dev/termination-log", TerminationMessagePolicy: "File", ImagePullPolicy: "IfNotPresent", + SecurityContext: containerSecurityContext(), }, }, + SecurityContext: podSecurityContext(opts.Flags.EnableRuntimeSeccompProfile), } if opts.Stack.Template != nil && opts.Stack.Template.Querier != nil { diff --git a/operator/internal/manifests/query-frontend.go b/operator/internal/manifests/query-frontend.go index 53402123f1..e6b50cccad 100644 --- a/operator/internal/manifests/query-frontend.go +++ b/operator/internal/manifests/query-frontend.go @@ -106,8 +106,10 @@ func NewQueryFrontendDeployment(opts Options) *appsv1.Deployment { TerminationMessagePath: "/dev/termination-log", TerminationMessagePolicy: "File", ImagePullPolicy: "IfNotPresent", + SecurityContext: containerSecurityContext(), }, }, + SecurityContext: podSecurityContext(opts.Flags.EnableRuntimeSeccompProfile), } if opts.Stack.Template != nil && opts.Stack.Template.QueryFrontend != nil { diff --git a/operator/internal/manifests/ruler.go b/operator/internal/manifests/ruler.go index 45001c34c1..34153365ab 100644 --- a/operator/internal/manifests/ruler.go +++ b/operator/internal/manifests/ruler.go @@ -124,8 +124,10 @@ func NewRulerStatefulSet(opts Options) *appsv1.StatefulSet { TerminationMessagePath: "/dev/termination-log", TerminationMessagePolicy: "File", ImagePullPolicy: "IfNotPresent", + SecurityContext: containerSecurityContext(), }, }, + SecurityContext: podSecurityContext(opts.Flags.EnableRuntimeSeccompProfile), } if opts.Stack.Template != nil && opts.Stack.Template.Ruler != nil { diff --git a/operator/internal/manifests/var.go b/operator/internal/manifests/var.go index c3eaf057d7..1eed3cc39d 100644 --- a/operator/internal/manifests/var.go +++ b/operator/internal/manifests/var.go @@ -9,6 +9,7 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/utils/pointer" ) const ( @@ -328,3 +329,26 @@ func lokiReadinessProbe() *corev1.Probe { FailureThreshold: 3, } } + +func containerSecurityContext() *corev1.SecurityContext { + return &corev1.SecurityContext{ + AllowPrivilegeEscalation: pointer.Bool(false), + Capabilities: &corev1.Capabilities{ + Drop: []corev1.Capability{"ALL"}, + }, + } +} + +func podSecurityContext(withSeccompProfile bool) *corev1.PodSecurityContext { + context := corev1.PodSecurityContext{ + RunAsNonRoot: pointer.Bool(true), + } + + if withSeccompProfile { + context.SeccompProfile = &corev1.SeccompProfile{ + Type: corev1.SeccompProfileTypeRuntimeDefault, + } + } + + return &context +} diff --git a/operator/main.go b/operator/main.go index 0816196c43..b770e6d1ed 100644 --- a/operator/main.go +++ b/operator/main.go @@ -104,6 +104,7 @@ func main() { EnableGateway: ctrlCfg.Flags.EnableGateway, EnableGatewayRoute: ctrlCfg.Flags.EnableGatewayRoute, EnableGrafanaLabsStats: ctrlCfg.Flags.EnableGrafanaLabsStats, + EnableRuntimeSeccompProfile: ctrlCfg.Flags.EnableRuntimeSeccompProfile, } if err = (&lokictrl.LokiStackReconciler{