Skip to main content
This document records the Firebolt Operator’s threat-model boundary: what the Firebolt Operator hardens by default versus what is the cluster-platform team’s responsibility.

What the Firebolt Operator enforces

The Firebolt Operator stamps a hardened security posture on the workloads it renders. How much you can change that posture depends on the CRD surface. Engine pods expose a wide pod-template merge layer through FireboltEngineClass and FireboltEngine. Gateway and metadata primary containers keep operator-owned hardening and only let you set image and resources on the primary container. Per-field allowlists for each template surface live in api/v1alpha1/operatorauthority.go (PodTemplateRules per component) and in the CRD reference pages linked in each subsection below.

Engine

When neither a referenced FireboltEngineClass nor the engine’s own spec.template sets a container securityContext, the Firebolt Operator applies these defaults on the engine container:
FieldDefault
UID / GID3473 / 3473
runAsNonRoottrue
Capabilitiesdrop ALL
allowPrivilegeEscalationfalse
Read-only root filesystemtrue (unix domain socket via emptyDir at /var/run/firebolt; status file and engine data on the PVC at /firebolt-core/volume)
Seccompnot set
You can replace that entire container securityContext wholesale through FireboltEngineClass.spec.template or FireboltEngine.spec.template.spec.containers[name=="engine"].securityContext. The engine template wins over the class. There is no merge or floor. A template value replaces the operator default completely, including the ability to weaken hardening. Pod-level spec.template.spec.securityContext is also user-settable. The Firebolt Operator only stamps fsGroup (3473) and fsGroupChangePolicy: OnRootMismatch when you leave those fields unset. Sidecar containers and init containers pass through from your template without operator hardening. Validating webhooks on FireboltEngine and FireboltEngineClass (and the engine reconciler when webhooks are off) reject operator-owned paths on engine templates: command, args, ports, probes, reserved env keys, and firebolt.io/* labels. They do not reject a weakened securityContext. See the FireboltEngineClass CRD reference and FireboltEngine CRD reference.

Gateway (Envoy)

The Envoy primary container is operator-rendered end to end. The validating webhook rejects user input on its securityContext. You may only set image and resources on spec.gateway.template.spec.containers[name=="envoy"]. The Firebolt Operator stamps:
FieldValue
UID101
runAsNonRoottrue
Capabilitiesdrop ALL
allowPrivilegeEscalationfalse
Read-only root filesystemtrue (scratch via emptyDir at /tmp)
Seccompnot set on the container
Pod-level fields on spec.gateway.template (node selector, tolerations, securityContext, sidecars, init containers) pass through when allowed by the template rules. See the FireboltInstance CRD reference.

Metadata (Pensieve)

The metadata primary container follows the same pattern as the gateway. Operator-stamped hardening applies to containers[name=="metadata"]. You may set only image and resources there:
FieldValue
UID1111 (pinned to the image’s dedicated-pensieve user)
runAsNonRoottrue
Capabilitiesdrop ALL
allowPrivilegeEscalationfalse
Read-only root filesystemtrue (scratch via emptyDir at /tmp)
Seccompnot set on the container
At the pod level, the Firebolt Operator floors any user-supplied PodSecurityContext to runAsNonRoot: true with UID/GID 1111 and sets seccompProfile: RuntimeDefault when you do not supply one. A template cannot run the metadata pod under a different user without failing image ownership checks.

PostgreSQL (internal)

Internal PostgreSQL has no user template surface. The Firebolt Operator stamps hardening on every reconcile:
LevelPosture
PodUID/GID 70, runAsNonRoot: true, seccompProfile: RuntimeDefault
ContainerUID 70, runAsNonRoot: true, drop ALL capabilities, allowPrivilegeEscalation: false, read-only root filesystem (PGDATA on the PVC, runtime sockets on emptyDir)
The Firebolt Operator’s own manager RBAC (rendered by the chart from the canonical config/rbac/role.yaml) is the minimal set of verbs needed to manage the three CRDs and their generated resources. The Firebolt Operator does not request * on any namespaced verb and does not request nodes, clusterrolebindings, or any other cluster-scope mutation. The chart renders the manager rules in one of two shapes, picked at install time by watchNamespaces:
  • Empty list (default): one cluster-scoped ClusterRole and one ClusterRoleBinding. The manager cache spans every namespace.
  • Non-empty list, e.g. {tenant-a, tenant-b}: a Role plus RoleBinding pair in each listed namespace, no ClusterRole. The manager cache spans only those namespaces. Use this posture when multi-tenant compliance constraints bound the operator’s blast radius.
The default FireboltInstance.spec.metricScrapeMode=PodIP reaches engine metrics through pod IPs and does not need pods/proxy: get, so the chart’s manager RBAC does not include that verb. Setting metricScrapeMode=ApiserverProxy on any FireboltInstance requires rbac.apiserverProxyGrant=true on the operator chart, which renders a dedicated ClusterRole (or per-namespace Role when watchNamespaces is set) granting only that one verb. Without the toggle, the metric scrape surfaces as a 403 from the apiserver. Resource maxima on the engine container’s resources block (set under FireboltEngine.spec.template.spec.containers[name=="engine"] or inherited from a referenced FireboltEngineClass) are enforced by the validating webhook (see “Resource bounds” below). The bounds protect a namespace from accidentally admitting an engine whose requests would starve sibling workloads at scheduling time.

What the Firebolt Operator does not enforce

Network isolation between pods

The Firebolt Operator emits no NetworkPolicy objects. All pod-to-pod and pod-to-external traffic is governed by whatever the cluster’s CNI and NetworkPolicy controller already enforce. In a default Kubernetes install with no NetworkPolicy controller installed, every pod can reach every other pod on every port. This is a deliberate scoping decision: NetworkPolicy semantics depend on the CNI plugin (Calico, Cilium, Antrea, etc.), the cluster’s default-allow-vs-default-deny posture, and the Firebolt Operator-vs-platform ownership boundary for security primitives. Encoding any of those assumptions into Firebolt Operator-emitted NetworkPolicies would either be a no-op (no controller installed) or actively wrong for the deployment target. Platform teams should apply NetworkPolicies covering at least the allowed flows below. Recommended selectors:
Pod kindSelector
Engine podsfirebolt.io/engine exists (matches any generation of any engine in the namespace)
Gateway / Metadata / PostgreSQLfirebolt.io/component={gateway,metadata,postgres}
Instance scopingfirebolt.io/instance=<instance-name> (present on instance-level workloads only. Engines carry firebolt.io/engine instead, which is unique per engine)

Allowed flows

FromToPortPurpose
External clientsGateway8080Query traffic (HTTP)
GatewayEngine pods3473Query forwarding
Engine podsMetadata7000Metadata gRPC
MetadataPostgreSQL5432Metadata catalog reads/writes
Engine podsExternal object store443 / 80Managed-storage reads/writes (S3, GCS, etc.)
PrometheusEngine / Gateway / Operator9090 / 9090 / 8443Metrics scraping
kube-apiserverOperator webhook9443Admission control
Engine-to-engine, engine-to-PostgreSQL, gateway-to-metadata, and gateway-to-PostgreSQL are not required by any Firebolt Operator-managed control flow and should be denied.

Example baseline NetworkPolicy

The snippet below denies all ingress and egress by default in the instance’s namespace, then re-allows the flows above. It assumes the gateway’s external clients live in a firebolt-clients namespace. The selector should be adjusted to match the actual client topology.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
spec:
  podSelector: {}
  policyTypes: [Ingress, Egress]
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: gateway-ingress
spec:
  podSelector:
    matchLabels:
      firebolt.io/component: gateway
  policyTypes: [Ingress]
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: firebolt-clients
      ports:
        - port: 8080
          protocol: TCP
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: engine-from-gateway
spec:
  podSelector:
    matchExpressions:
      - key: firebolt.io/engine
        operator: Exists
  policyTypes: [Ingress]
  ingress:
    - from:
        - podSelector:
            matchLabels:
              firebolt.io/component: gateway
      ports:
        - port: 3473
          protocol: TCP
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: metadata-from-engine
spec:
  podSelector:
    matchLabels:
      firebolt.io/component: metadata
  policyTypes: [Ingress]
  ingress:
    - from:
        - podSelector:
            matchExpressions:
              - key: firebolt.io/engine
                operator: Exists
      ports:
        - port: 7000
          protocol: TCP
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: postgres-from-metadata
spec:
  podSelector:
    matchLabels:
      firebolt.io/component: postgres
  policyTypes: [Ingress]
  ingress:
    - from:
        - podSelector:
            matchLabels:
              firebolt.io/component: metadata
      ports:
        - port: 5432
          protocol: TCP
Add egress allow-rules in the same shape. The Firebolt Operator does not generate them.

Namespace-level resource ceilings

A ResourceQuota capping the aggregate of requests.cpu / requests.memory / pod count / PVC size across all engines in a namespace is a platform concern. The Firebolt Operator enforces per-engine upper bounds in admission (see below) but does not emit a ResourceQuota. The per-namespace budget is a deployment-target decision (test cluster vs. multi-tenant production).

Image provenance and supply-chain attestation

The Firebolt Operator pulls whatever image the user supplies via FireboltEngine.spec.template.spec.containers[engine].image, the referenced FireboltEngineClass.spec.template.spec.containers[engine].image, or the embedded defaults shipped with the Firebolt Operator binary (merged in that order, top wins). The Firebolt Operator does not validate signatures, attestations, or SBOMs. Use a cluster-level admission controller (Kyverno, Sigstore Policy Controller, etc.) if image-policy enforcement is required.

Resource bounds

The FireboltEngine validating webhook rejects engine-container resources entries above Firebolt Operator-configured maxima. The gate resolves the effective container the same way the reconciler will: the engine’s own spec.template.spec.containers[name=="engine"].resources wins wholesale when set, otherwise the referenced FireboltEngineClass’s container resources fill in. Both sources are checked, so a class with oversized requests cannot escape admission by being referenced from an engine that omits its own resources. The error message names the source class when the offending value came from class so the user knows which side to edit. This is a defense-in-depth control against accidental over-provisioning. A typoed 100Gi instead of 10Gi is caught at admission rather than at scheduling time when it would silently exhaust namespace capacity and block other engines. The maxima are configurable at Firebolt Operator install time. Defaults are sized for typical production deployments. Override via Helm values when running larger or smaller engines.

Secrets handling

The Firebolt Operator generates one Secret: the internal PostgreSQL credentials (<instance>-metadata-postgres-creds). The password is generated at first reconcile, persisted to a Kubernetes Secret with owner reference to the FireboltInstance, and never re-rotated by the Firebolt Operator. The metadata and PostgreSQL Deployments load it via envFrom. User-supplied credentials (external PostgreSQL, external object store) are referenced by name on the FireboltInstance / FireboltEngine spec and resolved at reconcile time. The Firebolt Operator never reads or materializes a user-supplied secret’s value into its own status, events, or logs.

See also