Shared Responsibility Model for Cloud AI Security
Understanding the division of security responsibilities between cloud providers and customers for AI/ML workloads across AWS, Azure, and GCP, with specific guidance for LLM deployments.
Overview
The shared responsibility model is a foundational concept in cloud security: the provider secures the infrastructure, and the customer secures what they build on it. AWS formalized this as "security OF the cloud vs. security IN the cloud." But when organizations deploy AI workloads — particularly LLM-based applications — this model breaks down in ways that create dangerous security gaps.
Consider a typical LLM deployment on AWS Bedrock. AWS secures the underlying compute infrastructure, manages model serving, and handles API availability. The customer is responsible for IAM policies, API key management, and application-level security. But who is responsible for the model's behavior? If the model generates harmful content, leaks its system prompt, or is susceptible to prompt injection, is that a provider failure (the model is defective) or a customer failure (the application lacks guardrails)? The answer is often both — and in practice, neither organization owns the gap.
This article maps the shared responsibility boundaries for AI workloads across the three major cloud providers, identifies the AI-specific gaps that the traditional model fails to address, and provides practical tools for organizations to close those gaps. The goal is not a theoretical framework but an operational guide that security teams can use to assign clear ownership for every AI security control.
The Traditional Model vs. AI Reality
Traditional Cloud Shared Responsibility
In traditional cloud deployments, the responsibility boundary is relatively clear:
| Layer | IaaS (EC2) | PaaS (Lambda) | SaaS (Gmail) |
|---|---|---|---|
| Physical security | Provider | Provider | Provider |
| Network infrastructure | Provider | Provider | Provider |
| Hypervisor/OS | Provider | Provider | Provider |
| Runtime/middleware | Customer | Provider | Provider |
| Application code | Customer | Customer | Provider |
| Data | Customer | Customer | Customer |
| Identity/access | Customer | Customer | Shared |
AI-Specific Responsibility Gaps
AI workloads introduce new security dimensions that do not map cleanly to existing layers:
| AI Security Dimension | Who Owns It? | Gap Description |
|---|---|---|
| Model weight integrity | Ambiguous | Provider hosts the model, but customer chose it. Who verifies it's not poisoned? |
| Safety alignment | Ambiguous | Provider trained the model, but customer defines acceptable behavior for their use case |
| Prompt injection defense | Customer (mostly) | Provider may offer basic guardrails, but application-level defense is customer's responsibility |
| Training data governance | Provider (for foundation models) | Customer has no visibility into what data the model was trained on |
| Fine-tuning data security | Customer | Customer provides the data; provider processes it but customer owns data governance |
| Output content safety | Shared | Provider offers content filters; customer must configure and supplement them |
| Model API abuse detection | Shared | Provider monitors for infrastructure abuse; customer monitors for application-level abuse |
| Regulatory compliance | Customer (primarily) | Provider offers compliance tools but customer must configure for their specific requirements |
# Tool: Shared responsibility mapper for cloud AI deployments
from dataclasses import dataclass, field
from enum import Enum
from typing import Optional
class ResponsibilityOwner(Enum):
PROVIDER = "provider"
CUSTOMER = "customer"
SHARED = "shared"
UNASSIGNED = "unassigned" # Gap — nobody owns this
class CloudProvider(Enum):
AWS_BEDROCK = "aws_bedrock"
AZURE_OPENAI = "azure_openai"
GCP_VERTEX = "gcp_vertex"
SELF_HOSTED = "self_hosted"
@dataclass
class SecurityControl:
"""A specific security control for AI workloads."""
control_id: str
name: str
description: str
category: str
owasp_llm_mapping: list[str]
nist_ai_rmf_function: str
@dataclass
class ResponsibilityAssignment:
"""Assignment of a security control to an owner for a specific provider."""
control: SecurityControl
provider: CloudProvider
owner: ResponsibilityOwner
provider_capabilities: str # What the provider offers for this control
customer_actions_required: str # What the customer must do
gap_description: Optional[str] = None # If UNASSIGNED, what's the gap?
evidence_of_implementation: str = ""
# Define the AI-specific security control catalog
AI_SECURITY_CONTROLS: list[SecurityControl] = [
SecurityControl(
control_id="AI-SEC-001",
name="Model Provenance Verification",
description="Verify the origin, integrity, and training methodology of foundation models before deployment",
category="supply_chain",
owasp_llm_mapping=["LLM03"],
nist_ai_rmf_function="MAP",
),
SecurityControl(
control_id="AI-SEC-002",
name="Prompt Injection Defense",
description="Detect and block prompt injection attacks in user inputs and retrieved content",
category="input_security",
owasp_llm_mapping=["LLM01"],
nist_ai_rmf_function="MANAGE",
),
SecurityControl(
control_id="AI-SEC-003",
name="Output Content Filtering",
description="Filter model outputs for harmful content, PII leakage, and policy violations",
category="output_security",
owasp_llm_mapping=["LLM02", "LLM05"],
nist_ai_rmf_function="MEASURE",
),
SecurityControl(
control_id="AI-SEC-004",
name="System Prompt Protection",
description="Prevent extraction or leakage of system prompts and instructions",
category="configuration_security",
owasp_llm_mapping=["LLM07"],
nist_ai_rmf_function="MANAGE",
),
SecurityControl(
control_id="AI-SEC-005",
name="Fine-tuning Data Governance",
description="Ensure training/fine-tuning data meets quality, privacy, and security standards",
category="data_governance",
owasp_llm_mapping=["LLM04"],
nist_ai_rmf_function="GOVERN",
),
SecurityControl(
control_id="AI-SEC-006",
name="API Authentication and Authorization",
description="Enforce strong authentication and least-privilege access to model API endpoints",
category="access_control",
owasp_llm_mapping=["LLM06"],
nist_ai_rmf_function="GOVERN",
),
SecurityControl(
control_id="AI-SEC-007",
name="Rate Limiting and Cost Controls",
description="Prevent model API abuse through rate limiting, budget caps, and anomaly detection",
category="availability",
owasp_llm_mapping=["LLM10"],
nist_ai_rmf_function="MANAGE",
),
SecurityControl(
control_id="AI-SEC-008",
name="Model Output Logging and Audit",
description="Log all model interactions with sufficient detail for security forensics and compliance",
category="monitoring",
owasp_llm_mapping=["LLM01", "LLM02"],
nist_ai_rmf_function="MEASURE",
),
SecurityControl(
control_id="AI-SEC-009",
name="RAG Pipeline Security",
description="Secure the retrieval pipeline against document poisoning and embedding manipulation",
category="data_pipeline",
owasp_llm_mapping=["LLM08"],
nist_ai_rmf_function="MAP",
),
SecurityControl(
control_id="AI-SEC-010",
name="Agent/Tool Authorization Controls",
description="Restrict and monitor tool/function calls made by AI agents to enforce least privilege",
category="agent_security",
owasp_llm_mapping=["LLM06"],
nist_ai_rmf_function="MANAGE",
),
]
# Provider-specific responsibility mappings
def get_aws_bedrock_assignments() -> list[ResponsibilityAssignment]:
"""Map security controls to responsibility owners for AWS Bedrock."""
return [
ResponsibilityAssignment(
control=AI_SECURITY_CONTROLS[0], # Model Provenance
provider=CloudProvider.AWS_BEDROCK,
owner=ResponsibilityOwner.SHARED,
provider_capabilities=(
"AWS vets foundation models before listing on Bedrock. Provides model cards "
"with training methodology summaries. Manages model serving infrastructure."
),
customer_actions_required=(
"Evaluate model cards for suitability. Test models against your specific "
"use case requirements. Maintain an internal model registry documenting "
"which models are approved for which use cases."
),
),
ResponsibilityAssignment(
control=AI_SECURITY_CONTROLS[1], # Prompt Injection
provider=CloudProvider.AWS_BEDROCK,
owner=ResponsibilityOwner.CUSTOMER,
provider_capabilities=(
"Bedrock Guardrails offers configurable content filtering and denied topics. "
"Does not include specialized prompt injection detection."
),
customer_actions_required=(
"Implement application-level prompt injection detection. Configure Bedrock "
"Guardrails for content filtering. Add input validation before the model API call. "
"Consider third-party tools like Prompt Guard or custom classifiers."
),
gap_description=(
"Bedrock Guardrails focuses on content policy, not prompt injection detection. "
"Customers must implement their own injection defense layer."
),
),
ResponsibilityAssignment(
control=AI_SECURITY_CONTROLS[2], # Output Filtering
provider=CloudProvider.AWS_BEDROCK,
owner=ResponsibilityOwner.SHARED,
provider_capabilities=(
"Bedrock Guardrails provides configurable output content filters for "
"hate, insults, sexual content, violence, and misconduct categories. "
"Supports custom denied topics and word filters."
),
customer_actions_required=(
"Configure Guardrails thresholds appropriate for your use case. "
"Implement additional application-specific output validation. "
"Add PII detection using Bedrock Guardrails PII filters or Amazon Comprehend."
),
),
ResponsibilityAssignment(
control=AI_SECURITY_CONTROLS[5], # API Auth
provider=CloudProvider.AWS_BEDROCK,
owner=ResponsibilityOwner.SHARED,
provider_capabilities=(
"Bedrock uses IAM for authentication. Supports resource-based policies, "
"VPC endpoints, and CloudTrail logging of API calls."
),
customer_actions_required=(
"Configure IAM policies with least privilege. Use VPC endpoints for "
"private access. Enable CloudTrail logging. Implement application-level "
"authentication for end users. Rotate credentials regularly."
),
),
ResponsibilityAssignment(
control=AI_SECURITY_CONTROLS[6], # Rate Limiting
provider=CloudProvider.AWS_BEDROCK,
owner=ResponsibilityOwner.SHARED,
provider_capabilities=(
"Bedrock enforces account-level quotas and throughput limits. "
"Supports provisioned throughput for predictable capacity."
),
customer_actions_required=(
"Set appropriate account quotas. Implement application-level rate limiting "
"per user/session. Configure AWS Budgets alerts for cost anomalies. "
"Monitor for abuse patterns in application logs."
),
),
ResponsibilityAssignment(
control=AI_SECURITY_CONTROLS[7], # Logging
provider=CloudProvider.AWS_BEDROCK,
owner=ResponsibilityOwner.SHARED,
provider_capabilities=(
"Bedrock supports model invocation logging to S3 and CloudWatch. "
"Logs include input/output content, token counts, and latency."
),
customer_actions_required=(
"Enable model invocation logging. Configure log retention and access controls. "
"Build monitoring dashboards and alert rules. Ensure logging configuration "
"meets regulatory retention requirements."
),
),
]
class SharedResponsibilityAuditor:
"""Audits an organization's AI deployment against the shared responsibility model."""
def __init__(self, provider: CloudProvider):
self.provider = provider
self.assignments = self._load_assignments()
def _load_assignments(self) -> list[ResponsibilityAssignment]:
if self.provider == CloudProvider.AWS_BEDROCK:
return get_aws_bedrock_assignments()
# Add other providers similarly
return []
def audit(self, implemented_controls: dict[str, dict]) -> dict:
"""
Audit implemented controls against required responsibilities.
Args:
implemented_controls: Dict mapping control_id to implementation details.
Expected keys: "implemented" (bool), "evidence" (str), "owner" (str).
Returns:
Audit report with gaps, risks, and recommendations.
"""
gaps = []
compliant = []
partial = []
for assignment in self.assignments:
control_id = assignment.control.control_id
impl = implemented_controls.get(control_id, {})
if not impl.get("implemented", False):
gaps.append({
"control_id": control_id,
"control_name": assignment.control.name,
"owner": assignment.owner.value,
"customer_action_required": assignment.customer_actions_required,
"owasp_mapping": assignment.control.owasp_llm_mapping,
"risk": "HIGH" if assignment.owner in (
ResponsibilityOwner.CUSTOMER, ResponsibilityOwner.SHARED
) else "MEDIUM",
})
elif assignment.gap_description and not impl.get("gap_addressed", False):
partial.append({
"control_id": control_id,
"control_name": assignment.control.name,
"gap": assignment.gap_description,
"current_state": impl.get("evidence", "No evidence provided"),
})
else:
compliant.append({
"control_id": control_id,
"control_name": assignment.control.name,
"evidence": impl.get("evidence", ""),
})
total = len(self.assignments)
compliant_count = len(compliant)
return {
"provider": self.provider.value,
"total_controls": total,
"compliant": compliant_count,
"partial": len(partial),
"gaps": len(gaps),
"compliance_rate": compliant_count / total if total > 0 else 0,
"gap_details": gaps,
"partial_details": partial,
"compliant_details": compliant,
"risk_summary": {
"high_risk_gaps": sum(1 for g in gaps if g["risk"] == "HIGH"),
"medium_risk_gaps": sum(1 for g in gaps if g["risk"] == "MEDIUM"),
},
"top_recommendations": [
g["customer_action_required"]
for g in sorted(gaps, key=lambda x: x["risk"], reverse=True)[:5]
],
}Provider-Specific Responsibility Maps
AWS Bedrock
AWS Bedrock operates as a managed service that abstracts model serving. AWS's responsibility includes infrastructure security, model hosting, API availability, and basic content safety features through Bedrock Guardrails. The customer is responsible for everything above the API layer: IAM configuration, application security, prompt engineering for safety, guardrail configuration, data pipeline security, and compliance mapping.
Key customer-side gaps to address:
- Prompt injection detection: Bedrock Guardrails does not include dedicated prompt injection detection. Deploy application-level classifiers.
- System prompt security: Bedrock does not enforce system prompt confidentiality. Implement output filtering to detect system prompt leakage.
- VPC configuration: Bedrock API calls traverse the public internet by default. Configure VPC endpoints for private access.
Azure OpenAI Service
Azure OpenAI Service provides the deepest integration with enterprise security tooling through Azure Active Directory, Private Endpoints, and Azure Content Safety. Microsoft's responsibility extends further than other providers, covering content filtering (on by default), abuse monitoring, and integration with Microsoft Defender for Cloud.
Key customer-side gaps:
- Content filter customization: Default filters may be too restrictive or too permissive for your use case. Test and calibrate filter severity levels.
- Data residency: Azure OpenAI processes data in the region of deployment but may send data to Microsoft for abuse monitoring unless opted out. Verify data residency meets regulatory requirements.
- Provisioned throughput security: PTU deployments have different security considerations than pay-as-you-go. Ensure network isolation for dedicated capacity.
GCP Vertex AI
GCP Vertex AI offers both API access to foundation models and infrastructure for self-hosted model deployment. Google's responsibility includes infrastructure security, model serving for API-accessed models, and Google Cloud Armor integration. The customer side includes IAM, VPC Service Controls, and application-level security.
Key customer-side gaps:
- Model Garden supply chain: Vertex AI Model Garden provides access to third-party models with varying security postures. Evaluate each model independently.
- Custom model security: When deploying custom models on Vertex AI endpoints, the customer owns the full model security stack.
- Grounding and RAG security: Vertex AI Search and Conversation grounding features introduce data pipeline security requirements that are entirely customer-managed.
Building Your Responsibility Matrix
# Template: RACI matrix for AI security responsibilities
from dataclasses import dataclass
@dataclass
class RACIEntry:
"""A single entry in the AI security RACI matrix."""
activity: str
responsible: str # Does the work
accountable: str # Makes the decision, has final authority
consulted: str # Provides input
informed: str # Kept up to date
AI_SECURITY_RACI: list[RACIEntry] = [
RACIEntry(
activity="Model selection and approval for production use",
responsible="AI/ML Engineering",
accountable="CISO / AI Governance Board",
consulted="Security Team, Legal, Compliance",
informed="Application Development Teams",
),
RACIEntry(
activity="Prompt injection defense implementation",
responsible="Application Security Team",
accountable="Security Engineering Lead",
consulted="AI/ML Engineering, Red Team",
informed="Development Teams, CISO",
),
RACIEntry(
activity="Cloud AI service IAM configuration",
responsible="Cloud Engineering / Platform Team",
accountable="Cloud Security Lead",
consulted="Security Team, AI/ML Engineering",
informed="Application Development Teams",
),
RACIEntry(
activity="Model output content safety configuration",
responsible="AI/ML Engineering",
accountable="Product Owner + Security",
consulted="Legal, Compliance, Trust & Safety",
informed="Customer Support, CISO",
),
RACIEntry(
activity="Fine-tuning data quality and security review",
responsible="Data Engineering + AI/ML Engineering",
accountable="Data Governance Lead",
consulted="Security Team, Legal/Privacy",
informed="AI/ML Engineering Lead",
),
RACIEntry(
activity="AI incident response",
responsible="Security Operations (SOC)",
accountable="CISO",
consulted="AI/ML Engineering, Application Team, Legal",
informed="Executive Leadership, Compliance",
),
RACIEntry(
activity="AI red teaming and safety evaluation",
responsible="Red Team / AI Security Team",
accountable="Security Engineering Lead",
consulted="AI/ML Engineering, Product",
informed="CISO, Development Teams",
),
RACIEntry(
activity="Regulatory compliance for AI systems",
responsible="Compliance Team",
accountable="General Counsel / CISO",
consulted="AI/ML Engineering, Security, Product",
informed="Executive Leadership",
),
]
def generate_raci_matrix(entries: list[RACIEntry]) -> str:
"""Generate a formatted RACI matrix for documentation."""
header = "| Activity | Responsible | Accountable | Consulted | Informed |"
separator = "|----------|------------|-------------|-----------|----------|"
rows = [
f"| {e.activity} | {e.responsible} | {e.accountable} | {e.consulted} | {e.informed} |"
for e in entries
]
return "\n".join([header, separator] + rows)Operationalizing the Model
Mapping responsibilities is the first step. Operationalizing the model requires sustained effort across multiple organizational functions.
Automated Compliance Verification
Use cloud-native tools (AWS Config, Azure Policy, GCP Organization Policy) to continuously verify that customer-side controls are deployed and correctly configured. Define custom rules that check AI-specific configurations:
- AWS Config: Custom rules that verify Bedrock model invocation logging is enabled, VPC endpoints are configured for Bedrock Runtime, and IAM policies restrict model access to approved roles.
- Azure Policy: Built-in and custom policies that verify Azure OpenAI content filtering is enabled, private endpoints are configured, and diagnostic settings capture model interaction logs.
- GCP Organization Policy: Constraints that restrict which Vertex AI models can be deployed, ensure VPC Service Controls are applied to AI API services, and verify that audit logging is active.
Regular Gap Assessments
Run the SharedResponsibilityAuditor quarterly against your actual deployment configuration to identify drift and new gaps. AI deployments change rapidly — new models are adopted, new integrations are built, and provider capabilities evolve. A quarterly cadence ensures that responsibility assignments stay current.
The assessment should include a reconciliation step where the security team validates that every AI asset in the inventory has a clear responsibility assignment for each security control. Assets without clear assignments represent unmitigated risk.
Provider Change Tracking
Monitor provider announcements for changes to their security capabilities and responsibility boundaries. AWS, Azure, and GCP frequently update their AI service features, which can shift the responsibility boundary. For example, when AWS Bedrock added Guardrails, some output content filtering responsibilities shifted partially to the provider — but only for organizations that configure and enable Guardrails. Organizations that do not enable the feature retain full customer-side responsibility.
Assign a team member to monitor the following sources for each provider:
- AWS: Bedrock release notes, Security Blog, and re:Invent announcements
- Azure: Azure OpenAI Service updates, Microsoft Security Blog
- GCP: Vertex AI release notes, Google Cloud Security summaries
Cross-Functional Reviews
The RACI matrix must be reviewed with all stakeholder teams at least annually to ensure ownership remains accurate as teams reorganize and products evolve. AI security is inherently cross-functional — it spans cloud engineering, data science, application security, legal, and compliance teams. If any team's structure changes, the RACI matrix may need updating to reflect new ownership.
Incident-Driven Updates
After any AI security incident, the shared responsibility model should be reviewed to determine whether the incident revealed a gap in responsibility assignment. If the root cause of an incident was that nobody owned a specific security control, the RACI matrix must be updated immediately — not at the next quarterly review.
Common Pitfalls
Organizations implementing the shared responsibility model for AI frequently encounter these problems:
-
Assuming the provider handles model safety. Cloud providers secure the infrastructure, not the model behavior. If a model generates harmful content, that is a customer-side problem to solve through guardrails, not a provider outage to report.
-
Treating AI security as a cloud engineering problem. Cloud engineers manage IAM and networking but typically lack the expertise to evaluate model safety, prompt injection risks, or output quality. AI security requires collaboration between cloud, data science, and security teams.
-
Not updating after provider feature releases. When a provider launches a new security feature (like Bedrock Guardrails or Azure Content Safety), organizations must evaluate whether to adopt it and update their responsibility assignments accordingly. Ignoring new features means missing available risk reduction.
-
Failing to account for shadow AI. Development teams often experiment with AI services outside of approved channels — using personal API keys, testing models through web interfaces, or deploying models on unmanaged infrastructure. The shared responsibility model only works for assets that are known and tracked.
-
Confusing compliance with security. Passing a compliance audit (SOC 2, ISO 27001) does not mean AI workloads are secure. Compliance frameworks are beginning to address AI-specific risks, but most current certifications do not evaluate prompt injection defense, model safety alignment, or AI-specific incident response capabilities.
Self-Hosted vs. Managed: How Hosting Model Shifts Responsibility
The shared responsibility model changes dramatically when organizations choose to self-host open-source models rather than using managed cloud AI services. Understanding this shift is critical for security planning.
Managed Services (Bedrock, Azure OpenAI, Vertex AI)
With managed services, the provider handles infrastructure security, model serving, patching, and availability. The customer's responsibility starts at the API boundary: authentication, authorization, content safety configuration, prompt engineering, application security, and compliance. This is the most common deployment model and the one most organizations should prefer unless they have specific requirements that mandate self-hosting.
Self-Hosted on Cloud Compute (EC2, GKE, AKS)
When self-hosting an open-source model on cloud compute, the customer assumes responsibility for the full model security stack: model weight integrity, inference server configuration, GPU driver patching, container security, network isolation, and model API authentication. The cloud provider is responsible only for the underlying compute and network infrastructure. This significantly increases the customer's security burden and requires specialized expertise in ML operations security that many organizations lack.
Self-Hosted on-Premises
On-premises deployments place all responsibility on the customer, from physical hardware security through model behavior. This option provides maximum control but maximum responsibility, and is typically only appropriate for organizations with specific data sovereignty or regulatory requirements that cannot be met by any cloud deployment.
The key insight is that self-hosting does not eliminate the provider relationship — it replaces a single AI service provider with multiple component providers (hardware vendor, OS vendor, inference framework maintainer, model developer). Each of these relationships has its own implicit shared responsibility model that must be mapped and managed.
The Open-Source Model Complication
Open-source models add another dimension to the responsibility matrix. When an organization deploys Meta's Llama or Mistral AI's models, the model provider has no ongoing security obligation — they released the weights under an open license and moved on. There is no SLA, no security patch cadence, and no incident response relationship. The organization assumes full responsibility for model security, including monitoring for newly discovered vulnerabilities, evaluating whether published jailbreaks affect their deployment, and deciding when to migrate to a newer model version.
This is fundamentally different from using a managed API like OpenAI's or Anthropic's, where the provider continuously updates the model, patches safety issues, and monitors for new attack techniques. Organizations choosing open-source models must build internal capability to perform these functions, or accept the risk that their deployed model will gradually fall behind the evolving threat landscape.
Red Team Assessment Approach
Security teams assessing an organization's AI shared responsibility implementation should focus on identifying gaps — responsibilities that neither the provider nor the customer has effectively addressed. The most common gaps are:
-
Prompt injection defense: Provider offers content filtering; customer assumes this covers prompt injection (it does not). Neither has deployed dedicated injection detection.
-
Model output monitoring: Provider logs API calls; customer monitors application metrics. Neither monitors model outputs for safety violations, data leakage, or anomalous patterns.
-
Supply chain verification: For managed services, the provider handles model integrity. For self-hosted models, nobody verifies model weight integrity after initial download.
-
Incident detection for AI-specific attacks: Provider monitors for infrastructure attacks; customer monitors for application attacks. Neither monitors for AI-specific attack patterns (gradual escalation, multi-turn manipulation, embedding poisoning).
The assessment should produce a clear gap map that identifies every unowned responsibility and recommends assignment to the appropriate team.
References
- AWS. "Shared Responsibility Model," https://aws.amazon.com/compliance/shared-responsibility-model/
- Microsoft. "Shared Responsibility in the Cloud," https://learn.microsoft.com/en-us/azure/security/fundamentals/shared-responsibility
- NIST AI 600-1, "Artificial Intelligence Risk Management Framework: Generative AI Profile," https://csrc.nist.gov/publications/detail/ai/600-1/final
- OWASP Top 10 for Large Language Model Applications 2025, https://owasp.org/www-project-top-10-for-large-language-model-applications/