How to configure network ACLs

Note

Network ACLs are available for the OVN NIC type, the OVN network and the Bridge network (with some exceptions; see Bridge limitations).

Network ACLs define rules for controlling traffic:

  • Between instances connected to the same network

  • To and from other networks

Network ACLs can be assigned directly to the NIC of an instance, or to a network. When assigned to a network, the ACL applies indirectly to all NICs connected to that network.

When an ACL is assigned to multiple instance NICs, either directly or indirectly, those NICs form a logical port group. You can use the name of that ACL to refer to that group in the traffic rules of other ACLs. For more information, see: Subject name selectors (ACL groups).

List ACLs

To list all ACLs, run:

lxc network acl list

Show an ACL

To show details about a specific ACL, run:

lxc network acl show <ACL-name>

Example:

lxc network acl show my-acl

Create an ACL

Name requirements

Network ACL names must meet the following requirements:

  • Must be between 1 and 63 characters long.

  • Can contain only ASCII letters (a–z, A–Z), numbers (0–9), and dashes (-).

  • Cannot begin with a digit or a dash.

  • Cannot end with a dash.

Instructions

To create an ACL, run:

lxc network acl create <ACL-name> [user.KEY=value ...]
  • You must provide an ACL name that meets the Name requirements.

  • You can optionally provide one or more custom user keys to store metadata or other information.

ACLs have no rules upon creation via command line, so as a next step, add rules to the ACL. You can also edit the ACL configuration, or assign the ACL to a network or NIC.

Another way to create ACLs from the command line is to provide a YAML configuration file:

lxc network acl create <ACL-name> < <filename.yaml>

This file can include any other ACL properties, including the egress and ingress properties for defining ACL rules. See the second example in the set below.

Examples

Create an ACL with the name my-acl and an optional custom user key:

lxc network acl create my-acl user.my-key=my-value

Create an ACL using a YAML configuration file:

First, create a file named config.yaml with the following content:

description: Allow web traffic from internal network
config:
  user.owner: devops
ingress:
  - action: allow
    description: Allow HTTP/HTTPS from internal
    protocol: tcp
    source: "@internal"
    destination_port: "80,443"
    state: enabled

Note that the custom user keys are stored under the config property.

The following command creates an ACL from that file’s configuration:

lxc network acl create my-acl < config.yaml

ACL properties

ACLs have the following properties:

config

User-provided free-form key/value pairs

Key: config
Type:

string set

Required:

no

The only supported keys are user.* custom keys.

description

Description of the network ACL

Key: description
Type:

string

Required:

no

egress

Egress traffic rules

Key: egress
Type:

rule list

Required:

no

ingress

Ingress traffic rules

Key: ingress
Type:

rule list

Required:

no

name

Unique name of the network ACL in the project

Key: name
Type:

string

Required:

yes

ACL rules

Each ACL contains two lists of rules:

  • Rules in the egress list apply to outbound traffic from the NIC.

  • Rules in the ingress list apply to inbound traffic to the NIC.

For both egress and ingress, the rule configuration looks like this:

action: <allow|reject|drop>
description: <description>
destination: <destination-IP-range>
destination_port: <destination-port-number>
icmp_code: <ICMP-code>
icmp_type: <ICMP-type>
protocol: <icmp4|icmp6|tcp|udp>
source: <source-of-traffic>
source_port: <source-port-number>
state: <enabled|disabled|logged>
  • The action property is required.

  • The state property defaults to "enabled" if unset.

  • The source and destination properties can be specified as one or more CIDR blocks, IP ranges, or selectors. If left empty, they match any source or destination. Comma-separate multiple values.

  • If the protocol is unset, it matches any protocol.

  • The "destination_port" and "source_port" properties and "icmp_code" and "icmp_type" properties are mutually exclusive sets. Although both sets are shown in the same rule above to demonstrate the syntax, they never appear together in practice.

    • The "destination_port" and "source_port" properties are only available when the "protocol" for the rule is "tcp" or "udp".

    • The "icmp_code" and "icmp_type" properties are only available when the "protocol" is "icmp4" or "icmp6".

  • The "state" is "enabled" by default. The "logged" value is used to log traffic to a rule.

For more information, see: Rule properties.

Add a rule

To add a rule to an ACL, run:

lxc network acl rule add <ACL-name> <egress|ingress> [properties...]

Example

Add an egress rule with an action of drop to my-acl:

lxc network acl rule add my-acl egress action=drop

Remove a rule

To remove a rule from an ACL, run:

lxc network acl rule remove <ACL-name> <egress|ingress> [properties...]

You must either specify all properties needed to uniquely identify a rule or add --force to the command to delete all matching rules.

Edit a rule

You cannot edit a rule directly. Instead, you must edit the full ACL, which contains the egress and ingress lists.

Rule ordering and application of actions

ACL rules are defined as lists, but their order within the list does not affect how they are applied.

LXD automatically prioritizes rules based on the action property, in the following order:

When you assign multiple ACLs to a NIC, you do not need to coordinate rule order across them. As soon as a rule matches, its action is applied and no further rules are evaluated.

Rule properties

ACL rules have the following properties:

action

Action to take for matching traffic

Key: action
Type:

string

Required:

yes

Possible values are allow, reject, and drop.

description

Description of the rule

Key: description
Type:

string

Required:

no

destination

Comma-separated list of destinations

Key: destination
Type:

string

Required:

no

Destinations can be specified as CIDR or IP ranges, destination subject name selectors (for egress rules), or be left empty for any.

destination_port

Destination ports or port ranges

Key: destination_port
Type:

string

Required:

no

This option is valid only if the protocol is udp or tcp. Specify a comma-separated list of ports or port ranges (start-end inclusive), or leave the value empty for any.

icmp_code

ICMP message code

Key: icmp_code
Type:

string

Required:

no

This option is valid only if the protocol is icmp4 or icmp6. Specify the ICMP code number, or leave the value empty for any.

icmp_type

Type of ICMP message

Key: icmp_type
Type:

string

Required:

no

This option is valid only if the protocol is icmp4 or icmp6. Specify the ICMP type number, or leave the value empty for any.

protocol

Protocol to match

Key: protocol
Type:

string

Required:

no

Possible values are icmp4, icmp6, tcp, and udp. Leave the value empty to match any protocol.

source

Comma-separated list of sources

Key: source
Type:

string

Required:

no

Sources can be specified as CIDR or IP ranges, source subject name selectors (for ingress rules), or be left empty for any.

source_port

Source ports or port ranges

Key: source_port
Type:

string

Required:

no

This option is valid only if the protocol is udp or tcp. Specify a comma-separated list of ports or port ranges (start-end inclusive), or leave the value empty for any.

state

State of the rule

Key: state
Type:

string

Default:

enabled

Required:

yes

Possible values are enabled, disabled, and logged.

Use selectors in rules

Note

This feature is supported only for the OVN NIC type and the OVN network.

In ACL rules, the source and destination properties support using selectors instead of CIDR blocks or IP ranges. You can only use selectors in the source of ingress rules, and in the destination of egress rules.

Using selectors allows you to define rules for groups of instances instead of managing lists of IP addresses or subnets manually.

There are two types of selectors:

  • subject name selectors (ACL groups)

  • network subject selectors

Subject name selectors (ACL groups)

When an ACL is assigned to multiple instance NICs, either directly or through their networks, those NICs form a logical port group. You can use the name of that ACL as a subject name selector to refer to that group in the egress and ingress lists of other ACLs.

For example, if you have an ACL with the name my-acl, you can specify the group of instance NICs that are assigned this ACL as an egress or ingress rule’s source by setting source to my-acl.

Network subject selectors

Use network subject selectors to define rules based on the network that the traffic is coming from or going to.

All network subject selectors begin with the @ symbol. There are two special network subject selectors called @internal and @external. They represent the network’s local and external traffic, respectively.

Here’s an example ACL rule (in YAML) that allows all internal traffic with the specified destination port:

ingress:
  - action: allow
    description: Allow HTTP/HTTPS from internal
    protocol: tcp
    source: "@internal"
    destination_port: "80,443"
    state: enabled

If your network supports network peers, you can reference traffic to or from the peer connection by using a network subject selector in the format @<network-name>/<peer-name>. Example:

source: "@my-network/my-peer"

When using a network subject selector, the network that has the ACL assigned to it must have the specified peer connection.

Log traffic

ACL rules are primarily used to control network traffic between instances and networks. However, they can also be used to log specific types of traffic, which is useful for monitoring or testing rules before enabling them.

To configure a rule so that it only logs traffic, configure its state to logged when you add the rule or edit the ACL.

View logs

To display the logs for all logged rules in an ACL, run:

lxc network acl show-log <ACL-name>

Note

If your attempt to view logs returns no data, that means either:

  • No logged rules have matched any traffic yet.

  • The ACL does not contain any rules with a state of logged.

When displaying logs for an ACL, LXD intentionally displays all existing logs for that ACL, including logs from formerly logged rules that are no longer set to log traffic. Thus, if you see logs from an ACL rule, that does not necessarily mean that its state is currently set to logged.

Edit an ACL

Rename an ACL

Requirements:

To rename an ACL, run:

lxc network acl rename <old-ACL-name> <new-ACL-name>

Edit other properties

Run:

lxc network acl edit <ACL-name>

This command opens the ACL configuration in YAML format for editing. You can edit any part of the configuration except for the ACL name, including the custom user keys.

Edit a custom user key via PATCH API

There’s one more way to add or update a custom config.user.* key when using the API. Instead of the PUT method shown in the Edit other properties section above, you can query the PATCH /1.0/network-acls/{ACL-name} endpoint:

lxc query --request PATCH /1.0/network-acls/{ACL-name} --data '{
  "config": {
    "user.<custom-key-name>": "<custom-key-value>"
  }
}'

Caution

Any ACL properties you omit from this request (aside from config and name) will be reset to defaults.

This PATCH endpoint allows you to add or update custom config.user.* keys without affecting other existing config.user.* entries. However, this partial update behavior applies only to the config property. For the description, egress, and ingress properties, this request behaves like a PUT request: it replaces any provided values and resets any omitted properties to their defaults. Thus, ensure you include any properties you want to keep.

Example

Consider an ACL named my-acl with the following properties (shown in JSON):

{
  "name": "my-acl",
  "description": "My test ACL",
  "config": {
    "user.my-key1": "1"
  },
}

The following query adds a config.user.my-key2 key with the value of 2:

lxc query --request PATCH /1.0/network-acls/my-acl --data '{
  "config": {
    "user.my-key2": "2"
  }
}'

After sending the above request, my-acl’s properties are updated to:

{
  "name": "my-acl",
  "description": "",
  "config": {
    "user.my-key1": "1",
    "user.my-key2": "2"
  }
}

Note that the request inserted the new user.my-key2 key without affecting the pre-existing user.my-key1 key. Also notice that the description property was not sent in the request, and thus was reset to an empty value.

Delete an ACL

You can only delete an ACL that is not assigned to a NIC or network.

To delete an ACL, run:

lxc network acl delete <ACL-name>

Assign an ACL

An ACL is inactive until it is assigned to one of the following targets:

To assign an ACL, you must update the security.acls option within its target’s configuration.

Assigning one or more ACLs to a NIC or network adds a default rule that rejects all unmatched traffic. See Configure default actions for details.

Assign an ACL to a bridge or OVN network

To set the network’s security.acls, run the following command. Set the value to a string that contains the ACL name or names you want to add, and comma-separate multiple names:

Set the network’s security.acls to a string that contains the ACL name or names you want to add. Comma-separate multiple names:

lxc network set <network-name> security.acls="<ACL-name>[,<ACL-name>,...]"

For more information about using lxc network set, see: How to configure a network.

Example

Set the my-network network’s security.acls to contain three ACLs:

lxc network set my-network security.acls="my-acl1,my-acl2,my-acl3"

Assign an ACL to the OVN NIC of an instance

For NICs, ACLs can only be used with the OVN NIC type.

An NIC is considered a type of instance device. For general information about configuring instance devices, see: Configure devices.

To assign an ACL to an instance’s OVN NIC, run:

lxc config device set <instance-name> <NIC-name> security.acls="<ACL-name>[,ACL-name,...]"

Example

Assign three ACLs to an instance’s OVN NIC:

lxc config device set my-instance my-ovn-nic security.acls="my-acl1,my-acl2,my-acl3"

Additional options

To view additional options for the security.acls lists, refer to the configuration options for the target network or NIC:

Configure default actions

When one or more ACLs are assigned to a NIC—either directly or through its network—a default reject rule is added to the NIC. This rule rejects all traffic that doesn’t match any of the rules in the assigned ACLs.

You can change this behavior with the network- and NIC-level security.acls.default.ingress.action and security.acls.default.egress.action settings. The NIC-level settings override the network-level settings.

Configure a default action for a network

To set the default action for a network’s egress or ingress traffic, run:

lxc network set <network-name> security.acls.default.<egress|ingress>.action=<allow|reject|drop>

Example

To set the default action for inbound traffic to allow for all instances on the my-network network, run:

lxc network set my-network security.acls.default.ingress.action=allow

Configure a default action for an instance OVN NIC device

To set the default action for an instance OVN NIC’s egress or ingress traffic, run:

lxc config device set <instance-name> <NIC-name> security.acls.default.<egress|ingress>.action=<allow|reject|drop>

Example

To set the default action for inbound traffic to allow for the my-ovn-nic device of my-instance, run:

lxc config device set my-instance my-ovn-nic security.acls.default.ingress.action=allow

Bridge limitations

When using network ACLs with a bridge network, be aware of the following limitations:

  • Unlike OVN ACLs, bridge ACLs apply only at the boundary between the bridge and the LXD host. This means they can enforce network policies only for traffic entering or leaving the host. Intra-bridge firewalls (rules controlling traffic between instances on the same bridge) are not supported.

  • ACL groups and network selectors are not supported.

  • If you’re using the iptables firewall driver, you cannot use IP range subjects (such as 192.0.2.1-192.0.2.10).

  • Baseline network service rules are added before ACL rules in their respective INPUT/OUTPUT chains. Because we cannot differentiate between INPUT/OUTPUT and FORWARD traffic after jumping into the ACL chain, ACL rules cannot block these baseline rules.