Key Components

To install the complete control plane on your own infrastructure, you need to install the following components:
  • Truefoundry Control Plane + Gateway (Shipped as a single helm chart called truefoundry)
  • PostgreSQL Database (Managed or Self-Hosted with PostgreSQL >= 13)
  • Blob Storage (S3, GCS, Azure Container or any other S3 compatible storage)

Compute Requirements

Truefoundry ships as a helm chart (https://github.com/truefoundry/infra-charts/tree/main/charts/truefoundry) that has configurable options to either deploy both Deployment and AI Gateway feature or just choose the one of them according to your needs. The compute requirements change based on the set of features and the scale of the number of users and requests. Here are a few scenarios that you can choose from based on your needs.
The small tier is recommended for development purposes. Here all the components are deployed on Kubernetes and in non HA mode (single replica). This is suitable if you are just testing out the different features of Truefoundry.
This setup brings up 1 replica of the services and is not highly-available. It can enable you to test the features but we do not recommend this for production mode.
ComponentCPUMemoryStorageMin NodesRemarks
Helm-Chart
(AI Gateway Control Plane components)
2 vCPU8GB60GB
Persistent Volumes (Block Storage) On Kubernetes
2
Pods should be spread over min 2 nodes
Cost: ~ $120 pm
Helm-Chart
(AI Gateway component only)
1 vCPU512Mi-1
Pods should be spread over min 1 node
Cost: ~ $10 pm
Postgres
(Deployed on Kubernetes)
0.5 vCPU0.5GB5GB
Persistent Volumes (Block Storage) On Kubernetes
PostgreSQL version >= 13
IOPS: Default (suitable for dev/testing)
For PostgreSQL 17+: Disable SSL, for AWS: by setting force_ssl parameter to 0 in the parameter group, for Azure: by setting require_secure_transport parameter to false in the parameter group
Blob Storage
(S3 Compatible)
20GB

Prerequisites for Installation

  1. Kubernetes Cluster: K8s cluster 1.27+.
  2. Support for dynamic provisioning of storage for PVC (for e.g AWS EBS, Azure Disk etc.) and support for ingress controller (for e.g. Nginx Ingress Controller) or istio service mesh for exposing the control plane dashboard and AI Gateway at an endpoint.
  3. Domain to map the ingress of the Control Plane dashboard and AI Gateway along with certificate for the domain.
    This Domain will be referred as Control Plane URL in our documentation.
  4. Egress access to TrueFoundry Central Auth Server: https://auth.truefoundry.com & https://login.truefoundry.com
  5. Tenant Name, Licence key, and image pull secret from TrueFoundry team. If you have not registered yet, please visit TrueFoundry to register.
  6. PostgreSQL database. We usually recommend managed PostgreSQL database (For e.g. AWS RDS, or Google Cloud SQL, or Azure Database for PostgreSQL) for production environments. For instance requirements, refer to the Compute Requirements section.
    In case, you do not have a managed database just for testing purposes, set devMode to true in the values file to spin up a local PostgreSQL database.
  7. Blob Storage to store the AI Gateway request logs (either S3, GCS, Azure Blob Storage, or any other S3 compatible storage). You can find the instructions in the guide below.

Installation Instructions

1

Setup Control Plane Platform IAM Role

Control Plane IAM Role needs to have permission to assume any other IAM role in or cross account to provide access to different cloud services like blob, secret, models, etc.
  • Create a new IAM role for Control Plane with a suitable name like tfy-control-plane-platform-deps
  • Following is the IAM policy that needs to be attached to the Control Plane IAM Role:
{
    "Statement": [
        {
            "Action": "sts:AssumeRole",
            "Effect": "Allow",
            "Resource": "*"
        }
    ],
    "Version": "2012-10-17"
}
Here ”*” is used to allow the Control Plane IAM Role to assume any other IAM role in or cross account. In place of ”*” you can also give specific ARNs of other IAM roles
  • Add the following trust policy to the Control Plane IAM Role:
{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Effect": "Allow",
          "Principal": {
              "Federated": "arn:aws:iam::<ACCOUNT_ID>:oidc-provider/oidc.eks.<AWS_REGION>.amazonaws.com/id/<OIDC_ID>"
          },
          "Action": "sts:AssumeRoleWithWebIdentity",
          "Condition": {
              "StringEquals": {
                  "oidc.eks.<AWS_REGION>.amazonaws.com/id/<OIDC_ID>:sub": [
                      "system:serviceaccount:truefoundry:truefoundry",
                  ]
              }
          }
      }
  ]
}
In place of <ACCOUNT_ID>, <AWS_REGION>, and <OIDC_ID> you can also give the values from your EKS cluster. You can find the OIDC_ID from the EKS cluster. Also, here we are assuming that the service account is truefoundry and the namespace is truefoundry, you can change it as per your needs.

Allow your IAM role to be assumed by Control Plane IAM Role

  • Add the following trust policy to your IAM Role to allow it to be assumed by the Control Plane IAM Role:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "AWS": "<CONTROL_PLANE_IAM_ROLE_ARN>"
            },
            "Action": "sts:AssumeRole"
        }
      ]
}
2

Create S3 Bucket

Create a S3 Bucket with following config:
  • Make sure the bucket has lifecycle configuration to abort multipart upload set for 7 days.
  • Make sure CORS is applied on the bucket with the below configuration:
[
  {
    "AllowedHeaders": ["*"],
    "AllowedMethods": ["GET", "POST", "PUT"],
    "AllowedOrigins": ["*"],
    "ExposeHeaders": ["ETag"],
    "MaxAgeSeconds": 3000
  }
]
Create a IAM Policy to allow access to the S3 Bucket with following config:
{
  "Sid": "S3",
  "Effect": "Allow",
  "Action": ["s3:*"],
  "Resource": [
    "arn:aws:s3:::<YOUR_S3_BUCKET_NAME>",
    "arn:aws:s3:::<YOUR_S3_BUCKET_NAME>/*"
  ]
}
Attach the IAM Policy to the Control Plane Platform IAM Role
3

Create Postgres RDS Database

Create a Postgres RDS instance of size db.t3.medium with storage size of 30GB.
Important Configuration Notes: - For PostgreSQL 17: Disable SSL by setting force_ssl parameter to 0 in the parameter group - Security Group: Ensure your RDS security group has inbound rules allowing traffic from EKS node security groups
In case you want to setup PostgreSQL on Kubernetes and not use RDS for testing purposes, skip this step and set devMode to true in the values file below
4

Create Kubernetes Secrets

We will create two secrets in this step:
  1. Store the License Key and DB Credentials
  2. Store the Image Pull Secret
We need to create a Kubernetes secret containing the licence key and db credentials.
If you are using PostgreSQL on Kubernetes in the dev mode, the values will be as follows:DB_HOST: <HELM_RELEASE_NAME>-postgresql.<NAMESPACE>.svc.cluster.local // eg. truefoundry-postgresql.truefoundry.svc.cluster.localDB_NAME: truefoundryDB_USERNAME: postgres # In order to use custom username, please update the same at postgresql.auth.usernameDB_PASSWORD: randompassword # You can change this to any value here.
truefoundry-creds.yaml
apiVersion: v1
kind: Secret
metadata:
  name: truefoundry-creds
type: Opaque
stringData:
  TFY_API_KEY: <TFY_API_KEY> # Provided by TrueFoundry team
  DB_HOST: <DB_HOST>
  DB_NAME: <DB_NAME>
  DB_USERNAME: <DB_USERNAME>
  DB_PASSWORD: <DB_PASSWORD>
Apply the secret to the Kubernetes cluster (Assuming you are installing the control plane in the truefoundry namespace)
kubectl apply -f truefoundry-creds.yaml -n truefoundry
We need to create a Image Pull Secret to enable pulling the truefoundry images from the private registry.
truefoundry-image-pull-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: truefoundry-image-pull-secret
type: kubernetes.io/dockerconfigjson
data:
  .dockerconfigjson: <IMAGE_PULL_SECRET> # Provided by TrueFoundry team
Apply the secret to the Kubernetes cluster (Assuming you are installing the control plane in the truefoundry namespace)
kubectl apply -f truefoundry-image-pull-secret.yaml -n truefoundry
5

Create HelmChart Values file

Create a values file as given below and replace the following values:
  • Control Plane URL: URL that you will map to the control plane dashboard (e.g., https://truefoundry.example.com)
  • Tenant Name: Tenant name provided by TrueFoundry team
  • AWS S3 Bucket Name: Name of the S3 bucket you created in the previous step (e.g., my-truefoundry-bucket)
  • AWS Region: Region of the S3 bucket you created in the previous step (e.g., us-west-2)
  • Control Plane IAM Role ARN: ARN of the IAM role you created in the previous step (e.g., arn:aws:iam::123456789012:role/tfy-control-plane-platform-deps)
truefoundry-values.yaml
global:
  # Domain to map the platform to
  controlPlaneURL: https://example.com

  # Ask TrueFoundry team to provide these
  tenantName: <TENANT_NAME>

  # Choose the resource tier as per your needs
  resourceTier: medium # or small or large

  # This is the reference to the secrets we created in the previous step
  existingTruefoundryCredsSecret: "truefoundry-creds"
  imagePullSecrets:
  - name: "truefoundry-image-pull-secret"

  config:
    defaultCloudProvider: "aws"
    storageConfiguration:
      awsS3BucketName: "<AWS_S3_BUCKET_NAME>"
      awsRegion: "<AWS_REGION>"

  serviceAccount:
    annotations:
      eks.amazonaws.com/role-arn: <CONTROL_PLANE_IAM_ROLE_ARN>

# In case, you want to spin up PostgreSQL on kubernetes, enable this
# Please add creds and host details in the secret `truefoundry-creds` in the previous step
devMode:
  enabled: false

truefoundryFrontendApp:
  ingress:
    hosts:
      - example.com
    enabled: false
    annotations: {}
    ingressClassName: nginx # Replace with your ingress class name
tags:
  llmGateway: true
  llmGatewayRequestLogging: true

# Disable few dependencies for only LLM Gateway setup
tfyBuild:
  enabled: false
sfyManifestService:
  enabled: false
tfyController:
  enabled: false
mlfoundryServer:
  enabled: false
tfy-buildkitd-service:
  enabled: false
tfy-clickhouse:
  enabled: false
6

Install Helm chart

helm upgrade --install truefoundry oci://tfy.jfrog.io/tfy-helm/truefoundry -n truefoundry --create-namespace -f truefoundry-values.yaml

FAQ

If you want to use private image registry for the LLM Gateway, you can do so by following the instructions below.1. Push all the required imaged to your private image registry. There are two ways to do this:
You can use your Artifactory as a mirror to pull images from our registry. The artifactory details for Truefoundry are as follows:Registry URL: https://tfy.jfrog.io/ To get the username and password, you can base64 decode the Image Pull Secret that you receive from Truefoundry team.
2. Update the truefoundry-values.yaml file to use your custom images.
global:
  image:
    registry: <YOUR_REGISTRY> # Replace with your registry
postgresql:
  image:
    registry: <YOUR_REGISTRY> # Replace with your registry, use this if `devMode` is enabled
Yes, you can use your Artifactory as a mirror to pull images from our registry. The artifactory details for Truefoundry are as follows:Registry URL: https://tfy.jfrog.io/ To get the username and password, you can base64 decode the Image Pull Secret that you receive from Truefoundry team.
No, we only need block storage for installing and running Truefoundry. This should be supported via the CSI driver and only ReadWriteOnce access is required.
We log access information in standard output with the following format:
  1. logfmt
  2. json
These can be switched with the help of an environment variable to the AI Gateway installation. (Default: logfmt)

Log format

Standard log format structure:
time="%START_TIME%" level=%LEVEL% ip=%IP_ADDRESS% tenant=%TENANT_NAME% user=%SUBJECT_TYPE%:%SUBJECT_SLUG% model=%MODEL_ID% method=%METHOD% path=%PATH% status=%STATUS_CODE% time_taken=%DURATION%ms trace_id=%TRACE_ID%
Log operatorDetails
START_TIMEISO timestamp for request start. eg. 2025-08-12 13:34:50
LEVELinfo|warn|error
IP_ADDRESSIP address of the caller. eg. ::ffff:10.99.55.142
TENANT_NAMEName of the tenant. eg. truefoundry
SUBJECT_TYPEuser|virtualaccount
SUBJECT_SLUGEmail or virtual account name. eg. tfy-user@truefoundry.com|demo-virtualaccount
MODEL_IDModel ID. eg. openai-default/gpt-5
METHODGET|POST|PUT
PATHPath of the request. eg. /api/inference/openai/chat/completions
STATUS_CODE200|400|401|403|429|500
DURATIONDuration of the request. eg. 12
TRACE_IDTrace ID of the request
Examples:
time="2025-08-12 13:34:50" level=info ip=::ffff:10.99.55.142 tenant=truefoundry user=virtualaccount:demo-virtualaccount model=openai-default/gpt-5 method=POST path=/api/inference/openai/chat/completions status=200 time_taken=53ms trace_id=587b2a946c13f62f9160674a8c983ce3
By default, the control plane uses TrueFoundry managed Central Auth server to authenticate users. However, you can also deploy the control plane without using the TrueFoundry managed Central Auth server. We currently support any OIDC compliant Identity Provider to be used as external identity provider.You need to add your OIDC application details under servicefoundryServer.env in the values.yaml file of truefoundry helm installation.
servicefoundryServer:
  env:
    OAUTH_PROVIDER_TYPE: "EXTERNAL"
    EXTERNAL_OAUTH_ISSUER: "<OIDC_ISSUER_URL>"
    EXTERNAL_OAUTH_CLIENT_ID: "<OIDC_CLIENT_ID>"
    EXTERNAL_OAUTH_CLIENT_SECRET: "<OIDC_CLIENT_SECRET>"
    ## Other optional configuration if required
    # USE_ID_TOKEN_AS_ACCESS_TOKEN: boolean (default: false)
    # EXTERNAL_OAUTH_USER_INFO_EMAIL_KEY_NAME: string (default: "email")
    # EXTERNAL_OAUTH_USER_INFO_ID_KEY_NAME: string (default: "id")
    # EXTERNAL_OAUTH_USER_INFO_NAME_KEY_NAME: string (default: "name")
    # EXTERNAL_OAUTH_USER_INFO_FIRST_NAME_KEY_NAME: string (default: "firstName")
    # EXTERNAL_OAUTH_USER_INFO_LAST_NAME_KEY_NAME: string (default: "lastName")
    # EXTERNAL_OAUTH_USER_INFO_IMAGE_URI_KEY_NAME: string (default: "picture")
    # EXTERNAL_OAUTH_TOKEN_EMAIL_CLAIM_KEY_NAME: string (default: "email")
    # EXTERNAL_OAUTH_TOKEN_USERNAME_CLAIM_KEY_NAME: string (default: "username")
    # EXTERNAL_OAUTH_TOKEN_ID_CLAIM_KEY_NAME: string (default: "sub")
    # EXTERNAL_OAUTH_USER_INFO_USERNAME_KEY_NAME: string (default: "username")

    INCLUDE_TRUEFOUNDRY_MANAGED_JWKS: "false"
    INTERNAL_JWT_SERVICE_ENABLED: "true"
    INTERNAL_JWT_JWKS: "<INTERNAL_JWT_JWKS>" # To be provided by TrueFoundry team
tfy-llm-gateway:
  env:
    ENABLE_EXTERNAL_OAUTH: "true"
    ## If you are using a custom email claim key, you can set it here
    # EXTERNAL_OAUTH_EMAIL_CLAIM_KEY: sub
Here we are assuming the identity provider is OIDC compliant and satisfies following:
  1. Openid configuration is available at <ISSUER_URL>/.well-known/openid-configuration.
  2. Scopes configured should include openid, email, profile and offline_access.
  3. Allowed Redirect URI should be set to <CONTROL_PLANE_URL>/auth/callback.
  4. OIDC issuer servers should be accessible from user’s browser, TrueFoundry control plane servers and all multi zone AI Gateway servers.