Skip to content

Service Binding Specification for Kubernetes #1539

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

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
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
108 changes: 108 additions & 0 deletions docs/design/proposals/provisioned-service/provisioned-service.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Service Binding Specification for Kubernetes

## Problem Statement

Application developers require specific values to connect their
applications to various services. In order to facilitate this connection
problem, the [Service Binding Specification for
Kubernetes](https://servicebinding.io) defines Provisioned
Services as a standard way to expose connection information from backing
services. Supporting Provisioned Services within AWS Controllers for
Kubernetes makes application connectivity to ACK-backed services easy
and seamless.

## Existing Solutions

AWS Controllers for Kubernetes have support for a [FieldExport
API](https://github.com/aws-controllers-k8s/community/blob/main/docs/design/proposals/native-binding/native-binding.md).
This can be used to create a Secret that can be used for [Direct Secret
Reference as per the
specification](https://github.com/servicebinding/spec#direct-secret-reference).
This solution needs more effort from the application developers.

The FieldExport resources required for application developers are the
same, but every developer needs to repeat this same configuration for
every application they deploy. The proposed solution avoids this
repetition through Provisioned Services.

## Proposed Solution

The proposed solution is to make various ACK resources become
Provisioned Services. For example, make the DBInstance resource provided
by the RDS controller a Provisioned Service. Each controller would use
their main custom resource as a Provisioned Service resource. For each
Provisioned Service, identify the fields that need to be exported to
create the Secret resource.

The application developer experience is explained in this demo video:
[https://www.youtube.com/watch?v=AXXWv7N12JM](https://www.youtube.com/watch?v=AXXWv7N12JM)

(This is created as part of a [Proof of
Concept](https://github.com/aws-controllers-k8s/community/issues/1289))

The structure change for DBInstance:

```
// ServiceBindingSecretReference defines a mirror of corev1.LocalObjectReference
type ServiceBindingSecretReference struct {
// Name of the referent secret.
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
Name string `json:"name"`
}

// DBInstanceStatus defines the observed state of DBInstance
type DBInstanceStatus struct {
// Binding exposes the Secret for Service Binding to conform the Provisioned Service
// as per the Service Binding Specification for Kubernetes.
// Ref. https://github.com/servicebinding/spec#provisioned-service
Binding *ServiceBindingSecretReference `json:"binding,omitempty"`
Copy link
Collaborator

Choose a reason for hiding this comment

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

We would want to place this field within the Status.ACKResourceMetadata subfield. That way, it won't conflict with any resources that might have a Binding field already in their status...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The Service Binding Specification expects the Provisioned Service (e.g., DBInstance) to point to the Secret resource from .status.binding.name attribute. I think we can confirm if that field is not conflicting with any existing fields.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@baijum the problem is that the Status and Spec fields for all ACK resources are automatically generated by looking at the AWS service API's model definition. We don't know if there are APIs that have a Binding field in any Create operation's Output shape. If there were, that would conflict with this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can we check if the.status.binding.name attribute exists for any API? Also is it possible to reserve this field for service binding, so that it will not conflict in the future?

Copy link
Collaborator

Choose a reason for hiding this comment

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

We could do this, sure, but the problem is we cannot predict the future. Since ACK CRDs are generated from the upstream API models, what happens if an upstream service API adds a Binding field in the future? This is why we place these kinds of fields into Status.ACKResourceMetadata to ensure that we don't conflict.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have created a proposal to the spec here: servicebinding/spec#223
Let me know if creating a Secret resource with the same name as that of DBInstance resource (or any other service) would be acceptable.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@baijum I left a comment in the other PR. I would be OK with a separate reconciler (ala the FieldExportReconciler we already have in ACK) that would create/manage Secret resources like servicebinding.io expects.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1 with Jay's comment here. This functionality seems similar enough to FieldExport, in that it accesses CRD fields and outputs into a Secret, that I believe it could simply be handled by that reconciler. In fact, we could add this feature by simply adding an optional field within the FieldExport CRD that provides an alternative to from.path, instead being from.bindingSpecification: true/false (name TBD). This would sidestep the need to reserve the .status.binding field.

```

### Benefits

When there are many microservices connecting to the same service, the
label selector feature helps to easily bind all of them with minimal
configuration. Service Binding Specification standard provides a uniform
experience for all the applications connectivity with services.

### Implementation

Since the API changes required for various custom resources are
standard, and they can be generated for all controllers. However, the
changes for each of these controllers can be implemented gradually.
Comment on lines +68 to +72
Copy link
Contributor

Choose a reason for hiding this comment

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

This implementation doesn't really touch on how we know which fields are required for the binding specification? I imagine that each of the bindings will need to be manually crafted. It would be good to have a section that describes how controller maintainers can add new bindings and how they know what the spec should be.


### RBAC

Since a Secret resource needs to be created, updated, and deleted, the
ClusterRole requires "*create",* "*update", and "delete"* permissions.
Currently, this permission is not set in the existing controllers.
Copy link
Collaborator

Choose a reason for hiding this comment

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

The current ClusterRole allows getting, patching, listing and watching Secret resources. Why would we need to add Create and Delete permissions?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The Service Binding Specification expects the Provisioned Service (e.g., DBInstance) to point to a Secret resource with all values required for connectivity from the application. In the case of DBInstance, the corresponding controller needs to ensure the presence of the Secret resource. To create a Secret, Create permission is required. Similarly when the DBInstance is getting deleted, cleaning up the corresponding Secret resource would be good. Hence the Delete permission.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@baijum how does the controller know what the Secret's name will be?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The DBInstance controller generates the Secret. For example, the name could be the same as the DBInstance name.

Copy link
Collaborator

Choose a reason for hiding this comment

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

The DBInstance controller generates the Secret. For example, the name could be the same as the DBInstance name.

@baijum ACK's approach is generally to give that power to the Kubernetes user, which is why the separate reconciler in ACK processes FieldExport CRs that allow the Kubernetes user to specify the name of the Secret or ConfigMap to export fields into.


## RDS Controller Fields

The RDS controller supports multiple databases. Based on the database,
the value for type could be set. For example, postgresql for PostgreSQL
and mysql for MySQL.

Here is a table with required fields for PostgreSQL and MySQL:

|**Field** | **Value** | **Remarks**
|-----------|--------------------------|-------------------------------
|type | postgresql/mysql | Based on Spec.Engine
|provider | aws |
|host | Status.Endpoint.Address |
|port | Status.Endpoint.Port |
|username | Spec.MasterUsername |
|password | | Based on Spec.MasterUserPassword
|database | Spec.Engine? |
Comment on lines +88 to +96
Copy link
Collaborator

Choose a reason for hiding this comment

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

Are the above fields intended to be populated as keys within a Secret?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, the keys will change depending on the service. The above keys are examples that can be used with a relational database.


Some of the fields will take more time to set the value. For example,
the address of an RDS service will only get set once the service has
become ready. The controller can set these fields dynamically.

## Conclusion

Provisioned Service support for ACK would make application connectivity
with services easy and seamless. When there are many microservices
connecting to the same service, the label selector feature helps to
easily bind all of them with minimal configuration. The application
developers receive a consistent experience across all services.