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

[Feature]: API Client can bind UPSIs via the POST /v3/service_credential_bindings API #458

Closed
tcdowney opened this issue Jan 13, 2022 · 3 comments
Assignees
Labels

Comments

@tcdowney
Copy link
Member

tcdowney commented Jan 13, 2022

Blockers/Dependencies


Background

⚠️ User-provided Service Instance == UPSI ⚠️

As an API Client
I want to be able to create service credential bindings for UPSI via the POST /v3/service_credential_bindings API
So that I can bind a UPSI to my apps


Acceptance Criteria

Happy Path: binding type is app

GIVEN I have permission to create K8s ServiceBindings in the requested namespace
WHEN I make the following request to POST /v3/service_credential_bindings

curl "https://api.example.org/v3/service_credential_bindings" \
  -X POST \
  -H "Authorization: bearer [token]" \
  -H "Content-type: application/json" \
  -d  '{
  "relationships": {
    "app": {
      "data": {
        "guid": "3bd795f2-8f50-4b75-b443-37b6e5dca393"
      }
    },
    "service_instance": {
      "data": {
        "guid": "0942349b-b69b-41e3-aaa8-65a4091a9ef5"
      }
    }
  },
  "type": "app"
}'

THEN I see the following response

HTTP/1.1 201 Created

{
  "created_at": "2022-01-13T19:35:14Z",
  "guid": "9b2129fa-94e4-4359-a83a-b577a57939d9",
  "last_operation": {
    "created_at": "2022-01-13T19:35:14Z",
    "description": null,
    "state": "succeeded",
    "type": "create",
    "updated_at": "2022-01-13T19:35:14Z"
  },
  "links": {
    "app": {
      "href": "https://api.cat-lasher.capi.land/v3/apps/3bd795f2-8f50-4b75-b443-37b6e5dca393"
    },
    "details": {
      "href": "https://api.cat-lasher.capi.land/v3/service_credential_bindings/9b2129fa-94e4-4359-a83a-b577a57939d9/details"
    },
    "self": {
      "href": "https://api.cat-lasher.capi.land/v3/service_credential_bindings/9b2129fa-94e4-4359-a83a-b577a57939d9"
    },
    "service_instance": {
      "href": "https://api.cat-lasher.capi.land/v3/service_instances/0942349b-b69b-41e3-aaa8-65a4091a9ef5"
    }
  },
  "metadata": {
    "annotations": {},
    "labels": {}
  },
  "name": null,
  "relationships": {
    "app": {
      "data": {
        "guid": "3bd795f2-8f50-4b75-b443-37b6e5dca393"
      }
    },
    "service_instance": {
      "data": {
        "guid": "3bd795f2-8f50-4b75-b443-37b6e5dca393"
      }
    }
  },
  "type": "app",
  "updated_at": "2022-01-13T19:35:14Z"
}

AND I See a CFServiceBinding resource pointing to the CFApp. Would look something like this:

---
apiVersion: services.cloudfoundry.org/v1alpha1
kind: CFServiceBinding

metadata:
  
  name: 9b2129fa-94e4-4359-a83a-b577a57939d9 # service binding guid
  namespace: my-cf-space-guid
  labels:
    servicebinding.io/provisioned-service: "true"
spec:
  name: my-binding-name
  service:
    apiVersion: services.cloudfoundry.org/v1alpha1
    kind: CFServiceInstance
    name: 3bd795f2-8f50-4b75-b443-37b6e5dca393 # service instance GUID
  secretName: cf-service-credentials-3bd795f2-8f50-4b75-b443-37b6e5dca393 #shares the same secret as the UPSI
  appRef:
    name: 3bd795f2-8f50-4b75-b443-37b6e5dca393 # CFApp GUID

status:
  
  binding:
    name: cf-service-credentials-my-upsi-guid

Sad Path: binding type is key

GIVEN I have permission to create K8s ServiceBindings in the requested namespace
WHEN I make the following request to POST /v3/service_credential_bindings

curl "https://api.example.org/v3/service_credential_bindings" \
  -X POST \
  -H "Authorization: bearer [token]" \
  -H "Content-type: application/json" \
  -d  '{
  "name": "mykey",
  "relationships": {
    "service_instance": {
      "data": {
        "guid": "0942349b-b69b-41e3-aaa8-65a4091a9ef5"
      }
    }
  },
  "type": "key"
}'

THEN I get a 422 response

HTTP/1.1 422 Unprocessable Entity

{
  "errors": [
    {
      "code": 10008,
      "detail": "Service credential bindings of type 'key' are not supported for user-provided service instances.",
      "title": "CF-UnprocessableEntity"
    }
  ]
}

Sad Path: App is already bound to the Service Instance

GIVEN I have already created a CFServiceBinding for a given App and Service Instance
WHEN I Try to create a duplicate binding
THEN I Get a 422 error saying "The app is already bound to the service instance"

Related code: https://github.com/cloudfoundry/cloud_controller_ng/blob/02e0035da375c20cafa807f895b2de60fbd4a862/app/actions/service_credential_binding_app_create.rb#L35


Sad Path: App and Service Instance are not in the same space

GIVEN The App and Service instance that I'm trying to bind are in separate spaces
WHEN I make the following request

curl "https://api.example.org/v3/service_credential_bindings" \
  -X POST \
  -H "Authorization: bearer [token]" \
  -H "Content-type: application/json" \
  -d  '{
  "relationships": {
    "app": {
      "data": {
        "guid": "3bd795f2-8f50-4b75-b443-37b6e5dca393"
      }
    },
    "service_instance": {
      "data": {
        "guid": "<service-instance-in-a-different-space-i-have-access-to>"
      }
    }
  },
  "type": "app"
}'

THEN I Get a 422 error saying "The service instance and the app are in different spaces"


Sad Path: service instance belongs to a space the user does not have permissions in

GIVEN I do not have permission to create service bindings in the namespace in which the service instance lives
WHEN I make the following request

curl "https://api.example.org/v3/service_credential_bindings" \
  -X POST \
  -H "Authorization: bearer [token]" \
  -H "Content-type: application/json" \
  -d  '{
  "relationships": {
    "app": {
      "data": {
        "guid": "3bd795f2-8f50-4b75-b443-37b6e5dca393"
      }
    },
    "service_instance": {
      "data": {
        "guid": "<service-instance-in-space-i-cant-access>"
      }
    }
  },
  "type": "app"
}'

THEN I get a 403 error with the message You are not authorized to perform the requested action


Dev Notes

  • This story only results in a CFServiceBinding being created. Credential projection will come in a future story
  • We should handle auth(n/z) as part of this story
  • "name" is optional for service bindings!
  • When an app is already bound to a service you get a 422, so you will need to add labels or some mechanism for detecting duplicate bindings

Resources:

@tcdowney tcdowney added the UPSI label Jan 13, 2022
@tcdowney
Copy link
Member Author

Updated since IPM with two additional acceptance criteria around the App/Service Instance being in separate spaces (422) and duplicate service bindings (422).

@matt-royal matt-royal self-assigned this Jan 27, 2022
@matt-royal
Copy link
Member

@tcdowney and I just talked this over, and decided that we should move the secret's name should only be present in the status, and that the controller should be responsible for setting it. This makes the flow the same for user-provided and managed services, so that the user/client doesn't have to handle the (potentially asynchronous) binding credential creation.

@tcdowney
Copy link
Member Author

Closing: This was completed by #673 and passed acceptance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Archived in project
Development

No branches or pull requests

2 participants