How to configure the SDN Firewall
The SDN Firewall filters the traffic that reaches your Cloud Servers over SDN Private Networks. You write the rules once, in a firewall ruleset, and attach the ruleset to every server that should use them. The firewall is stateful, so replies to allowed connections need no rules of their own.
This guide creates a ruleset, attaches it to a server and changes it later, using the UpCloud API. The SDN Firewall filters SDN interfaces only. To filter a server's public and utility traffic, use the Public & Utility Firewall as well. See Firewall for how the two compare.
Before you start
You need:
- An API token, available in the
UPCLOUD_TOKENenvironment variable. - One or more Cloud Servers with an interface on an SDN Private Network.
curlandjqon the computer you run the commands from.
The examples allow SSH from an admin network, 172.16.3.0/24, and HTTP from a load balancer address, 172.16.1.4. Replace these with your own addresses and ports.
1. Create a ruleset
Create the ruleset with "stateful": true. The API refuses a ruleset without it, with the error ERROR_INVALID_FIREWALL_TYPE.
RULESET_UUID=$(curl -s -H "Authorization: Bearer $UPCLOUD_TOKEN" -H "Content-Type: application/json" \
-X POST https://api.upcloud.com/1.3/firewall-ruleset \
-d '{"name":"web-servers","stateful":true}' | jq -r .uuid)
echo "$RULESET_UUID"The command prints the UUID of the new ruleset.
2. Add rules
Send all the rules in one request. Each rule accepts incoming IPv4 traffic from a source range to a port. Set "enabled": true on every rule: a rule added on its own, outside a request like this one, is created disabled unless you set it.
curl -s -H "Authorization: Bearer $UPCLOUD_TOKEN" -H "Content-Type: application/json" \
-X PUT https://api.upcloud.com/1.3/firewall-ruleset/$RULESET_UUID/rule \
-d '{"rules":[
{"direction":"in","action":"accept","family":"IPv4","protocol":"tcp","destination_port_start":22,"destination_port_end":22,"source_address_cidr":"172.16.3.0/24","enabled":true,"comment":"ssh from admin network"},
{"direction":"in","action":"accept","family":"IPv4","protocol":"tcp","destination_port_start":80,"destination_port_end":80,"source_address_cidr":"172.16.1.4/32","enabled":true,"comment":"http from load balancer"}
]}' | jq '[.rules[] | {comment, enabled}]'Incoming traffic that no rule accepts is dropped once the ruleset is attached and the private firewall is on.
Read the ruleset back to check it:
curl -s -H "Authorization: Bearer $UPCLOUD_TOKEN" \
https://api.upcloud.com/1.3/firewall-ruleset/$RULESET_UUID \
| jq '{name, stateful, version, rules: [.rules[] | {destination_port_start, source_address_cidr, enabled}]}'Make sure stateful is true and every rule has "enabled": true.
3. Attach the ruleset and switch on the private firewall
Attach the ruleset to a server, then switch on the server's private firewall. A ruleset filters nothing while the private firewall is off. Repeat both commands for every server that should use the ruleset.
SERVER_UUID=your-server-uuid
curl -s -H "Authorization: Bearer $UPCLOUD_TOKEN" -H "Content-Type: application/json" \
-X POST https://api.upcloud.com/1.3/server/$SERVER_UUID/attach_firewall_ruleset/private \
-d "{\"firewall_ruleset\":{\"firewall_ruleset_uuid\":\"$RULESET_UUID\"}}"
curl -s -H "Authorization: Bearer $UPCLOUD_TOKEN" -H "Content-Type: application/json" \
-X PUT https://api.upcloud.com/1.3/server/$SERVER_UUID \
-d '{"server":{"firewall_private":"on"}}' | jq -r .server.firewall_privateThe last command prints on.
With Terraform, the upcloud_server_private_firewall_ruleset resource attaches a ruleset. Switch the private firewall on through the API, as above.
4. Check that the rules apply
The server reports which version of each attached ruleset it enforces:
curl -s -H "Authorization: Bearer $UPCLOUD_TOKEN" \
https://api.upcloud.com/1.3/server/$SERVER_UUID/firewall_ruleset_relationships/private \
| jq '.firewall_ruleset_relationships.private[] | {firewall_ruleset_uuid, applied_version, last_applied_at}'The rules apply once applied_version matches the version of the ruleset from step 2. Then test one connection that a rule allows and one that no rule allows, for example with nc -zv from another server on the private network. The allowed connection succeeds and the other one times out.
5. Change rules later
A PUT request to the rules endpoint, as in step 2, replaces all the rules of the ruleset. Send the complete new set in one request. Every saved change goes live on its own, usually within a minute or two, on every server that uses the ruleset. Changing related rules one request at a time could leave a half-finished set live in between.
To start the rollout straight away instead of waiting, attach the ruleset to the server again with the attach command from step 3. Then check applied_version as in step 4 before you test the change.
