Skip to content

Commit

Permalink
Key-Manager Standard (#599)
Browse files Browse the repository at this point in the history
* Create scs-XXXX-vN-key-manager-standard.md

Signed-off-by: josephineSei <[email protected]>

* Update scs-XXXX-vN-key-manager-standard.md

Signed-off-by: josephineSei <[email protected]>

* Create check-for-key-manager.py

This test should be added to the mandatory service test as soon as a Key-Manager MUST be present in csc-conformant deployments.

Signed-off-by: josephineSei <[email protected]>

* Update scs-XXXX-vN-key-manager-standard.md

Signed-off-by: josephineSei <[email protected]>

* Update scs-XXXX-vN-key-manager-standard.md

Signed-off-by: josephineSei <[email protected]>

* Apply suggestions from code review

Co-authored-by: Sven <[email protected]>
Signed-off-by: josephineSei <[email protected]>

* Create scs-XXXX-wN-key-manager-implementation-testing.md

Signed-off-by: josephineSei <[email protected]>

* Update scs-XXXX-vN-key-manager-standard.md

adjusted the phrasing, as gtema said.

Signed-off-by: josephineSei <[email protected]>

* Update scs-XXXX-wN-key-manager-implementation-testing.md

Signed-off-by: josephineSei <[email protected]>

* Update check-for-key-manager.py

Signed-off-by: josephineSei <[email protected]>

* Apply suggestions from code review

Co-authored-by: Sven <[email protected]>
Signed-off-by: josephineSei <[email protected]>

* unify all times "Key Manager" is written

Signed-off-by: josephineSei <[email protected]>

* Update scs-XXXX-wN-key-manager-implementation-testing.md

Signed-off-by: josephineSei <[email protected]>

* Rephrasing many sentences for a better understanding.

Signed-off-by: josephineSei <[email protected]>

* Rephrasing

Signed-off-by: josephineSei <[email protected]>

* Add section for the Key Manager Policies

Signed-off-by: josephineSei <[email protected]>

* Update scs-XXXX-vN-key-manager-standard.md

Signed-off-by: josephineSei <[email protected]>

* add policies to the implementation notes

Signed-off-by: josephineSei <[email protected]>

* Update scs-XXXX-vN-key-manager-standard.md

Signed-off-by: josephineSei <[email protected]>

* Update scs-XXXX-wN-key-manager-implementation-testing.md

Signed-off-by: josephineSei <[email protected]>

* Update check-for-key-manager.py

Signed-off-by: josephineSei <[email protected]>

* Update check-for-key-manager.py

Signed-off-by: josephineSei <[email protected]>

* Update check-for-key-manager.py

Signed-off-by: josephineSei <[email protected]>

* Update check-for-key-manager.py

Signed-off-by: josephineSei <[email protected]>

* Update check-for-key-manager.py

Signed-off-by: josephineSei <[email protected]>

* Update check-for-key-manager.py

Signed-off-by: josephineSei <[email protected]>

* Adjust Spelling and some phrases.

Signed-off-by: josephineSei <[email protected]>

* Update scs-XXXX-wN-key-manager-implementation-testing.md

Signed-off-by: josephineSei <[email protected]>

* Rename scs-XXXX-vN-key-manager-standard.md to scs-0116-v1-key-manager-standard.md

Signed-off-by: josephineSei <[email protected]>

* Update and rename scs-XXXX-wN-key-manager-implementation-testing.md to scs-0116-w1-key-manager-implementation-testing.md

Signed-off-by: josephineSei <[email protected]>

---------

Signed-off-by: Josephine Seifert <[email protected]>
Co-authored-by: Sven <[email protected]>
Co-authored-by: Markus Hentsch <[email protected]>
  • Loading branch information
3 people authored Aug 26, 2024
1 parent 20131c8 commit 4caa5f9
Show file tree
Hide file tree
Showing 3 changed files with 346 additions and 0 deletions.
105 changes: 105 additions & 0 deletions Standards/scs-0116-v1-key-manager-standard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
---
title: Key Manager Standard
type: Standard
status: Draft
track: IaaS
---

## Introduction

To encrypt user data like volumes or in the future also Images and ephemeral storage for VMs, the key has to be present in the infrastructure.
A Key Manager service within the infrastructure can be utilized to store keys.
Consequently providing keys for every encryption or decryption is possible without including the user.
Also authorization policies can be applied on every request to the Key Manager service.
OpenStack offers a Key Manager implementation that is named Barbican, which provides these features.
This standard aims to provide a base level of security for Cloud Service Providers that integrate a Key Manager into their deployments.

## Terminology

| Term | Meaning |
|---|---|
| API | Application Programming Interface, often referring to the REST API interfaces provided by OpenStack and related services |
| Barbican | The Key Manager implementation in OpenStack |
| CSP | Cloud Service Provider, provider managing the OpenStack infrastructure |
| IaaS | Infrastructure-as-a-Service |
| HSM | Hardware Security Module |
| KEK | Key Encryption Key |
| RBAC | Role Based Access Control |

## Motivation

User data encryption requires an encryption key to be known during encryption and decryption processes.
Key Managers like Barbican provide this functionality on the IaaS-Level.
Not every IaaS deployment currently offers user data encryption as part of their standard offering.
This standard should encourage CSPs to integrate a Key Manager and thus increase the amount of Clouds with offerings of data encryption.
It is also important to take a closer look into the Key Manager and analyze how such a service can be configured securely.

A Key Manager service manages keys in a secure manner, but this can be achieved differently and is not primarily in scope of this standard.
The OpenStack Key Manager Barbican stores keys encrypted with a project specific KEK in the database.
The KEKs are also stored encrypted in the same database.
The Master-KEK, used to encrypt the project specific KEKs is not stored in the database and is stored differently depending on the backend storage plugin used.
This standard also abstracts the used plugins and wants to ensure that the Master-KEK is protected, too.

## Design Considerations

While discussing what this standard should aim for it was discovered that some CSPs don't use Barbican or another Key Manager at all and do not provide the feature to encrypt user data to their customers.
This should change, but the exact change comes with financial burden, when choosing a plugin in Barbican to store the Master-KEK or choosing to integrate another Key Manager service instead.
To minimize the burden and enable more CSPs to step up and provide encryption, this standard will only make recommendations about plugins from Barbican.

### Options considered

#### Recommend or even mandate specific Key Manager plugins

It was considered to only recommend a certain set of plugins or backends for the Key Manager, but this may be very prone to change if e.g. Barbican adds a new plugin.
As the SCS only wants to mandate the API that can be abstracted through the Castellan library in OpenStack, integrating any other Key Manager implementation is not uncommon, so this standard needs to consider other possible Key Managers as well.
Due to these reasons this option was disregarded.

#### Recommendation regarding the handling of the Master KEK

Looking into the available Barbican plugins and possible attack vectors one design decision in the plugins is very important: where and how to store the Master-KEK.
Because the Plugins might use different technologies there are many locations for the Master KEK possible.
Most of the Plugins increase the security level by not storing the Master-KEK in plain text on the physical machine Barbican is running on.
This mechanism as a whole, is something that CSPs should aim to do.

#### Standardization of the Key Manager Policy

Because this standards recommends or even eventually mandates the presence of a Key Manager, the situation about the policy of the Key Manager needs to be discussed.
The policy of an IaaS service should use the same roles as the other IaaS services.
Unfortunately this does not apply to the Key Manager implementation Barbican.
It has the roles `reader`, `audit` and `creator`, which are not present in the Keystone role concept.
The roles a customer usually gets through the Identity API is `member`.
Leaving it this way will prevent users from creating and using secrets even when a Key Manager is integrated.

To unify the roles among all IaaS services, there is currently work done in the OpenStack Community.
This initiative is called secure RBAC[^1].
Also the SCS is discussing a standard concerning the roles[^2].
When this is done, there is no further work needed.
But as of the 2024.1 release, this is still under development.

In conclusion this standard should mandate everyone who uses a Key Manager that does not include the secure RBAC, to adjust the policies to have a mapping between the internal `creator` and the identity-based `member` role.
This will result in a `member` being allowed to do everything a `creator` can do.

[^1]: [Secure RBAC work in OpenStack](https://etherpad.opendev.org/p/rbac-goal-tracking)
[^2]: [Issue for a role standard in SCS](https://github.com/SovereignCloudStack/issues/issues/396)

## Key Manager Standard

To increase security and allow user data encryption, CSPs SHOULD implement the Key Manager API (e.g. implemented by Barbican).
The Keys managed by this Key Manager MUST be stored encrypted and the Master-KEK of the Key Manager MUST be stored in another place than the Keys.

If possible CSPs SHOULD NOT store the Master-KEK in plain-text on the physical host the Key Manager is running on.

### Key Manager Policies

If a Key Manager without secure RBAC enabled is used, the policies MUST be adjusted to let the `member` role of the Identity service be equivalent to the Key Manager internal `creator` role.

## Related Documents

[Barbican Plugins](https://docs.openstack.org/de/security-guide/secrets-management/barbican.html)

## Conformance Tests

Conformance must be tested in two steps.

1. The check whether a Key Manager is present can be done in a similar way as in the mandatory OpenStack service APIs standard and the test should be merged into the mandatory service test as soon as a Key Manager is required in scs-conformant infrastructures.
2. The check, that there is no Master-KEK present on the Key Manager Node, has to be done by the CSP themself.
51 changes: 51 additions & 0 deletions Standards/scs-0116-w1-key-manager-implementation-testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
title: "SCS Key Manager Standard: Implementation and Testing Notes"
type: Supplement
track: IaaS
status: Proposal
supplements:
- scs-0116-v1-key-manager-standard.md
---

## Implementation

A Key Manager service can have different backends.
For Barbican these are called Plugins.
The standard plugin is `simple_crypto`, which has the Master-KEK written in the Barbican config file.
In that case the Master-KEK needs additional protection.
When the `simple_crypto` plugin is used, securing the Master-KEK can be achieved through protection of the Barbican config e.g. through running Barbican in an enclave.

Another option to secure the Master-KEK would be using an HSM with a corresponding plugin in Barbican.
In that case the Master-KEK will be stored inside the HSM and encryption and decryption of the Project-KEKs will also happen in the HSM.
There are also software HSMs available, that should be tested for their integration into the Barbican workflow.

Other Plugins in Barbican are the KMIP plugin and Vault[^1].
They are storing the keys differently and CSPs need to make sure, that the access to the keys is configured securely.

:::tip

Barbican supports deploying out-of-tree drivers what enables operators to satisfy their specific needs.

:::

[^1]:[Barbican Plugins](https://docs.openstack.org/barbican/latest/install/barbican-backend.html)

### Policies

When a Key Manager is used, but it uses the old policies and does not enforce the new secure RBAC work, the roles between Barbican and the other IaaS services differ.
This can be done with a small change in the policy.yaml file. The `creator` has to be defined like this:

```yaml
"creator": "role:member"
```
## Automated Tests
The check for the presence of a Key Manager is done with a test script, that checks the presence of a Key Manager service in the catalog endpoint of Openstack.
This check can eventually be moved to the checks for the mandatory an supported service/API list, in case of a promotion of the Key Manager to the mandatory list.
## Manual Tests
It is not possible to check a deployment for a correctly protected Master KEK automatically from the outside.
Even audits would need to check the complete host for plain-text keys.
CSPs are responsible for ensuring the protection of the Master KEK and they have to make at least their architecture for that protection auditable.
190 changes: 190 additions & 0 deletions Tests/iaas/key-manager/check-for-key-manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
"""Mandatory APIs checker
This script retrieves the endpoint catalog from Keystone using the OpenStack
SDK and checks whether a key manager APi endpoint is present.
The script relies on an OpenStack SDK compatible clouds.yaml file for
authentication with Keystone.
"""

import argparse
import json
import logging
import os

import openstack


logger = logging.getLogger(__name__)


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 check_for_member_role(conn: openstack.connection.Connection
) -> None:
"""Checks whether the current user has at maximum privileges
of the member role.
:param connection:
The current connection to an OpenStack cloud.
:returns: boolean, when role with most priviledges is member
"""

auth_data = conn.auth
auth_dict = {
"identity": {
"methods": ["password"],
"password": {
"user": {
"name": auth_data['username'],
"domain": {"name": auth_data['project_domain_name']},
"password": auth_data['password']
}
},
},
"scope": {
"project": {
"domain": {"name": auth_data['project_domain_name']},
"name": auth_data['project_name']
}
}
}

has_member_role = False
request = conn.session.request(auth_data['auth_url'] + '/v3/auth/tokens',
'POST',
json={'auth': auth_dict})
for role in json.loads(request.content)["token"]["roles"]:
role_name = role["name"]
if role_name == "admin" or role_name == "manager":
return False
elif role_name == "member":
print("User has member role.")
has_member_role = True
elif role_name == "reader":
print("User has reader role.")
else:
print("User has custom role.")
return False
return has_member_role


def check_presence_of_key_manager(cloud_name: str):
try:
connection = connect(cloud_name)
services = connection.service_catalog
except Exception as e:
print(str(e))
raise Exception(
f"Connection to cloud '{cloud_name}' was not successfully. "
f"The Catalog endpoint could not be accessed. "
f"Please check your cloud connection and authorization."
)

for svc in services:
svc_type = svc['type']
if svc_type == "key-manager":
# key-manager is present
# now we want to check whether a user with member role
# can create and access secrets
check_key_manager_permissions(connection)
return 0

# we did not find the key-manager service
logger.warning("There is no key-manager endpoint in the cloud.")
# we do not fail, until a key-manager MUST be present
return 0


def check_key_manager_permissions(conn: openstack.connection.Connection
) -> None:
"""
After checking that the current user only has the member and maybe the
reader role, this method verifies that the user with a member role
has sufficient access to the Key Manager API functionality.
"""
secret_name = "scs-member-role-test-secret"
if not check_for_member_role(conn):
logger.warning("Cannot test key-manager permissions. "
"User has wrong roles")
return None

def _find_secret(secret_name_or_id: str):
"""Replacement method for finding secrets.
Mimicks the behavior of Connection.key_manager.find_secret()
but fixes an issue with the internal implementation raising an
exception due to an unexpected microversion parameter.
"""
secrets = conn.key_manager.secrets()
for s in secrets:
if s.name == secret_name_or_id or s.id == secret_name_or_id:
return s
return None

try:
existing_secret = _find_secret(secret_name)
if existing_secret:
conn.key_manager.delete_secret(existing_secret)

conn.key_manager.create_secret(
name=secret_name,
payload_content_type="text/plain",
secret_type="opaque",
payload="foo"
)

new_secret = _find_secret(secret_name)
assert new_secret, (
f"Secret created with name '{secret_name}' was not discoverable by "
f"the user"
)
conn.key_manager.delete_secret(new_secret)
except openstack.exceptions.ForbiddenException as e:
print(
"Users of the 'member' role can use Key Manager API: FAIL"
)
print(
f"ERROR: {str(e)}"
)
exit(1)
print(
"Users of the 'member' role can use Key Manager API: PASS"
)


def main():
parser = argparse.ArgumentParser(
description="SCS Mandatory IaaS Service 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"
)

return check_presence_of_key_manager(cloud)


if __name__ == "__main__":
main()

0 comments on commit 4caa5f9

Please sign in to comment.