Get icon
OutputValues icon
Switch icon
Log icon
Update icon
SlackIncomingWebhook icon
NewAddressTrigger icon

phpIPAM New Address Hostname Compliance Gate

Fire on new phpIPAM address assignments, alert Slack or auto-flag missing hostnames, and log the result for network engineering teams.

Categories
Infrastructure

An IP address handed out without a hostname is the start of a long-term mystery: six months later nobody can tell what is actually using it, whether it is safe to reclaim, or who to ask. phpIPAM records every new address as it is assigned, but it has no policy that catches a blank hostname the moment it happens, only a static record waiting for someone to notice. This blueprint watches a subnet in real time, checks every new address against a hostname-required policy, and can flag the gap for review automatically once you have explicitly said this flow is allowed to.

This blueprint was created by Mohit Jeswani.

How it works

  1. watch_subnet (io.kestra.plugin.phpipam.ipam.address.NewAddressTrigger) polls a subnet and fires one execution per newly detected address, deduplicated via the namespace KV store so each address fires exactly once.
  2. get_address (io.kestra.plugin.phpipam.ipam.address.Get) re-fetches the full address record by trigger.addressId, reading the authoritative current hostname rather than trusting the trigger's own summary. Read-only; nothing is changed here.
  3. evaluate (io.kestra.plugin.core.output.OutputValues) classifies the address as COMPLIANT, NONCOMPLIANT_AUTO_FLAG, NONCOMPLIANT_NEEDS_HUMAN, or PROBE_FAILED, folding confirm_flag_noncompliant into the non-compliant classification itself.
  4. route (io.kestra.plugin.core.flow.Switch):
    • COMPLIANT: logs the assigned hostname.
    • NONCOMPLIANT_AUTO_FLAG: runs io.kestra.plugin.phpipam.ipam.address.Update (the safe remediation, since writing a review note into the description changes no network configuration), then posts a Slack notice.
    • NONCOMPLIANT_NEEDS_HUMAN / PROBE_FAILED: posts a Slack alert instead of flagging.
  5. summary logs the severity, closing the governance cycle.
  6. errors alerts Slack if the flow itself fails, for example an expired app token.

What you get

  • A hostname policy enforced the moment an address is assigned, not discovered during a quarterly subnet audit.
  • A flag that only ever edits the address's description, never its hostname or network configuration, and only once you have explicitly set confirm_flag_noncompliant to allow it.
  • A real-time Slack alert naming the exact IP and subnet, so whoever owns that subnet can chase down the assignment while it is still fresh.

Who it's for

  • Network engineering and IPAM-owning teams who want a hostname-required policy enforced on every new address, not just checked during an occasional sweep.
  • Teams evaluating the phpIPAM plugin who want a worked example of address.NewAddressTrigger used as a standing event-driven compliance gate, distinct from this repo's existing phpIPAM blueprints, which scan a subnet on a schedule for capacity, stale reservations, or VLAN/VRF drift rather than reacting to a single new assignment in real time.

Why orchestrate this with Kestra

phpIPAM records a new address as it happens, but it has no hostname policy, no escalation, and no Slack integration of its own. Kestra keeps confirm_flag_noncompliant as an explicit flow input, turns a trigger detection into a policy decision, and keeps a full execution history of every address this flow has seen and what it did about it.

Prerequisites

  • A phpIPAM instance with the API enabled and an app token with read and update access to the watched subnet's addresses.
  • At least one address you can create without a hostname, to confirm the non-compliant path.
  • A Slack incoming webhook URL.

A local phpIPAM instance can be run via the official phpipam/phpipam-www and phpipam/phpipam-cron Docker images (with a MariaDB/MySQL container) for a fully local end-to-end test, no managed account required.

Secrets

  • PHPIPAM_APP_TOKEN: the phpIPAM API app token used by get_address and flag_address, and by the watch_subnet trigger. In Kestra OSS, provide it as the base64-encoded environment variable SECRET_PHPIPAM_APP_TOKEN.
  • SLACK_WEBHOOK_URL: used by all three Slack alert cases and the errors block. In Kestra OSS, provide it as the base64-encoded environment variable SECRET_SLACK_WEBHOOK_URL.

Inputs

Input Default Purpose
base_url http://localhost phpIPAM instance root URL
app_id myapp phpIPAM API application identifier
confirm_flag_noncompliant false Authorizes this flow to flag a missing hostname itself

The watched subnet is set directly on the watch_subnet trigger's subnetId, not as a flow input; see Pitfalls.

Outputs

  • {{ trigger.addressId }} / .ip / .hostname / .subnetId: the newly detected address, as NewAddressTrigger reports it.
  • {{ outputs.get_address.address }}: the full, re-fetched address record (hostname, description, owner, tag, mac, and more).
  • {{ outputs.evaluate.values.severity }}: COMPLIANT, NONCOMPLIANT_AUTO_FLAG, NONCOMPLIANT_NEEDS_HUMAN, or PROBE_FAILED.

Pitfalls

  • NewAddressTrigger's own Javadoc example uses io.kestra.core.tasks.log.Log for its companion Log task, which is not a real Kestra class; the correct, verified class is io.kestra.plugin.core.log.Log, used throughout this blueprint instead. Flagging this as a stale example in the plugin's own source, not something this blueprint itself does.
  • address.Update's field for the address description is named resourceDescription, not description, even though it updates phpIPAM's description field; verified directly against the task's source, since its own Javadoc example does not show this field at all.
  • subnetId, baseUrl, appId, and auth are trigger-level configuration, not flow inputs; a polling trigger has no per-execution input overrides the way a Schedule trigger does, so watching a different subnet means editing the trigger block directly.
  • NewAddressTrigger emits one execution per newly detected address, one at a time per poll cycle (the remaining new addresses in the same poll fire on the next cycle); a burst of address assignments produces a burst of flow executions and possible Slack alerts, not one aggregated message.

Quick start

  1. Add the PHPIPAM_APP_TOKEN and SLACK_WEBHOOK_URL secrets.
  2. Run phpIPAM locally via Docker, create a subnet, and set watch_subnet's subnetId to its real ID.
  3. Enable the trigger, assign a new address with a hostname set, and confirm log_compliant fires.
  4. Assign another address with no hostname and confirm_flag_noncompliant: false; confirm alert_noncompliant fires.
  5. Set confirm_flag_noncompliant: true, assign a third address with no hostname, and confirm flag_address writes the review note and alert_auto_flagged fires.

How to extend

  • Extend evaluate to also require a non-blank owner or description, not just a hostname, for a stricter asset-tracking policy.
  • Chain a lookup of the subnet's VLAN via io.kestra.plugin.phpipam.ipam.subnet.Get to route the Slack alert to the team that owns that VLAN instead of one shared channel.
  • Watch several subnets by deploying one copy of this flow per watch_subnet trigger configuration, one per subnet your team is responsible for.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.