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
View ACL information from the Networking section of the main navigation.
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
userkeys 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
ingressandegresslists 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
egresslist apply to outbound traffic from the NIC.Rules in the
ingresslist 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
actionproperty is required.The
stateproperty defaults to"enabled"if unset.The
sourceanddestinationproperties 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
protocolis 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.
To add an ingress or egress rule to an ACL, go to its detail page.
Click Add rule, then configure your ingress or egress settings.
Note that the Save changes button displays the number of changes you have made. Save your changes.
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.
To remove a rule from an ACL, go to the ACL’s detail page. From the row of the rule to remove, click the Delete button.
Note that the Save changes button displays the number of changes you have made. Save your changes.
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:
droprejectallowThe 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
Download a .log file of your ACL’s logs from its detail page by clicking the Download logs button in the upper-right corner.
Note
If your attempt to view logs returns no data, that means either:
No
loggedrules have matched any traffic yet.The ACL does not contain any rules with a
stateoflogged.
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"
}'
To rename an ACL, go to its detail page and select its name in the header.
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"
}
]
}'
To edit an ACL, navigate to its detail page. From here, you can add or remove ingress or egress rules, as well as configure other settings.
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}
To delete an ACL, ensure that it is not assigned to an NIC or network. You can then delete it from its detail page.
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.aclsOVN network’s
security.aclsInstance’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
iptablesfirewall 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.