Reach L3 governance in two weeks

A golden-path guide for teams running Postgres (pgvector, Neon, or Supabase) or Pinecone with Okta or Microsoft Entra ID. This matches the most common production profile and takes roughly 75 minutes of active work spread across a few sessions.

Team plan or above required

What you will achieve

By the end of this guide you will have a Gateco deployment at L3 readiness: a connected Postgres or Pinecone vector database with active policies, identity sync from Okta or Microsoft Entra, and a verified first secured retrieval. L3 is the minimum governance posture for production. Your AI agent will only receive content the requesting principal is authorized to see.

The readiness levels work as a progression. L0 means no connection. L1 means authentication verified. L2 means search works. L3 means resource-level policies are active on a connected connector. L4 (covered at the end of this guide) adds chunk-level metadata enforcement for teams that need finer granularity. Each step in this guide advances you one level.

StepTaskTime
1Connect your vector database15 min
2Configure search5 min
3Register resources10 min
4Connect your identity provider20 min
5Create your first policy15 min
6Validate with Access Simulator10 min
7Execute your first secured retrieval5 min

Prerequisites

Before starting, make sure you have the following available. You do not need all of them upfront; the guide notes where each is needed.

  • A Gateco account on the Team plan or above
  • A Postgres database with the pgvector extension enabled (or a Pinecone index with existing vectors)
  • Okta, Microsoft Entra ID (Azure AD), AWS IAM Identity Center, or GCP Cloud Identity tenant with admin access
  • Python 3.9+ or Node.js 18+ for the SDK
  • Network access from the Gateco backend to your vector database (allowlist Gateco IPs if your DB is behind a firewall)
Note: The free plan supports only one connector and does not include real identity provider sync. You need Team or above to follow this guide end-to-end.

Step 1: Connect your vector database (15 min)

In the Gateco dashboard, go to Settings → Connectors → New Connector. Select your connector type. For pgvector, Neon, or Supabase, paste your connection string. For Pinecone, enter your API key and index name.

Connection strings for Postgres-family connectors must use the direct (non-pooled) endpoint and include sslmode=require. The format is:

# pgvector / Neon / Supabase direct connection string
postgresql://gateco_user:password@your-host:5432/your_db?sslmode=require

# Pinecone: enter API key and index name separately in the UI
# Index host example: my-index-abc123.svc.us-east-1-aws.pinecone.io

After saving the connector, run a connection test. Gateco verifies authentication, introspects your schema, and returns the number of tables or index vectors it can reach. A successful test advances you to L1 readiness.

Note: For Postgres-family connectors, use a dedicated database user rather than a superuser. Grant that user SELECT, INSERT, UPDATE, DELETE on your vector table and USAGE on the public schema. This limits the blast radius if credentials are ever rotated incorrectly.

Step 2: Configure search (5 min)

After the connection test passes, click Search config on the connector row. For Postgres-family connectors, you need to tell Gateco which table holds your embeddings and which columns contain the vector, content, and row ID.

FieldExampleNotes
table_nameembeddingsThe table containing vector data
embedding_columnembeddingColumn of type vector(n)
content_columncontentOriginal text. Required for keyword and hybrid search.
id_columnidPrimary key (default: id)
text_search_configenglishPostgres FTS config for keyword/hybrid mode

If you are not sure of your table or column names, use the schema introspection endpoint to discover them. It returns every table in the connected database that has at least one vector-typed column:

GET /api/connectors/{connector_id}/db-schema

# Response
{
  "tables": [
    {
      "name": "embeddings",
      "columns": [
        { "name": "id", "type": "uuid" },
        { "name": "content", "type": "text" },
        { "name": "embedding", "type": "vector(1536)" }
      ]
    }
  ]
}

Saving a valid search config advances you to L2 readiness. Gateco will run a test query against the vector table to confirm the config is reachable.

Note: For Pinecone connectors, the search config is simpler: set your embedding dimension and the namespace (if you use namespaces). Pinecone handles its own index structure, so no table or column names are needed.

Step 3: Register resources (10 min)

Gateco can only enforce policies on resources it knows about. If your vector database already has embeddings, use retroactive registration to bring them under governance without re-ingesting anything. Gateco scans the connected vector store, enumerates existing vector IDs, and registers them as gated resources. No data is moved or modified.

# CLI
gateco retroactive-register --connector-id <your-connector-id>

# Python SDK
from gateco_sdk import GatecoClient

client = GatecoClient(api_key="gck_live_...")
client.connectors.register_retroactive(connector_id="<your-connector-id>")

The command returns the number of newly registered resources and any that were already known. Registration typically takes a few seconds for indexes under 100,000 vectors. For larger indexes, run it as a background task and check the onboarding checklist in the dashboard for completion status.

Onboarding completion requires at least 10 registered resources. Once that threshold is crossed, the Register resources step on the setup checklist turns green.

Note: Retroactive registration is available for all Tier 1 connectors (pgvector, Neon, Supabase, Pinecone, Qdrant) and for any other connector that supports vector ID listing. It is not available for Vertex AI Vector Search, which has no listing API.

Step 4: Connect your identity provider (20 min)

Policies are only meaningful when Gateco knows who the requesting principal is and what groups they belong to. Connect your identity provider so that Gateco can sync users and groups and make them available in policy conditions.

Okta

Go to Settings → Identity Providers → New → Okta. You need two values from your Okta Admin Console:

  • Domain: the hostname of your Okta org (e.g. acmecorp.okta.com). Do not include https:// or /admin.
  • API token: generate one in Okta at Security → API → Tokens → Create Token. For least-privilege access, create the token from an account with the Read-only Administrator role.

Microsoft Entra ID (Azure AD)

Go to Settings → Identity Providers → New → Azure Entra ID. Register an application in the Azure Portal (Entra ID → App registrations → New registration), then grant it three application permissions in Microsoft Graph:

  • User.Read.All(application type, not delegated)
  • Group.Read.All(application type, not delegated)
  • GroupMember.Read.All(application type, not delegated)

Grant admin consent for all three, then create a client secret (Certificates & secrets → New client secret). Enter the Tenant ID, Client ID, and Client Secret in Gateco.

Warning: Admin consent is required and can only be granted by a Global Administrator or Application Administrator. If you do not see the grant button, ask your Azure admin to approve the permissions for the app registration.

Trigger initial sync

After saving the provider, click Sync now. The initial sync fetches all active users and groups. For organizations up to 10,000 users, this completes in under 60 seconds. Synced principals appear in the Principals list and are immediately available in policy conditions.

Enable scheduled sync to keep principals current automatically. Set a sync interval (15, 30, or 60 minutes) in the identity provider settings. Gateco uses PostgreSQL advisory locks so only one instance runs sync per IDP per interval, even in multi-replica deployments.

See the Okta setup guide and Azure Entra ID setup guide for step-by-step walkthroughs including credential setup and troubleshooting.

Step 5: Create your first policy (15 min)

Go to Policy Studio → Create from Template. The group_rbac template is the right starting point for most production deployments. It creates an allow policy that grants a named group access to resources at or below a specified classification level.

Fill in the placeholder values. For a policy that lets the engineering group access internal documents:

PlaceholderExample value
groupengineering
classificationinternal

The template creates a draft policy. Do not activate it yet. First validate it in the Access Simulator (Step 6) to confirm the allowed and denied split matches your expectations before enforcement goes live.

Policy condition field prefix rules

This is the most common source of policy misconfiguration. Every condition field must be prefixed with either resource. or principal.. A bare field name like classification (without prefix) silently resolves against the principal, not the resource. The policy evaluator will not return an error, it will just check the wrong thing.

# Correct: resource. prefix checks resource metadata
{"field": "resource.classification", "operator": "lte", "value": "internal"}
{"field": "resource.sensitivity",    "operator": "lte", "value": "medium"}
{"field": "resource.domain",         "operator": "eq",  "value": "engineering"}

# Correct: principal. prefix checks the requesting identity
{"field": "principal.groups",        "operator": "contains", "value": "engineering"}
{"field": "principal.roles",         "operator": "contains", "value": "engineer"}

# Wrong: bare field resolves against principal, not resource
{"field": "classification",          "operator": "lte", "value": "internal"}  # bug

Step 6: Validate with Access Simulator (10 min)

Before activating any policy, use the Access Simulator to run a live preview. Go to Access Simulator → Live Preview. Select your connector, enter a representative search query, and pick a test principal (an Okta or Entra user who was synced in Step 4). The simulator executes a real retrieval as that principal and splits results into allowed and denied panels.

Check the diagnostics field in the response. It shows which policies fired, the conditions that matched or failed, and the policy trace for each chunk. This is the fastest way to identify prefix mistakes or misconfigured selectors before they affect real traffic.

Run the preview with at least two principals: one who should be allowed (a member of the engineering group) and one who should be denied (a principal outside that group). Confirm the allowed and denied counts match your intent. Once they do, go back to Policy Studio and activate the draft policy.

Note: Live Preview is rate-limited to 10 calls per minute per organization. Results cap at 20 chunks. This is a deliberate limit to prevent the simulator from being used as a production retrieval path. Use POST /api/retrievals/execute (or the SDK) for production traffic.

Step 7: Your first secured retrieval (5 min)

Install the SDK, resolve a principal by email, and run your first policy-gated retrieval. Hybrid search mode is recommended for production: it blends semantic similarity with keyword ranking, which outperforms vector-only search on most domain-specific corpora.

pip install gateco
from gateco_sdk import GatecoClient

client = GatecoClient(api_key="gck_live_...")

# Resolve a principal by email (read-only; principal must be synced from IDP)
principal = client.principals.resolve(email="alice@acmecorp.com")

# Execute a policy-gated retrieval
results = client.retrievals.execute(
    connector_id="<your-connector-id>",
    query="What is our refund policy for enterprise customers?",
    principal_id=principal.id,
    top_k=10,
    search_mode="hybrid",
    alpha=0.5,  # 0.0 = all-keyword, 1.0 = all-vector, 0.5 = balanced
)

for r in results.results:
    if r.granted:
        print(r.content_preview, r.score)
    else:
        # Denied chunks include the reason but never the content
        print(f"[denied] {r.denial_reason}")

The resolve() call is read-only. It looks up an existing principal by email and fails with a clear error if the address is not synced or is inactive. This is intentional: Gateco never silently creates a principal or falls back to a default identity.

A successful retrieval with at least one allowed result advances your connector to L3 readiness. The dashboard shows the readiness badge update within a few seconds. Every retrieval is recorded in the audit trail with a full policy trace.

For TypeScript, the pattern is the same:

npm install @gateco/sdk
import { GatecoClient } from "@gateco/sdk";

const client = new GatecoClient({ apiKey: "gck_live_..." });

const principal = await client.principals.resolve({ email: "alice@acmecorp.com" });

const results = await client.retrievals.execute({
  connectorId: "<your-connector-id>",
  query: "What is our refund policy for enterprise customers?",
  principalId: principal.id,
  topK: 10,
  searchMode: "hybrid",
  alpha: 0.5,
});

for (const r of results.results) {
  if (r.granted) {
    console.log(r.contentPreview, r.score);
  }
}

client.close();

Reaching L4 (advanced)

L3 uses Gateco's sidecar store to resolve policy metadata: the classification, sensitivity, domain, and labels you set when registering resources. This covers the vast majority of production use cases. L4 adds chunk-level enforcement, where policy metadata is resolved from the vector payload itself or from a Postgres view that lives alongside your vector table.

Switch metadata_resolution_mode on the connector to enable L4. The three available modes beyond the default:

inline

Policy metadata is read directly from the vector payload. Requires a metadata_field_mapping in search config that maps Gateco fields (classification, sensitivity, domain) to payload keys. Fastest at query time since no sidecar lookup is needed.

sql_view

Metadata is read from a structured Postgres view alongside the vector table. Postgres-family connectors only. Requires a validated view name and column mapping in search config. Useful when your metadata lives in a separate normalized table.

auto

Tries inline first, then sql_view, then sidecar as a fallback. Useful during a migration from sidecar to inline without downtime risk.

Warning: inline mode requires a metadata_field_mapping object in search config. Without it, all retrievals fail with a search_config_invalid error. For most teams, sidecar (the L3 default) is the right choice. Only switch to inline or sql_view if your vectors already carry rich policy metadata and you want to avoid maintaining a parallel sidecar registry.

Next steps

With L3 readiness confirmed, the most common next steps are hardening your policy set, enabling agent workflows via the MCP server, and setting up SCIM provisioning for real-time identity sync.