AIAC-Agentic System is a policy-as-code access control backend for AI agents, built with Spring Boot and Open Policy Agent (OPA).
It enables dynamic, auditable authorization decisions using a pluggable policy engine with fallback mechanisms and persistent audit logging.
The system follows a Zero Trust model and is designed to demonstrate Policy-as-Code, AI Governance, and Auditability.
The goal of this project is to build a backend system that evaluates an AI agent’s access request before the agent performs a resource access, tool call, sensitive action, or task-chain step.
The platform is designed to:
- identify the requesting agent
- analyze request context
- evaluate policy
- allow or deny execution
- record an audit trail for every decision
This repository implements a Spring Boot backend with pluggable policy providers, real OPA integration path, local fallback logic, and persistent audit logging.
- Policy-as-Code architecture using Open Policy Agent (OPA) and Rego
- Pluggable policy providers supporting both local and OPA-based evaluation
- Automatic fallback to local policy when OPA is unavailable
- Dynamic access decisions based on agent identity, role, resource, action, and context
- Persistent audit logging with H2 and Spring Data JPA
- Queryable audit logs with filtering support for
agentIdanddecision - Clean layered backend architecture designed for extensibility
- Zero Trust-oriented design for AI agent governance
The backend now delivers a working end-to-end access control flow with policy abstraction, OPA integration support, and database-backed audit persistence.
The current implementation can:
- receive an access request
- validate request fields and contextual inputs
- delegate the decision to a pluggable policy provider
- return
ALLOWorDENY - persist an audit log entry
- expose log history and filtered audit queries through an API
The implementation is intentionally focused on backend security architecture and avoids unrelated complexity such as authentication frameworks, message queues, and frontend-heavy features at this stage.
- Java 17
- Spring Boot
- Maven Wrapper
- H2 Database
- Spring Data JPA
- Open Policy Agent (OPA)
- Rego (Policy Language)
- REST API / JSON
Current architecture:
Client -> Controller -> AccessControlService -> (LocalPolicyDecisionService | OpaPolicyDecisionService) -> AuditLogService -> H2 / JPA Repository
- Phase 1: Backend MVP ✅
- Phase 2: Policy abstraction ✅
- Phase 3: OPA integration ✅
- Phase 4: Audit persistence (H2 + JPA) ✅
src/main/java/com/aiac/agentic/
├── AiacApplication.java
├── controller/
├── service/
├── model/
├── repository/
├── config/
└── exception/
GET /api/health
Response example:
{
"success": true,
"data": {
"status": "UP",
"service": "AIAC-Agentic-System"
},
"message": "Service is running"
}POST /api/access/check
Request body:
{
"requestId": "req-001",
"agentId": "agent-007",
"agentType": "assistant",
"role": "analyst",
"resource": "financial_report",
"action": "read",
"environment": "dev",
"sensitivityLevel": "medium"
}Response example:
{
"success": true,
"data": {
"agentId": "agent-007",
"decision": "ALLOW",
"reason": "Analyst role may read financial_report."
},
"message": "Access decision generated successfully"
}GET /api/logs
Optional filters:
GET /api/logs?agentId=agent-007GET /api/logs?decision=ALLOW
Response example:
{
"success": true,
"data": [
{
"id": 1,
"requestId": "req-010",
"agentId": "agent-007",
"role": "analyst",
"resource": "financial_report",
"action": "read",
"decision": "ALLOW",
"policyProvider": "opa",
"timestamp": "2026-03-25T06:00:00Z",
"decisionLatencyMs": 14
}
],
"message": "Audit logs fetched successfully"
}The backend now supports two policy provider paths:
local-> usesLocalPolicyDecisionServiceopa-> usesOpaPolicyDecisionService
The currently active provider is selected through configuration:
policy.provider=local
policy.opa.url=http://localhost:8181/v1/data/aiac/allowThe local rules remain intentionally simple:
admin-> may access any resource/action -> ALLOWanalyst+financial_report+read-> ALLOW- all other cases -> DENY
OpaPolicyDecisionService now:
- builds an OPA input payload from
AccessRequest - sends a real HTTP
POSTrequest to the configured OPA endpoint - parses the boolean OPA decision from the response body
- converts that result into
ALLOWorDENY - falls back to local policy when OPA is unreachable or returns an invalid response
This keeps the system runnable even when no OPA server is present, while allowing real OPA evaluation whenever OPA is available.
- Java 17+
- Maven 3.9+
./mvnw spring-boot:runThe service starts on port 8080.
If port 8080 is already in use, run on another port:
./mvnw spring-boot:run -Dspring-boot.run.arguments=--server.port=18080./mvnw clean package./mvnw testcurl http://localhost:8080/api/healthcurl -X POST http://localhost:8080/api/access/check \
-H "Content-Type: application/json" \
-d '{
"requestId": "req-001",
"agentId": "agent-007",
"agentType": "assistant",
"role": "analyst",
"resource": "financial_report",
"action": "read",
"environment": "dev",
"sensitivityLevel": "medium"
}'curl -X POST http://localhost:8080/api/access/check \
-H "Content-Type: application/json" \
-d '{
"requestId": "req-002",
"agentId": "guest-001",
"agentType": "automation-bot",
"role": "guest",
"resource": "financial_report",
"action": "delete",
"environment": "dev",
"sensitivityLevel": "high"
}'curl http://localhost:8080/api/logsSample Rego policy file:
policies/aiac.rego
Start OPA locally from the project root:
opa run --server --addr :8181 policies/aiac.regoThen run the backend in OPA mode:
./mvnw spring-boot:run -Dspring-boot.run.arguments='--policy.provider=opa'Or if 8080 is occupied:
./mvnw spring-boot:run -Dspring-boot.run.arguments='--server.port=18080 --policy.provider=opa'You can also keep src/main/resources/application.properties set to:
policy.provider=opa
policy.opa.url=http://localhost:8181/v1/data/aiac/allowOPA test request directly:
curl -X POST http://localhost:8181/v1/data/aiac/allow \
-H "Content-Type: application/json" \
-d '{
"input": {
"agentId": "agent-007",
"role": "analyst",
"resource": "financial_report",
"action": "read",
"environment": "dev",
"sensitivityLevel": "medium"
}
}'Expected OPA response:
{
"result": true
}With the backend running in OPA mode, test the full flow:
curl -X POST http://localhost:8080/api/access/check \
-H "Content-Type: application/json" \
-d '{
"requestId": "req-010",
"agentId": "agent-007",
"agentType": "assistant",
"role": "analyst",
"resource": "financial_report",
"action": "read",
"environment": "dev",
"sensitivityLevel": "medium"
}'Audit logs now persist to an in-memory H2 database through Spring Data JPA.
Configured defaults:
spring.datasource.url=jdbc:h2:mem:aiacdb
spring.jpa.hibernate.ddl-auto=update
spring.h2.console.enabled=true
spring.h2.console.path=/h2-consoleThe AccessLog entity stores:
requestIdagentIdroleresourceactiondecisionpolicyProvidertimestampdecisionLatencyMs
Query by agent:
curl "http://localhost:8080/api/logs?agentId=agent-007"Example response:
{
"success": true,
"data": [
{
"id": 1,
"requestId": "req-010",
"agentId": "agent-007",
"role": "analyst",
"resource": "financial_report",
"action": "read",
"decision": "ALLOW",
"policyProvider": "opa",
"timestamp": "2026-03-25T06:00:00Z",
"decisionLatencyMs": 14
}
],
"message": "Audit logs fetched successfully"
}Query by decision:
curl "http://localhost:8080/api/logs?decision=DENY"- controllers are thin and only handle HTTP concerns
- decision logic stays in the service layer
- audit logging is automatic on each access decision
- logs are now persisted with H2 + JPA
- response format is unified with
success,data, andmessage - validation and exception handling are centralized
- Spring Boot MVP
- local mock policy rules
- in-memory audit logging
- basic REST APIs
- richer request context (
requestId,agentType,environment,sensitivityLevel,toolName,taskType) - pluggable policy architecture
- stronger validation and domain-specific error handling
- improved response contracts
- real HTTP-based OPA integration
- send access context as OPA
input - parse OPA decisions into backend responses
- keep fallback handling when OPA is unavailable
- persist audit logs with H2 or PostgreSQL
- add filter/query support
- enrich logs with policy version, matched rule, latency, source IP, and timestamps
- later switch from H2 to PostgreSQL with minimal repository/service changes
- add Go enforcement gateway as the execution and interception layer
- evolve toward
Client -> Go Gateway -> Java Backend -> OPA -> DB
- add React admin console
- display access events, ALLOW/DENY distributions, and decision details
- support submitting test access requests visually
Verified with Maven Wrapper:
./mvnw testpasses- application boots successfully with
./mvnw spring-boot:run - H2/JPA schema initializes automatically
/api/healthresponds correctly/api/access/checkreturns bothALLOWandDENY/api/logsreturns persisted audit records/api/logs?agentId=...and/api/logs?decision=...work- OPA mode configuration works and falls back to local policy when OPA is unreachable
This project is meant to demonstrate that AI systems should not directly execute sensitive actions without a governance layer. Even in MVP form, the backend shows the most important security loop:
request -> decision -> enforcement basis -> audit trail
That loop is the foundation for a more complete AI access governance platform.