Install MaaS Components
Complete Operator Setup before proceeding.
Installation flow:
- Database Setup — Create the PostgreSQL connection Secret
- Create Gateway — Deploy maas-default-gateway (required before modelsAsService)
- Configure DataScienceCluster — Enable KServe and modelsAsService in your DataScienceCluster
- Model Setup (On Cluster) — Deploy sample models
- Validation — Verify the deployment
Database Setup
A PostgreSQL database is required. Create the maas-db-config Secret in your ODH/RHOAI namespace (typically opendatahub for ODH or redhat-ods-applications for RHOAI):
kubectl create secret generic maas-db-config \
-n opendatahub \
--from-literal=DB_CONNECTION_URL='postgresql://username:password@hostname:5432/database?sslmode=require'
Connection string format:
Development
For development, you can deploy a PostgreSQL instance and Secret using the setup script:
Setting the namespace: The script defaults to opendatahub. Set the NAMESPACE environment variable if your MaaS deployment uses a different namespace:
# RHOAI uses redhat-ods-applications
NAMESPACE=redhat-ods-applications ./scripts/setup-database.sh
# Custom namespace
NAMESPACE=my-maas-namespace ./scripts/setup-database.sh
The full scripts/deploy.sh script also creates PostgreSQL automatically when deploying MaaS.
Using deploy.sh with an external database
If you use scripts/deploy.sh, you can supply your own PostgreSQL connection string with the --postgres-connection flag. This skips the built-in POC PostgreSQL deployment and creates the maas-db-config Secret automatically:
Restarting maas-api
If you add or update the Secret after the DataScienceCluster already has modelsAsService in managed state, restart the maas-api deployment to pick up the config:
This is not required when the Secret exists before enabling modelsAsService in your DataScienceCluster.
Create Gateway
The Gateway must exist before enabling modelsAsService in your DataScienceCluster. Create the MaaS Gateway:
Example Gateway Configuration
The Gateway configuration below is an example. You may need TLS certificates, specific listener settings, or custom infrastructure labels depending on your cluster. For TLS setup, see TLS Configuration. To quickly apply Authorino TLS for maas-api communication, run:
Setting the namespace: The script defaults to kuadrant-system (ODH with Kuadrant). Set AUTHORINO_NAMESPACE for RHOAI, which uses RHCL:
Required annotations
The Gateway must include these annotations to trust Authorino's certificates:
| Annotation | Purpose |
|---|---|
opendatahub.io/managed: "false" |
Read by maas-controller: allows it to manage AuthPolicies and related resources; prevents the ODH Model Controller from overwriting them. |
security.opendatahub.io/authorino-tls-bootstrap: "true" |
Used by the ODH platform (not maas-controller) to create the EnvoyFilter for Gateway → Authorino TLS when Authorino uses a TLS listener. Required when Authorino TLS is enabled. |
The authorino-tls-bootstrap annotation is an interim solution until CONNLINK-528 ships native support for configuring TLS between the Gateway and Authorino without mesh sidecars. It decouples TLS configuration from AuthPolicy management, allowing TLS even when opendatahub.io/managed is "false".
CLUSTER_DOMAIN=$(kubectl get ingresses.config.openshift.io cluster -o jsonpath='{.spec.domain}')
# Use default ingress cert for HTTPS, or set CERT_NAME to your TLS secret name
CERT_NAME=${CERT_NAME:-$(kubectl get ingresscontroller default -n openshift-ingress-operator -o jsonpath='{.spec.defaultCertificate.name}' 2>/dev/null)}
[[ -z "$CERT_NAME" ]] && CERT_NAME="router-certs-default"
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: maas-default-gateway
namespace: openshift-ingress
annotations:
opendatahub.io/managed: "false"
security.opendatahub.io/authorino-tls-bootstrap: "true"
spec:
gatewayClassName: openshift-default
listeners:
- name: http
hostname: maas.${CLUSTER_DOMAIN}
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All
- name: https
hostname: maas.${CLUSTER_DOMAIN}
port: 443
protocol: HTTPS
allowedRoutes:
namespaces:
from: All
tls:
certificateRefs:
- group: ""
kind: Secret
name: ${CERT_NAME}
mode: Terminate
EOF
TLS certificate
The HTTPS listener uses a Secret in openshift-ingress. The script auto-detects the default ingress cert; if that fails, it uses router-certs-default. If the Gateway fails to program, ensure the Secret exists: kubectl get secret -n openshift-ingress. See TLS Configuration for custom certs.
kubectl wait --for=condition=Programmed gateway/maas-default-gateway -n openshift-ingress --timeout=60s
Configure DataScienceCluster
After creating the database Secret and Gateways, create or update your DataScienceCluster. Choose your deployment method:
The operator deploys maas-controller, which self-bootstraps a default-tenant CR and reconciles the MaaS platform workloads (maas-api, gateway policies, telemetry). Create or update your DataScienceCluster with modelsAsService in Managed state:
kubectl apply -f - <<EOF
apiVersion: datasciencecluster.opendatahub.io/v2
kind: DataScienceCluster
metadata:
name: default-dsc
spec:
components:
kserve:
managementState: Managed
rawDeploymentServiceConfig: Headed
modelsAsService:
managementState: Managed
dashboard:
managementState: Managed
llamastackoperator:
managementState: Managed
EOF
LlamaStack Operator (GenAI Studio)
The llamastackoperator component is required for GenAI Studio functionality.
If you do not need GenAI Studio, you can omit it or set it to Removed.
You also need to enable the genAiStudio feature flag on OdhDashboardConfig —
see OdhDashboardConfig Feature Flags below.
Connectivity Link warning (ODH with Kuadrant)
When using ODH with Kuadrant (upstream), you may see Warning: Red Hat Connectivity Link is not installed, LLMInferenceService cannot be used in the Kserve status initially. This typically resolves after a few minutes as the operator reconciles. If it persists, apply the scripts/workaround-odh-rhcl-check.yaml workaround.
Validate DataScienceCluster:
# Check DataScienceCluster status
kubectl get datasciencecluster default-dsc
# Wait for KServe and ModelsAsService to be ready (optional)
kubectl wait --for=jsonpath='{.status.conditions[?(@.type=="KserveReady")].status}'=True \
datasciencecluster/default-dsc --timeout=300s
kubectl wait --for=jsonpath='{.status.conditions[?(@.type=="ModelControllerReady")].status}'=True \
datasciencecluster/default-dsc --timeout=300s
# Verify maas-api deployment is running (use opendatahub for ODH, redhat-ods-applications for RHOAI)
kubectl get deployment maas-api -n opendatahub
kubectl rollout status deployment/maas-api -n opendatahub --timeout=120s
The maas-controller (deployed by the operator) will automatically create a default-tenant CR and reconcile:
- MaaS API (Deployment, Service, ServiceAccount, ClusterRole, ClusterRoleBinding, HTTPRoute)
- MaaS API AuthPolicy (maas-api-auth-policy) - Protects the MaaS API endpoint
- Gateway default AuthPolicy (gateway-default-auth) - Denies unauthenticated traffic
- Gateway default TokenRateLimitPolicy (gateway-default-deny) - Denies unsubscribed traffic
- TelemetryPolicy and Istio Telemetry (when telemetry is enabled)
- DestinationRule (when TLS is enabled)
- NetworkPolicy (maas-authorino-allow) - Allows Authorino to reach MaaS API
Tenant CR
With modelsAsService Managed, the Open Data Hub operator deploys maas-controller, which self-bootstraps a namespace-scoped Tenant object on startup. The resource name must be default-tenant (enforced via CEL validation). The Tenant CR lives in the models-as-a-service namespace (same namespace as MaaSSubscription and MaaSAuthPolicy). The authoritative API definition is in the maas-controller repo: tenant_types.go.
Nothing in spec is required for a default install. If you omit spec, the controller uses the same defaults as this guide: Gateway openshift-ingress / maas-default-gateway, and telemetry metric toggles use the defaults described below.
| Field | What to set |
|---|---|
spec.gatewayRef.namespace |
Namespace of your Gateway API Gateway (default openshift-ingress). |
spec.gatewayRef.name |
Name of that Gateway (default maas-default-gateway). Set these if your MaaS hostname is exposed through a different Gateway than the default. |
spec.apiKeys.maxExpirationDays |
Maximum allowed API key lifetime in days. When set, users cannot mint keys with a longer lifetime than this value (via expiresIn). Optional; if unset, the controller does not apply a cap through this field (see also maas-api / API_KEY_MAX_EXPIRATION_DAYS in your deployment). |
spec.externalOIDC.issuerUrl |
OIDC issuer URL for external identity provider (optional; enables OIDC on the maas-api AuthPolicy). |
spec.externalOIDC.clientId |
OIDC client ID (required when issuerUrl is set). |
spec.telemetry.enabled |
Enable TelemetryPolicy and Istio Telemetry (default true). |
spec.telemetry.metrics.captureOrganization |
Include organization_id on metrics (default true). |
spec.telemetry.metrics.captureUser |
Include user labels on metrics (default false; privacy-sensitive). |
spec.telemetry.metrics.captureGroup |
Include group labels on metrics (default false; higher cardinality). |
spec.telemetry.metrics.captureModelUsage |
Include model labels on usage metrics (default true). |
Example (patch common values):
Development and early testing
Kustomize deployment can be used for development and early testing purposes. For production, use the Managed tab above.
Set modelsAsService to Removed so the operator does not deploy the MaaS API, then deploy MaaS via the ODH overlay:
kubectl apply -f - <<EOF
apiVersion: datasciencecluster.opendatahub.io/v2
kind: DataScienceCluster
metadata:
name: default-dsc
spec:
components:
kserve:
managementState: Managed
rawDeploymentServiceConfig: Headed
modelsAsService:
managementState: Removed
dashboard:
managementState: Managed
EOF
Apply the ODH overlay to deploy the MaaS API and controller (run from the project root; ensure the maas-db-config Secret exists per Database Setup):
Troubleshooting
If components do not become ready, run kubectl describe datasciencecluster default-dsc to inspect conditions and events.
OdhDashboardConfig Feature Flags
The RHOAI Dashboard uses feature flags in the OdhDashboardConfig resource to control which tabs
and features are visible in the UI. The operator creates this resource automatically when the
Dashboard component is deployed, but the following flags may need to be enabled manually.
Patch the OdhDashboardConfig in your applications namespace (typically redhat-ods-applications
for RHOAI or opendatahub for ODH):
kubectl patch odhdashboardconfig odh-dashboard-config \
-n redhat-ods-applications --type=merge \
-p '{"spec":{"dashboardConfig":{"genAiStudio":true,"observabilityDashboard":true}}}'
| Flag | Effect | Prerequisites |
|---|---|---|
genAiStudio: true |
Shows the GenAI Studio tab in the Dashboard | llamastackoperator set to Managed in DSC |
observabilityDashboard: true |
Shows the Observability tab in the Dashboard | COO, OpenTelemetry Operator installed; DSCI monitoring.metrics configured |
Namespace
For ODH installations, replace redhat-ods-applications with opendatahub (or your configured
applications namespace from DSCI spec.applicationsNamespace).
Flag names
These flags are defined in the odh-dashboard source. The OdhDashboardConfig CRD is of
API version opendatahub.io/v1alpha. The operator re-creates this resource with factory
defaults if it is deleted, but does not overwrite user changes to existing fields.
Next steps
- Deploy models. See Model Setup (On Cluster) for sample model deployments.
- Perform validation. Follow the validation guide to verify that MaaS is working correctly.