Skip to content

ACI Stateful Contracts

Estimated time to read: 7 minutes

  • Originally Written: March, 2024

Info

This post uses the Nexus as Code (NaC) project which makes it very easy to configure ACI fabrics through a YAML file. More details and examples can be found at https://developer.cisco.com/docs/nexus-as-code/#!aci-introduction

ACI contracts permit communication between groups of endpoints (EPGs or ESGs). Think of them like an access control list which permits traffic between a source and destination subnet on a specific port.

A contract contains one or more subjects, each subject contains one or more filters, and each filter contains one or more entries. This provides a flexible way to build access policies.

When building contracts you may have seen the Stateful checkbox as part of the filter entries. This is not the equivalent of a stateful firewall which performs connection tracking and other activities. In ACI it's simply a check to ensure the ACK flag of a TCP packet is set in the direction of the consumer to the provider.

Info

To learn more about stateful firewalls see the A bit about stateful firewalls and intrusion prevention post

The example setup

Here's an example showing the two different scenarios, one with the stateful checkbox set to false and one with it set to true.

netcat is used to send some traffic between the endpoints and the following is the Nexus as Code YAML file used to configure the ACI fabric for these scenarios.

Configuration
---
apic:
  tenants:
    - name: conmurph-01
      managed: false

      vrfs:
      - name: conmurph-01.vrf-02

      bridge_domains:
        - name: 192.168.101.0_24
          vrf: conmurph-01.vrf-02
          subnets:
            - ip: 192.168.101.254/24

        - name: 192.168.102.0_24
          vrf: conmurph-01.vrf-02
          subnets:
            - ip: 192.168.102.254/24

      application_profiles:
        - name: network-segments
          managed: false
          endpoint_groups:
            - name: 192.168.101.0_24
              alias: consumer
              bridge_domain: 192.168.101.0_24
              vmware_vmm_domains:
                - name: hx-dev-01-vds-01
              contracts:
                consumers:
                  - permit_to_192.168.102.0

            - name: 192.168.102.0_24
              alias: provider
              bridge_domain: 192.168.102.0_24
              vmware_vmm_domains:
                - name: hx-dev-01-vds-01
              contracts:
                providers:
                  - permit_to_192.168.102.0

      filters:
        - name: tcp-filters
          entries:
            - name: tcp-src-any-to-any-dst
              ethertype: ip
              protocol: tcp
              stateful: false

      contracts:

        - name: permit_to_192.168.102.0
          scope: tenant
          subjects:
            - name: permit-tcp
              filters:
                - filter: tcp-filters
  • On the provider endpoint or server side: sudo netcat -l 8080 <<< _hello_
  • On the consumer endpoint or client side: sudo netcat 192.168.102.10 8080

If everything is setup correctly you should see the message, _hello_, on the consumer endpoint.

Connections both ways

Here is the Wireshark output showing the successful flow between source and destination taken from the provider side.

You can also run the connection in reverse i.e. the provider endpoint is connecting to the the server running on the consumer endpoint

Again here is the Wireshark output showing the successful flow between source and destination taken from the consumer side

In the simplified diagram below you can see a TCP three-way handshake where the client initiates a connection to the server. The SYN flag is set in the first leg. The server sends a return packet with the SYN and ACK flags set and finally the client sends an ACK.

sequenceDiagram
    participant C as Client <br><br> 192.168.101.10
    participant P as Server <br><br> 192.168.102.20
    C->>P: SYN
    Note over C,P: TCP three-way handshake starts
    P->>C: SYN-ACK
    C->>P: ACK
    Note over C,P: TCP connection established

Looking at the fourth packet in the Wireshark output you can see the PSH (push) and ACK flags set. Once the TCP session is established (the first three packets), the data (_hello_) is sent from the server/provider.

The TCP PSH flag

The PSH (push) flag is used to tell the receiving end that the data should be pushed up to the receiving application immediately without waiting for the buffer to fill up to its usual threshold.

An ACK is received from the consumer/client and the TCP session is closed (FIN, ACK).

Note that the ACK bit is present in all packets except for the initial connection packet which only has a SYN.

Single direction

Now have a look what happens when the stateful flag in the ACI contract is set to true. You can reuse the Nexus as Code configuration above and just update the stateful flag.

In this example no TCP connection can be established from the provider to the consumer. As you can see from the provider side screenshot below, the first packet is sent from the provider side with only the SYN flag set. This is dropped by the ACI fabric and the connection is not established. You can see the retransmissions in Wireshark.

Output from the consumer endpoint showing no packets are received.

Finally, you can confirm on the ACI fabric by looking at the dropped flows and packets which can be found under the Tenant -> Operational tabs. Notice that the source port matches the source port found in the Wireshark outputs.

Summary

As you've seen in the different scenarios, the stateful checkbox in ACI is simply a check to ensure the ACK flag of a TCP packet is set in the direction of the consumer to the provider.

Comments