Skip to content

Install MaaS Components

Complete Operator Setup before proceeding.

Installation flow:

  1. Database Setup — Create the PostgreSQL connection Secret
  2. Create Gateway — Deploy maas-default-gateway (required before modelsAsService)
  3. Configure DataScienceCluster — Enable KServe and modelsAsService in your DataScienceCluster
  4. Model Setup (On Cluster) — Deploy sample models
  5. 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:

postgresql://USERNAME:PASSWORD@HOSTNAME:PORT/DATABASE?sslmode=require

Development

For development, you can deploy a PostgreSQL instance and Secret using the setup script:

./scripts/setup-database.sh

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:

./scripts/deploy.sh --postgres-connection 'postgresql://username:password@hostname:5432/database?sslmode=require'

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:

kubectl rollout restart deployment/maas-api -n opendatahub

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:

./scripts/setup-authorino-tls.sh

Setting the namespace: The script defaults to kuadrant-system (ODH with Kuadrant). Set AUTHORINO_NAMESPACE for RHOAI, which uses RHCL:

AUTHORINO_NAMESPACE=rh-connectivity-link ./scripts/setup-authorino-tls.sh

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):

apiVersion: maas.opendatahub.io/v1alpha1
kind: Tenant
metadata:
  name: default-tenant
  namespace: models-as-a-service
spec:
  gatewayRef:
    namespace: openshift-ingress
    name: maas-default-gateway
  apiKeys:
    maxExpirationDays: 90
  telemetry:
    enabled: true
    metrics:
      captureUser: false
      captureGroup: false
kubectl apply -f tenant.yaml
kubectl get tenant default-tenant -n models-as-a-service -o yaml

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):

kustomize build deployment/overlays/odh | kubectl apply -f -

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