PRE-RELEASE INFORMATION: SUBJECT TO CHANGE

Policy Cookbook

This cookbook provides comprehensive real-world scenarios for using Housecarl's policy engine to solve authorization challenges. Each scenario demonstrates how to structure domains, policies, and resources to achieve different access control patterns with complete setup workflows.

For quick policy patterns and recipes, see the Policy Recipes. For a formal understanding of the algorithm, see the Algorithm Reference. For the policy language details, see the Language Reference.

Core Concepts

Before diving into scenarios, understand these key concepts:

  • Resource: A hierarchical identifier in the format hc://<tenant-uuid>/<domain-name>/path/to/resource
  • Policy: A set of rules (written in TOML format) that evaluate whether an action is allowed
  • Domain: A container for policies, can inherit from superior domains
  • Statement: Individual rules within a policy using key-value pairs
  • Evaluation Engines:
    • Fixed: Exact string matching (fastest, use for exact matches)
    • Prefix: String prefix matching (ideal for hierarchical resources)
    • Regex: Regular expression matching (most flexible, higher computational cost)

Testing Policies Locally

All scenarios in this cookbook can be tested offline using housectl authz can-i-local. This command evaluates authorization requests against local policy files without requiring a running housecarl server.

Basic Usage:

# Test a request against local policies
housectl authz can-i-local \
  --request request.json \
  --tenant <tenant-uuid> \
  ./policies/

# With domain specified
housectl authz can-i-local \
  --request request.json \
  --tenant <tenant-uuid> \
  --domain <domain-name-or-uuid> \
  ./policies/

Policy File Format: Policies are written in TOML format (see examples below) Request File Format: JSON file with a context object containing subject, action, object

Scenario 1: Typical CRUD Application

Overview

A standard CRUD (Create, Read, Update, Delete) application where users can manage their own resources, and administrators have full access.

Architecture

Tenant ID: 550e8400-e29b-41d4-a716-446655440000
Tenant Name: myapp-tenant
Domain: app-domain

Resources: hc://550e8400-e29b-41d4-a716-446655440000/app-domain/myapp/users/{user_id}
          hc://550e8400-e29b-41d4-a716-446655440000/app-domain/myapp/posts/{post_id}
          hc://550e8400-e29b-41d4-a716-446655440000/app-domain/myapp/comments/{comment_id}

Setup

1. Create the Tenant and Domain

# Create tenant (returns tenant UUID)
housectl admin create-tenant "myapp-tenant" "My CRUD Application"
# Example output: Tenant created with ID: 550e8400-e29b-41d4-a716-446655440000

# Login as admin
housectl config login --url http://localhost:1234 --username admin --tenant myapp-tenant

# Create domain
housectl domain create --name app-domain
# Example output: Domain created with ID: 7c9e6679-7425-40de-944b-e07fc1f90ae7

2. Define Policies

Policies are written in TOML format. Create a directory for your policies and save each policy as a separate .toml file.

Policy 1: Admin Full Access (admin-full-access.toml) Administrators can perform any action on any resource.

name = "admin-full-access"
description = "Administrators have full access to all resources"
invert = false
deny = false
engine = "Regex"
statements = [
    { "subject" = "admin", "action" = ".*", "object" = "hc://550e8400-e29b-41d4-a716-446655440000/app-domain/myapp/.*" }
]

Policy 2: User Self-Management (user-self-management.toml) Users can read and update their own user records.

name = "user-self-management"
description = "Users can manage their own user records"
invert = false
deny = false
engine = "Fixed"
statements = [
    { "subject" = "$current_user()", "action" = "read", "object" = "hc://550e8400-e29b-41d4-a716-446655440000/app-domain/myapp/users/$current_user()" },
    { "subject" = "$current_user()", "action" = "update", "object" = "hc://550e8400-e29b-41d4-a716-446655440000/app-domain/myapp/users/$current_user()" }
]

Policy 3: Post Ownership (post-ownership.toml) Users can create posts and manage (update/delete) their own posts. Anyone can read posts.

name = "post-ownership"
description = "Users manage their own posts, everyone can read"
invert = false
deny = false
engine = "Regex"
statements = [
    { "action" = "read", "object" = "hc://550e8400-e29b-41d4-a716-446655440000/app-domain/myapp/posts/.*" },
    { "subject" = "$current_user()", "owner" = "$current_user()", "action" = "(update|delete)", "object" = "hc://550e8400-e29b-41d4-a716-446655440000/app-domain/myapp/posts/.*" },
    { "subject" = "$current_user()", "action" = "create", "object" = "hc://550e8400-e29b-41d4-a716-446655440000/app-domain/myapp/posts" }
]

Policy 4: Comment Management (comment-management.toml) Users can create comments and delete their own comments.

name = "comment-management"
description = "Users can create and delete their own comments"
invert = false
deny = false
engine = "Fixed"
statements = [
    { "action" = "read", "object" = "hc://550e8400-e29b-41d4-a716-446655440000/app-domain/myapp/comments" },
    { "subject" = "$current_user()", "action" = "create", "object" = "hc://550e8400-e29b-41d4-a716-446655440000/app-domain/myapp/comments" },
    { "subject" = "$current_user()", "owner" = "$current_user()", "action" = "delete", "object" = "hc://550e8400-e29b-41d4-a716-446655440000/app-domain/myapp/comments" }
]

3. Apply Policies to Domain (Server Deployment)

If deploying to a running housecarl server, save the policies to a directory and upload them:

# Create policies directory
mkdir -p ./scenario1-policies
# Save each policy from above to ./scenario1-policies/*.toml

# Upload policies to server
housectl domain put-policies --domain app-domain --policies ./scenario1-policies/

4. Testing Authorization Locally

Test your policies offline using housectl authz can-i-local. Create JSON request files for each test case:

Test Case 1: Admin deletes post (admin-delete-post.json)

{
  "context": {
    "subject": "admin",
    "action": "delete",
    "object": "hc://550e8400-e29b-41d4-a716-446655440000/app-domain/myapp/posts/123"
  }
}

Test Case 2: Alice reads own profile (alice-read-own-profile.json)

{
  "context": {
    "subject": "alice",
    "action": "read",
    "object": "hc://550e8400-e29b-41d4-a716-446655440000/app-domain/myapp/users/alice"
  }
}

Test Case 3: Alice tries to update Bob's profile (alice-update-bob.json)

{
  "context": {
    "subject": "alice",
    "action": "update",
    "object": "hc://550e8400-e29b-41d4-a716-446655440000/app-domain/myapp/users/bob"
  }
}

Test Case 4: Alice deletes own post (alice-delete-own-post.json)

{
  "context": {
    "subject": "alice",
    "owner": "alice",
    "action": "delete",
    "object": "hc://550e8400-e29b-41d4-a716-446655440000/app-domain/myapp/posts/456"
  }
}

Run the tests:

# Test admin access (should succeed - returns allowed: true)
housectl authz can-i-local \
  --request admin-delete-post.json \
  --tenant 550e8400-e29b-41d4-a716-446655440000 \
  ./scenario1-policies/

# Test user reading own profile (should succeed)
housectl authz can-i-local \
  --request alice-read-own-profile.json \
  --tenant 550e8400-e29b-41d4-a716-446655440000 \
  ./scenario1-policies/

# Test user updating another user (should fail - returns allowed: false)
housectl authz can-i-local \
  --request alice-update-bob.json \
  --tenant 550e8400-e29b-41d4-a716-446655440000 \
  ./scenario1-policies/

# Test user deleting own post (should succeed)
housectl authz can-i-local \
  --request alice-delete-own-post.json \
  --tenant 550e8400-e29b-41d4-a716-446655440000 \
  ./scenario1-policies/

Expected Results:

  • Admin deleting post: ✅ Allowed (admin-full-access policy matches)
  • Alice reading own profile: ✅ Allowed (user-self-management policy matches)
  • Alice updating Bob's profile: ❌ Denied (no matching policy)
  • Alice deleting own post: ✅ Allowed (post-ownership policy with owner check)

Scenario 2: Team and CRUD App with Shared Resources

Overview

A CRUD application where a dedicated team manages secrets and configuration, while the application has read-only access to those secrets. This models a separation of concerns where operators manage sensitive data and applications consume it.

Note: This scenario follows the same pattern as Scenario 1. All policies should be written in TOML format and can be tested locally with housectl authz can-i-local.

Architecture

Tenant ID: 660e8400-e29b-41d4-a716-446655440001
Tenant Name: platform-tenant

Domains:
  - secrets-domain (superior)
  - app-domain (inherits from secrets-domain)

Resources:
  - hc://660e8400-e29b-41d4-a716-446655440001/secrets-domain/platform/secrets/{secret_name}      (managed by ops-team)
  - hc://660e8400-e29b-41d4-a716-446655440001/secrets-domain/platform/config/{config_name}       (managed by ops-team)
  - hc://660e8400-e29b-41d4-a716-446655440001/app-domain/platform/app/data/{resource_id}     (managed by app)

Setup

1. Create Tenant and Domains

# Create tenant
housectl admin create-tenant "platform-tenant" "Platform with shared resources"

# Login
housectl config login --url http://localhost:1234 --username admin --tenant platform-tenant

# Create secrets domain (superior)
housectl domain create --tenant platform-tenant --name secrets-domain

# Create app domain (inherits from secrets-domain)
housectl domain create --tenant platform-tenant --name app-domain --superior-domains secrets-domain

2. Define Policies for Secrets Domain

Policy 1: Ops Team Full Access to Secrets The operations team can create, read, update, and delete secrets and configuration.

{
  "name": "ops-team-secrets-management",
  "description": "Ops team has full access to secrets and config",
  "invert": false,
  "deny": false,
  "engine": "Regex",
  "statements": [
    {
      "rules": {
        "subject": "ops-team",
        "action": "(create|read|update|delete)",
        "object": "hc://platform/secrets/.*"
      }
    },
    {
      "rules": {
        "subject": "ops-team",
        "action": "(create|read|update|delete)",
        "object": "hc://platform/config/.*"
      }
    }
  ]
}

Policy 2: Application Read-Only Access to Secrets The application service accounts can only read secrets and configuration.

{
  "name": "app-readonly-secrets",
  "description": "Applications have read-only access to secrets",
  "invert": false,
  "deny": false,
  "engine": "Regex",
  "statements": [
    {
      "rules": {
        "subject": "svc:crud-app",
        "action": "read",
        "object": "hc://platform/secrets/.*"
      }
    },
    {
      "rules": {
        "subject": "svc:crud-app",
        "action": "read",
        "object": "hc://platform/config/.*"
      }
    }
  ]
}

Policy 3: Deny Application Write to Secrets Explicitly prevent applications from modifying secrets (defense in depth).

{
  "name": "deny-app-write-secrets",
  "description": "Prevent applications from writing secrets",
  "invert": false,
  "deny": true,
  "engine": "Regex",
  "statements": [
    {
      "rules": {
        "subject": "svc:.*",
        "action": "(create|update|delete)",
        "object": "hc://platform/secrets/.*"
      }
    }
  ]
}

3. Define Policies for App Domain

Policy 4: Application Data Management The application can fully manage its own data resources.

{
  "name": "app-data-management",
  "description": "Application manages its own data",
  "invert": false,
  "deny": false,
  "engine": "Regex",
  "statements": [
    {
      "rules": {
        "subject": "svc:crud-app",
        "action": "(create|read|update|delete)",
        "object": "hc://platform/app/data/.*"
      }
    }
  ]
}

Policy 5: User Read Access to App Data End users can read application data based on ownership.

{
  "name": "user-read-app-data",
  "description": "Users can read their own app data",
  "invert": false,
  "deny": false,
  "engine": "Fixed",
  "statements": [
    {
      "rules": {
        "subject": "$current_user()",
        "owner": "$current_user()",
        "action": "read",
        "object": "hc://platform/app/data"
      }
    }
  ]
}

4. Apply Policies

# Apply secrets domain policies
cat > secrets-policies.json <<EOF
[
  {
    "name": "ops-team-secrets-management",
    "description": "Ops team has full access to secrets and config",
    "invert": false,
    "deny": false,
    "engine": "Regex",
    "statements": [
      {
        "rules": {
          "subject": "ops-team",
          "action": "(create|read|update|delete)",
          "object": "hc://platform/secrets/.*"
        }
      },
      {
        "rules": {
          "subject": "ops-team",
          "action": "(create|read|update|delete)",
          "object": "hc://platform/config/.*"
        }
      }
    ]
  },
  {
    "name": "app-readonly-secrets",
    "description": "Applications have read-only access to secrets",
    "invert": false,
    "deny": false,
    "engine": "Regex",
    "statements": [
      {
        "rules": {
          "subject": "svc:crud-app",
          "action": "read",
          "object": "hc://platform/secrets/.*"
        }
      },
      {
        "rules": {
          "subject": "svc:crud-app",
          "action": "read",
          "object": "hc://platform/config/.*"
        }
      }
    ]
  },
  {
    "name": "deny-app-write-secrets",
    "description": "Prevent applications from writing secrets",
    "invert": false,
    "deny": true,
    "engine": "Regex",
    "statements": [
      {
        "rules": {
          "subject": "svc:.*",
          "action": "(create|update|delete)",
          "object": "hc://platform/secrets/.*"
        }
      }
    ]
  }
]
EOF

housectl domain put-policies --tenant platform-tenant --domain secrets-domain --policies secrets-policies.json

# Apply app domain policies
cat > app-policies.json <<EOF
[
  {
    "name": "app-data-management",
    "description": "Application manages its own data",
    "invert": false,
    "deny": false,
    "engine": "Regex",
    "statements": [
      {
        "rules": {
          "subject": "svc:crud-app",
          "action": "(create|read|update|delete)",
          "object": "hc://platform/app/data/.*"
        }
      }
    ]
  },
  {
    "name": "user-read-app-data",
    "description": "Users can read their own app data",
    "invert": false,
    "deny": false,
    "engine": "Fixed",
    "statements": [
      {
        "rules": {
          "subject": "$current_user()",
          "owner": "$current_user()",
          "action": "read",
          "object": "hc://platform/app/data"
        }
      }
    ]
  }
]
EOF

housectl domain put-policies --tenant platform-tenant --domain app-domain --policies app-policies.json

Testing Authorization

# Ops team creates a secret (should succeed)
housectl authz can-i --context '{
  "subject": "ops-team",
  "action": "create",
  "object": "hc://platform/secrets/db-password"
}'

# Application reads secret (should succeed - inherits from secrets-domain)
housectl authz can-i --context '{
  "subject": "svc:crud-app",
  "action": "read",
  "object": "hc://platform/secrets/db-password"
}'

# Application tries to update secret (should fail - deny policy)
housectl authz can-i --context '{
  "subject": "svc:crud-app",
  "action": "update",
  "object": "hc://platform/secrets/db-password"
}'

# Application manages its data (should succeed)
housectl authz can-i --context '{
  "subject": "svc:crud-app",
  "action": "create",
  "object": "hc://platform/app/data/record-123"
}'

Scenario 3: Multi-Team Review and Approval

Overview

Three teams (Operations, Development, Compliance) need different levels of access to review and approve a CRUD application, its data pipeline, and deployment configuration. This models a GitOps-style workflow with separation of duties.

Note: This scenario follows the same pattern as Scenario 1. All policies should be written in TOML format and can be tested locally with housectl authz can-i-local.

Architecture

Tenant ID: 770e8400-e29b-41d4-a716-446655440002
Tenant Name: enterprise-tenant

Domain Hierarchy:
  - compliance-domain (root)
    - ops-domain (inherits compliance)
      - dev-domain (inherits ops)

Resources:
  - hc://770e8400-e29b-41d4-a716-446655440002/compliance-domain/enterprise/app/code/*           (source code)
  - hc://770e8400-e29b-41d4-a716-446655440002/compliance-domain/enterprise/app/config/*         (application config)
  - hc://770e8400-e29b-41d4-a716-446655440002/compliance-domain/enterprise/pipeline/*           (data pipeline definitions)
  - hc://770e8400-e29b-41d4-a716-446655440002/compliance-domain/enterprise/deployment/*         (K8s manifests, Terraform)
  - hc://770e8400-e29b-41d4-a716-446655440002/compliance-domain/enterprise/compliance/*         (audit reports, policies)

Setup

1. Create Tenant and Domain Hierarchy

# Create tenant
housectl admin create-tenant "enterprise-tenant" "Enterprise multi-team environment"

# Login
housectl config login --url http://localhost:1234 --username admin --tenant enterprise-tenant

# Create domain hierarchy
housectl domain create --tenant enterprise-tenant --name compliance-domain

housectl domain create --tenant enterprise-tenant --name ops-domain --superior-domains compliance-domain

housectl domain create --tenant enterprise-tenant --name dev-domain --superior-domains ops-domain

2. Define Compliance Domain Policies

Policy 1: Compliance Team Read-All Access Compliance can read everything but cannot modify operational systems.

{
  "name": "compliance-read-all",
  "description": "Compliance team has read access to all resources",
  "invert": false,
  "deny": false,
  "engine": "Regex",
  "statements": [
    {
      "rules": {
        "subject": "compliance-team",
        "action": "read",
        "object": "hc://enterprise/.*"
      }
    }
  ]
}

Policy 2: Compliance Team Manages Compliance Resources Compliance can manage compliance-specific resources (audit reports, policy documents).

{
  "name": "compliance-manage-compliance-resources",
  "description": "Compliance team manages compliance resources",
  "invert": false,
  "deny": false,
  "engine": "Regex",
  "statements": [
    {
      "rules": {
        "subject": "compliance-team",
        "action": "(create|update|delete|approve)",
        "object": "hc://enterprise/compliance/.*"
      }
    }
  ]
}

Policy 3: Deny Non-Compliance Modification of Compliance Resources Only compliance team can modify compliance resources.

{
  "name": "deny-non-compliance-write",
  "description": "Only compliance can modify compliance resources",
  "invert": false,
  "deny": true,
  "engine": "Regex",
  "statements": [
    {
      "rules": {
        "subject": "(?!compliance-team).*",
        "action": "(create|update|delete)",
        "object": "hc://enterprise/compliance/.*"
      }
    }
  ]
}

3. Define Operations Domain Policies

Policy 4: Ops Team Deployment Management Operations team can read and deploy infrastructure and application configurations.

{
  "name": "ops-deployment-management",
  "description": "Ops team manages deployments and infrastructure",
  "invert": false,
  "deny": false,
  "engine": "Regex",
  "statements": [
    {
      "rules": {
        "subject": "ops-team",
        "action": "(read|deploy|rollback)",
        "object": "hc://enterprise/deployment/.*"
      }
    },
    {
      "rules": {
        "subject": "ops-team",
        "action": "(read|update)",
        "object": "hc://enterprise/app/config/.*"
      }
    }
  ]
}

Policy 5: Ops Team Pipeline Management Operations can read and execute data pipelines.

{
  "name": "ops-pipeline-management",
  "description": "Ops team manages data pipelines",
  "invert": false,
  "deny": false,
  "engine": "Regex",
  "statements": [
    {
      "rules": {
        "subject": "ops-team",
        "action": "(read|execute|monitor)",
        "object": "hc://enterprise/pipeline/.*"
      }
    }
  ]
}

Policy 6: Ops Approval Required for Production Deployments Production deployments require ops team approval.

{
  "name": "ops-approve-prod-deployment",
  "description": "Ops must approve production deployments",
  "invert": false,
  "deny": false,
  "engine": "Regex",
  "statements": [
    {
      "rules": {
        "subject": "ops-team",
        "action": "approve",
        "object": "hc://enterprise/deployment/production/.*"
      }
    }
  ]
}

4. Define Development Domain Policies

Policy 7: Dev Team Source Code Management Developers can manage source code and create merge requests.

{
  "name": "dev-code-management",
  "description": "Developers manage source code",
  "invert": false,
  "deny": false,
  "engine": "Regex",
  "statements": [
    {
      "rules": {
        "subject": "dev-team",
        "action": "(read|write|create|update)",
        "object": "hc://enterprise/app/code/.*"
      }
    }
  ]
}

Policy 8: Dev Team Limited Config Access Developers can read configs and propose changes but cannot deploy directly.

{
  "name": "dev-config-read-propose",
  "description": "Developers can read and propose config changes",
  "invert": false,
  "deny": false,
  "engine": "Regex",
  "statements": [
    {
      "rules": {
        "subject": "dev-team",
        "action": "read",
        "object": "hc://enterprise/app/config/.*"
      }
    },
    {
      "rules": {
        "subject": "dev-team",
        "action": "propose",
        "object": "hc://enterprise/app/config/.*"
      }
    }
  ]
}

Policy 9: Dev Team Pipeline Read Access Developers can read pipeline definitions and logs for debugging.

{
  "name": "dev-pipeline-read",
  "description": "Developers can read pipeline definitions and logs",
  "invert": false,
  "deny": false,
  "engine": "Regex",
  "statements": [
    {
      "rules": {
        "subject": "dev-team",
        "action": "(read|logs)",
        "object": "hc://enterprise/pipeline/.*"
      }
    }
  ]
}

Policy 10: Deny Dev Direct Production Deployment Developers cannot deploy directly to production.

{
  "name": "deny-dev-prod-deploy",
  "description": "Prevent developers from deploying to production",
  "invert": false,
  "deny": true,
  "engine": "Regex",
  "statements": [
    {
      "rules": {
        "subject": "dev-team",
        "action": "deploy",
        "object": "hc://enterprise/deployment/production/.*"
      }
    }
  ]
}

5. Apply Policies to Domains

# Compliance domain policies
cat > compliance-policies.json <<EOF
[
  {
    "name": "compliance-read-all",
    "description": "Compliance team has read access to all resources",
    "invert": false,
    "deny": false,
    "engine": "Regex",
    "statements": [
      {
        "rules": {
          "subject": "compliance-team",
          "action": "read",
          "object": "hc://enterprise/.*"
        }
      }
    ]
  },
  {
    "name": "compliance-manage-compliance-resources",
    "description": "Compliance team manages compliance resources",
    "invert": false,
    "deny": false,
    "engine": "Regex",
    "statements": [
      {
        "rules": {
          "subject": "compliance-team",
          "action": "(create|update|delete|approve)",
          "object": "hc://enterprise/compliance/.*"
        }
      }
    ]
  },
  {
    "name": "deny-non-compliance-write",
    "description": "Only compliance can modify compliance resources",
    "invert": false,
    "deny": true,
    "engine": "Regex",
    "statements": [
      {
        "rules": {
          "subject": "(?!compliance-team).*",
          "action": "(create|update|delete)",
          "object": "hc://enterprise/compliance/.*"
        }
      }
    ]
  }
]
EOF

housectl domain put-policies --tenant enterprise-tenant --domain compliance-domain --policies compliance-policies.json

# Ops domain policies
cat > ops-policies.json <<EOF
[
  {
    "name": "ops-deployment-management",
    "description": "Ops team manages deployments and infrastructure",
    "invert": false,
    "deny": false,
    "engine": "Regex",
    "statements": [
      {
        "rules": {
          "subject": "ops-team",
          "action": "(read|deploy|rollback)",
          "object": "hc://enterprise/deployment/.*"
        }
      },
      {
        "rules": {
          "subject": "ops-team",
          "action": "(read|update)",
          "object": "hc://enterprise/app/config/.*"
        }
      }
    ]
  },
  {
    "name": "ops-pipeline-management",
    "description": "Ops team manages data pipelines",
    "invert": false,
    "deny": false,
    "engine": "Regex",
    "statements": [
      {
        "rules": {
          "subject": "ops-team",
          "action": "(read|execute|monitor)",
          "object": "hc://enterprise/pipeline/.*"
        }
      }
    ]
  },
  {
    "name": "ops-approve-prod-deployment",
    "description": "Ops must approve production deployments",
    "invert": false,
    "deny": false,
    "engine": "Regex",
    "statements": [
      {
        "rules": {
          "subject": "ops-team",
          "action": "approve",
          "object": "hc://enterprise/deployment/production/.*"
        }
      }
    ]
  }
]
EOF

housectl domain put-policies --tenant enterprise-tenant --domain ops-domain --policies ops-policies.json

# Dev domain policies
cat > dev-policies.json <<EOF
[
  {
    "name": "dev-code-management",
    "description": "Developers manage source code",
    "invert": false,
    "deny": false,
    "engine": "Regex",
    "statements": [
      {
        "rules": {
          "subject": "dev-team",
          "action": "(read|write|create|update)",
          "object": "hc://enterprise/app/code/.*"
        }
      }
    ]
  },
  {
    "name": "dev-config-read-propose",
    "description": "Developers can read and propose config changes",
    "invert": false,
    "deny": false,
    "engine": "Regex",
    "statements": [
      {
        "rules": {
          "subject": "dev-team",
          "action": "read",
          "object": "hc://enterprise/app/config/.*"
        }
      },
      {
        "rules": {
          "subject": "dev-team",
          "action": "propose",
          "object": "hc://enterprise/app/config/.*"
        }
      }
    ]
  },
  {
    "name": "dev-pipeline-read",
    "description": "Developers can read pipeline definitions and logs",
    "invert": false,
    "deny": false,
    "engine": "Regex",
    "statements": [
      {
        "rules": {
          "subject": "dev-team",
          "action": "(read|logs)",
          "object": "hc://enterprise/pipeline/.*"
        }
      }
    ]
  },
  {
    "name": "deny-dev-prod-deploy",
    "description": "Prevent developers from deploying to production",
    "invert": false,
    "deny": true,
    "engine": "Regex",
    "statements": [
      {
        "rules": {
          "subject": "dev-team",
          "action": "deploy",
          "object": "hc://enterprise/deployment/production/.*"
        }
      }
    ]
  }
]
EOF

housectl domain put-policies --tenant enterprise-tenant --domain dev-domain --policies dev-policies.json

Testing Authorization

# Compliance reads deployment config (should succeed)
housectl authz can-i --context '{
  "subject": "compliance-team",
  "action": "read",
  "object": "hc://enterprise/deployment/production/k8s-manifests"
}'

# Compliance tries to deploy (should fail - no deploy policy)
housectl authz can-i --context '{
  "subject": "compliance-team",
  "action": "deploy",
  "object": "hc://enterprise/deployment/production/k8s-manifests"
}'

# Ops deploys to production (should succeed - inherits compliance read + has deploy)
housectl authz can-i --context '{
  "subject": "ops-team",
  "action": "deploy",
  "object": "hc://enterprise/deployment/production/k8s-manifests"
}'

# Ops reads source code (should succeed - inherits from compliance)
housectl authz can-i --context '{
  "subject": "ops-team",
  "action": "read",
  "object": "hc://enterprise/app/code/main.rs"
}'

# Developer writes code (should succeed)
housectl authz can-i --context '{
  "subject": "dev-team",
  "action": "write",
  "object": "hc://enterprise/app/code/main.rs"
}'

# Developer tries to deploy to production (should fail - deny policy)
housectl authz can-i --context '{
  "subject": "dev-team",
  "action": "deploy",
  "object": "hc://enterprise/deployment/production/k8s-manifests"
}'

# Developer proposes config change (should succeed)
housectl authz can-i --context '{
  "subject": "dev-team",
  "action": "propose",
  "object": "hc://enterprise/app/config/database.toml"
}'

# Developer reads pipeline logs (should succeed - inherits compliance read + has logs action)
housectl authz can-i --context '{
  "subject": "dev-team",
  "action": "logs",
  "object": "hc://enterprise/pipeline/etl-job"
}'

Workflow Example

A typical workflow in this setup:

  1. Developer writes code: hc://enterprise/app/code/feature.rs
  2. Developer proposes config change: hc://enterprise/app/config/feature-flags.toml
  3. Ops Team reviews and approves config change, updates it
  4. Ops Team approves production deployment: hc://enterprise/deployment/production/app-v2
  5. Compliance Team audits all changes: reads all resources to verify compliance
  6. Ops Team executes deployment: deploy action on production resources
  7. Developer monitors pipeline: logs action on pipeline resources

Best Practices

1. Use Domain Hierarchy for Policy Inheritance

Structure your domains from least-privileged (root) to most-privileged (leaf) so that broader policies propagate down. This prevents accidental privilege escalation.

2. Prefer Deny Policies for Critical Resources

Use explicit deny policies with "deny": true for sensitive resources like production deployments or secrets. Deny policies take precedence over allow policies.

3. Leverage Macros for Dynamic Authorization

Use macros like $current_user(), $resource_owner(), and $current_time() to create flexible, context-aware policies that reduce duplication.

4. Choose the Right Evaluation Engine

  • Fixed: For exact matches (fastest, most secure)
  • Prefix: For hierarchical resources (e.g., hc://app/users/alice/)
  • Regex: For complex patterns (most flexible, higher computational cost)

Choose the simplest engine that meets your requirements - Fixed and Prefix have lower computational overhead than Regex.

5. Test Policies Before Production

Always test authorization policies with housectl authz can-i before deploying to production. Create test scenarios covering both allowed and denied cases.

6. Document Policy Intent

Use descriptive policy names and detailed descriptions. Future operators need to understand why a policy exists.

7. Regular Policy Audits

Periodically review policies with compliance team to ensure they still match business requirements and security posture.


Next Steps