Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create scs-XXXX-v1-default-rules-for-security-groups.md #525

Merged
merged 36 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
197339b
Create scs-XXXX-v1-default-rules-for-security-groups.md
josephineSei Mar 15, 2024
76a4e62
Update scs-XXXX-v1-default-rules-for-security-groups.md
josephineSei Mar 15, 2024
5b250a6
Update Standards/scs-XXXX-v1-default-rules-for-security-groups.md
josephineSei Mar 18, 2024
69df994
Create default-security-group-rules.py
josephineSei Mar 18, 2024
75fa14f
Update default-security-group-rules.py
josephineSei Mar 18, 2024
8dc4e77
Update default-security-group-rules.py
josephineSei Mar 18, 2024
d7f03c4
Update default-security-group-rules.py
josephineSei Mar 19, 2024
c09e5f2
Update default-security-group-rules.py
josephineSei Mar 19, 2024
a1af016
Apply suggestions from code review
josephineSei Mar 19, 2024
4821f06
Update scs-XXXX-v1-default-rules-for-security-groups.md
josephineSei Mar 19, 2024
b4eb9e0
Merge branch 'main' into SG-rules-standard
josephineSei Mar 19, 2024
f89ff13
Update scs-XXXX-v1-default-rules-for-security-groups.md
josephineSei Mar 20, 2024
6f2b7b0
Restructure Tests to allow the special ingress case but only for defa…
josephineSei Apr 22, 2024
e6ec1ae
Change to allow the OpenStack default default SG rules
josephineSei Apr 22, 2024
0473729
change indentation
josephineSei Apr 22, 2024
cc275aa
adjust the if clause
josephineSei Apr 22, 2024
dc6600d
Update scs-XXXX-v1-default-rules-for-security-groups.md
josephineSei Apr 26, 2024
8966417
remove unnecessary sentence
josephineSei Apr 26, 2024
0f69cea
Update scs-XXXX-v1-default-rules-for-security-groups.md
josephineSei May 2, 2024
0539045
Merge branch 'main' into SG-rules-standard
josephineSei May 7, 2024
2488491
Update scs-XXXX-v1-default-rules-for-security-groups.md
josephineSei May 8, 2024
b276b6e
Update scs-XXXX-v1-default-rules-for-security-groups.md
josephineSei May 10, 2024
2c0962b
Update scs-XXXX-v1-default-rules-for-security-groups.md
josephineSei May 10, 2024
d37643f
add tests for egress traffic rules to be present
josephineSei May 10, 2024
f3af042
Update default-security-group-rules.py
josephineSei May 10, 2024
00fd925
Merge branch 'main' into SG-rules-standard
josephineSei May 16, 2024
6bd64d4
clarify conformance test abstract
josephineSei May 28, 2024
da27d33
Update default-security-group-rules.py
josephineSei Jun 3, 2024
5e32986
Apply suggestions from code review
josephineSei Jun 5, 2024
ad3f062
Update scs-XXXX-v1-default-rules-for-security-groups.md
josephineSei Jun 5, 2024
fcf1052
Apply suggestions from code review
josephineSei Jun 5, 2024
6a1b057
Merge branch 'main' into SG-rules-standard
josephineSei Jun 10, 2024
252851c
Update scs-XXXX-v1-default-rules-for-security-groups.md
josephineSei Jun 12, 2024
d541578
Rename scs-XXXX-v1-default-rules-for-security-groups.md to scs-0115-v…
josephineSei Jun 12, 2024
b30e297
Merge branch 'main' into SG-rules-standard
josephineSei Jun 12, 2024
0330f70
Merge branch 'main' into SG-rules-standard
josephineSei Jun 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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()