Congress Hands-on Lab
Mitaka Openstack Summit, Tokyo, Japan
Alexander Yip, Tim Hinrichs
This hands-on lab illustrates what the Congress policy system does, and how to use it. This guide includes how to configure a datasource, write a policy, monitor that policy, and enforce that policy in your own Openstack environment.
We provide a virtual machine image containing devstack environment for you to experiment with; the devstack VM runs inside of VirtualBox. Congress, Nova, Keystone, and Neutron are running in devstack inside of the virtual machine.
The devstack VM is running typical Openstack services like Keystone, Nova, and Neutron, plus a Congress server. The devstack VM also contains four virtual machine instances, and two virtual routers. The example policy we’re working with treats a port differently depending on whether it can route to the Internet, so TenantA-VM1 and TenantA-VM2 are able to route to the Internet via router 1 (R1). TenantB-VM1 and TenantB-VM2 are not able to route to the Internet.
This hands-on does not actually require the host machine to be connected to the Internet; the policies check whether a VM can route to the external Internet.
The policy we will be working with in this hands-on is a security policy that says:
No virtual machine may be connected to the Internet and allow ingress traffic to TCP port 80.
A site administrator might create this policy to ensure that all web servers listening to the open Internet are listening with HTTPS instead of HTTP. To enforce this policy, a port that is connected to the internet must have an Openstack security-group, and that security-group must not have any rules that allow ingress on TCP port 80.
To implement this policy, Congress needs inputs from three datacenter services, Nova, Neutron, and Keystone. Nova provides the list of virtual machines in the Openstack deployment. Neutron provides the ports, and port connectivity information. Keystone provides contact information for a VM that violates the policy.
We have already connected Neutron and Keystone to Congress, but you need to connect Nova.
First configure the Openstack client with admin credentials:
$ cd /home/congress/devstack
$ source openrc admin admin
Next configure Congress to fetch data from Nova and make it available to Congress policies, using the given URL, the given username and password, and a 5 second polling interval:
$ openstack congress datasource create --config username=admin --config tenant_name=admin --config auth_url=http://127.0.0.1:5000/v2.0 --config password=password --config poll_time=5 nova nova
The output echos the configuration parameters, plus some metadata from Congress. If the output is garbled, try widening your Terminal:
+-------------+-------------------------------------------------------------------------
| Field | Value
+-------------+-------------------------------------------------------------------------
| config | {u'username': u'admin', u'tenant_name': u'admin', u'auth_url': u'http://...
| description | None
| driver | nova
| enabled | True
| id | 9e49604b-8d29-4fd6-968d-33f419217048
| name | nova
| type | None
+-------------+-------------------------------------------------------------------------
To see what tables the Nova datasource makes available, first open the “Admin”, “Policy”, and “Data Sources” tabs on the left:
There, you can find each datasource (Nova and others). If you scroll down, you will see the “Service Data” section which lists each table that originates from a datasource. Click on the “flavors” table from the Nova datasource to see a list of Nova flavors.
The same table and row information is available via the Congress CLI. To list the Nova tables using the CLI, use the following command:
$ openstack congress datasource table list nova
+--------------+
| id |
+--------------+
| flavors |
| hosts |
| floating_IPs |
| servers |
+--------------+
To request the table contents:
$ openstack congress datasource row list nova flavors
+----+-----------+-------+-------+------+-----------+-------------+
| id | name | vcpus | ram | disk | ephemeral | rxtx_factor |
+----+-----------+-------+-------+------+-----------+-------------+
| 5 | m1.xlarge | 8 | 16384 | 160 | 0 | 1.0 |
| 84 | m1.micro | 1 | 128 | 0 | 0 | 1.0 |
| 4 | m1.large | 4 | 8192 | 80 | 0 | 1.0 |
| 3 | m1.medium | 2 | 4096 | 40 | 0 | 1.0 |
| 42 | m1.nano | 1 | 64 | 0 | 0 | 1.0 |
| 2 | m1.small | 1 | 2048 | 20 | 0 | 1.0 |
| 1 | m1.tiny | 1 | 512 | 1 | 0 | 1.0 |
+----+-----------+-------+-------+------+-----------+-------------+
At this point, Congress is configured to use Nova, Neutron, and Keystone (remember that we setup Neutron and Keystone for you).
There are two ways to configure the policy, via the Horizon UI and via the Congress command-line tool. We’ll just give instructions for the CLI; using the UI is in the extra-credit portion of this hands-on lab. Congress uses datalog as its policy language; to learn more about datalog see our documentation here: http://congress.readthedocs.org/en/latest/policy.html.
Remember that we are giving Congress the following policy.
No virtual machine may be connected to the Internet and allow ingress traffic to TCP port 80.
We write this statement using 4 different Datalog rules. Each of the four commands below inserts one of those Datalog rules into the Congress server.
Rule 1:
This rule defines the connected_to_internet table, which contains a row for each logical port that is both connected to a VM and routable to the Internet. The other rules use connected_to_internet as an input.
$ openstack congress policy rule create classification '
connected_to_internet(port_id, vm_id) :-
neutronv2:external_gateway_infos(router_id=router_id,
network_id=network_id_gw),
neutronv2:ports(network_id = all_network, device_id = router_id),
neutronv2:ports(network_id = all_network, id=port_id, device_id=vm_id),
nova:servers(id=vm_id)'
Rule 2:
This rule defines the has_security_group table, which contains a row for each logical port that has a neutron security-group. The other rules use has_security_group as an input.
$ openstack congress policy rule create classification '
has_security_group(id) :-
neutronv2:security_group_port_bindings (port_id=id)'
Rule 3:
The error table contains a row for each VM instances that violates the Congress policy above. Rule 3 adds a row to error if the security-group rule allows ingress traffic on TCP port 80.
$ openstack congress policy rule create classification '
error(user_id,email,vm_name,id) :-
connected_to_internet(id,device_id),
neutronv2:security_group_port_bindings (port_id=id, security_group_id=group_id),
neutronv2:security_group_rules(security_group_id=group_id, direction="ingress",
protocol="tcp", ethertype="IPv4",
port_range_min=port_min , port_range_max=port_max),
lteq(port_min,80),
gteq(port_max,80),
nova:servers(id=device_id, name = vm_name, user_id=user_id),
keystone:users(id=user_id, email=email)'
Rule 4:
Rule 4 also adds rows to error if a user detaches or removes a security group from a logical port.
Together, rules 3 and 4 implement the policy stated early in this document.
$ openstack congress policy rule create classification '
error(user_id,email,vm_name,id) :-
connected_to_internet(id,device_id),
not has_security_group(id),
nova:servers(id=device_id, name = vm_name, user_id=user_id),
keystone:users(id=user_id, email=email)'
In summary, error contains a row for every VM instance that is connected to the Internet, and also either lacks a security group or contains a security group that permits ingress on TCP port 80.
To list the rules, run the following command. You should see the four rules you just inserted.
$ openstack congress policy rule list classification
There are three ways to use Congress policy today: monitoring, proactive enforcement, and reactive enforcement. The following steps illustrate how to use each capability.
When monitoring, Congress continually reads the state of the data center services, and computes the policy violations when a client asks for them. If there is a violation, it will appear in the error table. We’ll go through an example of monitoring now.
First, check the contents of error usings the following command. Note that it returns zero rows:
$ openstack congress policy row list classification error
The UI will also show no rows in error. To find the error table in the UI, open the “Admin”, “Policy”, and “Data Sources” tabs on the left side. Then click the “error” table in the Policy Data list:
That will open the list of rows in the error table which is empty:
Let’s create a violation of the Congress policy by adding a security-group rule that permits ingress on TCP port 80. First click on “Access & Security” in the Project/Compute tab, and then click on “Manage Rules” for the “Default security group”:
Then click on the “+ Add Rule” button.
And create a Custom TCP Rule that allows ingress on TCP port 80, and then click the “Add” button.
Adding the security-group rule creates a violation for all VM ports that can access the Internet. In our example, TenantA-VM1 and TenantA-VM2 meet this criteria, so Congress flags them as violations. To see the violations, check the CLI and UI again:
$ openstack congress policy row list classification error
+----------------------------------+------+-------------+--------------------------------------+
| Col0 | Col1 | Col2 | Col3 |
+----------------------------------+------+-------------+--------------------------------------+
| ba9690eb4b95492283dd50eadada8d87 | None | TenantA-VM1 | 7f1d556b-f870-4048-9df6-a56661f1b3d8 |
| ba9690eb4b95492283dd50eadada8d87 | None | TenantA-VM2 | 732ec66f-e227-485a-bb24-050bcd5fa90a |
+----------------------------------+------+-------------+--------------------------------------+
TenantA-VM1 and TenantA-VM2 both violate the policy because they are connected to the Internet via router 1, so Congress puts them in the error table. The TenantB instances do not violate the policy because they are not connected to the Internet, so they do not show up in the error table. Another way for an instance to violate the policy is if the instance has no security-group at all; we will illustrate that later in the Proactive Enforcement section.
Now, remove the new security-group rule so the violations disappear from the CLI and UI. To remove the rule, first click on “Manage Rules” for the “Default security group”.
and then click “Delete Rule” for the port 80 rule:
Now, check the contents of error usings the following command. Note that it returns zero rows once again:
$ openstack congress policy row list classification error
Congress can also help prevent violations before they happen by allowing API clients to simulate changes to the Congress datasource data. For example, if a client wants to remove a binding between a virtual port and a security-group, the client can first ask Congress if removing the binding would cause any new policy violations.
To ask Congress to simulate the removal of a security-group binding, first get the security group’s ID:
$ GROUP_ID=`openstack congress datasource row list neutronv2 security_group_port_bindings | grep -v -E "port_id|-----" | head -1 | awk '{print $4}'`
Then assign PORT_ID to TenantA-VM1’s port ID:
$ PORT_ID=7f1d556b-f870-4048-9df6-a56661f1b3d8
Then, execute this simulate CLI command which asks Congress to simulate removing the binding and check for new violations in error:
$ openstack congress policy simulate classification "error(user_id,email,vm_name,id)" "neutronv2:security_group_port_bindings-('$PORT_ID', '$GROUP_ID')" action
The above command does not modify the state within Congress, but the command should print a response from Congress warning of a violation in error, namely that TenantA-VM1 would violate the security-group policy:
error("ba9690eb4b95492283dd50eadada8d87", "None", "TenantA-VM1", "7f1d556b-f870-4048-9df6-a56661f1b3d8")
To use proactive enforcement in practice, the API handling code would make a simulate request to Congress as a permission check. In this example, each time a user makes a request to add a security-group rule, the request handler in Neutron would make a simulate call to Congress to check if the new security-group rule would violate any policies. If Congress does find a new violation, it will inform Neutron, and Neutron can deny the request to add the new security-group rule.
Congress can also react to violations by fixing them. Add the following execution rule which tells Congress to delete a security-group rule if it allows a VM that is connected to the Internet to accept ingress traffic on TCP port 80:
$ openstack congress policy rule create classification '
execute[neutronv2:delete_security_group_rule(rule_id)] :-
connected_to_internet(id,device_id),
neutronv2:security_group_port_bindings(port_id=id,security_group_id=group_id),
neutronv2:security_group_rules(security_group_id=group_id, direction=ingress,
protocol=tcp,ethertype=IPv4, port_range_min=port_min,
port_range_max=port_max,id=rule_id),
lteq(port_min,80),
gteq(port_max,80)'
Now, re-add the same security-group rule we added above in “Creating a Violation”. Then refresh the page that lists the security rules in the UI. You should not see the security-group rule there because Congress automatically removed the security-group rule that was causing a violation.
No cleanup is necessary, simply delete the demo VM.
If you want to build your own version of the OpenStack environment that we used in this lab, try the instructions that follow. Fair warning: this is basically a brain dump of what we did, written a couple of months after we did it, so there’s likely things we missed. But we’re happy to help and update these instructions--just let us know.
1) Create 4 Logical Networks (TenantA-1, TenantA-2, TenantB-1, TenantB-2) using respectively 192.168.1.0/24 for the TenantX-1 subnets, and 192.168.2.0 for the TenantX-2)
2) Create 2 Default Router
a) TenantA Router has 3 interfaces: #1 connected to an uplink interface using floating IP. #2 to TenantA-VM1. #3 to TenantA-VM2
b) TenantB Router has 2 interfaces: #1 to TenantB-VM1. #2 to TenantB-VM2
3) Create Tenant A VMs (you can create more VMs if desired)
a) Create 1VM on TenantA-VM1
b) Create 1VM on TenantA-VM2
4) Create Tenant B VMs (you can create more VMs if desired)
a) Create 1VM on TenantB-VM1
b) Create 1VM on TenantB-VM2
5) Change default security group to only have egress ports allowed, save the config
6) Make sure that all the VMs are using default security group.
7) run through the lab and you should be able to follow all the exercises.