This guide will walk you through deploying the complete demo in under 15 minutes.
Step 1: Create the Policy Store
AWS Verified Permissions stores your authorization policies in a Policy Store. You’ll create this manually in the AWS Console.
Open AWS Verified Permissions console
Navigate to the AWS Console and search for “Verified Permissions” in the services search bar. Make sure you’re in the same AWS region where you’ll deploy the Lambda functions (e.g., us-west-2).
Create a new Policy Store
Click “Create policy store” Select “Empty policy store” - do NOT use the “Guided setup” option. The guided setup creates a different schema structure.
Configure the Policy Store
Policy store name: FinancialDocsStore
Validation mode: Schema-based (default)
Click “Create”
Copy the Policy Store ID
After creation, you’ll see the Policy Store dashboard. Copy the Policy Store ID (format: PSEXAMPLEabcdefg12345678). Save this ID - you’ll need it in Step 3 for the SAM deployment.
Step 2: Define the schema
The schema defines the structure of your entities (users, resources) and their attributes.
Open the Schema editor
In your Policy Store dashboard, navigate to Schema → Edit
Replace with the FinancialApp schema
Delete any existing content and paste this complete schema: {
"FinancialApp" : {
"entityTypes" : {
"User" : {
"shape" : {
"type" : "Record" ,
"attributes" : {
"department" : {
"type" : "String" ,
"required" : true
},
"clearance_level" : {
"type" : "Long" ,
"required" : true
}
}
},
"memberOfTypes" : [ "Role" ]
},
"Document" : {
"shape" : {
"type" : "Record" ,
"attributes" : {
"classification" : {
"type" : "String" ,
"required" : true
},
"department" : {
"type" : "String" ,
"required" : true
}
}
}
},
"Role" : {
"memberOfTypes" : []
}
},
"actions" : {
"Read" : {
"appliesTo" : {
"principalTypes" : [ "User" ],
"resourceTypes" : [ "Document" ]
}
},
"Edit" : {
"appliesTo" : {
"principalTypes" : [ "User" ],
"resourceTypes" : [ "Document" ]
}
},
"Delete" : {
"appliesTo" : {
"principalTypes" : [ "User" ],
"resourceTypes" : [ "Document" ]
}
}
}
}
}
The "memberOfTypes": ["Role"] field in the User entity is critical. It tells AVP that a User can belong to a Role, which is necessary for Cedar to evaluate principal in Role::"Analyst".
Save the schema
Click “Save changes” The console will validate your schema. If there are any errors, double-check that you copied the entire JSON correctly.
Step 3: Build and deploy with SAM
Now you’ll use AWS SAM to build and deploy the Lambda functions and API Gateway.
Navigate to the project directory
Build the SAM application
This command packages your Lambda functions and their dependencies. You should see output like: Build Succeeded
Built Artifacts : .aws-sam/build
Built Template : .aws-sam/build/template.yaml
Deploy with guided mode
SAM will ask you several configuration questions. Use these answers: Question Your answer Stack Name avp-demoAWS Region us-west-2 (or your preferred region)Parameter PolicyStoreId Paste the ID from Step 1 Parameter AnthropicApiKey Your sk-ant-... key (or placeholder) Confirm changes before deploy yAllow SAM CLI to create IAM roles yDisable rollback nCheckAccessFunction has no authentication yGetUsersFunction has no authentication yAgentFunction has no authentication ySave arguments to configuration file ySAM configuration file Press ENTER (uses samconfig.toml) SAM configuration environment Press ENTER (uses default) Deploy this changeset? y
If you don’t plan to use the AI agent, enter placeholder as the Anthropic API key. The main demo will work without it.
Copy the API URL
After successful deployment, SAM will display the outputs: Outputs
-------
ApiUrl = https://abc123xyz.execute-api.us-west-2.amazonaws.com/prod
AgentEndpoint = https://abc123xyz.execute-api.us-west-2.amazonaws.com/prod/agent
Copy the ApiUrl value - you’ll need it in the next step.
The frontend HTML files need to know your API Gateway URL.
Open index.html
Open ~/workspace/source/frontend/index.html in your code editor.
Update the API URL
Find line ~837 and replace the placeholder URL with your API URL from Step 3: const API_BASE_URL = "https://abc123xyz.execute-api.us-west-2.amazonaws.com/prod" ;
The URL must end with /prod - do not add any additional paths like /check-access.
Update avp-agent.html (if using AI agent)
If you provided an Anthropic API key, also update ~/workspace/source/frontend/avp-agent.html at line ~237: const API_BASE = "https://abc123xyz.execute-api.us-west-2.amazonaws.com/prod" ;
Step 5: Run the demo locally
Start a local web server to access the frontend.
Navigate to the frontend directory
cd ~/workspace/source/frontend
Start the web server
python3 -m http.server 8000
You should see: Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
Open in your browser
Navigate to one of these URLs: URL Description http://localhost:8000/index.htmlMain AVP demo lab http://localhost:8000/avp-agent.htmlAI agent with natural language
Do NOT open the files using file:// protocol. The browser will block API calls due to CORS. Always use http://localhost:8000.
Demo walkthrough
Now that everything is deployed, let’s run through the core demo scenarios.
Act 1: Zero Trust (deny by default)
Enter your Policy Store ID
In the web interface, paste your Policy Store ID in the configuration field.
Test Alice's access
Select user: Alice Garcia (Analyst, Finance)
Select resource: Q4-Report-2024
Select action: Read
Click Check Access
Result: 🚫 DENY This demonstrates Zero Trust: even though Alice has valid credentials and works in Finance (same department as the document), AVP denies access because no policy explicitly permits it.
Act 2: Cedar policy in action
Create your first policy
Go to AWS Console → Verified Permissions → Your Policy Store → Policies → Create → Static policy Policy name: AllowAnalystReadOwnDepartmentpermit (
principal in FinancialApp::Role::"Analyst",
action == FinancialApp::Action::"Read",
resource
)
when {
principal.department == resource.department
};
This policy allows users in the Analyst role to Read documents, but only if the user’s department matches the document’s department (ABAC condition).
Test Alice again
Repeat the same request:
User: Alice Garcia
Resource: Q4-Report-2024
Action: Read
Result: ✅ ALLOW You didn’t change any code. You didn’t redeploy. You just added a Cedar policy, and it took effect immediately.
Act 3: Attribute-based access control
Test cross-department access
User: Carol Mendez (Auditor, HR)
Resource: Q4-Report-2024 (Finance department)
Action: Read
Result: 🚫 DENY Carol is denied because her department (HR) doesn’t match the document’s department (Finance), even though she’s an Auditor.
Create an Auditor policy
Create a new policy that allows Auditors to read any document: permit (
principal in FinancialApp::Role::"Auditor",
action == FinancialApp::Action::"Read",
resource
);
Test Carol again
Same request as before: Result: ✅ ALLOW Now Carol can access the Finance document because her Auditor role grants cross-department read access.
Act 4: Forbid overrides permit
Add a forbid policy
Create this policy to block Auditors from editing or deleting: forbid (
principal in FinancialApp::Role::"Auditor",
action in [FinancialApp::Action::"Edit", FinancialApp::Action::"Delete"],
resource
);
Test Carol's edit access
User: Carol Mendez
Resource: Q4-Report-2024
Action: Edit
Result: 🚫 DENY Even if you created a permit policy for Edit, the forbid would win. In Cedar, forbid always takes precedence over permit.
Act 5 (Bonus): AI agent
This requires an Anthropic API key. Skip this if you used placeholder during deployment.
Open the AI agent interface
Navigate to http://localhost:8000/avp-agent.html
Ask a natural language question
Type in the chat:
“Check access for all users to Q4-Report-2024 for Read action”
The AI agent will:
Understand your request
Make multiple calls to the AVP check_avp_access tool
Summarize the results in natural language
All without you having to specify the exact API calls or structure.
Understanding the Lambda code
The core authorization logic lives in lambda/app.py. Here’s how it works:
lambda/app.py (IsAuthorized call)
lambda/app.py (Building entity context)
avp_response = avp_client.is_authorized(
policyStoreId = POLICY_STORE_ID ,
principal = {
"entityType" : "FinancialApp::User" ,
"entityId" : user_id
},
action = {
"actionType" : "FinancialApp::Action" ,
"actionId" : action_id
},
resource = {
"entityType" : "FinancialApp::Document" ,
"entityId" : resource_id
},
entities = {
"entityList" : build_entity_list(user_id, resource_id)
}
)
decision = avp_response[ "decision" ] # "ALLOW" or "DENY"
The build_entity_list function provides AVP with the full context needed to evaluate Cedar policies, including user attributes, role membership, and resource properties.
Next steps
Learn Cedar policy language Practice writing Cedar policies in the interactive playground
AWS Verified Permissions docs Explore the official AVP documentation
AVP Workshop Take the official AWS workshop on Verified Permissions
Cedar on GitHub Explore the open-source Cedar policy engine
Cleanup
When you’re done with the demo, remove all AWS resources to avoid charges:
# Delete the CloudFormation stack (Lambdas and API Gateway)
sam delete --stack-name avp-demo
Then manually delete the Policy Store:
Go to AWS Console → Verified Permissions
Select your FinancialDocsStore
Click Delete
Confirm deletion
The demo uses serverless resources that scale to zero when not in use, so costs are minimal. However, it’s good practice to clean up resources you’re not using.