Arista EOS Zero-Touch Provisioning (ZTP): A Practical Guide - 夜莺博客

Arista EOS Zero-Touch Provisioning (ZTP): A Practical Guide

Zero-Touch Provisioning (ZTP) is how Arista EOS switches deploy themselves: plug a new switch into the network, and it automatically discovers a provisioning server, downloads its configuration (and even a new EOS image), and comes up ready for production - no console session, no USB stick. For teams deploying dozens of leaf switches, ZTP turns hours of rack-and-config work into minutes. This guide explains how EOS ZTP works, what your DHCP server must provide, what the provisioning script does, and how to disable ZTP on devices you want to configure manually.

The value is not just speed. A ZTP-driven deployment is reproducible: every switch is built from the same versioned scripts and per-device configuration files, so a rebuild after a hardware replacement produces an identical device rather than one that differs in whatever the engineer typed differently that day.

How EOS ZTP Works

When an EOS switch boots without a startup configuration, it enters ZTP mode and acts as a DHCP client. The provisioning flow is:

  1. The switch sends DHCP requests on all front-panel interfaces.
  2. The DHCP server responds with a bootfile (DHCP option 67) or TFTP server (option 66).
  3. The switch downloads the bootfile - a shell script - via TFTP/HTTP/FTP.
  4. The script runs locally with root privileges; typical scripts fetch a startup-config and/or an EOS image, install them, and reboot.

Two conditions must hold for ZTP to run at all. First, the switch must have no saved startup configuration — as soon as a config is written to flash with write memory, ZTP is no longer triggered on subsequent boots. Second, ZTP must not have been explicitly disabled. A factory-fresh switch satisfies both, which is why unpacking a new leaf and cabling it to a provisioning VLAN is the entire physical workflow.

ZTP also has a time window. If no DHCP server answers within its discovery period, the switch gives up and drops to an empty prompt. That is a safety behaviour rather than a failure: an unconfigured switch that cannot find a provisioning server should not sit indefinitely waiting for one. It does mean that a switch racked before the DHCP scope is ready ends up needing a console session or a reload once the infrastructure is in place.

DHCP Server Configuration (ISC DHCP)

subnet 10.0.0.0 netmask 255.255.255.0 {
    range 10.0.0.100 10.0.0.200;
    option routers 10.0.0.1;
    option bootfile-name "http://10.0.0.5/ztp/ztp-script.sh";
    option tftp-server-name "10.0.0.5";
    option domain-name-servers 10.0.0.5;
}

Use the HTTP URL in bootfile-name - EOS ZTP scripts support http://, tftp:// and ftp:// URLs. You can also use a per-host statement to give each switch its own script based on MAC address.

The per-host form is what you need once switches are no longer identical. ISC DHCP matches on the client identifier, which for EOS is the interface MAC by default:

host leaf-01 {
    hardware ethernet 001c.73aa.bb01;
    fixed-address 10.0.0.101;
    option bootfile-name "http://10.0.0.5/ztp/scripts/leaf.sh";
    option tftp-server-name "10.0.0.5";
}
host spine-01 {
    hardware ethernet 001c.73aa.bb99;
    fixed-address 10.0.0.199;
    option bootfile-name "http://10.0.0.5/ztp/scripts/spine.sh";
}

Most servers can also match on the DHCP vendor class identifier (option 60) that the switch sends, which lets you hand every Arista device the same generic script while other vendor hardware gets something else from the same scope. Whichever mechanism you use, keep the DHCP scope on a dedicated provisioning VLAN that is not reachable from production hosts — a DHCP server that will hand a bootfile to anything that asks is a provisioning convenience and a security liability at the same time.

A Minimal ZTP Script

#!/bin/bash
# This script runs on the switch during ZTP
HOSTNAME=$(hostname)
echo "ZTP: provisioning $HOSTNAME"

# Download the startup configuration
curl -s -o /tmp/startup-config     "http://10.0.0.5/configs/${HOSTNAME}.conf" || exit 1

# Download a specific EOS image if needed
curl -s -o /tmp/eos.swi     "http://10.0.0.5/images/EOS-4.30.0F.swi" || exit 1

# Load the configuration into the running config
FastCli -p 15 -c "copy /tmp/startup-config running-config"
FastCli -p 15 -c "copy running-config startup-config"

# Install the image and reboot
FastCli -p 15 -c "install source /tmp/eos.swi"
sleep 5
FastCli -p 15 -c "reload now"

Notes: FastCli is the CLI automation tool available during ZTP; the script must be executable (chmod +x) on your HTTP server. Keep the script idempotent - it can run more than once.

Identity: Naming Each Switch Correctly

The single most common ZTP bug is a script that fetches the wrong configuration because it guessed the device name. Hostname at ZTP time is not the hostname you want — it is the factory default. Derive identity from something physical instead:

#!/bin/bash
# Identify the device from the serial number, not from hostname
SERIAL=$(FastCli -p 15 -c "show version" | awk -F': ' '/Serial number/{print $2}' | tr -d ' ')
MODEL=$(FastCli -p 15 -c "show version" | awk -F': ' '/^Model number/{print $2}' | awk '{print $1}')
echo "ZTP: model=${MODEL} serial=${SERIAL}"

curl -fsS -o /tmp/startup-config \
  "http://10.0.0.5/configs/${MODEL}/${SERIAL}.conf" || exit 2

FastCli -p 15 -c "copy /tmp/startup-config running-config"
FastCli -p 15 -c "copy running-config startup-config"

Serial-based naming means the configuration tree maps directly onto your asset inventory, which pays off three years later when a switch is replaced under RMA and the spare simply inherits the failed unit's file name. The alternative — MAC-address naming — works too, but MAC addresses are harder to read off a switch and get reused when a chassis is retired.

Use the exit codes deliberately. A script that returns 0 signals success; a non-zero exit aborts provisioning and leaves the switch at a prompt with a clear indication that something failed. Failing loudly at the curl step is much better than silently loading a stale or empty configuration.

Installing versus Pre-Loading an Image

Every ZTP script has a branching decision: does the switch download an EOS image, or just a configuration? Downloading a 1-2 GB image for every switch in a fleet moves a lot of data and adds several minutes per device, so the practical pattern is:

  • New hardware with the wrong factory image — download and install the target image, then reboot.
  • Hardware already on the target image — install the configuration only and skip the download entirely.

The script can detect which case it is in and take the cheap path when possible, which cuts fleet deployment time dramatically. Note the ordering: load the configuration before installing a new image only if the configuration is valid for both versions; otherwise install first and reload, then configure on the second pass. A second ZTP pass does not happen automatically once a startup configuration exists, so scripts that need two stages usually chain them explicitly by writing a marker file the second run checks for.

Verifying and Disabling ZTP

switch# show ztp status
switch(config)# no ztp
switch(config)# write memory

show ztp status displays the ZTP state (active/completed). Once a switch has a saved startup configuration, ZTP does not run on the next boot. To disable ZTP explicitly, use no ztp in config mode and save. You can also abort an in-progress ZTP by answering the on-console prompt, or by configuring the switch manually during the ZTP window.

Current EOS releases also expose an interactive ztp command from enable mode with subcommands for checking status, aborting an in-progress run and restarting provisioning — useful when a script failed halfway and you want another attempt without a full reload. Check ztp ? on your release to see which subcommands are present.

Disabling ZTP should be an explicit, recorded step in your build procedure, not a side effect of saving a config. A switch with ZTP left enabled and no configuration will happily try to provision itself from whatever DHCP server happens to answer, which is precisely the behaviour you do not want on a device that has been repurposed into a lab.

Security: ZTP Is a Trust Relationship

ZTP as described here is unauthenticated. TFTP has no authentication at all, and a plain HTTP bootfile is fetched without any verification that the script you receive is the script you intended. Three controls make the workflow defensible:

  • Isolate the provisioning network. Put the DHCP scope and the provisioning server on a dedicated VLAN with no route to production management. The trust relationship is then bounded by the VLAN.
  • Prefer HTTPS or a checksum gate. Serve scripts over TLS, or have the script verify a known SHA-256 of the configuration and image before applying them. A one-line sha256sum -c check turns a tampering risk into a hard failure.
  • Verify image signatures. EOS can verify signed image files; do this in the script before install source so a corrupted or substituted .swi never reaches the flash.

None of this replaces the need to pull the provisioning VLAN out of the design once the deployment window closes. Leaving a live ZTP scope on the network permanently means any device that boots without a config can ask for one — including a switch an attacker has just racked.

ZTP at Scale

ZTP is the last mile of a pipeline, not the whole pipeline. The pattern that scales looks like this:

  1. Source of truth. Serial number, role and rack position live in an IPAM or inventory system (NetBox is the usual choice).
  2. Template rendering. A generator reads the inventory and renders each device's configuration from a shared template, so the per-switch file differs only in the variables that genuinely differ.
  3. Publish. The rendered files land in the directory tree the ZTP server exports, under a path the script can predict.
  4. Provision. The switch boots, ZTP fetches its file, reloads, and appears in monitoring.
  5. Reconcile. Ansible or a similar tool verifies the running configuration against the source of truth and corrects drift.

The ZTP script stays small in this design: it identifies the device and pulls whatever the pipeline produced. All the intelligence lives upstream where it can be reviewed, tested and versioned. If you are building that pipeline, Ansible network automation inventory and playbook examples covers the inventory side, and Terraform for Cisco, Junos and Arista is the declarative alternative for the same problem. For pushing subsequent configuration changes, use config sessions with commit and rollback rather than editing startup-config directly — see Arista EOS configuration sessions.

Troubleshooting a Failed ZTP

Symptom Likely cause Fix
Switch never leaves "ZTP in progress" No DHCP response reached the switch Confirm the provisioning VLAN is trunked to the port and the scope is enabled
DHCP lease obtained, no config loaded Script URL wrong, or the HTTP server returns 404 Fetch the bootfile URL from another host; check file permissions and chmod +x
Script runs, config empty The per-device file did not exist and curl wrote an error page Use curl -f and a non-zero exit so the failure is loud
Wrong device's configuration applied Script keyed on hostname rather than serial or MAC Key the config path on show version serial number
Image install fails Disk space or a corrupted download Verify the checksum in the script; confirm free space on flash

Always test the script on a lab switch before racking a fleet. A broken ZTP script strands the switch at an empty prompt, and in a rack of forty leaves you plugging in a console cable forty times.

Best Practices

  • Version the ZTP scripts and configs - every deployment reproduces from the same tree (GitOps).
  • Name configs by serial number or MAC (show version / show inventory) for per-device uniqueness.
  • Combine with DHCP option 125 or per-host reservations to steer different switch models to different image versions.
  • Always test the script on a lab switch before racking a fleet - a broken ZTP script strands the switch at an empty prompt.
  • Log from the script to a file under /mnt/flash so a failed run leaves evidence on the device itself.
  • Make the script idempotent; a second execution should be harmless.
  • Disable ZTP explicitly on every fully provisioned switch and record it in the build checklist.

FAQ

Will ZTP overwrite an existing configuration? No. ZTP only runs when the switch boots without a startup configuration. Once a config is saved, the mechanism is inactive regardless of the DHCP scope.

Can I re-run ZTP deliberately? Yes, by clearing the startup configuration and reloading, or by using the interactive ztp commands where supported. Do it in a maintenance window — the switch will be unconfigured while it runs.

Does ZTP work over the management port? That depends on the release and configuration. Verify which interfaces issue DHCP requests on your EOS version before designing the provisioning VLAN around an assumption.

What if the switch is on the wrong EOS image for its config? Install the image first, reload, and let a second stage apply the configuration. A configuration is not version-independent, so ordering matters more than it appears.

Is ZTP only for Arista? No — the same model exists across vendors. Dell OS10 zero-touch deployment implements it as ZTD, and the ONIE installer used by whitebox switches covers a similar problem at the bootloader level.

Related: SONiC install via ONIE and Ansible network automation for Cisco, Juniper and Arista. If you use DHCP relay to reach the provisioning server from a routed segment, the helper-address mechanics are in Arista EOS DHCP relay.

原文链接:https://www.arista.com/en/support/toi/eos-4-24-2f/15231-ztp-zero-touch-provisioning