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

Draft: Roles Standard #590

Draft
wants to merge 25 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6be442b
First parts of the role standards draft
markus-hentsch May 14, 2024
dfc7b04
Add further details and open question section
markus-hentsch May 14, 2024
76444ea
Content additions and rephrasing for better clarity
markus-hentsch May 15, 2024
717642a
Remove reader role and add reasoning
markus-hentsch May 15, 2024
acd431c
Document necessary future changes to the standard
markus-hentsch May 15, 2024
f7513f3
Add reference to service list standard
markus-hentsch May 15, 2024
c8885cd
Add remark about Barbican inaccessibility for users
markus-hentsch May 15, 2024
6a59376
Add test script for checking role presence
markus-hentsch May 15, 2024
5b571b3
Integrate Barbican adjustments
markus-hentsch May 16, 2024
a0b332a
Add rationale for keeping the creator role for service accounts
markus-hentsch May 16, 2024
77a7c5b
Downgrade "manager" role to service-specific roles
markus-hentsch May 17, 2024
8546f35
Implement tests for verifying Key Manager role permissions
markus-hentsch May 17, 2024
148e3a5
Add README for test suite
markus-hentsch May 17, 2024
20e9567
Cleanup application credential after testing
markus-hentsch May 17, 2024
65d72d4
Update remarks about oslo.policy options to reflect latest findings
markus-hentsch Jun 28, 2024
0fde99f
Address review comments
markus-hentsch Aug 31, 2024
beb6557
Update standard to reflect latest changes in SCS and upstream
markus-hentsch Sep 2, 2024
df70355
Add more regulation to policy rules, add Octavia quirks
markus-hentsch Sep 9, 2024
dca05da
Update test instructions to re-use the manager role if possible
markus-hentsch Sep 19, 2024
1557c08
Add remark about the standard being applicable to 2024.2 and later
markus-hentsch Sep 19, 2024
67a4a1d
Improve phrasing
markus-hentsch Sep 19, 2024
2af152e
Move role overview to design considerations
markus-hentsch Sep 19, 2024
ed3b755
Remove paragraph about Barbican creator role
markus-hentsch Sep 30, 2024
5bfe232
Reference the Key Manager standard in related documents
markus-hentsch Sep 30, 2024
688da00
Remove outdated tests from test script
markus-hentsch Sep 30, 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
250 changes: 250 additions & 0 deletions Standards/scs-03XX-v1-standard-roles.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
---
title: SCS Standard Roles
type: Standard
status: Draft
track: IAM
---

## Introduction

SCS aims to provide a standardized role model for RBAC roles across all supported OpenStack API services that applies sensible and consistent permission sets based on a set list of roles defined by a standard.
markus-hentsch marked this conversation as resolved.
Show resolved Hide resolved
It is closely guided by the OpenStack defaults.

## Terminology

The following special terms are used throughout this standard document:

| Term | Meaning |
|---|---|
| API | Application Programming Interface, often referring to the REST API interfaces provided by OpenStack and related services |
| CSP | Cloud Service Provider, provider managing the OpenStack infrastructure |
| IaaS | Infrastructure-as-a-Service |
| IAM | Identity and Access Management |
| RBAC | Role-Based Access Control[^1] established by OpenStack Keystone |

[^1]: [OpenStack Documentation: Role-Based Access Control Overview](https://static.opendev.org/docs/patrole/latest/rbac-overview.html)

## Motivation

The permission settings of OpenStack RBAC roles are configured in service-specific deployment configuration files (usually the respective "`policy.yaml`") in a rather static way and have to be carefully managed.
markus-hentsch marked this conversation as resolved.
Show resolved Hide resolved
In contrast to many of OpenStack's IAM and IaaS resources, these settings cannot be changed via its API at runtime.
For this reason it is important to have a secure and sensible default configuration in SCS clouds that is both intuitive and flexible enough to cover all necessary use cases of permission models desired by CSPs and customers.

## Design Considerations

One key aspect of the design considerations for this standard is to be as close to the native (upstream) OpenStack role model and role definitions as possible to not introduce unnecessary complexity or divergence from OpenStack.
Meanwhile the standardized roles and permission sets should cover all scenarios and use cases that SCS deems necessary.

Due to the high level of modularity and the large amount of available services for OpenStack clouds, this standard cannot address all possible manifestations of OpenStack clouds.
This standard will therefore only cover IaaS APIs and services that are classified as either mandatory or supported by the SCS project.

### Scope Enforcement Compatibility

The API policy library used by OpenStack (oslo.policy) introduced two new [configuration options](https://docs.openstack.org/oslo.policy/latest/configuration/#oslo-policy) during the ongoing RBAC rework of OpenStack[^2]:

- `enforce_scope`
- `enforce_new_defaults`

Using those new defaults and scope-enforcing options [will currently break](https://governance.openstack.org/tc/goals/selected/consistent-and-secure-rbac.html#the-issues-we-are-facing-with-scope-concept) orchestration tooling such as **OpenStack Heat** and Tacker.
Due to OpenStack Heat being a service supported by the SCS project, those conflicting options cannot be mandated by a SCS standard.
markus-hentsch marked this conversation as resolved.
Show resolved Hide resolved

Some service-specific role sets currently found in OpenStack services can only be eliminated and streamlined with the general roles (reader, member etc.) when those new options are enabled.
Due to their currently unresolved compatibility issues, this standard cannot consider role models dependent on the those oslo.policy options and must keep incorporating the service-specific role sets for the time being.
The affected services and roles are documented below.

#### Core Role Set

Independently from any service-specific roles, the set of core roles is fundamentally affected by the scope enforcement options as well.

The proper distinction between reader, member and manager roles is only fully implemented in all services when the `enforce_scope` and `enforce_new_defaults` oslo.policy options are used.
Otherwise the OpenStack APIs will oftentimes fall back to their earlier policy implementations which do not fully differentiate between reader, member and manager.

This results in more elevated permissions for users possessing the reader role than its role description suggests.
Since this standard cannot mandate or expect the use of the aforementioned oslo.policy options due to their current compatibility issues as stated above, this reduces the usefulness of the reader role and will introduce unexpected behavior when using it.

Due to this, the standard will omit the reader role in its current state.

#### Barbican Role Set

The Key Manager component Barbican [established a set of dedicated roles](https://docs.openstack.org/barbican/2024.1/admin/access_control.html#default-policy):

- key-manager:service-admin
- creator
- observer
- audit

This set of roles is Barbican-specific and not used by any other API.
It became deprecated during the RBAC rework of OpenStack[^2] but is still included per default in recent OpenStack releases (as of the 2024.1 release).

Due to its deprecation it is possible to enable Barbican's use of the already established reader, member and admin roles instead.
This however requires the olso.policy options `enforce_scope` and `enforce_new_default` to be enabled, which are currently non-defaults and break compatibility with orchestration tooling, see above.

#### Octavia Role Set

The Load-Balancer-as-a-Service (LBaaS) component Octavia comes with a set of specific roles in its default API policy configuration:

- load-balancer_observer
- load-balancer_global_observer
- load-balancer_member
- load-balancer_quota_admin
- load-balancer_admin

This set of roles is Octavia-specific and not used by any other API.
However, Octavia also [officially supports alternative policy configurations](https://docs.openstack.org/octavia/2024.1/configuration/policy.html#openstack-default-roles-policy-override-file) that use the already established reader, member and admin roles instead.

Using the alternative configurations would streamline Octavia's policies with the rest of the services and reduce complexity as well as ambiguity in the global role model of this standard.

However, both of the alternative policy files that omit the Octavia-specific roles currently state "The [oslo_policy] `enforce_scope` and `enforce_new_defaults` must be `True`.".
This would mean enabling the new defaults and scope-enforcing options that currently break compatibility with orchestration tooling like explained above.

### Key Manager Role Model

The OpenStack policy defaults for the Key Manager service Barbican establish service-specific roles as documented above.
Unless the new scoping defaults (`enforce_new_defaults`) are used, this leads to users possessing the generic "member" role being unable to access the Key Manager API to create and manage secrets.
This in turn renders encryption features like the volume encryption of OpenStack's volume service unusable for customers unless the corresponding users are assigned the Barbican-specific "creator" role in projects additionally.
This creates unnecessary management overhead on the CSP side and ambiguity for users since the role is only useful in Barbican but its name does not communicate this.

To improve user experience and make the encryption features easily accessible, this standard should adjust the Key Manager API policies to extend permissions referencing the Barbican-specific "creator" role by the "member" role.
This offers users easy access to the Key Manager API and aligns the permission set with the future rework (as per `enforce_new_defaults`), because it will later replace the "creator" role by the "member" role entirely.

The "creator" role will be kept for compatibility reasons concerning service integration.
For example, the block storage service Cinder usually has a technical user in Keystone possessing the "creator" role in the "service" project.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FTR, I considered replacing the "creator" role by "member" entirely. However, I decided against it for the following reasons:

  • both DevStack and RedHat setups1 seem to assign the "creator" role to a "cinder" user in the "service" project, which is registered in Cinder's [keystone_authtoken] config section
  • mandating to switch Cinder's service user to "member" role here could open up permissions in other services' APIs potentially which otherwise wouldn't react to the "creator" role (which is Barbican-specific)
    • without enforce_scope (which this standard cannot use), the scoping would not protect us here

However, I'm not exactly sure in which workflow Cinder needs its own Barbican-enabled role, i.e. what the reasoning for this is. Usually, the user's auth token is passed around during requests so it would simply take the role permissions from there. However, it is most likely there for a reason, so I'm leaving it in because I don't know the context and don't want to break things.

Footnotes

  1. https://access.redhat.com/documentation/en-us/red_hat_openstack_platform/13/html/manage_secrets_with_openstack_key_manager/encrypting_cinder_volumes#overview_of_the_migration_steps

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess Cinder will need it in case of a deletion of an encrypted volume (to delete the key) or to create a backup or snapshot (to copy the key). Maybe there is an edge case, where e.g. a backup is not triggered by someone from the project (hence no chance to aquire the key) or a deletion of a key is done so late, that the user conetxt is already omitted, so cinder does not have the token of the user anymore.


### Open questions

#### Incorporating future upstream defaults into this standard

Due to the ongoing RBAC rework in upstream OpenStack[^2], not all changes which are to be introduced by it will be included in the first iteration of this standard to avoid prematurely adopting role and policy definitions which might still change before being stabilized or have unresolved compatibility issues with certain services.

This results in a need of keeping this standard in sync once the upstream rework finishes.
It is currently unknown when the upstream rework will conclude exactly and how this standard will need to be adjusted as a result.

This primarily concerns the new scoping and defaults in `oslo.policy`:

```ini
[oslo_policy]
enforce_new_defaults = True
enforce_scope = True
```

As of the time of writing this standard, those options currently default to `False`[^3] for all OpenStack services.
markus-hentsch marked this conversation as resolved.
Show resolved Hide resolved
Once those options default to `True` in a future OpenStack release, this standard must be updated to properly account for the resulting changes in policy and role defaults.
Due to the fact that the details on how the remaining compatibility issues will be addressed upstream are still unknown, the full implications on when and how this standard will need to be updated specifically remains an open question.
However, at the very least this will most likely result in the following changes to this standard:

- mandate the use of the new olso.policy options in all APIs
- remove the service-specific roles of Barbican and Octavia from the standard
- add the reader role to the core roles of this standard
- remove the design considerations sections related to the above
- if applicable, update any policy generation workflows to use the new role model

[^2]: [OpenStack Technical Committee Governance Documents: Consistent and Secure Default RBAC](https://governance.openstack.org/tc/goals/selected/consistent-and-secure-rbac.html)

[^3]: [Current parameter defaults in `oslo_policy/opts.py` (2023-12-11)](https://github.com/openstack/oslo.policy/blob/a1e76258180002b288e64532676ba2bc2d1ec800/oslo_policy/opts.py#L26-L51)

## Standard

### Roles

This standard establishes the following roles in SCS clouds.
**Core Roles** MUST be present in the Identity API at all times.
**Service-specific Roles** MUST be present in the Identity API as long as the corresponding service (denoted in parentheses) is part of the infrastructure.

**Core Roles:**

- member
- manager
- admin
- service

**Service-specific Roles:**

- key-manager:service-admin (Barbican)
- creator (Barbican)
- observer (Barbican)
- audit (Barbican)
- load-balancer_observer (Octavia)
- load-balancer_global_observer (Octavia)
- load-balancer_member (Octavia)
- load-balancer_quota_admin (Octavia)
- load-balancer_admin (Octavia)
- ResellerAdmin (Swift + Ceilometer)
- heat_stack_user (Heat)

#### Role Definitions

The following overview will explain the roles' purposes and target scopes.
Roles marked as "internal" are roles only meant to be assigned to technical user accounts intended for internal use by OpenStack services.

Core Roles:

| Role | Primary Target(s) | Purpose |
|---|---|---|
| member | customer | read and write access to resources in the scope of authentication (e.g. project) |
| manager | customer, CSP | slightly more elevated privileges than *member*, able to manage core resources or settings of a project or domain |
| admin | CSP | cloud-level global administrative access to all resources (cross-domain, cross-project) |
| service | internal | internal technical user role for service communication |

Service-specific Roles:

| Service | Role | Primary Target(s) | Purpose |
|---|---|---|---|
| Barbican | audit | customer | allows read-only access to metadata of secrets within a project; does not allow secret retrieval or decryption |
| Barbican | observer | customer | allows read-only access to secrets within a project, including retrieval and decryption |
| Barbican | creator | customer | allows access to, creation and deletion of secrets within a project, including retrieval and decryption, equal to the member role |
| Barbican | key-manager:service-admin | CSP | management API access for the cloud administrator, e.g. for project quota settings |
| Octavia | load-balancer_observer | customer | access to read-only APIs |
| Octavia | load-balancer_global_observer | CSP | access to read-only APIs including resources owned by others |
| Octavia | load-balancer_member | customer | access to read and write APIs |
| Octavia | load-balancer_quota_admin | CSP | admin access to quota APIs only, including quota resources owned by others |
| Octavia | load-balancer_admin | CSP | admin access to all LB APIs including resources owned by others |
| Swift | ResellerAdmin | Ceilometer (internal) | assigned to technical users of Ceilometer to integrate with Swift for access privileges in the object storage API to store statistics for metering |
| Heat | heat_stack_user | internal | assigned to technical user accounts resulting from other resources' creation in Heat templates |

### API Policies

TODO: what does the CSP need to adhere to when it comes to API policy configuration?
markus-hentsch marked this conversation as resolved.
Show resolved Hide resolved

#### Key Manager API

For the Key Manager API, the policy rule called "creator" MUST be adjusted to incorporate the "member" role as shown below.
This can be achieved by adding the following entry to a `policy.yaml` for Barbican (usually located at "`/etc/barbican/policy.yaml`"):

```yaml
"creator": "role:creator or role:member"
```

Exemplary contents of a "`/etc/barbican/barbican.conf`":

```ini
[oslo_policy]
enforce_new_defaults = False
enforce_scope = False
policy_file = policy.yaml
```

## Related Documents

### SCS Mandatory and Supported IaaS Services

**Description:** SCS standard that lists mandatory and supported OpenStack APIs for SCS clouds.
This list is decisive for the standard on roles as all applicable services need to be taken into consideration.

**Link:** TBD <!-- https://github.com/SovereignCloudStack/standards/pull/587 -->
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs to be replaced by a genuine link once #587 is merged.


### SCS Domain Manager standard

**Description:** SCS standard that describes the Domain Manager role introduced by SCS and its configuration.

**Link:** [SCS Standards: Domain Manager configuration for Keystone](https://docs.scs.community/standards/scs-0302-v1-domain-manager-role)

### Consistent and Secure Default RBAC

**Description:** Upstream rework of the default role definitions and hierarchy across all OpenStack services.
Explains the reasoning for the `enforce_scope` and `enforce_new_defaults` options and the transition process.

**Link:** [OpenStack Technical Committee Governance Documents: Consistent and Secure Default RBAC](https://governance.openstack.org/tc/goals/selected/consistent-and-secure-rbac.html)

## Conformance Tests

Conformance Tests, OPTIONAL
132 changes: 132 additions & 0 deletions Tests/iam/iaas-roles/standard-roles-check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import argparse
import getpass
import os
import typing

import openstack

CORE_ROLES = {
"member",
"manager",
"admin",
"service"
}

# The dict index key here equals the corresponding endpoint type as per
# Keystone's service catalog. Those roles will only be checked if that
# endpoint type is registered.
# Denoted by a colon, optionally the service name can also be matched against.
SERVICE_ROLES = {
"load-balancer": {
"load-balancer_observer",
"load-balancer_global_observer",
"load-balancer_member",
"load-balancer_quota_admin",
"load-balancer_admin ",
},
"key-manager": {
"key-manager:service-admin",
"creator",
"observer",
"audit",
},
"object-store:swift": {
"ResellerAdmin",
},
"orchestration:heat": {
"heat_stack_user",
}
}


def connect(cloud_name: str, password: typing.Optional[str] = None
) -> openstack.connection.Connection:
"""Create a connection to an OpenStack cloud

:param string cloud_name:
The name of the configuration to load from clouds.yaml.

:param string password:
Optional password override for the connection.

:returns: openstack.connnection.Connection
"""

if password:
return openstack.connect(
cloud=cloud_name,
password=password
)
else:
return openstack.connect(
cloud=cloud_name,
)


def check_list_of_roles(conn: openstack.connection.Connection,
expected_roles: typing.Iterable[str]) -> None:
actual_roles = [role.name for role in conn.identity.roles()]
for role in expected_roles:
assert role in actual_roles, (
f"Expected role '{role}' was not found."
)
print(f"Role '{role}' is present: PASS")


def main():
parser = argparse.ArgumentParser(
description="SCS Standard Roles Conformance 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(
"--ask",
help="Ask for password interactively instead of reading it from the "
"clouds.yaml",
action="store_true"
)
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"
)
conn = connect(
cloud,
password=getpass.getpass("Enter password: ") if args.ask else None
)
service_catalog = [
(svc.get("type"), svc.get("name")) for svc in conn.service_catalog
]

check_list_of_roles(conn, CORE_ROLES)
for service_identifier in SERVICE_ROLES:
if ":" in service_identifier:
# match both service type and service name
svc_type, svc_name = service_identifier.split(":", 1)
if (svc_type, svc_name) not in service_catalog:
# if the service is not present, do not check its roles
continue
else:
# match only service type
if service_identifier not in [svc[0] for svc in service_catalog]:
# if the service is not present, do not check its roles
continue
print(f"INFO: service '{service_identifier}' is present and its "
f"roles will be checked ...")
check_list_of_roles(conn, SERVICE_ROLES[service_identifier])


if __name__ == "__main__":
main()
Loading