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
To list all ACLs, query the GET /1.0/network-acls
endpoint:
lxc query --request GET /1.0/network-acls
You can also use recursion to list the ACLs with a higher level of detail:
lxc query --request GET /1.0/network-acls?recursion=1
Show an ACL¶
To show details about a specific ACL, run:
lxc network acl show <ACL-name>
Example:
lxc network acl show my-acl
For details about a specific ACL, query the GET /1.0/network-acls/{ACL-name}
endpoint`:
lxc query --request GET /1.0/network-acls/{ACL-name}
Example:
lxc query --request GET /1.0/network-acls/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
To create an ACL, query the POST /1.0/network-acls
endpoint:
lxc query --request POST /1.0/network-acls --data '{
"name": "<ACL-name>",
"config": {
"user.<custom-key-name>": "<custom-key-value>"
},
"description": "<description of the ACL>",
"egress": [{<egress rule object>}, {<another egress rule object>, ...}],
"ingress": [{<ingress rule object>}, {<another ingress rule object>, ...}]
}'
You must provide an ACL name that meets the Name requirements.
You can optionally provide one or more custom
config.user.*
keys to store metadata or other information.The
ingress
andegress
lists contain rules for inbound and outbound traffic. See ACL rules for details.
Examples
Create an ACL with the name my-acl
, a custom user key of my-key
, and a description
:
lxc query --request POST /1.0/network-acls --data '{
"name": "my-acl",
"config": {
"user.my-key": "my-value"
},
"description": "Web servers"
}'
Create an ACL with the name my-acl
and an ingress
rule:
lxc query --request POST /1.0/network-acls --data '{
"name": "my-acl",
"ingress": [
{
"action": "drop",
"state": "enabled"
}
]
}'
ACL properties¶
ACLs have the following properties:
Key: | config |
Type: | string set |
Required: | no |
The only supported keys are user.*
custom keys.
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>
{
"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
anddestination
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
There is no specific endpoint for adding a rule. Instead, you must edit the full ACL, which contains the egress
and ingress
lists.
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.
There is no specific endpoint for removing a rule. Instead, you must edit the full ACL, which contains the egress
and ingress
lists.
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:
drop
reject
allow
The default action for unmatched traffic (defaults to
reject
, see Configure default actions)
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:
Key: | action |
Type: | string |
Required: | yes |
Possible values are allow
, reject
, and drop
.
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.
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.
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.
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.
Key: | protocol |
Type: | string |
Required: | no |
Possible values are icmp4
, icmp6
, tcp
, and udp
.
Leave the value empty to match any protocol.
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.
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.
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>
To display the logs for all logged
rules in an ACL, query the GET /1.0/network-acls/{ACL-name}/log
endpoint:
lxc query --request GET /1.0/network-acls/{ACL-name}/log
Example
lxc query --request GET /1.0/network-acls/my-acl/log
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
oflogged
.
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:
You can only rename an ACL that is not currently assigned to a NIC or network.
The new name must meet the Name requirements.
To rename an ACL, run:
lxc network acl rename <old-ACL-name> <new-ACL-name>
To rename an ACL, query the POST /1.0/network-acls/{ACL-name}
endpoint:
lxc query --request POST /1.0/network-acls/{ACL-name} --data '{
"name": "<new-ACL-name>"
}'
Example
Rename an ACL named web-traffic
to internal-web-traffic
:
lxc query --request POST /1.0/network-acls/web-traffic --data '{
"name": "internal-web-traffic"
}'
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.
You can update any ACL property except for name
, including the custom user keys, by querying the PUT /1.0/network-acls/{ACL-name}
endpoint:
lxc query --request PUT /1.0/network-acls/{ACL-name} --data '{
"config": {
"user.<custom key name>": "<custom key value>"
},
"description": "<description of the ACL>",
"egress": [<egress rule>, <another egress rule...>,...],
"ingress": [<ingress rule>, <another ingress rule...>,...]
}'
Caution
Any properties you omit from this request (aside from the ACL name
) will be reset to defaults. See: The PUT method.
If you only want to update the config
custom user keys, see: Edit a custom user key via PATCH API.
Example
Consider an ACL named my-acl
with the following properties (shown in JSON):
{
"name": "my-acl",
"config": {
"user.my-key": "my-value"
},
"description": "My test ACL",
"egress": [
{
"action": "allow",
"state": "logged"
}
]
"ingress": [
{
"action": "drop",
"state": "enabled"
}
]
}
This query updates that ACL’s egress
rule state
from logged
to enabled
:
lxc query --request PUT /1.0/network-acls/my-acl --data '{
"egress": [
{
"action": "allow",
"state": "enabled"
}
]
}'
After the above query is run, my-acl
contains the following properties:
{
"name": "test",
"config": {},
"description": "",
"egress": [
{
"action": "allow",
"state": "enabled"
}
],
"ingress": []
}
Note that the description
and ingress
properties have been reset to defaults because they were not provided in the API request.
To avoid this behavior and preserve the values of any existing properties, you must include them in the PUT
request along with the updated property:
lxc query --request PUT /1.0/network-acls/my-acl --data '{
"description": "My test ACL",
"egress": [
{
"action": "allow",
"state": "enabled"
}
],
"ingress": [
{
"action": "drop",
"state": "enabled"
}
]
}'
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>
To delete an ACL, query the DELETE /1.0/network-acls/{ACL-name}
endpoint:
lxc query --request DELETE /1.0/network-acls/{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"
To set the network’s security.acls
, query the PATCH /1.0/networks/{network-name}
endpoint. Set the value to a string that contains the ACL name or names you want to add, and comma-separate multiple names:
lxc query --request PATCH /1.0/networks/{network-name} --data '{
"config": {
"security.acls": "<ACL-name>[,<ACL-name>,...]"
}
}'
Example
Set the my-network
network’s security.acls
to contain three ACLs:
lxc query --request PATCH /1.0/networks/my-network --data '{
"config": {
"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"
To assign an ACL to an instance’s OVN NIC, query the PATCH /1.0/instances/{instance-name}
endpoint. Set security.acls
to a string that contains the ACL name or names you want to add, and comma-separate multiple names:
lxc query --request PATCH /1.0/instances/{instance-name} --data '{
"devices": {
"<NIC-name>": {
"network": <network-name>,
"type": "nic",
"security.acls": "<ACL-name>[,<ACL-name>,...]",
<other options>
}
}
}'
The type
and network
options are required in the body (see: Required device options).
Caution
Patching an instance device’s configuration unsets any options for that device omitted from the PATCH request body. For more information, see Effects of patching device options.
Example
For my-instance
, set its my-ovn-nic
device’s security.acls
to contain three ACLs:
lxc query --request PATCH /1.0/instances/my-instance --data '{
"devices": {
"my-ovn-nic": {
"network": "my-ovn-network",
"type": "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:
Bridget network’s
security.acls
OVN network’s
security.acls
Instance’s OVN NIC
security.acls
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
Configure a default action for a network
To set the default action for a network’s egress or ingress traffic, query the PATCH /1.0/networks/{network-name}
endpoint:
lxc query --request PATCH /1.0/networks/{network-name} --data '{
"config": {
"security.acls.default.egress.action": "<allow|reject|drop>",
"security.acls.default.ingress.action": "<allow|reject|drop>",
}
}'
Example
Set the my-network
network’s default egress action to allow
:
lxc query --request PATCH /1.0/networks/my-network --data '{
"config": {
"security.acls.default.egress.action": "allow"
}
}'
Configure a default action for an instance’s OVN NIC device
To set the default action for an instance’s OVN NIC’s traffic, query the PATCH /1.0/instances/{instance-name}
endpoint:
lxc query --request PATCH /1.0/instances/{instance-name} --data '{
"devices": {
"<NIC-name>": {
"network": <network-name>,
"type": "nic",
"security.acls.default.<egress|ingress>.action": "<allow|reject|drop>"
<other-options>
}
}
}'
The type
and network
options are required in the body (see: Required device options).
Caution
Patching an instance device’s configuration unsets any options for that device omitted from the PATCH request body. For more information, see Effects of patching device options.
Example
This request sets the default action for inbound traffic to allow
for the my-ovn-nic
device of my-instance
:
lxc query --request PATCH /1.0/instances/my-instance --data '{
"devices": {
"my-ovn-nic": {
"network": "my-network",
"type": "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 as192.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.