orange-cloudfoundry / osb-cmdb

A configuration management db for Open Service Broker API broker implementations
Apache License 2.0
14 stars 1 forks source link

Support sharing service instances across osb client platforms/tenants #88

Open gberche-orange opened 3 years ago

gberche-orange commented 3 years ago

Expected behavior

As an app developer

Observed behavior

Alternatives UXs

Sharing opt-in with osb-cmdb tenants In this UX, an owner of an existing service instance grants a specific 3rd party osb client permission to access a share of its service instance. When a 3rd party service instance then asks to create the service instance with the specified instance correlation key, then a share is used instead This is a bit similar to [CF service instance sharing UX](https://docs.cloudfoundry.org/devguide/services/sharing-instances.html) #### Step 1: service owner: specifies accepted sharing requests save the following json in `authZ.json`specifying sharing authorization ```json { "x_osb_cmdb": { "sharing_to": [ { "tenant": "cf1", "profile": "cloudfoundry", "org_name": "my_org", "space_name": "my_space", "org_guid": "my_org_guid", "space_guid": "my_space_guid", "instance_name": "my_instance" }, { "tenant": "ks2", "profile": "kubernetes", "namespace": "my_namespace", "originating_identity_groups": "[\"system:serviceaccounts\",\"system:serviceaccounts:catalog\",\"system:authenticated\"]", "originating_identity_username": "system:serviceaccount:catalog:service-catalog-controller-manager", "service_instance_guid": "a-service-instance-guid" } ] } } ``` `cf create-service-instance mysql 10mb mydb -c authZ.json ` or `cf update-instance mydb -c authZ.json ` Details about the `sharing_to` structure: * each field defines a `sharing constraint` * all sharing constraints need to match for a lease request to be accepted * some sharing constraints are mutually exclusive: `*-name` and `*-guid`. When both are specified (e.g. `space-name` and `space-guid`) then `*-name` (e.g. `space-name`) are ignored and are considered as documentation commenting the value of `*-guid` constraints. * `*-name` constraints may be used among trusted tenants where there is low risk that an attacker can forge a space/org of the same name to obtain a lease without being granted actual permissions. Names are easier to reason with but grant a lower security. * `*-guid` constraints are used among less trusted tenants, where a service owner needs to actually control exactly the org/space of the leaser (as guid are immutable and hard to inject into osb client platforms). Guids are harder to reason on #### Step 2: service leaser: instanciate service instance lease A distinct user provisions a service instance with all of the matching criteria (tenant, org/space/instance), plus service offering type ``` # cf login to cf1 cf t -o my_org -s my_space cf create-service-instance mysql 10mb mydb-share ``` The status message indicates this is a shared instance (aka a lease) ``` cf service mydb-share Showing info of service gberche-pmysql in org diod-gcp-demo-sosh-care / space front-end as gberche... name: mydb-share service: p-mysql tags: plan: 10mb description: MariaDB databases 10.3.22 on demand on shared cluster documentation: https://mariadb.com/kb/en/library/ dashboard: https://[..] service broker: p-mysql Showing status of last operation from service mydb-share... status: create succeeded message: This is a lease from instance in tenant 1 with guid=1234 started: 2020-12-17T15:53:15Z updated: 2020-12-17T15:53:15Z ``` #### Step 2b: service owner: review list of leases The service owner can obtain a list of leases from a shared service instance: ``` $ cf service-instance mydb --params { , "x_osb_cmdb": { "sharing-to":[ ...], "leases": [ { "tenant": "cf1", "profile": "cloudfoundry", "org_name": "my_org", "space_name": "my_space", "org_guid": "my_org_guid", "space_guid": "my_space_guid", "instance_name": "my_instance", "instance_guid": "my_instance-guid" }, { "tenant": "cf2", "profile": "cloudfoundry", "org_name": "my_org", "space_name": "my_space", "org_guid": "my_org_guid", "space_guid": "my_space_guid", "instance_name": "my_instance", "instance_guid": "my_instance-guid" } ] } } #### Step 3: service owner: fails to delete a shared service instance The service owner can not delete a shared service instance when there are remaining leases ``` $ cf delete-service-instance -f mydb FAILED Broker Error: service instance can not deleted as it is still shared ``` [ ] TODO: consider displaying shares in the error message `Broker Error: service instance can not deleted as it is still shared with [ { "tenant": "cf1", "profile": "cloudfoundry", "org_name": "my_org", "space_name": "my_space", "org_guid": "my_org_guid", "space_guid": "my_space_guid", "instance_name": "my_instance" }` #### Step 4a: service owner: revokes service sharing permissions The service owner revokes the service sharing permissions which prevents new leases from being created. Note that revoking sharing permissions does not delete leases as there is no notification mechanism available to notify platforms of deletion of a shared service instance in order to delete leases. Save the following json in `authZ.json` specifying sharing authorization: ```json { "x_osb_cmdb": { "sharing_to": [ ] } } ``` `cf update-instance mydb -c authZ.json ` #### Step 4b: service leaser: delete lease The service leaser can always delete a lease ``` # cf login to cf1 cf t -o my_org -s my_space cf delete-service-instance -f mydb-lease ``` #### Step 5: service owner: unprovision share without leases The service owner can delete its shared service instance when there are no associated leases ``` $ cf delete-service-instance -f mydb OK ``` #### Step 5a: service owner: purge leases The service owner can purge any leases associated to a shared service instance: ``` $ cf update-service-instance mydb -c { , "x_osb_cmdb": { "sharing-to":[ ...], "leases": [ // one or all leases removed from here ] } } ``` #### Step 5b: service owner: unprovision share and purge leases In case the service owner lost control over the leases, he can delete a shared service instance and purging any associated leases. This creates dangling orphan leases that will need to be purged manually by service leasers Save the following json in `authZ.json` specifying sharing authorization: ```json { "x_osb_cmdb": { "sharing_to": [ ], "purge_leases_on_delete": "true" } } ``` ``` $ cf update-instance mydb -c authZ.json OK $ cf delete-service-instance -f mydb OK ```
Explicit lease creation using sharing token exchanged out-of-bands In this UX, an owner of an existing service instance obtains a sharing secret that it provides out-of-bands to a service leaser. The service leaser uses the sharing token to create a lease before the token expiration date. #### Step 1: service owner: obtains sharing token The service owner looks up a sharing token that it may send to another team or use himself to create a service lease ``` $ cf service mydb --params { "x_osb_cmdb": { "sharing_token": { "token": "123456...", "expiration-date": "Mon, 22 Mar 2021 17:42:55 +0100" } // other osb-cmdb backend service instance params omited }, // other brokered service instance params omited } ``` ``` $ cf service mydb --params | jq -r .x_osb_cmdb.sharing_token.token 123456... ``` #### Step 2: service owner: obtains sharing token A distinct user provisions a service instance matching the same service offering type and sharing token ``` # cf login to any other platform # cf login to cf1 cf create-service-instance mysql 10mb mydb-share -c '{"sharing_token":"123456..."} ``` The status message indicates this is a shared instance (aka a lease) ``` cf service mydb-share Showing info of service gberche-pmysql in org diod-gcp-demo-sosh-care / space front-end as gberche... name: mydb-share service: p-mysql tags: plan: 10mb description: MariaDB databases 10.3.22 on demand on shared cluster documentation: https://mariadb.com/kb/en/library/ dashboard: https://[..] service broker: p-mysql Showing status of last operation from service mydb-share... status: create succeeded message: This is a lease from instance in tenant 1 with guid=1234 started: 2020-12-17T15:53:15Z updated: 2020-12-17T15:53:15Z ``` #### Step 2b: service owner: review list of leases The service owner can obtain a list of leases from a shared service instance: ``` $ cf service-instance mydb --params { , "x_osb_cmdb": { "sharing_token":[ ...], "leases": [ { "tenant": "cf1", "profile": "cloudfoundry", "org_name": "my_org", "space_name": "my_space", "org_guid": "my_org_guid", "space_guid": "my_space_guid", "instance_name": "my_instance", "instance_guid": "my_instance-guid" }, { "tenant": "cf2", "profile": "cloudfoundry", "org_name": "my_org", "space_name": "my_space", "org_guid": "my_org_guid", "space_guid": "my_space_guid", "instance_name": "my_instance", "instance_guid": "my_instance-guid" } ] } } #### Step 3: service owner: fails to delete a shared service instance The service owner can not delete a shared service instance when there are remaining leases ``` $ cf delete-service-instance -f mydb FAILED Broker Error: service instance can not deleted as it is still shared ``` [ ] TODO: consider displaying shares in the error message `Broker Error: service instance can not deleted as it is still shared with [ { "tenant": "cf1", "profile": "cloudfoundry", "org_name": "my_org", "space_name": "my_space", "org_guid": "my_org_guid", "space_guid": "my_space_guid", "instance_name": "my_instance" }` #### Step 5: service owner: unprovision share without leases The service owner can delete its shared service instance when there are no associated leases ``` $ cf delete-service-instance -f mydb OK ``` #### Step 5a: service owner: purge leases The service owner can purge any leases associated to a shared service instance: ``` $ cf update-service-instance mydb -c { , "x_osb_cmdb": { "sharing-to":[ ...], "leases": [ // one or all leases removed from here ] } } OK ``` #### Step 5b: service owner: unprovision share and purge leases In case the service owner lost control over the leases, he can delete a shared service instance and purging any associated leases. This creates dangling orphan leases that will need to be purged manually by service leasers Save the following json in `authZ.json` specifying sharing authorization: ```json { "x_osb_cmdb": { // other params omitted here "purge_leases_on_delete": "true" } } ``` ``` $ cf update-instance mydb -c authZ.json OK $ cf delete-service-instance -f mydb OK ```

The following table summarizes key differences/implications among the alternative UXs

Actor Use case Sharing opt-in Sharing token
Owner Control where leases can be created Explicit via lease constraints Out-of-band exchange of sharing token with leaser(s)
Owner Audit traces of granting leases Platform audits of assigned lease constraints Hard to control the dissemination of the sharing token
Leaser Create lease Implicit, no additional action Explicit by specifying sharing token before expiration time

Under the hood, osb-cmdb uses:

Service broker involvements

Affected release

Reproduced on version x.y -->

gberche-orange commented 3 years ago

Pending improvements/fixes to the proposed UX above:

bgandon commented 3 years ago

Hi Guillaume,

After reading this, here is some feedback.

When specifying a sharing authorisation, specifying both Org name and Org GUID might cause confusion whenever they don't match. The same applies for Space name and GUID.

{
  "x-osb-cmdb": {
    "sharing-to": [
      {
        "tenant": "cf1",
        "profile": "cloudfoundry",
        "org-name": "my-org",
        "space-name": "my-space",
        "org-guid": "my-org2-guid",
        "space-guid": "my-space2-guid",
        "instance-name": "my-instance"
      },
      ...

Whenever an Org (or Space) would be renamed, then the Org names/GUIDs specified in authZ.json specs would not match anymore.

In case inconsistent Org name & GUID is supported in authZ.json, this specification would benefit from detailing the algorithm for resolving the exact target Org. Or, just choose one of the fields to rely on. Names are for humans, whereas GUIDs are for machines. Humans need readable things, and machine needs precise references.

Whenever names would be preferred, then the actual GUIDs should be resolved by the broker in some way so that the system is resistant to Orgs renames. This resolving could be made through a read-only access to the target tenant, or through a unique “meta” resolver API that would have read-only access to all tenants.

Whenever GUIDs would be preferred, then humans would need some easy way to convert them into understandable names, just for the sake of verifying that the parameters are correct (useful for debugging).

Best, Benjamin

gberche-orange commented 3 years ago

thanks @bgandon for your feedback

I refined the sharing optin ux with the following details. Please let me know if this makes sense to you.

Details about the sharing_to structure:

  • each field defines a sharing constraint
  • all sharing constraints need to match for a lease request to be accepted
  • some sharing constraints are mutually exclusive: *-name and *-guid. When both are specified (e.g. space-name and space-guid) then *-name (e.g. space-name) are ignored and are considered as documentation commenting the value of *-guid constraints.
    • *-name constraints may be used among trusted tenants where there is low risk that an attacker can forge a space/org of the same name to obtain a lease without being granted actual permissions. Names are easier to reason with but grant a lower security.
    • *-guid constraints are used among less trusted tenants, where a service owner needs to actually control exactly the org/space of the leaser (as guid are immutable and hard to inject into osb client platforms). Guids are harder to reason on
gberche-orange commented 2 years ago

Suggested refinement by @poblin-orange