Oslo Policy
Oslo Policy is a core OpenStack library providing a robust and flexible authorization framework. It allows developers to define fine-grained access control rules using a policy file (JSON or YAML) and enforce them within their applications. As part of the OpenStack Oslo project, it is actively maintained with releases tied to the OpenStack development cycle, currently at version 5.0.0.
Common errors
-
oslo_policy.policy.PolicyNotAuthorized: Policy doesn't allow [...] to perform [...] on [...]
cause The authorization context (user roles, project, etc.) does not satisfy the requirements defined by the policy rule.fixInspect the policy rule that failed and the `context` and `target` dictionaries passed to `enforcer.authorize()`. Ensure the user's attributes (e.g., `roles`, `project_id`) match what the policy expects. Modify the policy rule or the user's context as needed. -
FileNotFoundError: [Errno 2] No such file or directory: 'policy.yaml'
cause The `policy_file` path provided to `policy.Enforcer` (or configured via `oslo.config`) is incorrect or the file does not exist at the specified location.fixVerify that `policy.yaml` (or your policy file) exists at the path specified. Ensure the path is absolute or correctly relative to the script's execution directory. Double-check for typos in the filename or path. -
KeyError: 'project_id' (or similar key) during policy evaluation
cause A policy rule references a key (e.g., `%(project_id)s`) that is missing from either the `context` or `target` dictionary passed to `enforcer.authorize()` during evaluation.fixEnsure all keys referenced in your policy rules (e.g., `user_id`, `project_id`, `is_admin`, `roles`) are present in the `context` or `target` dictionaries when calling `authorize()`. Provide default values for optional keys if appropriate.
Warnings
- breaking The default policy rule has changed significantly in oslo-policy 5.0.0. Previously, a policy rule like `"example_action": ""` (empty string) implied `rule:default` (allowing any authenticated user). In 5.0.0+, the default for an unlisted rule is now `role:admin`.
- gotcha Incorrect or missing policy file paths can lead to `FileNotFoundError` or unexpected `PolicyNotAuthorized` exceptions if no rules are loaded. Policy files often use YAML or JSON formats, and syntax errors can be subtle.
- gotcha Distinguishing between `context` and `target` parameters in `enforcer.authorize(rule, context, target)` can be confusing. `context` represents the current user/request attributes, while `target` represents the resource being accessed.
Install
-
pip install oslo-policy
Imports
- Enforcer
from oslo_policy.policy import Enforcer
from oslo_policy import policy enforcer = policy.Enforcer(...)
- PolicyNotAuthorized
from oslo_policy.policy import PolicyNotAuthorized
from oslo_policy import policy except policy.PolicyNotAuthorized:
Quickstart
from oslo_policy import policy
# Define policy rules inline for simplicity.
# In a real application, these would typically be loaded from a policy file
# (e.g., policy.yaml or policy.json) configured via oslo.config.
# Example: enforcer = policy.Enforcer(policy_file='path/to/policy.yaml')
rules = {
"admin_api": "role:admin",
"member_api": "role:member",
"owner_api": "project_id:%(project_id)s"
}
# Initialize the Policy Enforcer
enforcer = policy.Enforcer(rules=rules)
# Context for an admin user
admin_context = {
"user_id": "admin_user",
"roles": ["admin"],
"project_id": "admin_project"
}
# Context for a regular member user
member_context = {
"user_id": "member_user",
"roles": ["member"],
"project_id": "member_project"
}
# Target data for owner check (e.g., a resource's project_id)
target_data_owner = {"project_id": "member_project"}
target_data_other = {"project_id": "another_project"}
print("--- Admin User Checks ---")
try:
enforcer.authorize("admin_api", admin_context)
print("Admin can access admin_api: YES")
except policy.PolicyNotAuthorized as e:
print(f"Admin can access admin_api: NO ({e})")
try:
enforcer.authorize("member_api", admin_context)
print("Admin can access member_api: YES")
except policy.PolicyNotAuthorized as e:
print(f"Admin can access member_api: NO ({e})")
print("\n--- Member User Checks ---")
try:
enforcer.authorize("admin_api", member_context)
print("Member can access admin_api: YES")
except policy.PolicyNotAuthorized as e:
print(f"Member can access admin_api: NO ({e})") # Expected: NO
try:
enforcer.authorize("member_api", member_context)
print("Member can access member_api: YES")
except policy.PolicyNotAuthorized as e:
print(f"Member can access member_api: NO ({e})")
# Check owner_api (member accessing their own project)
try:
enforcer.authorize("owner_api", member_context, target_data_owner)
print("Member can access owner_api for their project: YES")
except policy.PolicyNotAuthorized as e:
print(f"Member can access owner_api for their project: NO ({e})")
# Check owner_api (member accessing another project)
try:
enforcer.authorize("owner_api", member_context, target_data_other)
print("Member can access owner_api for another project: YES")
except policy.PolicyNotAuthorized as e:
print(f"Member can access owner_api for another project: NO ({e})") # Expected: NO