Skip to content

Create Your First Policy

This guide walks you through creating your first access policy from scratch. You’ll learn the policy syntax, test your policy, and deploy it to control data access.

A policy is a declarative rule that defines who can access what data, when, where, and why. Think of it as an access control list (ACL) written in a human-readable format that’s version-controlled alongside your code.

Instead of manually granting database access each time someone needs data, you write the rules once, and Alien Giraffe enforces them automatically.

Every policy follows a formal access control model with five key components:

  • Subjects - Which users or teams need access (e.g., team: customer-support)
  • Resources - Which data sources and datasets they can access (e.g., source: production-db, datasets: [customers])
  • Constraints - Time windows and duration limits (e.g., timeframe: business-hours, duration: 4h)
  • Channels - Access methods and operations allowed (e.g., name: sql, operation: rw)
  • Context - Purpose or justification (e.g., customer-support, incident-response)

Let’s create a simple policy that grants customer support team access to customer data.

Create a file policies/customer-support-access.yaml:

apiVersion: v1
kind: Policy
metadata:
name: customer-support-access
namespace: production
description: Allow customer support to view customer data during business hours
owner: customer-support-lead
spec:
# Subjects (who can access)
subjects:
- team: customer-support
# Resources (what data they can access)
resources:
- source: production-postgres
datasets:
- customers
- orders
- support_tickets
# Constraints (when they can access)
constraints:
- timeframe: business-hours # 9 AM - 5 PM local time
- duration: 4h # Sessions last 4 hours max
# Channels (where they can access from)
channels:
- name: sql
operation: rw
- name: web
operation: r
# Context (why they need access)
context:
- customer-support
- order-inquiries

Before deploying, validate your policy:

Terminal window
# Validate syntax and structure
a10e policy validate policies/customer-support-access.yaml
# Expected output:
# ✓ Syntax valid
# ✓ All referenced sources exist
# ✓ All referenced teams exist
# ✓ Policy ready to apply

When working with multiple policies, you can validate all policies and configurations at once to ensure they can be properly executed and applied:

Terminal window
# Compile and validate all policies in a directory
a10e policy compile policies/
# Expected output:
# Compiling policies...
# ✓ policies/customer-support-access.yaml
# ✓ policies/engineering-access.yaml
# ✓ policies/analytics-access.yaml
#
# Validating cross-policy dependencies...
# ✓ No conflicting policies detected
# ✓ All source references valid
# ✓ All team references valid
# ✓ All time schedules valid
#
# Summary: 3 policies compiled successfully
Terminal window
# Compile with verbose output for detailed validation
a10e policy compile policies/ --verbose
# Compile specific namespace
a10e policy compile policies/production/ --namespace production
# Compile and check for conflicts
a10e policy compile policies/ --check-conflicts
# Compile with JSON output for CI/CD integration
a10e policy compile policies/ --output json

Example compile output with issues:

Terminal window
a10e policy compile policies/
# Expected output with errors:
# Compiling policies...
# ✓ policies/customer-support-access.yaml
# ✗ policies/engineering-access.yaml
# Error: Referenced source 'staging-db' does not exist
# Line 48: source: staging-db
# ✗ policies/analytics-access.yaml
# Warning: Team 'legacy-team' has no members
# Line 44: team: legacy-team
#
# Validating cross-policy dependencies...
# ✗ Policy conflict detected:
# - customer-support-access (line 50)
# - engineering-access (line 62)
# Both grant access to 'customers' dataset with different permissions
#
# Summary: 1 policy compiled, 2 failed
# Exit code: 1

Test how the policy would behave without actually deploying it:

Terminal window
# Simulate an access request
a10e policy test customer-support-access \
--user alice@company.com \
--source production-postgres \
--dataset customers \
--dry-run
# Expected output:
# ✓ Access would be GRANTED
# Reason: User alice@company.com is member of team customer-support
# Duration: 4 hours
# Channels: sql, web-ui

Deploy the policy to production:

Terminal window
# Apply the policy
a10e policy apply -f policies/customer-support-access.yaml
# Verify it was created
a10e policy list
# View policy details
a10e policy get customer-support-access

Now test that a user can actually access data:

Terminal window
# Request access as a customer support team member
a10e access request \
--source production-postgres \
--datasets customers \
--purpose "customer-support" \
--duration 2h
# Expected output:
# ✓ Access granted
# Session ID: sess-abc123
# Expires: 2025-11-18 16:30:00 UTC
# Credentials saved to ~/.a10e/credentials

Congratulations! You’ve created and deployed your first policy.

Grant access to specific users:

spec:
subjects:
- user: alice@company.com
- user: bob@company.com
resources:
- source: analytics-db
datasets: [reports, dashboards]
constraints:
- duration: 8h
channels:
- name: sql
operation: rw

Grant read-only access for analytics work:

metadata:
name: analytics-read-access
spec:
subjects:
- team: data-analysts
- team: data-scientists
resources:
- source: analytics-replica # Read replica, not production
datasets: ["*"] # All datasets
permissions: [SELECT] # Read-only
constraints:
- timeframe: business-hours
- duration: 8h
channels:
- name: sql
operation: r
- name: api
operation: r
context:
- analytics
- reporting

Limit access to specific time windows:

metadata:
name: weekend-maintenance
spec:
subjects:
- team: sre
resources:
- source: production-db
datasets: [schema_migrations, system_config]
constraints:
- timeframe:
days: [saturday, sunday]
hours: [2-6] # 2 AM - 6 AM
- duration: 4h
channels:
- name: sql
operation: rw
context:
- maintenance
- database-upgrades

Require manager approval for sensitive data:

metadata:
name: pii-access-with-approval
spec:
subjects:
- team: engineering
resources:
- source: production-db
datasets: [users_pii, payment_info]
constraints:
- duration: 2h
channels:
- name: sql
operation: rw
context:
- debugging
- incident-response
approval:
required: true
approvers:
- role: manager
- role: data-privacy-officer
timeout: 1h # Approval expires after 1 hour

Fast access for critical incidents:

metadata:
name: emergency-production-access
spec:
subjects:
- team: on-call-engineers
resources:
- source: production-db
datasets: ["*"]
constraints:
- timeframe: "*" # 24/7 access
- duration: 1h # Short emergency sessions
channels:
- name: sql
operation: rw
context:
- incident-response
- outage
mfa:
required: true # Require multi-factor auth
audit:
level: verbose # Enhanced logging
notify:
immediate:
- slack: "#security-alerts"
- email: security@company.com

Grant access to multiple data sources in one policy:

spec:
resources:
- source: production-postgres
datasets: [customers, orders]
- source: production-redis
datasets: [sessions, cache]
- source: data-lake-s3
paths: [/analytics/*, /reports/*]

Apply conditions based on context:

spec:
conditions:
# Require VPN connection
vpnRequired: true
# Restrict to specific IP ranges
ipAllowlist:
- 203.0.113.0/24
- 198.51.100.42
# Require device compliance
deviceCompliance: true
# Time-based conditions
timeConditions:
- condition: weekend
requireApproval: true
- condition: after-hours
requireMFA: true

Automatically mask sensitive fields:

spec:
resources:
- source: production-db
datasets: [customers]
masking:
email: partial # j***@example.com
phone: last4 # ***-***-1234
ssn: blocked # Completely blocked

Allow users to extend sessions:

spec:
constraints:
- duration: 4h
maxExtensions: 2 # Can extend twice
extensionDuration: 2h # 2 hours each time
Terminal window
# List all policies
a10e policy list
# Filter by namespace
a10e policy list --namespace production
# Show detailed information
a10e policy list --detailed
Terminal window
# Edit the YAML file
vim policies/customer-support-access.yaml
# Apply changes
a10e policy apply -f policies/customer-support-access.yaml
# Or edit interactively
a10e policy edit customer-support-access
Terminal window
# See who's using this policy
a10e policy usage customer-support-access
# View access history
a10e policy audit customer-support-access --since 7d
Terminal window
# Delete a policy (requires confirmation)
a10e policy delete customer-support-access
# Force delete without confirmation
a10e policy delete customer-support-access --force
# Note: Active sessions are not affected by deletion
Terminal window
# Test if a user would be granted access
a10e policy test customer-support-access \
--user alice@company.com \
--source production-postgres \
--dataset customers
# Test with specific context
a10e policy test customer-support-access \
--user bob@company.com \
--source production-postgres \
--dataset customers \
--time "2025-11-18 14:00:00" \
--ip "203.0.113.42"
# Test why access was denied
a10e policy test customer-support-access \
--user charlie@company.com \
--explain

Simulate policy behavior over time:

Terminal window
# Simulate policy over a week
a10e policy simulate customer-support-access \
--start "2025-11-18" \
--end "2025-11-25" \
--users alice@company.com,bob@company.com
# Generates report showing:
# - When access would be granted/denied
# - Duration limits
# - Approval requirements

Organize policies in a Git repository:

policies/
├── README.md
├── production/
│ ├── customer-support-access.yaml
│ ├── engineering-access.yaml
│ └── analytics-access.yaml
├── staging/
│ └── developer-access.yaml
└── development/
└── unrestricted-access.yaml
  1. Create feature branch

    Terminal window
    git checkout -b feature/new-analytics-policy
  2. Write the policy

    Terminal window
    vim policies/production/analytics-access.yaml
  3. Validate and test

    Terminal window
    a10e policy validate policies/production/analytics-access.yaml
    a10e policy test analytics-access --dry-run
  4. Commit and push

    Terminal window
    git add policies/production/analytics-access.yaml
    git commit -m "Add analytics team access policy"
    git push origin feature/new-analytics-policy
  5. Create pull request

    • Request review from security team and data owners
    • Include test results in PR description
  6. Merge and deploy

    Terminal window
    git checkout main
    git merge feature/new-analytics-policy
    a10e policy apply -f policies/production/analytics-access.yaml

Automate policy validation in your CI pipeline:

.github/workflows/validate-policies.yml
name: Validate Policies
on: [pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Alien Giraffe CLI
run: pip install alien-giraffe
- name: Compile and validate all policies
run: |
# Compile all policies to validate syntax and cross-policy dependencies
a10e policy compile policies/ --check-conflicts --output json > validation-results.json
# Individual policy validation
for policy in policies/**/*.yaml; do
a10e policy validate $policy
done
- name: Test policies
run: |
for policy in policies/**/*.yaml; do
a10e policy test $(basename $policy .yaml) --dry-run
done
- name: Upload validation results
if: always()
uses: actions/upload-artifact@v3
with:
name: policy-validation-results
path: validation-results.json

Problem: User access denied despite policy

Terminal window
# Check policy is applied
a10e policy get customer-support-access
# Verify user is in the team
a10e user get alice@company.com --teams
# Test the specific scenario
a10e policy test customer-support-access \
--user alice@company.com \
--explain
# Check audit logs
a10e audit logs --user alice@company.com --since 1h

Problem: Policy conflicts

Terminal window
# Check for overlapping policies
a10e policy conflicts customer-support-access
# View policy evaluation order
a10e policy explain \
--user alice@company.com \
--source production-postgres

Problem: “Referenced source does not exist”

Terminal window
# List available sources
a10e source list
# Fix policy to reference existing source
# or create the missing source

Problem: “Invalid time format”

# Correct time formats:
constraints:
- timeframe: business-hours # Named range
- timeframe: "*" # Always
- timeframe:
days: [monday, friday] # Specific days
hours: [9-17] # Hour range
- timeframe: "2025-11-18T09:00:00Z" # Specific timestamp

Begin restrictive, then expand as needed:

# Start here
spec:
resources:
- source: analytics-replica # Read replica
datasets: [public_reports] # Specific dataset
permissions: [SELECT] # Read-only
# Not here
spec:
resources:
- source: production-db # Production!
datasets: ["*"] # Everything!
permissions: ["*"] # All permissions!

Choose descriptive policy names:

  • customer-support-business-hours-access
  • engineering-readonly-analytics
  • policy-1
  • test-policy

Include clear descriptions:

metadata:
description: |
Allows customer support team to view customer data during business
hours for resolving customer inquiries and support tickets.
Approved by: Security Team (2025-11-01)
Review date: 2026-11-01

Schedule policy audits:

Terminal window
# Review policy usage quarterly
a10e policy audit customer-support-access --since 90d
# Identify unused policies
a10e policy unused --since 30d
# Review access patterns
a10e policy analytics customer-support-access

Now that you have a policy in place:

  1. Set Up Identity Integration - Connect your identity provider for team management
  2. Configure Monitoring - Set up audit logging and alerts
  3. Policies Component Reference - Learn advanced policy features
  4. Constraints (Just-In-Time Access) - Understand temporary access workflows

For more examples: