eqixiacEquinix Infrastructure as Code

Network functions with Network Edge

A virtual firewall and router pair in a metro without a cage, chained between the internet, a Cloud Router and the clouds.

Scenario#

A company has no colocation footprint in Frankfurt and needs three functions there: a firewall between its Azure and AWS environments, an IPsec termination point for branch offices, and internet breakout. Network Edge provides the devices as virtual appliances, and Fabric connects them.

When Network Edge fits#

SituationNetwork EdgePhysical device in a cage
No cage in the metroYesNeeds space, power, cross connects, shipping, hands
Time to first packetMinutes to hours after the orderWeeks
ThroughputUp to the licensed throughput of the device typeHardware limit
Hardware features: specific optics, crypto acceleration, very high throughputNoYes
Cost shapeMonthly, by cores, throughput and licenceCapital plus colocation
Vendor operating modelThe same software as the physical productSame

Architecture#

Metro FR (Frankfurt), no cageInternet Accessbreakout, VPN underlayFirewall, primaryNetwork EdgeFirewall, secondarydiverse hardwareFabric Cloud RouterAzure West EuropeAWS eu-central-1Branch officesIPsecIPsecIP_VCIP_VCIP_VCIP_VC
A redundant firewall pair on Network Edge sits between the Cloud Router, the internet and the branch VPNs. All cloud-to-cloud traffic is routed through the firewalls.

Traffic can be forced through the firewall in two ways. In the design shown here, the clouds attach to the Cloud Router, and the router's routes for inter-cloud prefixes point at the firewall. In the other design the clouds attach to firewall interfaces and there is no Cloud Router, which needs fewer components for two clouds and uses one device interface per cloud.

Step 1: check the catalog and the prerequisites#

Java
import com.eqixiac.equinix.core.enums.MetroCode;
import com.eqixiac.equinix.networkedge.model.DeviceType;

for (DeviceType type : networkEdge.devices().listDeviceTypes()) {
    System.out.println(type.getDeviceTypeCode() + " " + type.getVendor() + " " + type.getName());
}
networkEdge.setup().listAccounts(MetroCode.FR)
    .forEach(a -> System.out.println(a.getAccountNumber() + " " + a.getAccountName()));

Pick the device type code, a software version, a core count and a licence mode that the type lists together. Network Edge defines no dry run for a device create, so the catalog and the pricing call are the checks available before the order.

Step 2: ACL template and SSH key#

An ACL template restricts the source addresses that can reach the management interface of a device. Create the ACL template and register the SSH key first, in the Network Edge portal or with aclTemplates().define(...) and publicKeys().define(...), and pass their identifiers to the device builder.

Step 3: the firewall pair#

Java
import com.eqixiac.equinix.core.enums.BandwidthUnit;
import com.eqixiac.equinix.networkedge.enums.DeviceManagementType;
import com.eqixiac.equinix.networkedge.enums.LicenseType;
import com.eqixiac.equinix.networkedge.model.Device;

Device primary = networkEdge.devices().define("fw-fr-01")
    .withDeviceTypeCode("FTD")                          // example code; take it from listDeviceTypes()
    .withMetroCode(MetroCode.FR)
    .withAccountNumber("123456")
    .withDeviceManagementType(DeviceManagementType.SELF_CONFIGURED)
    .withLicenseMode(LicenseType.SUB)
    .withPackageCode("STD")
    .withVersion("7.2.0")
    .withCore(4)
    .withThroughput(1)
    .withThroughputUnit(BandwidthUnit.GBPS)
    .withInterfaceCount(10)
    .withAclTemplateUuid("acl-template-uuid")
    .withNewSSHUser("netops", "change-me-at-first-login")
    .withNotification("noc@example.com")
    .agreeToOrderTerms()
    .create();

Device secondary = networkEdge.devices().define("fw-fr-02")
    .withDeviceTypeCode("FTD")
    .withMetroCode(MetroCode.FR)
    .withAccountNumber("123456")
    .withDeviceManagementType(DeviceManagementType.SELF_CONFIGURED)
    .withLicenseMode(LicenseType.SUB)
    .withPackageCode("STD")
    .withVersion("7.2.0")
    .withCore(4)
    .withThroughput(1)
    .withThroughputUnit(BandwidthUnit.GBPS)
    .withInterfaceCount(10)
    .withAclTemplateUuid("acl-template-uuid")
    .withExistingSSHUser("netops")
    .withDiverseFromDevice(primary)                     // place on different hardware
    .withNotification("noc@example.com")
    .agreeToOrderTerms()
    .create();

Network Edge also offers a managed redundant pair and clustering through withSecondary(...) and withClusterDetails(...), for device types that support them. Two independent devices with withDiverseFromDevice leave the high-availability protocol to the vendor software.

A device takes minutes to become ready. Before connecting it, poll networkEdge.devices().getByUuid(uuid).getStatus() until it reports a provisioned state.

Step 4: connect the devices to the Cloud Router#

Java
import com.eqixiac.equinix.fabric.enums.ConnectionType;
import com.eqixiac.equinix.fabric.enums.InterfaceType;
import com.eqixiac.equinix.fabric.model.CloudRouter;
import com.eqixiac.equinix.fabric.model.Connection;

CloudRouter router = fabric.cloudRouters().getByUuid(routerUuid);

for (Device firewall : List.of(primary, secondary)) {
    Connection toRouter = fabric.connections().define(ConnectionType.IP_VC)
        .name(firewall.getName() + "-to-fcr-fr")
        .bandwidth(1000)
        .aSideAccessPointCloudRouter(router)
        .zSideAccessPoint(firewall.getUuid(), null, InterfaceType.NETWORK, 5)     // device, link protocol, type, interface id
        .notification("noc@example.com")
        .create();
}

Run the first of these with dryRun() to confirm the interface and the connection type before creating both. Then add DIRECT and BGP protocols on each connection, as in Cloud Routers and routing. The firewall-side BGP configuration is done on the device.

Step 5: steer cloud-to-cloud traffic through the firewall#

Without further configuration the Cloud Router routes AWS and Azure prefixes directly to each other. The following three steps send that traffic through the firewall.

  1. On the AWS and Azure connections, attach an outbound route filter that denies the other cloud's prefixes. The clouds then do not learn each other's routes from the router directly.
  2. The firewalls advertise a summary that covers both clouds, or a default route, to the router over their BGP sessions.
  3. The clouds follow that summary to the firewall, which inspects and routes back to the router with the specific prefix.
Java
import com.eqixiac.equinix.fabric.enums.Direction;
import com.eqixiac.equinix.fabric.enums.RouteFilterAction;
import com.eqixiac.equinix.fabric.enums.RouteFilterType;
import com.eqixiac.equinix.fabric.model.RouteFilter;

RouteFilter toAws = fabric.routeFilters().define()
    .ofType(RouteFilterType.BGP_IPv4_PREFIX_FILTER)
    .name("to-aws-no-azure-specifics")
    .notMatchedRuleAction(RouteFilterAction.PERMIT)
    .create();

fabric.routeFilterRules().define(toAws.getUuid())
    .name("deny-azure-vnets")
    .prefix("10.20.0.0/16")
    .prefixMatch("orlonger")
    .action(RouteFilterAction.DENY)
    .create();

fabric.connections().attachRouteFilter("uuid-of-fcr-fr-to-aws", toAws.getUuid(), Direction.OUTBOUND);

Verify with searchAdvertisedRoutes on the AWS connection that the Azure prefixes are gone and the firewall's summary is present. Then test with a flow between the clouds and check the firewall's session table. If the filter is missing, traffic between the clouds bypasses the firewall and still reaches its destination, so a missing filter produces no visible fault.

Step 6: internet breakout and VPN#

Internet Access attaches to a device interface as a Fabric connection to the Internet Access service, see Internet Access. Branch IPsec tunnels terminate on the firewall's public addresses. For an Equinix-configured device, networkEdge.vpns().define(...) configures the tunnel. For a self-configured device, the tunnel is configured in the vendor software.

Operations#

Java
import com.eqixiac.equinix.networkedge.model.Backup;

for (Device device : networkEdge.devices().list()) {
    System.out.println(device.getUuid() + " " + device.getName() + " " + device.getStatus());
}
for (Backup backup : networkEdge.backups().list(primary.getUuid())) {
    System.out.println(backup.getName() + " feasible: "
        + networkEdge.backups().checkRestoreFeasibility(backup.getUuid(), primary.getUuid()).getRestoreAllowedAfterDeleteOrEdit());
}
  • Take a backup before each change and check its restore feasibility, because a backup can become unrestorable after interfaces were deleted or edited.
  • Plan software upgrades through the vendor's process. listUpgradeHistory and listReloadHistory show what happened to a device.
  • The MCP tool ne_list_devices gives an agent the inventory.

Trade-offs#

  • A device forwards up to its licensed throughput and drops or queues traffic above it. The licence should cover the peak rate. The device's own counters show the drops, which the Fabric connection metrics do not.
  • A virtual device shares hardware with other tenants, which the rules for a regulated workload may not permit.
  • The firewall adds a hop that can fail. The design has to state what happens when both firewalls are down: either traffic between the clouds stops, or it flows uninspected.