Waiting for input...
Star SPIKE on GitHub

ADR-0025: Path Patterns as Key Namespaces with Regular Expression Matching

  • Status: accepted
  • Date: 2025-09-01
  • Tags: Security, Policy, Architecture, UX

Context

SPIKE uses path patterns in two primary contexts:

  1. Secret paths: Logical namespaces where secrets are stored (e.g., secrets/app/config)
  2. Policy patterns: Regular expressions used to match secret paths and SPIFFE IDs for access control

This creates potential confusion because:

  • Secret paths are not Unix filesystem paths: They are logical key namespaces that happen to use slash-separated hierarchical notation for familiarity
  • Policy patterns use regular expressions: Pattern matching in policies uses full regex syntax, not shell globs or simple wildcards
  • Documentation and examples mix conventions: Some examples used to incorrectly suggest Unix path semantics or glob patterns: we have fixed those in the recent documentation updates.

The current implementation correctly uses regular expressions for policy matching, but the terminology and documentation can mislead users into thinking they’re working with filesystem paths or simple glob patterns.

Decision

We establish the following architectural principles for path handling in SPIKE:

1. Secret Paths Are Key Namespaces

Secret paths represent logical key namespaces, not filesystem paths:

  • Paths SHOULD NOT start with a forward slash (/)
  • Paths are relative to the secrets engine mount point
  • The slash separator (/) is used purely for hierarchical organization and familiarity
  • Future versions MAY restrict trailing slashes for consistency

Examples:

  • ✅ Correct: secrets/app/config
  • ❌ Discouraged: /secrets/app/config

2. Policy Patterns Use Regular Expressions

All pattern matching in SPIKE policies uses regular expressions:

  • spiffeidPattern fields contain regex patterns, not globs
  • pathPattern fields contain regex patterns, not globs
  • Patterns are compiled using Go’s regexp.Compile()
  • For exact matches, patterns should include ^ (start) and $ (end) anchors

Examples:

  • ✅ Regex: ^secrets/app/.*$ (matches secrets/app/config, secrets/app/env, etc.)
  • ✅ Regex: ^spiffe://example\.org/service$ (exact match, escaped dots)
  • ❌ Not glob: secrets/app/* (this is NOT a valid SPIKE pattern)
  • ❌ Not glob: spiffe://example.org/service* (this is NOT a valid SPIKE pattern)

3. Terminology Clarification

  • Path: Refers to secret storage locations (key namespaces)
  • Pattern: Refers to regular expressions used in policies for matching
  • Route or Namespace: Alternative terms that may be used to emphasize the non-filesystem nature of paths

Consequences

Positive

  • Clear semantics: Users understand that paths are logical namespaces, not filesystem paths
  • Powerful matching: Regular expressions provide precise and flexible pattern matching
  • Consistent behavior: All pattern matching uses the same regex engine
  • Predictable results: Users can test patterns using standard regex tools
  • Security focused: Regex patterns allow for precise access control rules

Negative

  • Learning curve: Users familiar with shell globs must learn regex syntax
  • Complexity: Regular expressions can be more complex than simple wildcards
  • Potential errors: Incorrect regex patterns can be overly permissive or overly restrictive

Neutral

  • Documentation updates: All examples and documentation will use the correct terminology

Implementation Guidelines

For Secret Paths

  1. Validation: Paths must match ^[a-zA-Z0-9._\-/()?+*|[\]{}\\]+$
  2. Conventions: Should not start with /, should use / for hierarchy
  3. Examples: secrets/database/creds, config/app/production

For Policy Patterns

  1. Compilation: All patterns are compiled with regexp.Compile(pattern)
  2. Anchoring: Use ^ and $ for exact matches
  3. Escaping: Literal dots should be escaped as \.
  4. Testing: Patterns can be tested using Go’s regex tools or online regex testers

Documentation Standards

  • Always refer to policy “patterns” not “paths” when discussing regex matching
  • Include regex examples with proper escaping and anchoring
  • Clearly distinguish between secret paths (storage keys) and policy patterns (regex)

Examples

Secret Path Examples

secrets/app/config                # Application configuration
secrets/database/production/creds # Production database credentials  
config/service/tls                # TLS configuration
tenantA/projectX/env1/key         # Multi-tenant organization

Policy Pattern Examples

# Match all secrets under app namespace
pathPattern: "^secrets/app/.*$"

# Match specific database credentials
pathPattern: "^secrets/database/production$"

# Match numbered database instances
pathPattern: "^secrets/db-[0-9]+/creds$"

# Match SPIFFE ID with escaped dots
spiffeidPattern: "^spiffe://example\\.org/service$"

Migration Guide

For users transitioning from glob-style thinking:

Glob PatternSPIKE Regex PatternNotes
secrets/*^secrets/[^/]*$Single level only
secrets/**^secrets/.*$All levels
secrets/app*^secrets/app.*$Prefix match
secrets/db-?^secrets/db-.$Single character
secrets/db-[123]^secrets/db-[123]$Character class