Service Binding Specification for Kubernetes standardizes exposing backing service secrets to applications. A backing service is any process that the application consumes over the network as part of its regular operation. Examples include datastores (such as MySQL or MongoDB), caching servers (such as Memcached), and stream processing systems (such as Kafka). If you are a backing service provider, this article gives you all the information required to evaluate Service Binding Specification for Kubernetes. There is an expository commentary on the spec related to backing service integration. Finally, the article has curated a list of frequently asked questions with answers.
The spec introduction presents a good summary of the importance of the specification. The key benefit for supporting the spec for a backing service is that the Secret resource will be collected and exposed to applications consistently and predictably.
Few facts about the spec:
- The spec is a collective effort of a community working with Kuberentes.
- Contributions from many organizations including VMware, IBM, and Red Hat.
- The spec is matured and GA release will happen soon
- The Provisioned Service part for backing service is stable and ready for adoption
Projects with Support for Service Binding
Currently the Kuberentes ecosystem is getting ready for the spec adoption. Here is a list of projects with support for Service Binding:
- Red Hat implementation
- VMware implementation
- KubePreset - A side-project of Baiju Muthukadan
- Service Binding Controller - Reference implementation
Provisioned Service is the key abstraction used in the spec to define a backing service. The spec consider Provisioned Service as a duck type with a definition like this:
Any type that meets the contract defined in a specification, without being an instance of a specific concrete type. For example, for specification that requires a given key on
status, any resource that has that key on its
statusregardless of its kind would be considered a duck type of the specification.
The Provisioned Service section starts like this:
A Provisioned Service resource MUST define a
.status.bindingwhich is a
LocalObjectReference-able (containing a single field
name) to a
is a type with
name field. The name should point to a Secret resource with
data entries for the application to connect to the backing service. Service
Binding recociler will project the Secret values in to the application as
defined in the Application
section of the spec. As you can see the sentence has the key word MUST in
full capital and bold, that indicates this is a mandatory requirement to comform
to the spec.
This is the next mandatory requirement:
SecretMUST be in the same namespace as the resource.
If the provisioned service and applications are in different namespaces, users may consider using Provisioned Service Syncer Operator to sync the Secret resource across namespace.
The next sentence is not a mandate, but a recommendation:
Secretdata SHOULD contain a
typeentry with a value that identifies the abstract classification of the binding.
This is a recommendation to the provisioned service, but when it comes to the
Application Projection, it becomes a mandatory requirement as part of the
projected bindings data. Even if the provisioned service provides a value for
type, it is possible to override the value from the
There is no standardization on the value for
type, but you can see some good
examples used in the Spring Cloud
.data.type) SHOULD reflect this value as
This recommendation helps to query Secret resources of particular type using field-selector. For example:
kubectl get secrets --field-selector="type=service.binding/postgresql"
will give the Secret resources of
It is RECOMMENDED that the
Secretdata also contain a
providerentry with a value that identifies the provider of the binding.
provider field helps to narrow down the tye further in the application.
The provider field could be used where there are different providers for the
same Provisioned Service type. For example, if the type is
provider value could be
aws-rds, etc. When
the application is reading the binding values, if necessary, the application
provider as a composite key to avoid ambiguity.
Secretdata MAY contain any other entry.
Apart from the
provider entries, the Secret data can include
To facilitate discoverability, it is RECOMMENDED that a
CustomResourceDefinitionexposing a Provisioned Service add
service.binding/provisioned-service: "true"as a label.
This helps to find all the Provisioned Service custom resouces. For example:
kubectl get customresourcedefinitions.apiextensions.k8s.io -l "service.binding/provisioned-service=true"
Next there is a side note:
Note: While the Provisioned Service referenced
Secretdata should contain a
typemust be defined before it is projected into an application workload. This allows a mapping to enrich an existing secret.
This is already discussed earlier.
Extensions and implementations MAY define additional mechanisms to consume a Provisioned Service that does not conform to the duck type.
This recommendation is added to unblock any extensions or implementations with special requirements.
Well-known Secret Entries
This is the mandatory requirement about well-known Secret entries. Thought, it is acceptable not to include any of these entries in the Secret resource.
Other than the recommended
providerentries, there are no other reserved
Secretentries. In the interests of consistency, if a
Secretincludes any of the following entry names, the entry value MUST meet the specified requirements:
If the Provisioned Service doesn’t include any of the following entry names, no need to follow the given requirements.
A DNS-resolvable host name or IP address
A valid port number
A valid URI as defined by RFC3986
A string-based username credential
A string-based password credential
A collection of PEM-encoded X.509 certificates, representing a certificate chain used in mTLS client authentication
A PEM-encoded private key used in mTLS client authentication
For Go based operators, you may consider using github.com/kubepreset/pkg/secret package to validate these entries.
Secretentries that do not meet these requirements MUST use different entry names.
If there is any entry that doesn’t follow the given requirement, you can choose different names. For example, if there is a URI-like string but not a valid one, as per RFC-3986, use another name (e.g., “custom-uri”).
Considerations for Role-Based Access Control (RBAC)
The spec has support for Role-Based Access Control (RBAC). Since the service binding reconciler needs permission to read Provisioned Service resources, there is a mandate about RBAC like this:
If a service binding reconciler implementation is using Role-Based Access Control (RBAC) it MUST define an aggregated
ClusterRolewith a label selector matching the label
So, there must be a
ClusterRole configured in the Kubernetes cluster something
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: ... aggregationRule: clusterRoleSelectors: - matchLabels: service.binding/controller: "true" rules:  # The control plane automatically fills in the rules
There is a recommendation for backing service about RBAC:
Cluster operators and CRD authors SHOULD opt-in resources to expose provisioned services by defining a
ClusterRolewith a label matching
watchverbs MUST be granted.
As a backing service author, you can offer a
ClusterRole with that same label
service.binding/controller=true) and the verbs (
listed in the rules. Here is an example
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: kubepostgres-service-bindings labels: service.binding/controller: "true" # matches the aggregation rule selector rules: - apiGroups: - kubepostgres.dev resources: - databases verbs: - get - list - watch
In the above example, the API group for the backing service CRD is
kubepostgres.dev and the resource name (plural form) is
databases. You can
change those values as per your Provisioned Service. While your operator is
getting installed, make sure this cluster role is also installed. For example,
if you us Helm charts, you can add the above
ClusterRole configuration into a
file inside the template directory (e.g.,
Frequently Asked Questions
Is it possible to use separate namespaces for Provisioned Services and applications?
Current spec has a strong recommendation to restrict service binding to provisioned service within the same namespace.
Restricting service binding to resources within the same namespace is strongly RECOMMENDED.
(From 2nd paragraph of Service Binding section)
If your provisioned service and applications are in different namespaces, you may consider using Provisioned Service Syncer Operator to sync the Secret resource across namespace.
Is it okay to replace the Secret resource name when there is a change in any of the entries?
Yes, it is a good practice to update
.status.binding.name field value with the
new name of the Secret resource. After the update, remove the old Secret
resource from the cluster. That should trigger Service Binding reconciliation
and, in turn, update the projected bindings. That’s the advantage of level
triggering and reconciliation in Kubernetes!