Manage HTTP container path rules with Terraform

A path rule applies basic authentication, rate limiting, or IP allow / deny lists to a specific URL prefix on an HTTP container. The longest matching path wins per request — a rule on /api/admin takes precedence over the container's defaults for requests that start with /api/admin.

Updated 1 Jul 20263 min read

A path rule applies basic authentication, rate limiting, or IP allow / deny lists to a specific URL prefix on an HTTP container. The longest matching path wins per request — a rule on /api/admin takes precedence over the container's defaults for requests that start with /api/admin.

Path rules are child resources of an HTTP container, scoped via container_id. You manage the parent container separately (bahriya_container) and reference its id.

Required fields

FieldTypeDescription
container_idstringUUID of the HTTP container the rule attaches to. Changing this replaces the rule.
handlestringA unique identifier for the rule on the container (DNS-1123 compliant: lowercase, alphanumeric, hyphens). Changing this replaces the rule.
pathstringURL path prefix the rule applies to. Must start with /.

Optional fields

FieldTypeDescription
priorityintegerTiebreaker for equal-length prefix matches. Higher wins. Defaults to 0.
ratelimitingenabledboolTurn on per-IP rate limiting on this path.
ratelimitingrequestspersecondintegerMax requests per second per IP.
ratelimitingrequestsperminuteintegerMax requests per minute per IP.
ratelimitingrequestsperhourintegerMax requests per hour per IP.
ipwhitelistenabledboolRestrict access to the listed IPs.
ipwhitelistlist(string)IP addresses or CIDR ranges.
ipblacklistenabledboolBlock the listed IPs.
ipblacklistlist(string)IP addresses or CIDR ranges.
basicauthenabledboolEnable HTTP basic authentication on this path.
basicauthcredentialslist(object)List of { username, password } pairs accepted on this path. Passwords are sensitive.

At least one control (basic auth, rate limiting, IP allow-list, or IP deny-list) must be enabled — the apply step fails otherwise.

Example

resource "bahriya_container" "api" {
  handle  = "my-api"
  name    = "Public API"
  type    = "http"
  image   = "ghcr.io/myorg/api:1.0.0"
  project = bahriya_project.production.id
 
  cpu              = "500"
  memory           = "512"
  containerport    = "8080"
  healthcheckpath  = "/health"
  activeregions    = ["falkenstein-1"]
}
 
resource "bahriya_path_rule" "admin_area" {
  container_id = bahriya_container.api.id
  handle       = "admin-area"
  path         = "/api/admin"
  priority     = 100
 
  basicauthenabled = true
  basicauthcredentials = [
    {
      username = "alice"
      password = var.admin_password
    },
  ]
 
  ipwhitelistenabled = true
  ipwhitelist        = ["10.0.0.0/8"]
}
 
resource "bahriya_path_rule" "webhook" {
  container_id = bahriya_container.api.id
  handle       = "webhook"
  path         = "/webhook"
 
  ratelimitingenabled         = true
  ratelimitingrequestsperminute = 60
  ratelimitingrequestsperhour   = 1000
}

How matching works

Per request, the longest matching path prefix wins. If two rules tie on path length, the rule with the higher priority wins. A rule's controls fully override the container-wide settings for the same control type on that path — there is no merge.

For example, a container with rate limiting at 1000 / minute and a path rule with rate limiting at 60 / minute caps the rule's path at 60 / minute (not 1000, not 1060).

Passwords and drift

The API stores basic auth passwords encrypted and never returns the plaintext on subsequent reads — it echoes the sentinel value-hidden-for-your-own-good instead. The provider treats the sentinel as a no-op so re-applying without changing the password does not show as drift. To rotate a password, update the value in your Terraform config and run terraform apply.

Importing an existing rule

To bring an existing path rule under Terraform management, import it with the composite id <container_id>:<path_rule_id>:

terraform import bahriya_path_rule.admin_area \
  c0ffee00-aaaa-bbbb-cccc-000000000001:dd0ffee0-1111-2222-3333-444444444444

After import the basic auth password starts as the sentinel — the next apply with a real password rotates it.

Pricing

Each enabled control on each rule bills at the same per-region rate as the corresponding container-wide control. A rule with both rate limiting and basic authentication enabled counts as two control instances per region; combined with the container-wide controls, the total per-region billed instances equals (container-wide-enabled ? 1 : 0) + N path rules with that plugin enabled.

See also