operator: Set seccomp profile to runtime default for all variants (#9457)

pull/9598/head
Gerard Vanloo 3 years ago committed by GitHub
parent 1b3f97fde4
commit 7b706eea8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      operator/CHANGELOG.md
  2. 6
      operator/apis/config/v1/projectconfig_types.go
  3. 2
      operator/bundle/community-openshift/manifests/loki-operator-manager-config_v1_configmap.yaml
  4. 4
      operator/bundle/community-openshift/manifests/loki-operator.clusterserviceversion.yaml
  5. 2
      operator/bundle/community/manifests/loki-operator-manager-config_v1_configmap.yaml
  6. 7
      operator/bundle/community/manifests/loki-operator.clusterserviceversion.yaml
  7. 2
      operator/bundle/openshift/manifests/loki-operator-manager-config_v1_configmap.yaml
  8. 4
      operator/bundle/openshift/manifests/loki-operator.clusterserviceversion.yaml
  9. 2
      operator/cmd/loki-broker/main.go
  10. 7
      operator/config/manager/manager.yaml
  11. 2
      operator/config/overlays/community-openshift/controller_manager_config.yaml
  12. 2
      operator/config/overlays/community/controller_manager_config.yaml
  13. 2
      operator/config/overlays/development/controller_manager_config.yaml
  14. 2
      operator/config/overlays/openshift/controller_manager_config.yaml
  15. 1
      operator/config/overlays/openshift/kustomization.yaml
  16. 18
      operator/config/overlays/openshift/manager_security_context_patch.yaml
  17. 29
      operator/internal/manifests/build_test.go
  18. 8
      operator/internal/manifests/compactor.go
  19. 8
      operator/internal/manifests/distributor.go
  20. 18
      operator/internal/manifests/gateway.go
  21. 8
      operator/internal/manifests/indexgateway.go
  22. 8
      operator/internal/manifests/ingester.go
  23. 8
      operator/internal/manifests/querier.go
  24. 8
      operator/internal/manifests/query-frontend.go
  25. 8
      operator/internal/manifests/ruler.go
  26. 43
      operator/internal/manifests/securitycontext.go
  27. 24
      operator/internal/manifests/var.go

@ -1,5 +1,6 @@
## Main
- [9457](https://github.com/grafana/loki/pull/9457) **Red-GV**: Set seccomp profile to runtime default
- [9448](https://github.com/grafana/loki/pull/9448) **btaani**: Include runtime-config in compiling the SHA1 checksum
- [9511](https://github.com/grafana/loki/pull/9511) **xperimental**: Do not update status after setting degraded condition
- [9405](https://github.com/grafana/loki/pull/9405) **periklis**: Add support for configuring HTTP server timeouts

@ -98,9 +98,9 @@ type FeatureGates struct {
// More details: https://grafana.com/docs/loki/latest/release-notes/v2-5/#usage-reporting
GrafanaLabsUsageReport bool `json:"grafanaLabsUsageReport,omitempty"`
// RuntimeSeccompProfile enables the restricted seccomp profile on all
// Lokistack components.
RuntimeSeccompProfile bool `json:"runtimeSeccompProfile,omitempty"`
// RestrictedPodSecurityStandard enables compliance with the restrictive pod security standard.
// More details: https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted
RestrictedPodSecurityStandard bool `json:"restrictedPodSecurityStandard,omitempty"`
// LokiStackWebhook enables the LokiStack CR validation and conversion webhooks.
LokiStackWebhook bool `json:"lokiStackWebhook,omitempty"`

@ -38,7 +38,7 @@ data:
# Component feature gates
#
lokiStackGateway: true
runtimeSeccompProfile: true
restrictedPodSecurityStandard: true
defaultNodeAffinity: true
#
# Webhook feature gates

@ -150,7 +150,7 @@ metadata:
categories: OpenShift Optional, Logging & Tracing
certified: "false"
containerImage: docker.io/grafana/loki-operator:main-ac1c1fd
createdAt: "2023-05-22T15:22:48Z"
createdAt: "2023-05-24T15:10:18Z"
description: The Community Loki Operator provides Kubernetes native deployment
and management of Loki and related logging components.
operators.operatorframework.io/builder: operator-sdk-unknown
@ -1643,6 +1643,8 @@ spec:
kubernetes.io/os: linux
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
terminationGracePeriodSeconds: 10
volumes:
- configMap:

@ -14,7 +14,7 @@ data:
resourceName: e3716011.grafana.com
featureGates:
lokiStackGateway: true
runtimeSeccompProfile: false
restrictedPodSecurityStandard: false
#
# Webhook feature gates
#

@ -150,7 +150,7 @@ metadata:
categories: OpenShift Optional, Logging & Tracing
certified: "false"
containerImage: docker.io/grafana/loki-operator:main-ac1c1fd
createdAt: "2023-05-22T15:22:44Z"
createdAt: "2023-05-24T15:10:16Z"
description: The Community Loki Operator provides Kubernetes native deployment
and management of Loki and related logging components.
operators.operatorframework.io/builder: operator-sdk-unknown
@ -1594,11 +1594,6 @@ spec:
initialDelaySeconds: 5
periodSeconds: 10
resources: {}
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
volumeMounts:
- mountPath: /tmp/k8s-webhook-server/serving-certs
name: webhook-cert

@ -41,7 +41,7 @@ data:
#
lokiStackGateway: true
grafanaLabsUsageReport: false
runtimeSeccompProfile: false
restrictedPodSecurityStandard: true
defaultNodeAffinity: true
#
# Webhook feature gates

@ -150,7 +150,7 @@ metadata:
categories: OpenShift Optional, Logging & Tracing
certified: "false"
containerImage: quay.io/openshift-logging/loki-operator:v0.1.0
createdAt: "2023-05-22T15:22:53Z"
createdAt: "2023-05-24T15:10:20Z"
description: |
The Loki Operator for OCP provides a means for configuring and managing a Loki stack for cluster logging.
## Prerequisites and Requirements
@ -1628,6 +1628,8 @@ spec:
kubernetes.io/os: linux
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
terminationGracePeriodSeconds: 10
volumes:
- configMap:

@ -49,7 +49,7 @@ func (c *config) registerFlags(f *flag.FlagSet) {
f.BoolVar(&c.featureFlags.ServiceMonitorTLSEndpoints, "with-service-monitor-tls-endpoints", false, "Enable TLS endpoint for service monitors.")
f.BoolVar(&c.featureFlags.LokiStackAlerts, "with-lokistack-alerts", false, "Enables prometheus alerts")
f.BoolVar(&c.featureFlags.LokiStackGateway, "with-lokistack-gateway", false, "Enables the manifest creation for the entire lokistack-gateway.")
f.BoolVar(&c.featureFlags.RuntimeSeccompProfile, "with-runtime-seccomp-profile", false, "Enables the usage of the runtime/default seccomp profile for pods and containers.")
f.BoolVar(&c.featureFlags.RestrictedPodSecurityStandard, "with-restricted-pod-security-standard", false, "Enable restricted security standard settings")
// Object storage options
c.objectStorage = storage.Options{
S3: &storage.S3StorageConfig{},

@ -25,11 +25,6 @@ spec:
ports:
- containerPort: 8080
name: metrics
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
livenessProbe:
httpGet:
path: /healthz
@ -45,5 +40,3 @@ spec:
nodeSelector:
kubernetes.io/os: linux
terminationGracePeriodSeconds: 10
securityContext:
runAsNonRoot: true

@ -35,7 +35,7 @@ featureGates:
# Component feature gates
#
lokiStackGateway: true
runtimeSeccompProfile: true
restrictedPodSecurityStandard: true
defaultNodeAffinity: true
#
# Webhook feature gates

@ -11,7 +11,7 @@ leaderElection:
resourceName: e3716011.grafana.com
featureGates:
lokiStackGateway: true
runtimeSeccompProfile: false
restrictedPodSecurityStandard: false
#
# Webhook feature gates
#

@ -19,7 +19,7 @@ featureGates:
# Component feature gates
#
lokiStackGateway: true
runtimeSeccompProfile: true
restrictedPodSecurityStandard: false
#
# Webhook feature gates
#

@ -38,7 +38,7 @@ featureGates:
#
lokiStackGateway: true
grafanaLabsUsageReport: false
runtimeSeccompProfile: false
restrictedPodSecurityStandard: true
defaultNodeAffinity: true
#
# Webhook feature gates

@ -38,6 +38,7 @@ patchesStrategicMerge:
- manager_auth_proxy_patch.yaml
- manager_related_image_patch.yaml
- manager_run_flags_patch.yaml
- manager_security_context_patch.yaml
- manager_webhook_patch.yaml
- prometheus_service_monitor_patch.yaml

@ -0,0 +1,18 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: controller-manager
spec:
template:
spec:
containers:
- name: manager
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault

@ -655,7 +655,7 @@ func TestBuildAll_WithFeatureGates_GRPCEncryption(t *testing.T) {
}
}
func TestBuildAll_WithFeatureGates_RuntimeSeccompProfile(t *testing.T) {
func TestBuildAll_WithFeatureGates_RestrictedPodSecurityStandard(t *testing.T) {
type test struct {
desc string
BuildOptions Options
@ -663,7 +663,7 @@ func TestBuildAll_WithFeatureGates_RuntimeSeccompProfile(t *testing.T) {
table := []test{
{
desc: "disabled default/runtime seccomp profile",
desc: "disabled restricted security standard",
BuildOptions: Options{
Name: "test",
Namespace: "test",
@ -700,13 +700,13 @@ func TestBuildAll_WithFeatureGates_RuntimeSeccompProfile(t *testing.T) {
},
},
Gates: configv1.FeatureGates{
RuntimeSeccompProfile: false,
RestrictedPodSecurityStandard: false,
},
Timeouts: defaultTimeoutConfig,
},
},
{
desc: "enabled default/runtime seccomp profile",
desc: "enabled restricted security standard",
BuildOptions: Options{
Name: "test",
Namespace: "test",
@ -743,7 +743,7 @@ func TestBuildAll_WithFeatureGates_RuntimeSeccompProfile(t *testing.T) {
},
},
Gates: configv1.FeatureGates{
RuntimeSeccompProfile: true,
RestrictedPodSecurityStandard: true,
},
Timeouts: defaultTimeoutConfig,
},
@ -778,11 +778,26 @@ func TestBuildAll_WithFeatureGates_RuntimeSeccompProfile(t *testing.T) {
}
t.Run(name, func(t *testing.T) {
if tst.BuildOptions.Gates.RuntimeSeccompProfile {
if tst.BuildOptions.Gates.RestrictedPodSecurityStandard {
require.NotNil(t, spec.SecurityContext)
require.True(t, *spec.SecurityContext.RunAsNonRoot)
require.NotNil(t, spec.SecurityContext.SeccompProfile)
require.Equal(t, spec.SecurityContext.SeccompProfile.Type, corev1.SeccompProfileTypeRuntimeDefault)
} else {
require.Nil(t, spec.SecurityContext.SeccompProfile)
require.Nil(t, spec.SecurityContext)
}
for _, c := range spec.Containers {
if tst.BuildOptions.Gates.RestrictedPodSecurityStandard {
require.False(t, *c.SecurityContext.AllowPrivilegeEscalation)
require.Empty(t, c.SecurityContext.Capabilities.Add)
require.Equal(t, c.SecurityContext.Capabilities.Drop, []corev1.Capability{"ALL"})
} else {
require.Nil(t, c.SecurityContext)
}
}
})
}

@ -43,6 +43,12 @@ func BuildCompactor(opts Options) ([]client.Object, error) {
}
}
if opts.Gates.RestrictedPodSecurityStandard {
if err := configurePodSpecForRestrictedStandard(&statefulSet.Spec.Template.Spec); err != nil {
return nil, err
}
}
if err := configureHashRingEnv(&statefulSet.Spec.Template.Spec, opts); err != nil {
return nil, err
}
@ -120,10 +126,8 @@ func NewCompactorStatefulSet(opts Options) *appsv1.StatefulSet {
TerminationMessagePath: "/dev/termination-log",
TerminationMessagePolicy: "File",
ImagePullPolicy: "IfNotPresent",
SecurityContext: containerSecurityContext(),
},
},
SecurityContext: podSecurityContext(opts.Gates.RuntimeSeccompProfile),
}
if opts.Stack.Template != nil && opts.Stack.Template.Compactor != nil {

@ -38,6 +38,12 @@ func BuildDistributor(opts Options) ([]client.Object, error) {
}
}
if opts.Gates.RestrictedPodSecurityStandard {
if err := configurePodSpecForRestrictedStandard(&deployment.Spec.Template.Spec); err != nil {
return nil, err
}
}
if err := configureHashRingEnv(&deployment.Spec.Template.Spec, opts); err != nil {
return nil, err
}
@ -117,10 +123,8 @@ func NewDistributorDeployment(opts Options) *appsv1.Deployment {
TerminationMessagePath: "/dev/termination-log",
TerminationMessagePolicy: "File",
ImagePullPolicy: "IfNotPresent",
SecurityContext: containerSecurityContext(),
},
},
SecurityContext: podSecurityContext(opts.Gates.RuntimeSeccompProfile),
}
if opts.Stack.Template != nil && opts.Stack.Template.Distributor != nil {

@ -10,7 +10,6 @@ import (
"github.com/ViaQ/logerr/v2/kverrors"
"github.com/imdario/mergo"
configv1 "github.com/grafana/loki/operator/apis/config/v1"
"github.com/grafana/loki/operator/internal/manifests/internal/gateway"
appsv1 "k8s.io/api/apps/v1"
@ -82,7 +81,11 @@ func BuildGateway(opts Options) ([]client.Object, error) {
objs = configureGatewayObjsForMode(objs, opts)
}
configureDeploymentForRestrictedPolicy(dpl, opts.Gates)
if opts.Gates.RestrictedPodSecurityStandard {
if err := configurePodSpecForRestrictedStandard(&dpl.Spec.Template.Spec); err != nil {
return nil, err
}
}
return objs, nil
}
@ -598,14 +601,3 @@ func configureGatewayRulesAPI(podSpec *corev1.PodSpec, stackName, stackNs string
return nil
}
func configureDeploymentForRestrictedPolicy(d *appsv1.Deployment, fg configv1.FeatureGates) {
podSpec := d.Spec.Template.Spec
podSpec.SecurityContext = podSecurityContext(fg.RuntimeSeccompProfile)
for i := range podSpec.Containers {
podSpec.Containers[i].SecurityContext = containerSecurityContext()
}
d.Spec.Template.Spec = podSpec
}

@ -44,6 +44,12 @@ func BuildIndexGateway(opts Options) ([]client.Object, error) {
}
}
if opts.Gates.RestrictedPodSecurityStandard {
if err := configurePodSpecForRestrictedStandard(&statefulSet.Spec.Template.Spec); err != nil {
return nil, err
}
}
if err := configureHashRingEnv(&statefulSet.Spec.Template.Spec, opts); err != nil {
return nil, err
}
@ -122,10 +128,8 @@ func NewIndexGatewayStatefulSet(opts Options) *appsv1.StatefulSet {
TerminationMessagePath: "/dev/termination-log",
TerminationMessagePolicy: "File",
ImagePullPolicy: "IfNotPresent",
SecurityContext: containerSecurityContext(),
},
},
SecurityContext: podSecurityContext(opts.Gates.RuntimeSeccompProfile),
}
if opts.Stack.Template != nil && opts.Stack.Template.IndexGateway != nil {

@ -44,6 +44,12 @@ func BuildIngester(opts Options) ([]client.Object, error) {
}
}
if opts.Gates.RestrictedPodSecurityStandard {
if err := configurePodSpecForRestrictedStandard(&statefulSet.Spec.Template.Spec); err != nil {
return nil, err
}
}
if err := configureHashRingEnv(&statefulSet.Spec.Template.Spec, opts); err != nil {
return nil, err
}
@ -132,10 +138,8 @@ func NewIngesterStatefulSet(opts Options) *appsv1.StatefulSet {
TerminationMessagePath: "/dev/termination-log",
TerminationMessagePolicy: "File",
ImagePullPolicy: "IfNotPresent",
SecurityContext: containerSecurityContext(),
},
},
SecurityContext: podSecurityContext(opts.Gates.RuntimeSeccompProfile),
}
if opts.Stack.Template != nil && opts.Stack.Template.Ingester != nil {

@ -44,6 +44,12 @@ func BuildQuerier(opts Options) ([]client.Object, error) {
}
}
if opts.Gates.RestrictedPodSecurityStandard {
if err := configurePodSpecForRestrictedStandard(&deployment.Spec.Template.Spec); err != nil {
return nil, err
}
}
if err := configureHashRingEnv(&deployment.Spec.Template.Spec, opts); err != nil {
return nil, err
}
@ -123,10 +129,8 @@ func NewQuerierDeployment(opts Options) *appsv1.Deployment {
TerminationMessagePath: "/dev/termination-log",
TerminationMessagePolicy: "File",
ImagePullPolicy: "IfNotPresent",
SecurityContext: containerSecurityContext(),
},
},
SecurityContext: podSecurityContext(opts.Gates.RuntimeSeccompProfile),
}
if opts.Stack.Template != nil && opts.Stack.Template.Querier != nil {

@ -38,6 +38,12 @@ func BuildQueryFrontend(opts Options) ([]client.Object, error) {
}
}
if opts.Gates.RestrictedPodSecurityStandard {
if err := configurePodSpecForRestrictedStandard(&deployment.Spec.Template.Spec); err != nil {
return nil, err
}
}
if err := configureHashRingEnv(&deployment.Spec.Template.Spec, opts); err != nil {
return nil, err
}
@ -128,10 +134,8 @@ func NewQueryFrontendDeployment(opts Options) *appsv1.Deployment {
TerminationMessagePath: "/dev/termination-log",
TerminationMessagePolicy: "File",
ImagePullPolicy: "IfNotPresent",
SecurityContext: containerSecurityContext(),
},
},
SecurityContext: podSecurityContext(opts.Gates.RuntimeSeccompProfile),
}
if opts.Stack.Template != nil && opts.Stack.Template.QueryFrontend != nil {

@ -50,6 +50,12 @@ func BuildRuler(opts Options) ([]client.Object, error) {
objs = configureRulerObjsForMode(opts)
}
if opts.Gates.RestrictedPodSecurityStandard {
if err := configurePodSpecForRestrictedStandard(&statefulSet.Spec.Template.Spec); err != nil {
return nil, err
}
}
if err := configureHashRingEnv(&statefulSet.Spec.Template.Spec, opts); err != nil {
return nil, err
}
@ -164,10 +170,8 @@ func NewRulerStatefulSet(opts Options) *appsv1.StatefulSet {
TerminationMessagePath: "/dev/termination-log",
TerminationMessagePolicy: "File",
ImagePullPolicy: "IfNotPresent",
SecurityContext: containerSecurityContext(),
},
},
SecurityContext: podSecurityContext(opts.Gates.RuntimeSeccompProfile),
}
if opts.Stack.Template != nil && opts.Stack.Template.Ruler != nil {

@ -0,0 +1,43 @@
package manifests
import (
"github.com/ViaQ/logerr/v2/kverrors"
corev1 "k8s.io/api/core/v1"
"k8s.io/utils/pointer"
"github.com/imdario/mergo"
)
func configurePodSpecForRestrictedStandard(podSpec *corev1.PodSpec) error {
podSecurityContext := corev1.PodSpec{
SecurityContext: &corev1.PodSecurityContext{
RunAsNonRoot: pointer.Bool(true),
SeccompProfile: &corev1.SeccompProfile{
Type: corev1.SeccompProfileTypeRuntimeDefault,
},
},
}
containerSecurityContext := corev1.Container{
SecurityContext: &corev1.SecurityContext{
AllowPrivilegeEscalation: pointer.Bool(false),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
},
}
for i, container := range podSpec.Containers {
if err := mergo.Merge(&container, containerSecurityContext, mergo.WithOverride); err != nil {
return err
}
podSpec.Containers[i] = container
}
if err := mergo.Merge(podSpec, podSecurityContext, mergo.WithOverride); err != nil {
return kverrors.Wrap(err, "failed to merge pod security context")
}
return nil
}

@ -10,7 +10,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/utils/pointer"
lokiv1 "github.com/grafana/loki/operator/apis/loki/v1"
"github.com/grafana/loki/operator/internal/manifests/openshift"
@ -620,26 +619,3 @@ 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
}

Loading…
Cancel
Save