Steg 9 (R4): unified migrate-corpus.mjs --write over engineering/governance/ infrastructure/security. 327 filer mutert, verified=null, prosa byte-identisk (fra første ## seksjon), advisor urørt (0 endringer). To applier-fixes oppdaget under kjøring (TDD, RED→GREEN): - insertHeaderFields: anker faller nå tilbake når en meta-linje selv passerer 500B (2 filer pakket et avsnitt i **Status:** → Type/Source landet utenfor scan-vinduet, applierens post-write-assertion fanget + restaurerte). - normalizeStaleVerified: fjerner nå ALLE stale non-date **Verified:** i 500B-vinduet, inkl. stray body-dup rett under --- (9 mlops-genaiops-filer var ellers falskt "verified"/fresh, droppet fra worklist). Operatør-godkjent utvidelse av carve-out; kun stray metadata-linjer, aldri prosa. test-transform-criterion: precondition oppdatert til post-migrasjons-sannhet (fila bærer nå Source). Suite 728/728 grønn.
15 KiB
Multi-Tenant Agent Isolation and Security
Last updated: 2026-02 Status: GA Category: Agent Orchestration & Automation Type: reference
Innhold
- Introduksjon
- Kjernekomponenter
- Isolasjonsmodeller for Azure OpenAI
- Tenant Data Isolation
- Permission Enforcement
- Audit Segregation
- Cross-Tenant Attack Prevention
- Resource Quotas
- Norsk offentlig sektor
- Beslutningsrammeverk
- For Cosmo
Introduksjon
Multi-tenant agentarkitektur er en fundamental utfordring for organisasjoner som tilbyr AI-agenter til flere kunder, avdelinger eller forretningsenheter. Korrekt isolasjon sikrer at data, konfigurasjoner og agentoppførsel ikke lekker mellom tenants, samtidig som man opprettholder kostnadseffektivitet og skalerbarhet.
Azure-plattformen tilbyr flere isolasjonsmodeller for AI-agenter -- fra logisk isolasjon med delt infrastruktur til fullstendig fysisk separasjon med dedikerte ressurser per tenant. Valget avhenger av regulatoriske krav, dataklassifisering, ytelsesgarantier og kostnadsbetraktninger. Microsoft Entra ID utgjør fundamentet for tenant-aware tilgangskontroll, mens Azure API Management, Azure OpenAI og Foundry Agent Service tilbyr tenant-isolasjon på ulike nivåer.
For norsk offentlig sektor med strenge krav til dataisolasjon (Schrems II, NSM, Sikkerhetsloven) er det kritisk å velge riktig isolasjonsmodell. Mange offentlige virksomheter opererer med skjermingsverdig informasjon som krever sterkere isolasjonsgarantier enn standard multi-tenant-løsninger tilbyr.
Kjernekomponenter
| Komponent | Formål | Teknologi |
|---|---|---|
| Identity Isolation | Tenant-bevisst autentisering og autorisasjon | Microsoft Entra ID, Entra Agent ID |
| Data Isolation | Separasjon av tenant-data i lagring og retrieval | Cosmos DB partitions, Azure AI Search per-tenant indexes |
| Model Isolation | Dedikerte eller delte modelldeployments | Azure OpenAI deployment models |
| Network Isolation | Nettverkssegmentering mellom tenants | Azure VNet, Private Endpoints |
| Quota Isolation | Ressurskvoter per tenant | Azure APIM rate limiting, TPM-kvoter |
| Audit Segregation | Separate revisjonslogger per tenant | Log Analytics workspaces, tenant-tagged telemetry |
Isolasjonsmodeller for Azure OpenAI
Oversikt
| Modell | Dataisolasjon | Ytelsesisolasjon | Kompleksitet | Kostnad |
|---|---|---|---|---|
| Delt instans, delt deployment | Lav | Lav | Lav | Lavest |
| Delt instans, dedikert deployment per tenant | Medium | Høy | Medium | Medium |
| Dedikert instans per tenant (provider-sub) | Høy | Høy | Lav-Medium | Høy |
| Tenant-provided instans (tenant-sub) | Høy | Høy | Lav for provider | Høyest |
Pattern 1: Logisk isolasjon med delt infrastruktur
// Tenant-bevisst agentorkestrering med Semantic Kernel
public class MultiTenantAgentOrchestrator
{
private readonly IKernelFactory _kernelFactory;
private readonly ITenantResolver _tenantResolver;
public async Task<AgentResponse> ProcessRequest(
string userId,
string prompt)
{
// Resolve tenant fra brukerens identitet
var tenant = await _tenantResolver.ResolveTenant(userId);
// Opprett tenant-scoped Kernel
var kernel = _kernelFactory.CreateForTenant(tenant.Id);
// Sett tenant-kontekst for alle operasjoner
kernel.Data["TenantId"] = tenant.Id;
kernel.Data["DataBoundary"] = tenant.DataBoundary;
// Agenten arver tenant-begrensninger
var agent = new ChatCompletionAgent
{
Name = "TenantScopedAgent",
Instructions = $"""
Du er en assistent for {tenant.Name}.
Du har KUN tilgang til data merket med tenant {tenant.Id}.
Aldri referer til eller avslør data fra andre tenants.
""",
Kernel = kernel
};
return await agent.InvokeAsync(prompt);
}
}
Pattern 2: Per-tenant Azure OpenAI deployments
// Dedikert modell-deployment per tenant for ytelsesisolasjon
public class TenantDeploymentManager
{
private readonly Dictionary<string, string> _tenantDeployments;
public AzureChatCompletion GetServiceForTenant(string tenantId)
{
var deploymentName = _tenantDeployments[tenantId];
return new AzureChatCompletion(
deploymentName: deploymentName, // f.eks. "gpt-4o-tenant-ddt"
endpoint: _endpoint,
credentials: new DefaultAzureCredential()
);
}
}
Pattern 3: Hybrid multi-tenant med Deployment Stamps
┌──────────────────────────────────────────────┐
│ Shared Infrastructure │
│ ┌─────────────────────────────────────────┐ │
│ │ Azure API Management (AI Gateway) │ │
│ │ - Tenant routing │ │
│ │ - Rate limiting per tenant │ │
│ │ - Token quota enforcement │ │
│ └───────────┬────────────┬────────────────┘ │
│ │ │ │
│ ┌───────────▼──┐ ┌─────▼──────────┐ │
│ │ Standard │ │ Premium │ │
│ │ Tenants │ │ Tenants │ │
│ │ │ │ │ │
│ │ Shared AOAI │ │ Dedicated AOAI │ │
│ │ Shared Index │ │ Per-tenant Index│ │
│ │ Shared CosmosDB│ │ Dedicated DB │ │
│ └──────────────┘ └────────────────┘ │
└──────────────────────────────────────────────┘
Tenant Data Isolation
RAG med tenant-isolasjon
# Azure AI Search med tenant-scoped retrieval
from azure.search.documents import SearchClient
from azure.identity import DefaultAzureCredential
class TenantScopedRetriever:
def __init__(self, search_endpoint: str, index_name: str):
self.client = SearchClient(
endpoint=search_endpoint,
index_name=index_name,
credential=DefaultAzureCredential()
)
def search(self, query: str, tenant_id: str) -> list:
"""Søk med obligatorisk tenant-filter"""
results = self.client.search(
search_text=query,
filter=f"tenant_id eq '{tenant_id}'",
# OData-filter sikrer at BARE tenant-data returneres
select=["content", "title", "source"],
top=5
)
return [r for r in results]
Cosmos DB partisjonering
// Tenant-ID som partition key i Cosmos DB
public class AgentConversationStore
{
private readonly Container _container;
public async Task<ConversationThread> GetThread(
string tenantId, string threadId)
{
// Partition key = tenant_id sikrer fysisk isolasjon
var response = await _container.ReadItemAsync<ConversationThread>(
id: threadId,
partitionKey: new PartitionKey(tenantId)
);
return response.Resource;
}
// Cross-tenant access er umulig uten riktig partition key
}
Permission Enforcement
Microsoft Entra Agent ID
Microsoft Entra Agent ID gir agenter dedikerte identiteter med kontrollerte tilganger:
// Opprett agent-identitet med tenant-scoped tilganger
public class AgentIdentityManager
{
public async Task<AgentIdentity> CreateTenantAgent(
string tenantId,
string agentPurpose)
{
// Hver tenant-agent får en unik managed identity
var identity = await _entraClient.CreateAgentIdentity(new
{
DisplayName = $"Agent-{agentPurpose}-{tenantId}",
// Scoped til kun denne tenantens ressurser
Permissions = new[]
{
$"data.read.tenant.{tenantId}",
$"tools.invoke.tenant.{tenantId}"
},
// Kort-levd tokens for minste privilegium
TokenLifetime = TimeSpan.FromMinutes(15)
});
return identity;
}
}
RBAC-modell for multi-tenant agenter
| Rolle | Tilgang | Scope |
|---|---|---|
| Agent.Reader | Les tenant-data via RAG | Spesifikk tenant |
| Agent.Writer | Opprett/oppdater agentressurser | Spesifikk tenant |
| Agent.Admin | Full kontroll over agenter | Spesifikk tenant |
| Platform.Admin | Konfigurer tverrtenants infrastruktur | Plattform-nivå |
| Audit.Reader | Les revisjonslogger | Per tenant eller global |
Audit Segregation
# Tenant-segregert logging til Application Insights
from opentelemetry import trace
tracer = trace.get_tracer("multi-tenant-agent")
def process_agent_request(tenant_id: str, user_id: str, prompt: str):
with tracer.start_as_current_span("agent_invocation") as span:
# Tenant-kontekst på alle spans
span.set_attribute("tenant.id", tenant_id)
span.set_attribute("user.id", user_id)
span.set_attribute("agent.name", "customer-support")
# Tenant-spesifikk logging
# KQL kan filtrere: traces | where customDimensions.tenant_id == "xxx"
result = invoke_agent(prompt, tenant_id)
span.set_attribute("response.token_count", result.token_count)
span.set_attribute("response.evaluation.relevance", result.relevance)
return result
KQL for tenant-isolert rapportering
// Kostnads- og bruksrapport per tenant
traces
| where timestamp > ago(30d)
| where customDimensions.tenant_id != ""
| summarize
total_requests = count(),
total_tokens = sum(todouble(customDimensions["response.token_count"])),
avg_latency = avg(duration),
avg_relevance = avg(todouble(customDimensions["response.evaluation.relevance"]))
by tostring(customDimensions["tenant_id"])
| order by total_tokens desc
Cross-Tenant Attack Prevention
Trusselmodell
| Trussel | Angrepsvei | Mitigering |
|---|---|---|
| Prompt injection for data-lekkasje | Bruker crafter prompt som ber om annen tenants data | Mandatory tenant-filter i alle data-queries |
| Token-sharing mellom tenants | Delt autentiseringstoken | Per-tenant managed identities |
| Side-channel via shared model | Informasjon lekker gjennom modellens kontekst | Separate deployments for sensitive tenants |
| Indirekte prompt injection | Malicious data i en tenants kunnskapsbase påvirker en annen | Strikt input-validering + Content Safety |
| Privilege escalation | Agent eskalerer tilgang utover tenant-scope | RBAC med kort-levde tokens + audit logging |
Defence-in-depth for tenant-isolasjon
// Multi-layer isolasjonsvalidering
public class TenantIsolationMiddleware
{
public async Task ValidateRequest(AgentRequest request)
{
// Layer 1: Identity verification
var tenantFromToken = ExtractTenantFromToken(request.AuthToken);
// Layer 2: Request parameter validation
if (request.TenantId != tenantFromToken)
throw new SecurityException("Tenant mismatch");
// Layer 3: Data access filter injection
request.DataFilters.Add(new TenantFilter(tenantFromToken));
// Layer 4: Response validation
// Verifiser at responsen ikke inneholder data fra andre tenants
request.OnResponseGenerated += async (response) =>
{
await ValidateResponseDoesNotLeakCrossTenantData(
response, tenantFromToken);
};
}
}
Resource Quotas
APIM-basert quota enforcement
<!-- Azure API Management policy for per-tenant kvoter -->
<policies>
<inbound>
<set-variable name="tenantId"
value="@(context.Request.Headers
.GetValueOrDefault("X-Tenant-Id","unknown"))" />
<!-- Token rate limiting per tenant -->
<azure-openai-token-limit
counter-key="@((string)context.Variables["tenantId"])"
tokens-per-minute="50000"
estimate-prompt-tokens="true" />
<!-- Request rate limiting per tenant -->
<rate-limit-by-key
calls="100"
renewal-period="60"
counter-key="@((string)context.Variables["tenantId"])" />
</inbound>
</policies>
Norsk offentlig sektor
Spesielle krav
| Krav | Regulering | Implementering |
|---|---|---|
| Data-suverenitet | Schrems II | Azure Norway East/West, eller Azure Local |
| Sikkerhetsgradert info | Sikkerhetsloven | Fysisk isolasjon, dedikert infrastruktur |
| Personvern | GDPR Art. 28 | Databehandleravtale per tenant, DPA |
| Logging | Arkivloven | Retensjonspolicies per tenant, minimum 5 år |
| Tilgangskontroll | eInnsyn, offentlighetsloven | Transparent tilgangslogg per tenant |
Anbefalt isolasjonsmodell for offentlig sektor
For de fleste offentlige virksomheter i Norge anbefales hybrid modell:
- Logisk isolasjon for standard tjenester (Cosmos DB partitioning, tenant-filter i AI Search)
- Fysisk isolasjon for sensitiv informasjon (dedikert Azure OpenAI, VNet-isolert)
- Azure Local for skjermingsverdig informasjon som ikke kan forlate norsk territorium
Beslutningsrammeverk
| Scenario | Anbefaling | Begrunnelse |
|---|---|---|
| SaaS med mange småkunder | Logisk isolasjon, delt AOAI | Kostnadseffektivt, skalerer |
| Enterprise med compliance-krav | Hybrid: delt infra + dedikerte AOAI | Balanse mellom kostnad og isolasjon |
| Offentlig sektor standard | Hybrid + Azure Norway region | Datalokalitet + kostnadseffektivitet |
| Skjermingsverdig informasjon | Full fysisk isolasjon | Regulatorisk krav, ingen kompromisser |
| Multi-region med data residency | Deployment stamps per region | Datasuverenitet per jurisdiksjon |
For Cosmo
- Velg isolasjonsmodell basert på dataklassifisering -- ikke overengineer for åpne data, men underestimer aldri kravene for sensitiv informasjon. Hybrid er vanligvis riktig svar.
- Tenant-filter i RAG er obligatorisk -- aldri stol på at agentens instruksjoner alene hindrer datalekkasje. Implementer tekniske kontroller (OData-filter, partition keys) som ikke kan omgås.
- Microsoft Entra Agent ID er den anbefalte måten å gi agenter identitet med tenant-scoped tilganger -- bruk kort-levde tokens og minste privilegium.
- APIM som AI Gateway er essensielt for multi-tenant -- det gir token rate limiting, kostnadsfordeling og audit logging per tenant uten kodeendringer i agentene.
- For norsk offentlig sektor: Start med Azure Norway East, vurder Azure Local for høysikkerhet, og sørg for at databehandleravtaler er på plass per tenant.