Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Temporal HBAC Rules

A contractor needs SSH access to development servers for three months. The ops team needs access to all hosts during a four-hour maintenance window on Saturday night. An on-call engineer needs emergency access for 24 hours after an incident.

TemporalHbacRule wraps a standard HBAC rule with a validity window. The rule participates in evaluation only when the current time falls within that window.

Creating a temporal rule

A TemporalHbacRule takes an HbacRule and optional start/end timestamps (milliseconds since the Unix epoch):

#![allow(unused)]
fn main() {
use hbac_rs::prelude::*;

let now = current_timestamp_millis();
let three_months = 90 * 24 * 60 * 60 * 1000_u64;

let rule = HbacRule::builder("contractor_access")
    .user("contractor-jane")
    .host_group("dev-servers")
    .service_category_all()
    .enabled(true)
    .build()
    .unwrap();

let temporal = TemporalHbacRule::new(
    rule,
    Some(now),                 // active immediately
    Some(now + three_months),  // expires in 3 months
);

assert!(temporal.is_currently_valid());
}

Convenience constructors

For common patterns, named constructors save boilerplate:

#![allow(unused)]
fn main() {
use hbac_rs::prelude::*;

let rule = HbacRule::builder("emergency_admin")
    .user("alice")
    .host_category_all()
    .service_category_all()
    .enabled(true)
    .build()
    .unwrap();

// Valid for the next 24 hours from now
let emergency = TemporalHbacRule::valid_for_duration(
    rule,
    24 * 60 * 60 * 1000, // 24 hours in milliseconds
);
}

All constructors:

ConstructorDescription
new(rule, from, until)Full control over start and end
valid_for_duration(rule, ms)Starts now, expires after the given duration
valid_from(rule, timestamp)Starts at the given time, never expires
valid_until(rule, timestamp)Starts immediately, expires at the given time

Adding to a policy

Use add_temporal_rule on the policy:

#![allow(unused)]
fn main() {
use hbac_rs::prelude::*;

let mut policy = HbacPolicy::new();

// ... create temporal rule as above ...

policy.add_temporal_rule(temporal);
}

Temporal rules coexist with permanent rules in the same policy.

Evaluating at a specific time

Use evaluate_at to evaluate against a specific timestamp instead of “now”:

#![allow(unused)]
fn main() {
use hbac_rs::prelude::*;

let now = current_timestamp_millis();
let request = HbacRequest::new(
    Subject::new("contractor-jane"),
    "dev-01.example.com",
    "sshd",
);

// Evaluate at the current time
let result = policy.evaluate_at(&request, now);
assert!(result.is_allowed());

// Evaluate after the rule has expired
let four_months = 120 * 24 * 60 * 60 * 1000_u64;
let result = policy.evaluate_at(&request, now + four_months);
assert!(result.is_denied());
}

There is also evaluate_detailed_at for debugging.

Checking validity

Query whether a temporal rule is active at a given time:

#![allow(unused)]
fn main() {
use hbac_rs::prelude::*;

let now = current_timestamp_millis();

// Is the rule active right now?
assert!(temporal.is_currently_valid());

// Is it active at a specific time?
assert!(temporal.is_valid_at(now + 1000));

// Get the underlying HbacRule only if currently valid
if let Some(rule) = temporal.current_rule() {
    println!("Active rule: {}", rule.name);
}

// Get the rule at a specific time
if let Some(rule) = temporal.rule_at(now + 1000) {
    println!("Rule active at time: {}", rule.name);
}
}

Maintenance window example

Grant the ops team access to all hosts for a four-hour maintenance window:

#![allow(unused)]
fn main() {
use hbac_rs::prelude::*;

let window_start = 1737338400_000_u64; // 2025-01-20 02:00 UTC
let window_end   = 1737352800_000_u64; // 2025-01-20 06:00 UTC

let rule = HbacRule::builder("maintenance_window")
    .user_group("ops-team")
    .host_category_all()
    .service_category_all()
    .enabled(true)
    .build()
    .unwrap();

let temporal = TemporalHbacRule::new(rule, Some(window_start), Some(window_end));

let mut policy = HbacPolicy::new();
policy.add_temporal_rule(temporal);

let ops_user = Subject::new("ops-alice");
let request = HbacRequest::new(ops_user, "prod-db-01.example.com", "sshd");

// During the window: allowed
let mid_window = window_start + 2 * 60 * 60 * 1000;
assert!(policy.evaluate_at(&request, mid_window).is_allowed());

// After the window: denied
assert!(policy.evaluate_at(&request, window_end + 1).is_denied());
}

Emergency access example

Grant immediate access that auto-expires after 24 hours:

#![allow(unused)]
fn main() {
use hbac_rs::prelude::*;

let rule = HbacRule::builder("incident_response")
    .user("oncall-bob")
    .host_category_all()
    .service_category_all()
    .enabled(true)
    .build()
    .unwrap();

let temporal = TemporalHbacRule::valid_for_duration(
    rule,
    24 * 60 * 60 * 1000, // 24 hours
);

policy.add_temporal_rule(temporal);
}

Recurring schedules

TemporalHbacRule models a single time window. Recurring schedules (e.g., “business hours only, Monday through Friday”) are not built in. To implement recurring access, manage the temporal rules yourself:

#![allow(unused)]
fn main() {
use hbac_rs::prelude::*;

fn create_business_hours_rule(date_start_ms: u64, date_end_ms: u64) -> TemporalHbacRule {
    let rule = HbacRule::builder("business_hours")
        .user_category_all()
        .host_category_all()
        .service("internal-app")
        .enabled(true)
        .build()
        .unwrap();

    TemporalHbacRule::new(rule, Some(date_start_ms), Some(date_end_ms))
}

// Generate rules for each business day and add them to the policy
}

Best practices

  • Always set an expiration. Open-ended temporary access defeats the purpose.
  • Use UTC timestamps internally. Convert to local time only for display.
  • Build in a small grace period to account for clock skew between hosts.
  • Log temporal grants and expirations for your audit trail.
  • Periodically remove expired temporal rules to keep the policy lean.

Next steps

Your organization now has HBAC for host access and RBAC for application permissions. The final HBAC chapter shows how to combine them into a unified policy where both must agree before granting access.

See Policy Composition.