Skip to content

Configure media storage

Select a media storage backend on spec.media.storage so the agent’s facade accepts file uploads.

  • An AgentRuntime. type: none is the default and disables media storage.
  • For local: a ReadWriteMany PersistentVolumeClaim in the agent’s namespace. The agent containers have a read-only root filesystem, so local needs a mounted volume.
  • For s3, gcs or azure: a bucket or container, and either a workload identity that can reach it or credentials in a Secret.
typeUse caseCredentials
localDevelopment, single-replica deploymentsNone
s3AWS, or S3-compatible services such as MinIOIRSA, EC2 instance profile, or a Secret
gcsGoogle CloudWorkload Identity (Application Default Credentials)
azureAzureAn account key in a Secret
  1. Give the agent pod access to the backend. Skip this step for local.

    Annotate the ServiceAccount the pod runs as. To use your own ServiceAccount, set spec.podOverrides.serviceAccountName.

    EKS (IRSA):

    apiVersion: v1
    kind: ServiceAccount
    metadata:
    name: omnia-agent
    annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/omnia-media-role

    The role needs s3:PutObject, s3:GetObject, s3:DeleteObject and s3:ListBucket on the bucket (arn:aws:s3:::my-media-bucket) and its objects (arn:aws:s3:::my-media-bucket/*).

    GKE (Workload Identity):

    apiVersion: v1
    kind: ServiceAccount
    metadata:
    name: omnia-agent
    annotations:
    iam.gke.io/gcp-service-account: omnia-media@my-project.iam.gserviceaccount.com

    Grant the Google service account roles/storage.objectAdmin on the bucket.

    To use explicit credentials instead, create a Secret and reference it in step 2. An S3 Secret holds the keys AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. An Azure Secret holds the key AZURE_ACCOUNT_KEY:

    apiVersion: v1
    kind: Secret
    metadata:
    name: azure-storage-key
    type: Opaque
    stringData:
    AZURE_ACCOUNT_KEY: <your-storage-account-key>

    Azure always needs the account key. Upload and download URLs are SAS URLs signed with that key, so workload identity alone cannot produce them, even when the pod also uses workload identity.

  2. Set spec.media.storage. Use the block for your backend.

    Local, with a PVC mounted at basePath in the facade and runtime containers:

    apiVersion: omnia.altairalabs.ai/v1alpha1
    kind: AgentRuntime
    metadata:
    name: my-agent
    spec:
    media:
    storage:
    type: local
    local:
    basePath: /var/lib/omnia/media
    volumeClaim: omnia-media

    S3, keyless. region is required: the API server rejects an s3 backend without one. An S3-compatible service that ignores regions still needs a value, such as us-east-1.

    spec:
    media:
    storage:
    type: s3
    s3:
    bucket: my-media-bucket
    region: us-west-2
    prefix: omnia/media/ # optional

    For MinIO or another S3-compatible service, add endpoint (this also forces path-style addressing). For explicit credentials, add secretRef:

    spec:
    media:
    storage:
    type: s3
    s3:
    bucket: my-bucket
    region: us-east-1
    endpoint: http://minio.minio-system:9000
    secretRef:
    name: my-s3-credentials

    GCS:

    spec:
    media:
    storage:
    type: gcs
    gcs:
    bucket: my-media-bucket
    prefix: omnia/media/ # optional

    Azure:

    spec:
    media:
    storage:
    type: azure
    azure:
    account: mystorageaccount
    container: media
    secretRef:
    name: azure-storage-key
  3. Optionally set limits next to type: maxFileSizeBytes, defaultTTL, uploadURLTTL and downloadURLTTL. See AgentRuntime media.storage for the fields and defaults.

  4. Apply the AgentRuntime.

    Terminal window
    kubectl apply -f agentruntime.yaml

The operator renders the settings into OMNIA_MEDIA_STORAGE_* environment variables on the facade container. List their names:

Terminal window
kubectl get deployment my-agent \
-o jsonpath='{.spec.template.spec.containers[?(@.name=="facade")].env[*].name}'

The output includes OMNIA_MEDIA_STORAGE_TYPE. Then confirm the facade started the backend:

Terminal window
kubectl logs deployment/my-agent -c facade

The log contains a media storage enabled entry with the backend type. To upload a file, follow Upload media to an agent.

The AgentRuntime is rejected with “type s3 requires spec.media.storage.s3.region”

Section titled “The AgentRuntime is rejected with “type s3 requires spec.media.storage.s3.region””

The facade needs both a bucket and a region for s3, so the CRD refuses an s3 backend without s3.region. Set it.

Upload fails with “upload not found or expired”

Section titled “Upload fails with “upload not found or expired””

The upload URL expired or was already used. The default uploadURLTTL is 15 minutes. Request a new upload URL, or raise uploadURLTTL.

  1. Check that the IAM role grants the four actions in step 1.
  2. Check the IRSA annotation on the ServiceAccount the pod runs as.
  3. Check that the bucket policy allows the role.
  1. Check that Workload Identity is configured for the pod’s ServiceAccount.
  2. Check that the Google service account has roles/storage.objectAdmin.
  3. Check the bucket IAM bindings.

Azure “SAS URL generation requires shared key credential”

Section titled “Azure “SAS URL generation requires shared key credential””

The facade has no account key. Add secretRef to spec.media.storage that points at a Secret with the key AZURE_ACCOUNT_KEY.