Private External Networks in Neutron
You might find yourself in a position where you need to restrict access by tenants to specific external networks. In Openstack there’s the notion that external networks are accessible by all tenants and anyone can attach their private router to it. This might not be the case if you want to only allow specific users to access a specific external networks.
There is no way to directly configure this in neutron. I.e. Any external network that you have in your deployment basically can have tenants attach their routers to it and make it their default gateway. In order to work around this, let’s look into how neutron saves router and ports in the neutron database schema , a router is defined as follows
MariaDB [neutron]> desc routers$$
+——————+————–+——+—–+———+——-+
| Field | Type | Null | Key | Default | Extra |
+——————+————–+——+—–+———+——-+
| project_id | varchar(255) | YES | MUL | NULL | |
| id | varchar(36) | NO | PRI | NULL | |
| name | varchar(255) | YES | | NULL | |
| status | varchar(16) | YES | | NULL | |
| admin_state_up | tinyint(1) | YES | | NULL | |
| gw_port_id | varchar(36) | YES | MUL | NULL | |
| enable_snat | tinyint(1) | NO | | 1 | |
| standard_attr_id | bigint(20) | NO | UNI | NULL | |
| flavor_id | varchar(36) | YES | MUL | NULL | |
+——————+————–+——+—–+———+——-+
each router has an id, name, project ID where it’s created under. You will notice also the field gateway_port_id. This is the port that connects the tenant router to its default gateway. i.e. your external network
Each router has a unique port for gateway. Tenant routers do not share a common port. Let’s look how a port looks like in the database schema
MariaDB [neutron]> desc ports$$
+——————+————–+——+—–+———+——-+
| Field | Type | Null | Key | Default | Extra |
+——————+————–+——+—–+———+——-+
| project_id | varchar(255) | YES | MUL | NULL | |
| id | varchar(36) | NO | PRI | NULL | |
| name | varchar(255) | YES | | NULL | |
| network_id | varchar(36) | NO | MUL | NULL | |
| mac_address | varchar(32) | NO | | NULL | |
| admin_state_up | tinyint(1) | NO | | NULL | |
| status | varchar(16) | NO | | NULL | |
| device_id | varchar(255) | NO | MUL | NULL | |
| device_owner | varchar(255) | NO | | NULL | |
| standard_attr_id | bigint(20) | NO | UNI | NULL | |
| ip_allocation | varchar(16) | YES | | NULL | |
+——————+————–+——+—–+———+——-+
As you can see , a port has an id and a network_id where it’s attached to. Note that in the ports table, network_id refer to both external and “tenant” networks.
If we know our external network ids, we can tell what ports are attached to them, and possibly enable/disable future attachments. To know our external network ids, it’s easy to run
(neutron) net-external-list
This will show you the IDs for the external networks and then with a simple query you can select from the ports table what ports are attached to your external network
select id from ports where network_id=$NETWORK_ID’ $$
This returns a list of the ports currently connected to your external network.
If you want to disable tenants from attaching anything (routers or floating IPs) to this external network, you can acheive this by using a BEFORE TRIGGER in mysql
DELIMITER $$
create trigger ports_insert before insert on ports for each row begin IF (new.network_id = ‘$NETWORK_ID’) then set new.id = NULL ; END IF ; END $$
This trigger basically changes the insert statement that neutron writes to the database when a tenant attaches a router to your external network. It sets the ID of the new port to NULL, which is invalid for this field as seen from the above description of the ports table. This effectively disables any routers/floating ips to be attached to the external network you choose. But remember , you’r also included in that, you can’t attach anything to this external network even as admin. You can always tweak the trigger to check project_id field and only restrict access to specific projects
Leave a Reply