Skip to content

Commit c54fc03

Browse files
authored
feat: Added support for templates in external secrets (#5874)
* feat: Added support for templates in external secrets * renamed dataFrom to esoDataFrom * deployment history data fixed * deployment history data diff view fixed * added validations and const * renamed EsoData to ESOData * chore: updated []json.RawMessage to json.RawMessage * feat: updated validations
1 parent 3060edb commit c54fc03

File tree

10 files changed

+123
-59
lines changed

10 files changed

+123
-59
lines changed

api/appbean/AppDetail.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,10 @@ type Secret struct {
179179
}
180180

181181
type ConfigMapSecretDataVolumeUsageConfig struct {
182-
MountPath string `json:"mountPath"`
183-
SubPath bool `json:"subPath"`
184-
FilePermission string `json:"filePermission"`
182+
MountPath string `json:"mountPath"`
183+
SubPath bool `json:"subPath"`
184+
FilePermission string `json:"filePermission"`
185+
ESOSubPath []string `json:"esoSubPath"`
185186
}
186187

187188
type ExternalSecret struct {

api/bean/ConfigMapAndSecret.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ type ConfigSecretMap struct {
5454
RoleARN string `json:"roleARN"`
5555
SecretData json.RawMessage `json:"secretData,omitempty"`
5656
SubPath bool `json:"subPath"`
57+
ESOSubPath []string `json:"esoSubPath"`
5758
FilePermission string `json:"filePermission"`
5859
}
5960

@@ -70,7 +71,7 @@ func (configSecretJson *ConfigSecretJson) SetReferencedSecrets(secrets []ConfigS
7071
configSecretJson.Secrets = util.GetReferencedArray(secrets)
7172
}
7273

73-
func (ConfigSecretRootJson) GetTransformedDataForSecretData(data string, mode util.SecretTransformMode) (string, error) {
74+
func GetTransformedDataForSecretData(data string, mode util.SecretTransformMode) (string, error) {
7475
secretsJson := ConfigSecretRootJson{}
7576
err := json.Unmarshal([]byte(data), &secretsJson)
7677
if err != nil {

api/restHandler/CoreAppRestHandler.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -891,7 +891,7 @@ func (handler CoreAppRestHandlerImpl) buildAppConfigMaps(appId int, envId int, c
891891
}
892892
var dataObj map[string]interface{}
893893
if data != nil {
894-
err := json.Unmarshal([]byte(data), &dataObj)
894+
err := json.Unmarshal(data, &dataObj)
895895
if err != nil {
896896
handler.logger.Errorw("service err, un-marshaling of data fail in config map", "err", err, "appId", appId)
897897
return nil, err, http.StatusInternalServerError
@@ -1041,6 +1041,7 @@ func (handler CoreAppRestHandlerImpl) buildAppSecrets(appId int, envId int, secr
10411041
globalSecret.DataVolumeUsageConfig = &appBean.ConfigMapSecretDataVolumeUsageConfig{
10421042
SubPath: secret.SubPath,
10431043
FilePermission: secret.FilePermission,
1044+
ESOSubPath: secret.ESOSubPath,
10441045
}
10451046
considerGlobalDefaultData := envId > 0 && secret.Data == nil
10461047
if considerGlobalDefaultData {
@@ -1486,6 +1487,7 @@ func (handler CoreAppRestHandlerImpl) createGlobalSecrets(appId int, userId int3
14861487
secretData.MountPath = dataVolumeUsageConfig.MountPath
14871488
secretData.SubPath = dataVolumeUsageConfig.SubPath
14881489
secretData.FilePermission = dataVolumeUsageConfig.FilePermission
1490+
secretData.ESOSubPath = dataVolumeUsageConfig.ESOSubPath
14891491
}
14901492

14911493
if secret.IsExternal {
@@ -1989,6 +1991,7 @@ func (handler CoreAppRestHandlerImpl) createEnvSecret(appId int, userId int32, e
19891991
secretData.MountPath = secretOverrideDataVolumeUsageConfig.MountPath
19901992
secretData.SubPath = secretOverrideDataVolumeUsageConfig.SubPath
19911993
secretData.FilePermission = secretOverrideDataVolumeUsageConfig.FilePermission
1994+
secretData.ESOSubPath = secretOverrideDataVolumeUsageConfig.ESOSubPath
19921995
}
19931996
var secretDataRequest []*bean2.ConfigData
19941997
secretDataRequest = append(secretDataRequest, secretData)

pkg/appClone/AppCloneService.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,7 @@ func (impl *AppCloneServiceImpl) configDataClone(cfData []*bean3.ConfigData) []*
556556
ExternalSecretType: refdata.ExternalSecretType,
557557
FilePermission: refdata.FilePermission,
558558
SubPath: refdata.SubPath,
559+
ESOSubPath: refdata.ESOSubPath,
559560
}
560561
copiedData = append(copiedData, data)
561562
}

pkg/bean/configSecretData.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package bean
1919
import (
2020
"encoding/json"
2121
"github.com/devtron-labs/devtron/util"
22+
"strings"
2223
)
2324

2425
type ConfigList struct {
@@ -29,6 +30,7 @@ type SecretList struct {
2930
ConfigData []*ConfigData `json:"secrets"`
3031
}
3132

33+
// TODO refactoring: duplicate struct of ConfigData in ConfigMapBean.go
3234
type ConfigData struct {
3335
Name string `json:"name"`
3436
Type string `json:"type"`
@@ -45,9 +47,14 @@ type ConfigData struct {
4547
DefaultESOSecretData ESOSecretData `json:"defaultESOSecretData,omitempty"`
4648
RoleARN string `json:"roleARN"`
4749
SubPath bool `json:"subPath"`
50+
ESOSubPath []string `json:"esoSubPath"`
4851
FilePermission string `json:"filePermission"`
4952
}
5053

54+
func (c *ConfigData) IsESOExternalSecretType() bool {
55+
return strings.HasPrefix(c.ExternalSecretType, "ESO")
56+
}
57+
5158
type ExternalSecret struct {
5259
Key string `json:"key"`
5360
Name string `json:"name"`
@@ -58,8 +65,10 @@ type ExternalSecret struct {
5865
type ESOSecretData struct {
5966
SecretStore json.RawMessage `json:"secretStore,omitempty"`
6067
SecretStoreRef json.RawMessage `json:"secretStoreRef,omitempty"`
61-
EsoData []ESOData `json:"esoData"`
68+
ESOData []ESOData `json:"esoData"`
6269
RefreshInterval string `json:"refreshInterval,omitempty"`
70+
ESODataFrom json.RawMessage `json:"esoDataFrom,omitempty"`
71+
Template json.RawMessage `json:"template,omitempty"`
6372
}
6473

6574
type ESOData struct {
@@ -68,7 +77,7 @@ type ESOData struct {
6877
Property string `json:"property,omitempty"`
6978
}
7079

71-
func (ConfigData) GetTransformedDataForSecretData(data string, mode util.SecretTransformMode) (string, error) {
80+
func GetTransformedDataForSecretData(data string, mode util.SecretTransformMode) (string, error) {
7281
secretDataMap := make(map[string]*ConfigData)
7382
err := json.Unmarshal([]byte(data), &secretDataMap)
7483
if err != nil {

pkg/pipeline/ConfigMapService.go

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -487,8 +487,6 @@ func (impl ConfigMapServiceImpl) CMEnvironmentFetch(appId int, envId int) (*bean
487487
item.DefaultMountPath = item.MountPath
488488
item.Data = nil
489489
item.MountPath = ""
490-
item.SubPath = item.SubPath
491-
item.FilePermission = item.FilePermission
492490
configDataRequest.ConfigData = append(configDataRequest.ConfigData, item)
493491
}
494492
}
@@ -580,6 +578,7 @@ func (impl ConfigMapServiceImpl) CSGlobalAddUpdate(configMapRequest *bean.Config
580578
item.ExternalSecret = configData.ExternalSecret
581579
item.RoleARN = configData.RoleARN
582580
item.SubPath = configData.SubPath
581+
item.ESOSubPath = configData.ESOSubPath
583582
item.FilePermission = configData.FilePermission
584583
}
585584
configs = append(configs, item)
@@ -736,6 +735,7 @@ func (impl ConfigMapServiceImpl) CSEnvironmentAddUpdate(configMapRequest *bean.C
736735
item.ExternalSecret = configData.ExternalSecret
737736
item.RoleARN = configData.RoleARN
738737
item.SubPath = configData.SubPath
738+
item.ESOSubPath = configData.ESOSubPath
739739
item.FilePermission = configData.FilePermission
740740
found = true
741741
}
@@ -873,16 +873,16 @@ func (impl ConfigMapServiceImpl) CSEnvironmentFetch(appId int, envId int) (*bean
873873
item.DefaultExternalSecret = item.ExternalSecret
874874
}
875875
item.DefaultESOSecretData = item.ESOSecretData
876-
item.ESOSecretData.EsoData = nil
876+
item.ESOSecretData.ESOData = nil
877877
item.ESOSecretData.SecretStore = nil
878+
item.ESOSecretData.ESODataFrom = nil
879+
item.ESOSecretData.Template = nil
878880
item.ESOSecretData.SecretStoreRef = nil
879881
item.ESOSecretData.RefreshInterval = ""
880882
item.DefaultMountPath = item.MountPath
881883
item.Data = nil
882884
item.ExternalSecret = nil
883885
item.MountPath = ""
884-
item.SubPath = item.SubPath
885-
item.FilePermission = item.FilePermission
886886
configDataRequest.ConfigData = append(configDataRequest.ConfigData, item)
887887
}
888888
}
@@ -1455,7 +1455,24 @@ func (impl ConfigMapServiceImpl) validateConfigDataForSecretsOnly(configData *be
14551455
if err != nil {
14561456
impl.logger.Errorw("error in decoding secret data", "error", err)
14571457
return false, util.NewApiError().WithHttpStatusCode(http.StatusUnprocessableEntity).WithCode(strconv.Itoa(http.StatusUnprocessableEntity)).
1458-
WithUserMessage("error in decoding data, make sure the secret data is encoded properly")
1458+
WithUserMessage("error in decoding data, make sure the secret data is encoded properly").
1459+
WithInternalMessage("error in decoding data, make sure the secret data is encoded properly")
1460+
}
1461+
}
1462+
if configData.IsESOExternalSecretType() {
1463+
if !configData.External {
1464+
return false, util.NewApiError().WithHttpStatusCode(http.StatusBadRequest).WithCode(strconv.Itoa(http.StatusBadRequest)).
1465+
WithUserMessage(fmt.Sprintf("external flag should be true for '%s' secret type", configData.ExternalSecretType)).
1466+
WithInternalMessage(fmt.Sprintf("external flag should be true for '%s' secret type", configData.ExternalSecretType))
1467+
}
1468+
if configData.ESOSecretData.ESODataFrom == nil && configData.ESOSecretData.ESOData == nil {
1469+
return false, util.NewApiError().WithHttpStatusCode(http.StatusBadRequest).WithCode(strconv.Itoa(http.StatusBadRequest)).
1470+
WithUserMessage("both esoSecretData.esoDataFrom and esoSecretData.esoData can't be empty").
1471+
WithInternalMessage("both esoSecretData.esoDataFrom and esoSecretData.esoData can't be empty")
1472+
} else if configData.ESOSecretData.SecretStore == nil && configData.ESOSecretData.SecretStoreRef == nil {
1473+
return false, util.NewApiError().WithHttpStatusCode(http.StatusBadRequest).WithCode(strconv.Itoa(http.StatusBadRequest)).
1474+
WithUserMessage("both esoSecretData.secretStore and esoSecretData.secretStoreRef can't be empty").
1475+
WithInternalMessage("both esoSecretData.secretStore and esoSecretData.secretStoreRef can't be empty")
14591476
}
14601477
}
14611478
return true, nil

pkg/pipeline/bean/ConfigMapBean.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package bean
1818

1919
import (
2020
"encoding/json"
21+
"strings"
2122
)
2223

2324
type ConfigDataRequest struct {
@@ -31,8 +32,10 @@ type ConfigDataRequest struct {
3132
type ESOSecretData struct {
3233
SecretStore json.RawMessage `json:"secretStore,omitempty"`
3334
SecretStoreRef json.RawMessage `json:"secretStoreRef,omitempty"`
34-
EsoData []ESOData `json:"esoData,omitempty"`
35+
ESOData []ESOData `json:"esoData,omitempty"`
3536
RefreshInterval string `json:"refreshInterval,omitempty"`
37+
ESODataFrom json.RawMessage `json:"esoDataFrom,omitempty"`
38+
Template json.RawMessage `json:"template,omitempty"`
3639
}
3740

3841
type ESOData struct {
@@ -57,9 +60,15 @@ type ConfigData struct {
5760
DefaultExternalSecret []ExternalSecret `json:"defaultSecretData,omitempty"`
5861
RoleARN string `json:"roleARN"`
5962
SubPath bool `json:"subPath"`
63+
ESOSubPath []string `json:"esoSubPath"`
6064
FilePermission string `json:"filePermission"`
6165
Overridden bool `json:"overridden"`
6266
}
67+
68+
func (c *ConfigData) IsESOExternalSecretType() bool {
69+
return strings.HasPrefix(c.ExternalSecretType, "ESO")
70+
}
71+
6372
type ExternalSecret struct {
6473
Key string `json:"key"`
6574
Name string `json:"name"`

pkg/pipeline/history/ConfigMapHistoryService.go

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import (
2020
"context"
2121
"encoding/json"
2222
"errors"
23-
"strings"
23+
globalUtil "github.com/devtron-labs/devtron/util"
2424
"time"
2525

2626
"github.com/devtron-labs/devtron/internal/sql/repository/chartConfig"
@@ -490,7 +490,7 @@ func (impl ConfigMapHistoryServiceImpl) GetHistoryForDeployedCMCSById(ctx contex
490490
SubPath: &config.SubPath,
491491
FilePermission: config.FilePermission,
492492
CodeEditorValue: &HistoryDetailConfig{
493-
DisplayName: "Data",
493+
DisplayName: DataDisplayName,
494494
Value: string(config.Data),
495495
VariableSnapshot: variableSnapshotMap,
496496
ResolvedValue: resolvedTemplate,
@@ -521,13 +521,27 @@ func (impl ConfigMapHistoryServiceImpl) GetHistoryForDeployedCMCSById(ctx contex
521521
}
522522
historyDto.ExternalSecretType = config.ExternalSecretType
523523
historyDto.RoleARN = config.RoleARN
524+
historyDto.ESOSubPath = config.ESOSubPath
524525
if config.External {
525-
externalSecretData, err := json.Marshal(config.ExternalSecret)
526-
if err != nil {
527-
impl.logger.Errorw("error in marshaling external secret data", "err", err)
528-
}
529-
if len(externalSecretData) > 0 {
530-
historyDto.CodeEditorValue.Value = string(externalSecretData)
526+
if config.ExternalSecretType == globalUtil.KubernetesSecret {
527+
externalSecretData, err := json.Marshal(config.ExternalSecret)
528+
if err != nil {
529+
impl.logger.Errorw("error in marshaling external secret data", "err", err)
530+
}
531+
if len(externalSecretData) > 0 {
532+
historyDto.CodeEditorValue.DisplayName = ExternalSecretDisplayName
533+
historyDto.CodeEditorValue.Value = string(externalSecretData)
534+
}
535+
} else if config.IsESOExternalSecretType() {
536+
externalSecretDataBytes, jErr := json.Marshal(config.ESOSecretData)
537+
if jErr != nil {
538+
impl.logger.Errorw("error in marshaling eso secret data", "esoSecretData", config.ESOSecretData, "err", jErr)
539+
return nil, jErr
540+
}
541+
if len(externalSecretDataBytes) > 0 {
542+
historyDto.CodeEditorValue.DisplayName = ESOSecretDataDisplayName
543+
historyDto.CodeEditorValue.Value = string(externalSecretDataBytes)
544+
}
531545
}
532546
}
533547
}
@@ -593,7 +607,7 @@ func (impl ConfigMapHistoryServiceImpl) ConvertConfigDataToComponentLevelDto(con
593607
SubPath: &config.SubPath,
594608
FilePermission: config.FilePermission,
595609
CodeEditorValue: &HistoryDetailConfig{
596-
DisplayName: "Data",
610+
DisplayName: DataDisplayName,
597611
Value: string(config.Data),
598612
},
599613
}
@@ -623,22 +637,27 @@ func (impl ConfigMapHistoryServiceImpl) ConvertConfigDataToComponentLevelDto(con
623637
}
624638
historyDto.ExternalSecretType = config.ExternalSecretType
625639
historyDto.RoleARN = config.RoleARN
640+
historyDto.ESOSubPath = config.ESOSubPath
626641
if config.External {
627642
var externalSecretData []byte
628-
if strings.HasPrefix(config.ExternalSecretType, "ESO") {
643+
displayName := historyDto.CodeEditorValue.DisplayName
644+
if config.IsESOExternalSecretType() {
645+
displayName = ESOSecretDataDisplayName
629646
externalSecretData, err = json.Marshal(config.ESOSecretData)
630647
if err != nil {
631648
impl.logger.Errorw("error in marshaling external secret data", "err", err)
632649
return nil, err
633650
}
634651
} else {
652+
displayName = ExternalSecretDisplayName
635653
externalSecretData, err = json.Marshal(config.ExternalSecret)
636654
if err != nil {
637655
impl.logger.Errorw("error in marshaling external secret data", "err", err)
638656
return nil, err
639657
}
640658
}
641659
if len(externalSecretData) > 0 {
660+
historyDto.CodeEditorValue.DisplayName = displayName
642661
historyDto.CodeEditorValue.Value = string(externalSecretData)
643662
}
644663
}

pkg/pipeline/history/bean.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ type HistoryDetailDto struct {
7272
ExternalSecretType string `json:"externalType,omitempty"`
7373
RoleARN string `json:"roleARN,omitempty"`
7474
SubPath *bool `json:"subPath,omitempty"`
75+
ESOSubPath []string `json:"esoSubPath,omitempty"`
7576
FilePermission string `json:"filePermission,omitempty"`
7677
CodeEditorValue *HistoryDetailConfig `json:"codeEditorValue"`
7778
SecretViewAccess bool `json:"secretViewAccess"` // this is being used to check whether a user can see obscured secret values or not.
@@ -84,6 +85,12 @@ type HistoryDetailConfig struct {
8485
ResolvedValue string `json:"resolvedValue"`
8586
}
8687

88+
const (
89+
DataDisplayName = "Data"
90+
ESOSecretDataDisplayName = "ESO Secret Data"
91+
ExternalSecretDisplayName = "External Secret Data"
92+
)
93+
8794
//history components(deployment template, configMaps, secrets, pipeline strategy) components below
8895

8996
type ConfigMapAndSecretHistoryDto struct {

0 commit comments

Comments
 (0)