Skip to content

Commit

Permalink
Create scs-XXXX-v1-default-rules-for-security-groups.md (#525)
Browse files Browse the repository at this point in the history
* Create scs-XXXX-v1-default-rules-for-security-groups.md

First draft of standard for default security group rules

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Update scs-XXXX-v1-default-rules-for-security-groups.md

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Update Standards/scs-XXXX-v1-default-rules-for-security-groups.md

fix typos

Co-authored-by: Sven <kieske@osism.tech>
Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Create default-security-group-rules.py

Create Test for the default security group rules

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Update default-security-group-rules.py

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Update default-security-group-rules.py

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Update default-security-group-rules.py

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Update default-security-group-rules.py

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Apply suggestions from code review

fix typos and adjust  some wording

Co-authored-by: Markus Hentsch <129268441+markus-hentsch@users.noreply.github.com>
Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Update scs-XXXX-v1-default-rules-for-security-groups.md

Add example on how to create a rule only for custom security groups

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Update scs-XXXX-v1-default-rules-for-security-groups.md

remove example in favor of the guide in docs:
SovereignCloudStack/docs#167

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Restructure Tests to allow the special ingress case but only for default security groups.

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Change to allow the OpenStack default default SG rules

This will only allow ingress traffic from the same SG for the default security groups.

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* change indentation

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* adjust the if clause

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Update scs-XXXX-v1-default-rules-for-security-groups.md

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* remove unnecessary sentence

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Update scs-XXXX-v1-default-rules-for-security-groups.md

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Update scs-XXXX-v1-default-rules-for-security-groups.md

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Update scs-XXXX-v1-default-rules-for-security-groups.md

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Update scs-XXXX-v1-default-rules-for-security-groups.md

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* add tests for egress traffic rules to be present

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Update default-security-group-rules.py

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* clarify conformance test abstract

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Update default-security-group-rules.py

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Markus Hentsch <129268441+markus-hentsch@users.noreply.github.com>
Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Update scs-XXXX-v1-default-rules-for-security-groups.md

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Markus Hentsch <129268441+markus-hentsch@users.noreply.github.com>
Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Update scs-XXXX-v1-default-rules-for-security-groups.md

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

* Rename scs-XXXX-v1-default-rules-for-security-groups.md to scs-0115-v1-default-rules-for-security-groups.md

Signed-off-by: josephineSei <128813814+josephineSei@users.noreply.github.com>

---------

Signed-off-by: josephineSei <josephine.seifert@cloudandheat.com>
Co-authored-by: Sven <kieske@osism.tech>
Co-authored-by: Markus Hentsch <129268441+markus-hentsch@users.noreply.github.com>
  • Loading branch information
3 people committed Jun 12, 2024
1 parent 08e72da commit 2547b38
Show file tree
Hide file tree
Showing 2 changed files with 270 additions and 0 deletions.
140 changes: 140 additions & 0 deletions Standards/scs-0115-v1-default-rules-for-security-groups.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
---
title: Default Rules for Security Groups
type: Standard
status: Draft
track: IaaS
---

## Introduction

Security Groups in IaaS (OpenStack) are part of the network security mechanisms provided for the users.
They resemble sets of virtual firewall rules allowing specific network traffic at a port of a VM that connects it to a network.
They are project-bound, which means that all Security Groups that are newly created are only available to the project in which they were created.
This is also the case for the default Security Group that is created for each project as soon as the project itself is created.

## Terminology

Security Group (abbr. SG)
Set of ip table rules, used for tenant network security.

Security Group Rule (abbr. SG Rule)
A single ip table rule, that is part of a SG.

Administrator (abbr. Admin)
Operator = User of an OpenStack cloud with the admin role.

### Default Security Groups, Custom Security Groups and default Security Group Rules

To properly understand the concepts in this standard and avoid ambiguity, is very important to distinguish between the following similar-sounding but different resources in the OpenStack Networking API:

1. default Security Group
2. custom Security Group
3. default Security Group Rules

A **default Security Group** is a predefined Security Group which is automatically created once a project is created and is specific to that project.
This Security Group is called "default" and there exists only one per project.
It will automatically be assigned to VMs that have no other Security Group explicitly assigned to it, when a VM is created.

A **custom Security Group** is any additional Security Group created within a project separate from the *default Security Group* of the project.

The **default Security Group Rules** may target the *default Security Groups* or the *custom Security Groups* or both.
They resemble a rule template and each Security Group will be initially created with rules according to this template.

Although the rules of a Security Group may be adjusted freely after its creation, these default rule presets applied on initialization are predefined.
In recent OpenStack releases, both presets can be adjusted independently by administrators of the infrastructure.

## Motivation

The rules of a Security Group can be edited by default by any user with the member role within a project.
But when a Security Group is created it automatically incorporates a few SG rules that are configured as default rules.
Since the 2023.2 release, the default set of Security Group rules can be adjusted.
This functionality is only available to administrators[^1][^2].
In combination with the OpenStack behavior that when a VM is created with no Security Group specified, the default SG of the project is automatically applied to the ports of the VM,
a user cannot be sure which firewall rules are applied to such a VM.

Therefore this standard proposes default Security Group rules that MUST be set by administrators to avoid divergence in default network security between different IaaS environments.

[^1]: [Tracking of development for editable default SG rules](https://bugs.launchpad.net/neutron/+bug/1983053)
[^2]: [Release Notes of Neutron 2023.2](https://docs.openstack.org/releasenotes/neutron/2023.2.html)

## Design Considerations

Up to the 2023.1 release (antelope) the default Security Group rules are hardcoded in the OpenStack code.
We should not require to change this behavior through code changes in deployments.

Beginning with the 2023.2 release (bobcat) the default Security Group rules can now be edited by administrators through an API.
All rules that should be present as default in Security Groups have to be configured by admins through this API.

There are two ways to approach a standard for the default rules of Security Groups.

1. **There could be a set of rules standardized that has to be configured by admins.**

OpenStack's default rules for Security Groups already provide a good baseline for port security, because they allow all egress traffic and for the default Security Group only ingress traffic from the same group.

Allowing more rules would not benefit the security level, while reducing or limiting the existing rules would barely improve it.
Nevertheless a standard could hold up the current security level against possible future release with more open default rules.
Changing the default rules will not change the rules of any existing Security Groups.

2. **With the already strict OpenStack default rules users are required in most use cases to create and manage their own Security Groups.**

This has the benefit that users need to explicitly think about the port security of their VMs and may be less likely to apply Security Groups which rules open up more ports than needed.
There is also a guide from the SCS project on how to set up a Security Group that also focuses on having a good port security[^3].

With the default OpenStack behavior of having already strict rules, which in most cases require users to manage their own Security Groups, this standard should mandate a middle way:
It should allow adjusting the default rules, but only to a stricter version.

Allowing all outgoing traffic in the default rules in combination with blocking all incoming traffic would be strict enough from a security point of view.
And it would make it necessary for users to check and change the rules of their Security Group to a meaningful set.

[^3]: [Guide for Security Groups](https://docs.scs.community/docs/iaas/guides/user-guide/security-groups/)

### Further Annotations

This standard should only be applied onto versions of OpenStack that implement the new endpoint for the default Security Group rules, which would only include 2023.2 or higher releases.

It is possible to have different default Security Group rules for the default SG and custom SGs.
And it is arguable to have a more strict standard for default rules for the default Security Group than for the custom Security Groups.
Because the latter ones are not automatically applied to a VM but are always edited by the users to apply to their requirements.

The allowlisting concept of Security Group rules makes it hard to allow traffic with an exception of certain ports.
It would be possible to just define many rules to achieve what a blocklist would achieve.
But having many rules may confuse users and they may not disable unnecessary default rules in their SGs.

## Standard

The default Security Group rules for the default Security Groups SHOULD allow incoming traffic from the same Security Group.
The default Security Group rules for ALL Security Groups MUST NOT allow any other incoming traffic. Neither IPv4 nor IPv6.
This can be achieved through having ingress rules in the default Security Group rules that allow ingress traffic from the Remote Security Group "PARENT" but are only used in the default Security Group.

The default Security Group rules for ALL Security Groups SHOULD allow egress Traffic for both IPv4 and IPv6.

### Example

In the following table, there is only ingress traffic between the same default Security Groups allowed plus all egress traffic:

```bash
$ openstack default security group rule list
+--------------------------+-------------+-----------+-----------+------------+-----------+-----------------------+----------------------+--------------------------------+-------------------------------+
| ID | IP Protocol | Ethertype | IP Range | Port Range | Direction | Remote Security Group | Remote Address Group | Used in default Security Group | Used in custom Security Group |
+--------------------------+-------------+-----------+-----------+------------+-----------+-----------------------+----------------------+--------------------------------+-------------------------------+
| 47b929fd-9b39-4f22-abc5- | None | IPv6 | ::/0 | | egress | None | None | True | True |
| 7d4f64d10909 | | | | | | | | | |
| 92a79600-5358-4fef-a390- | None | IPv4 | 0.0.0.0/0 | | egress | None | None | True | True |
| 822665f46070 | | | | | | | | | |
| 93e35d0c-2482-4ec1-9fbd- | None | IPv4 | 0.0.0.0/0 | | ingress | PARENT | None | True | False |
| fd8c9a21a04e | | | | | | | | | |
| ed5cd662-add2-4e42-b0a7- | None | IPv6 | ::/0 | | ingress | PARENT | None | True | False |
| 3b585d348820 | | | | | | | | | |
+--------------------------+-------------+-----------+-----------+------------+-----------+-----------------------+----------------------+--------------------------------+-------------------------------+
```

## Related Documents

The spec for introducing configurability for the default Security Groups Rules can be found [here](https://specs.openstack.org/openstack/neutron-specs/specs/2023.2/configurable-default-sg-rules.html).

More about Security Groups as a resource in OpenStack can be found [here](https://docs.openstack.org/nova/latest/user/security-groups.html).

## Conformance Tests

The conformance tests should check for the absence of any ingress traffic rules except traffic from the same Security Group in the `openstack default security group rule list`.
As having egress rules is allowed by this standard, but not forced and can be set in various ways, the tests should check for presence of any egress rules.
130 changes: 130 additions & 0 deletions Tests/iaas/security-groups/default-security-group-rules.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
"""Default Security Group Rules Checker
This script tests the absence of any ingress default security group rule
except for ingress rules from the same Security Group. Furthermore the
presence of default rules for egress traffic is checked.
"""

import openstack
import os
import argparse


def connect(cloud_name: str) -> openstack.connection.Connection:
"""Create a connection to an OpenStack cloud
:param string cloud_name:
The name of the configuration to load from clouds.yaml.
:returns: openstack.connnection.Connection
"""
return openstack.connect(
cloud=cloud_name,
)


def test_rules(cloud_name: str):
try:
connection = connect(cloud_name)
rules = connection.network.default_security_group_rules()
except Exception as e:
print(str(e))
raise Exception(
f"Connection to cloud '{cloud_name}' was not successfully. "
f"The default Security Group Rules could not be accessed. "
f"Please check your cloud connection and authorization."
)

# count all overall ingress rules and egress rules.
ingress_rules = 0
ingress_from_same_sg = 0
egress_rules = 0
egress_ipv4_default_sg = 0
egress_ipv4_custom_sg = 0
egress_ipv6_default_sg = 0
egress_ipv6_custom_sg = 0
if not rules:
print("No default security group rules defined.")
else:
for rule in rules:
direction = rule.direction
ethertype = rule.ethertype
r_custom_sg = rule.used_in_non_default_sg
r_default_sg = rule.used_in_default_sg
if direction == "ingress":
ingress_rules += 1
# we allow ingress from the same security group
# but only for the default security group
r_group_id = rule.remote_group_id
if (r_group_id == "PARENT" and not r_custom_sg):
ingress_from_same_sg += 1
elif direction == "egress" and ethertype == "IPv4":
egress_rules += 1
if rule.remote_ip_prefix:
# this rule does not allow traffic to all external ips
continue
if r_custom_sg:
egress_ipv4_custom_sg += 1
if r_default_sg:
egress_ipv4_default_sg += 1
elif direction == "egress" and ethertype == "IPv6":
egress_rules += 1
if rule.remote_ip_prefix:
# this rule does not allow traffic to all external ips
continue
if r_custom_sg:
egress_ipv6_custom_sg += 1
if r_default_sg:
egress_ipv6_default_sg += 1

# test whether there are no other than the allowed ingress rules
assert ingress_rules == ingress_from_same_sg, (
f"Expected only ingress rules for default security groups, "
f"that allow ingress traffic from the same group. "
f"But there are more - in total {ingress_rules} ingress rules. "
f"There should be only {ingress_from_same_sg} ingress rules.")
assert egress_rules > 0, (
f"Expected to have more than {egress_rules} egress rules present.")
var_list = [egress_ipv4_default_sg, egress_ipv4_custom_sg,
egress_ipv6_default_sg, egress_ipv6_custom_sg]
assert all([var > 0 for var in var_list]), (
"Not all expected egress rules are present. "
"Expected rules for egress for IPv4 and IPv6 "
"both for default and custom security groups.")

result_dict = {
"Ingress Rules": ingress_rules,
"Egress Rules": egress_rules
}
return result_dict


def main():
parser = argparse.ArgumentParser(
description="SCS Default Security Group Rules Checker")
parser.add_argument(
"--os-cloud", type=str,
help="Name of the cloud from clouds.yaml, alternative "
"to the OS_CLOUD environment variable"
)
parser.add_argument(
"--debug", action="store_true",
help="Enable OpenStack SDK debug logging"
)
args = parser.parse_args()
openstack.enable_logging(debug=args.debug)

# parse cloud name for lookup in clouds.yaml
cloud = os.environ.get("OS_CLOUD", None)
if args.os_cloud:
cloud = args.os_cloud
assert cloud, (
"You need to have the OS_CLOUD environment variable set to your cloud "
"name or pass it via --os-cloud"
)

print(test_rules(cloud))


if __name__ == "__main__":
main()

0 comments on commit 2547b38

Please sign in to comment.