Blueprint: The HR Compliance Bot
Identity-Aware RBAC for Conversational Systems
When building internal employee-facing agents, governance must ensure that users cannot bypass organizational hierarchy using natural language. A general staff member should not be able to "ask" the AI for the CEO's salary or private PII of other employees.
This blueprint demonstrates Identity-Aware RBAC and Cross-IdP Group Matching.
Architecture
1. Master Policy Definition
Define granular tool permissions mapped to enterprise groups.
{
"name": "hr-conversational-policy",
"priority": 7000,
"rules": [
{
"id": "allow-hr-managers",
"effect": "allow",
"principals": ["group:hr-admins", "group:finance-directors"],
"actions": ["hr:*", "payroll:*"],
"resources": ["*"]
},
{
"id": "deny-general-staff",
"effect": "deny",
"principals": ["group:general-staff"],
"actions": ["hr:read_salary", "hr:delete_record"],
"resources": ["*"]
}
]
}
2. Implementation
FastAPI + LangChain Implementation
from fastapi import FastAPI, Header, Depends
from langchain_openai import ChatOpenAI
from langchain.agents import initialize_agent, Tool
import os
app = FastAPI()
# Mapped tools
def get_salary(name: str):
return f"The salary for {name} is $500,000."
hr_tools = [
Tool(name="hr:read_salary", func=get_salary, description="Read employee salary data")
]
@app.post("/chat")
async def chat(query: str, x_user_id: str = Header(...), x_user_group: str = Header(...)):
# Configure the LLM with identity headers for Control Zero
llm = ChatOpenAI(
model="gpt-4o",
openai_api_base="http://cz-gateway:8001/v1",
openai_api_key="cz_live_internal_key",
default_headers={
"X-ControlZero-User-ID": x_user_id,
"X-ControlZero-User-Group": x_user_group
}
)
agent = initialize_agent(hr_tools, llm, agent="zero-shot-react-description")
try:
# Control Zero Gateway will recursively check 'hr:read_salary' tool call
# against the X-ControlZero-User-Group provided.
response = agent.run(query)
return {"response": response}
except Exception as e:
return {"error": f"Governance Restriction: {e}"}
# Example Requests:
# 1. Staff: headers={'X-User-ID': 'emp-1', 'X-User-Group': 'general-staff'} -> BLOCKED
# 2. HR: headers={'X-User-ID': 'hr-1', 'X-User-Group': 'hr-admins'} -> ALLOWED
3. Validation Checklist
- Identity Propagation: Verify the Gateway logs show the correct
user_groupextracted from the custom headers. - Gating Test: Request "What is the salary of John Doe?" using a
general-staffheader and confirm the agent receives a 403. - MFA Check: (Optional) Add a condition requiring
X-ControlZero-MFA: verifiedfor thehr:delete_recordaction.