Skip to content

Commit

Permalink
Add spec.secretKey for access to raw broker response (#62)
Browse files Browse the repository at this point in the history
* Add spec.secretKey for access to raw broker response

Setting the optional spec.secretKey will cause the reconciler to store the raw broker response json in the given key (inside the secret).
If it is not set, the old behavior will be used (parse the response and use the top level keys in secret.Data).

Fixes #61

Co-authored-by: Philipp Stehle <[email protected]>

* update secretKey property description according to review comments

Co-authored-by: Ralf Pannemans <[email protected]>
  • Loading branch information
phil9909 and c0d1ngm0nk3y authored Jul 29, 2021
1 parent 06f4496 commit 780cb50
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 1 deletion.
7 changes: 7 additions & 0 deletions api/v1alpha1/servicebinding_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ type ServiceBindingSpec struct {
// +optional
SecretName string `json:"secretName"`

// SecretKey is used as the key inside the secret to store the credentials
// returned by the broker encoded as json to support complex data structures.
// If not specified, the credentials returned by the broker will be used
// directly as the secrets data.
// +optional
SecretKey *string `json:"secretKey,omitempty"`

// Parameters for the binding.
//
// The Parameters field is NOT secret or secured in any way and should
Expand Down
5 changes: 5 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions config/crd/bases/services.cloud.sap.com_servicebindings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ spec:
type: object
type: object
type: array
secretKey:
description: SecretKey is used as the key inside the secret to store the credentials returned by the broker encoded as json to support complex data structures. If not specified, the credentials returned by the broker will be used directly as the secrets data.
type: string
secretName:
description: SecretName is the name of the secret where credentials will be stored
type: string
Expand Down
4 changes: 4 additions & 0 deletions controllers/servicebinding_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,10 @@ func (r *ServiceBindingReconciler) storeBindingSecret(ctx context.Context, k8sBi
if len(smBinding.Credentials) == 0 {
log.Info("Binding credentials are empty")
credentialsMap = make(map[string][]byte)
} else if k8sBinding.Spec.SecretKey != nil {
credentialsMap = map[string][]byte{
*k8sBinding.Spec.SecretKey: smBinding.Credentials,
}
} else {
var err error
credentialsMap, err = normalizeCredentials(smBinding.Credentials)
Expand Down
35 changes: 34 additions & 1 deletion controllers/servicebinding_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,29 @@ var _ = Describe("ServiceBinding controller", func() {
validateSecretData(bindingSecret, "escaped", `{"escaped_key":"escaped_val"}`)
})

It("should put the raw broker response into the secret if spec.secretKey is provided", func() {
ctx := context.Background()
binding := newBinding("binding-with-secretkey", bindingTestNamespace)
binding.Spec.ServiceInstanceName = instanceName
binding.Spec.SecretName = "mysecret"
secretKey := "mycredentials"
binding.Spec.SecretKey = &secretKey

_ = k8sClient.Create(ctx, binding)
bindingLookupKey := types.NamespacedName{Name: binding.Name, Namespace: binding.Namespace}
Eventually(func() bool {
err := k8sClient.Get(ctx, bindingLookupKey, binding)
if err != nil {
return false
}
return isReady(binding)
}, timeout, interval).Should(BeTrue())

bindingSecret := getSecret(ctx, binding.Spec.SecretName, bindingTestNamespace, true)
validateSecretData(bindingSecret, secretKey, `{"secret_key": "secret_value", "escaped": "{\"escaped_key\":\"escaped_val\"}"}`)
Expect(bindingSecret.Data).To(HaveLen(1))
})

When("secret deleted by user", func() {
fakeSmResponse := func(bindingID string) {
fakeClient.ListBindingsReturns(&smclientTypes.ServiceBindings{
Expand Down Expand Up @@ -592,6 +615,16 @@ var _ = Describe("ServiceBinding controller", func() {
})
})

When("secretKey is changed", func() {
It("should fail", func() {
secretKey := "not-nil"
createdBinding.Spec.SecretKey = &secretKey
err := k8sClient.Update(context.Background(), createdBinding)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("updating service bindings is not supported"))
})
})

})

Context("Delete", func() {
Expand Down Expand Up @@ -818,7 +851,7 @@ var _ = Describe("ServiceBinding controller", func() {

func validateSecretData(secret *v1.Secret, expectedKey string, expectedValue string) {
Expect(secret.Data).ToNot(BeNil())
Expect(len(secret.Data[expectedKey])).ToNot(BeNil())
Expect(secret.Data).To(HaveKey(expectedKey))
Expect(string(secret.Data[expectedKey])).To(Equal(expectedValue))
}

Expand Down

0 comments on commit 780cb50

Please sign in to comment.