Skip to content

Commit

Permalink
Support for secret store reference in Dapr components (radius-project…
Browse files Browse the repository at this point in the history
…#7823)

# Description
Hey,

This PR adds support for building Dapr components with an optional
reference to a Dapr secret store.

The new property is named _secretStoreComponentName_. This name is
totally arbitrary but was chosen to try to be as clear as possible.

A secret reference can be created using a _secretKeyRef_ object,
following the same [naming convention as
Dapr](https://docs.dapr.io/operations/components/component-secrets/).

Example : 
```yaml
resource stateStore 'Applications.Dapr/stateStores@2023-10-01-preview' = {
  name: 'statestore'
  properties: {
    environment: environment
    application: application
    resourceProvisioning: 'manual'
    type: 'state.redis'
    version: 'v1'
    metadata: {
      redisHost: {
        secretKeyRef: {
            name: 'redisHost'
            key: 'redisHost'
        }

      }
      redisPassword: ''
    }
    secretStoreComponentName: daprSecretStore.name
  }
}
```

## Type of change

- This pull request adds or changes features of Radius and has an
approved issue (issue link required).

Fixes: radius-project#7704

---------

Signed-off-by: SoTrx <[email protected]>
  • Loading branch information
SoTrx authored Sep 5, 2024
1 parent dca3a27 commit a1ab146
Show file tree
Hide file tree
Showing 47 changed files with 1,731 additions and 326 deletions.

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions hack/bicep-types-radius/generated/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@
"$ref": "applications/applications.core/2023-10-01-preview/types.json#/271"
},
"Applications.Dapr/pubSubBrokers@2023-10-01-preview": {
"$ref": "applications/applications.dapr/2023-10-01-preview/types.json#/44"
"$ref": "applications/applications.dapr/2023-10-01-preview/types.json#/48"
},
"Applications.Dapr/secretStores@2023-10-01-preview": {
"$ref": "applications/applications.dapr/2023-10-01-preview/types.json#/61"
"$ref": "applications/applications.dapr/2023-10-01-preview/types.json#/66"
},
"Applications.Dapr/stateStores@2023-10-01-preview": {
"$ref": "applications/applications.dapr/2023-10-01-preview/types.json#/79"
"$ref": "applications/applications.dapr/2023-10-01-preview/types.json#/85"
},
"Applications.Datastores/mongoDatabases@2023-10-01-preview": {
"$ref": "applications/applications.datastores/2023-10-01-preview/types.json#/48"
Expand Down
62 changes: 62 additions & 0 deletions pkg/daprrp/api/v20231001preview/datamodel_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,68 @@ func fromRecipeDataModel(r portableresources.ResourceRecipe) *Recipe {
}
}

func toMetadataDataModel(metadata map[string]*MetadataValue) map[string]*rpv1.DaprComponentMetadataValue {
if metadata == nil {
return nil
}

dmMeta := make(map[string]*rpv1.DaprComponentMetadataValue, len(metadata))
for name, valueNode := range metadata {
dmMeta[name] = &rpv1.DaprComponentMetadataValue{
Value: to.String(valueNode.Value),
}

if valueNode.SecretKeyRef != nil {
dmMeta[name].SecretKeyRef = &rpv1.DaprComponentSecretRef{
Name: to.String(valueNode.SecretKeyRef.Name),
Key: to.String(valueNode.SecretKeyRef.Key),
}
}
}
return dmMeta
}

func fromMetadataDataModel(metadata map[string]*rpv1.DaprComponentMetadataValue) map[string]*MetadataValue {
if metadata == nil {
return nil
}

meta := make(map[string]*MetadataValue, len(metadata))
for name, valueNode := range metadata {
meta[name] = &MetadataValue{
Value: to.Ptr(valueNode.Value),
}

if valueNode.SecretKeyRef != nil {
meta[name].SecretKeyRef = &MetadataValueFromSecret{
Name: to.Ptr(valueNode.SecretKeyRef.Name),
Key: to.Ptr(valueNode.SecretKeyRef.Key),
}
}
}
return meta
}

func toAuthDataModel(auth *DaprResourceAuth) *rpv1.DaprComponentAuth {
if auth == nil {
return nil
}

return &rpv1.DaprComponentAuth{
SecretStore: to.String(auth.SecretStore),
}
}

func fromAuthDataModel(auth *rpv1.DaprComponentAuth) *DaprResourceAuth {
if auth == nil {
return nil
}

return &DaprResourceAuth{
SecretStore: to.Ptr(auth.SecretStore),
}
}

func toResourcesDataModel(r []*ResourceReference) []*portableresources.ResourceReference {
if r == nil {
return nil
Expand Down
153 changes: 153 additions & 0 deletions pkg/daprrp/api/v20231001preview/datamodel_util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,3 +293,156 @@ func TestToRecipeDataModel(t *testing.T) {
require.Equal(t, testCase.datamodel, sc)
}
}

func TestToMetadataDataModel(t *testing.T) {
testCases := []struct {
metadata map[string]*MetadataValue
expected map[string]*rpv1.DaprComponentMetadataValue
}{
{
metadata: nil,
expected: nil,
},
{
metadata: map[string]*MetadataValue{"config": {Value: to.Ptr("extrasecure")}},
expected: map[string]*rpv1.DaprComponentMetadataValue{"config": {Value: "extrasecure"}},
},
{
metadata: map[string]*MetadataValue{
"secret": {
SecretKeyRef: &MetadataValueFromSecret{
Key: to.Ptr("secretKey"),
Name: to.Ptr("secretValue"),
},
},
},
expected: map[string]*rpv1.DaprComponentMetadataValue{
"secret": {
SecretKeyRef: &rpv1.DaprComponentSecretRef{
Key: "secretKey",
Name: "secretValue",
},
},
},
},
}

for _, tt := range testCases {
actual := toMetadataDataModel(tt.metadata)
require.Equal(t, tt.expected, actual)
}
}

func TestFromMetadataDataModel(t *testing.T) {
testCases := []struct {
metadata map[string]*rpv1.DaprComponentMetadataValue
expected map[string]*MetadataValue
}{
{
metadata: nil,
expected: nil,
},
{
metadata: map[string]*rpv1.DaprComponentMetadataValue{"config": {Value: "extrasecure"}},
expected: map[string]*MetadataValue{"config": {Value: to.Ptr("extrasecure")}},
},
{
metadata: map[string]*rpv1.DaprComponentMetadataValue{
"secret": {
SecretKeyRef: &rpv1.DaprComponentSecretRef{
Key: "secretKey",
Name: "secretValue",
},
},
},
expected: map[string]*MetadataValue{
"secret": {
Value: to.Ptr(""),
SecretKeyRef: &MetadataValueFromSecret{
Key: to.Ptr("secretKey"),
Name: to.Ptr("secretValue"),
},
},
},
},
}

for _, tt := range testCases {
actual := fromMetadataDataModel(tt.metadata)
require.Equal(t, tt.expected, actual)
}
}

func TestToAuthDataModel(t *testing.T) {
testCases := []struct {
auth *DaprResourceAuth
expected *rpv1.DaprComponentAuth
}{
{
auth: nil,
expected: nil,
},
{
auth: &DaprResourceAuth{
SecretStore: to.Ptr("test-secretstore"),
},
expected: &rpv1.DaprComponentAuth{
SecretStore: "test-secretstore",
},
},
{
auth: &DaprResourceAuth{
SecretStore: nil,
},
expected: &rpv1.DaprComponentAuth{
SecretStore: "",
},
},
{
auth: &DaprResourceAuth{
SecretStore: to.Ptr(""),
},
expected: &rpv1.DaprComponentAuth{
SecretStore: "",
},
},
}

for _, tt := range testCases {
actual := toAuthDataModel(tt.auth)
require.Equal(t, tt.expected, actual)
}
}

func TestFromAuthDataModel(t *testing.T) {
testCases := []struct {
auth *rpv1.DaprComponentAuth
expected *DaprResourceAuth
}{
{
auth: nil,
expected: nil,
},
{
auth: &rpv1.DaprComponentAuth{
SecretStore: "test-secretstore",
},
expected: &DaprResourceAuth{
SecretStore: to.Ptr("test-secretstore"),
},
},
{
auth: &rpv1.DaprComponentAuth{
SecretStore: "",
},
expected: &DaprResourceAuth{
SecretStore: to.Ptr(""),
},
},
}

for _, tt := range testCases {
actual := fromAuthDataModel(tt.auth)
require.Equal(t, tt.expected, actual)
}
}
7 changes: 4 additions & 3 deletions pkg/daprrp/api/v20231001preview/pubsubbroker_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ func (src *DaprPubSubBrokerResource) ConvertTo() (v1.DataModelInterface, error)
}

converted.Properties.Resources = toResourcesDataModel(src.Properties.Resources)
converted.Properties.Auth = toAuthDataModel(src.Properties.Auth)

// Note: The metadata, type, and version fields cannot be specified when using recipes since
// the recipe is expected to create the Dapr Component manifest. However, they are required
Expand All @@ -79,8 +80,7 @@ func (src *DaprPubSubBrokerResource) ConvertTo() (v1.DataModelInterface, error)
if src.Properties.Version == nil || *src.Properties.Version == "" {
msgs = append(msgs, "version must be specified when resourceProvisioning is set to manual")
}

converted.Properties.Metadata = src.Properties.Metadata
converted.Properties.Metadata = toMetadataDataModel(src.Properties.Metadata)
converted.Properties.Type = to.String(src.Properties.Type)
converted.Properties.Version = to.String(src.Properties.Version)
} else {
Expand Down Expand Up @@ -132,10 +132,11 @@ func (dst *DaprPubSubBrokerResource) ConvertFrom(src v1.DataModelInterface) erro
OutputResources: toOutputResources(daprPubSub.Properties.Status.OutputResources),
Recipe: fromRecipeStatus(daprPubSub.Properties.Status.Recipe),
},
Auth: fromAuthDataModel(daprPubSub.Properties.Auth),
}

if daprPubSub.Properties.ResourceProvisioning == portableresources.ResourceProvisioningManual {
dst.Properties.Metadata = daprPubSub.Properties.Metadata
dst.Properties.Metadata = fromMetadataDataModel(daprPubSub.Properties.Metadata)
dst.Properties.Type = to.Ptr(daprPubSub.Properties.Type)
dst.Properties.Version = to.Ptr(daprPubSub.Properties.Version)
} else {
Expand Down
14 changes: 10 additions & 4 deletions pkg/daprrp/api/v20231001preview/pubsubbroker_conversion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ func TestDaprPubSubBroker_ConvertVersionedToDataModel(t *testing.T) {
Environment: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/test-env",
},
ResourceProvisioning: portableresources.ResourceProvisioningManual,
Metadata: map[string]any{
"foo": "bar",
Metadata: map[string]*rpv1.DaprComponentMetadataValue{
"foo": {
Value: "bar",
},
},
Resources: []*portableresources.ResourceReference{
{
Expand Down Expand Up @@ -180,8 +182,10 @@ func TestDaprPubSubBroker_ConvertDataModelToVersioned(t *testing.T) {
Properties: &DaprPubSubBrokerProperties{
Environment: to.Ptr("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/test-env"),
Application: to.Ptr("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/applications/test-app"),
Metadata: map[string]any{
"foo": "bar",
Metadata: map[string]*MetadataValue{
"foo": {
Value: to.Ptr("bar"),
},
},
ResourceProvisioning: to.Ptr(ResourceProvisioningManual),
Resources: []*ResourceReference{
Expand All @@ -194,6 +198,7 @@ func TestDaprPubSubBroker_ConvertDataModelToVersioned(t *testing.T) {
ComponentName: to.Ptr("test-dpsb"),
ProvisioningState: to.Ptr(ProvisioningStateAccepted),
Status: resourcetypeutil.MustPopulateResourceStatus(&ResourceStatus{}),
Auth: &DaprResourceAuth{SecretStore: to.Ptr("test-secret-store")},
},
Tags: map[string]*string{
"env": to.Ptr("dev"),
Expand All @@ -218,6 +223,7 @@ func TestDaprPubSubBroker_ConvertDataModelToVersioned(t *testing.T) {
ComponentName: to.Ptr("test-dpsb"),
ProvisioningState: to.Ptr(ProvisioningStateAccepted),
Status: resourcetypeutil.MustPopulateResourceStatusWithRecipe(&ResourceStatus{}),
Auth: nil,
},
Tags: map[string]*string{
"env": to.Ptr("dev"),
Expand Down
6 changes: 3 additions & 3 deletions pkg/daprrp/api/v20231001preview/secretstore_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func (src *DaprSecretStoreResource) ConvertTo() (v1.DataModelInterface, error) {
msgs = append(msgs, "version must be specified when resourceProvisioning is set to manual")
}

converted.Properties.Metadata = src.Properties.Metadata
converted.Properties.Metadata = toMetadataDataModel(src.Properties.Metadata)
converted.Properties.Type = to.String(src.Properties.Type)
converted.Properties.Version = to.String(src.Properties.Version)
} else {
Expand Down Expand Up @@ -120,15 +120,15 @@ func (dst *DaprSecretStoreResource) ConvertFrom(src v1.DataModelInterface) error
Application: to.Ptr(daprSecretStore.Properties.Application),
Type: to.Ptr(daprSecretStore.Properties.Type),
Version: to.Ptr(daprSecretStore.Properties.Version),
Metadata: daprSecretStore.Properties.Metadata,
Metadata: fromMetadataDataModel(daprSecretStore.Properties.Metadata),
ComponentName: to.Ptr(daprSecretStore.Properties.ComponentName),
Status: &ResourceStatus{
OutputResources: toOutputResources(daprSecretStore.Properties.Status.OutputResources),
Recipe: fromRecipeStatus(daprSecretStore.Properties.Status.Recipe),
},
}
if daprSecretStore.Properties.ResourceProvisioning == portableresources.ResourceProvisioningManual {
dst.Properties.Metadata = daprSecretStore.Properties.Metadata
dst.Properties.Metadata = fromMetadataDataModel(daprSecretStore.Properties.Metadata)
dst.Properties.Type = to.Ptr(daprSecretStore.Properties.Type)
dst.Properties.Version = to.Ptr(daprSecretStore.Properties.Version)
} else {
Expand Down
22 changes: 15 additions & 7 deletions pkg/daprrp/api/v20231001preview/secretstore_conversion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ func TestDaprSecretStore_ConvertVersionedToDataModel(t *testing.T) {
Environment: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/test-env",
},
ResourceProvisioning: portableresources.ResourceProvisioningManual,
Metadata: map[string]any{
"foo": "bar",
Metadata: map[string]*rpv1.DaprComponentMetadataValue{
"foo": {
Value: "bar",
},
},
Type: "secretstores.hashicorp.vault",
Version: "v1",
Expand Down Expand Up @@ -143,8 +145,10 @@ func TestDaprSecretStore_ConvertDataModelToVersioned(t *testing.T) {
Properties: &DaprSecretStoreProperties{
Environment: to.Ptr("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/environments/test-env"),
Application: to.Ptr("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/radius-test-rg/providers/Applications.Core/applications/test-app"),
Metadata: map[string]any{
"foo": "bar",
Metadata: map[string]*MetadataValue{
"foo": {
Value: to.Ptr("bar"),
},
},
ResourceProvisioning: to.Ptr(ResourceProvisioningManual),
Type: to.Ptr("secretstores.hashicorp.vault"),
Expand Down Expand Up @@ -176,9 +180,13 @@ func TestDaprSecretStore_ConvertDataModelToVersioned(t *testing.T) {
"foo": "bar",
},
},
Type: to.Ptr("secretstores.hashicorp.vault"),
Version: to.Ptr("v1"),
Metadata: map[string]any{"foo": "bar"},
Type: to.Ptr("secretstores.hashicorp.vault"),
Version: to.Ptr("v1"),
Metadata: map[string]*MetadataValue{
"foo": {
Value: to.Ptr("bar"),
},
},
ComponentName: to.Ptr("test-dss"),
ProvisioningState: to.Ptr(ProvisioningStateAccepted),
Status: resourcetypeutil.MustPopulateResourceStatus(&ResourceStatus{
Expand Down
Loading

0 comments on commit a1ab146

Please sign in to comment.