diff --git a/k8-operator/packages/api/api.go b/k8-operator/packages/api/api.go index 0dd3d7a6f..0b750469f 100644 --- a/k8-operator/packages/api/api.go +++ b/k8-operator/packages/api/api.go @@ -56,6 +56,7 @@ func CallGetSecretsV3(httpClient *resty.Client, request GetEncryptedSecretsV3Req SetHeader("User-Agent", USER_AGENT_NAME). SetHeader("If-None-Match", request.ETag). SetQueryParam("environment", request.Environment). + SetQueryParam("include_imports", "true"). // TODO needs to be set as a option SetQueryParam("workspaceId", request.WorkspaceId) if request.SecretPath != "" { diff --git a/k8-operator/packages/api/models.go b/k8-operator/packages/api/models.go index 8e68d65c5..a72ccfc49 100644 --- a/k8-operator/packages/api/models.go +++ b/k8-operator/packages/api/models.go @@ -29,43 +29,54 @@ type GetEncryptedWorkspaceKeyResponse struct { } type GetEncryptedSecretsV3Request struct { - Environment string `json:"environment"` - WorkspaceId string `json:"workspaceId"` - SecretPath string `json:"secretPath"` - ETag string `json:"etag,omitempty"` + Environment string `json:"environment"` + WorkspaceId string `json:"workspaceId"` + SecretPath string `json:"secretPath"` + IncludeImport bool `json:"include_imports"` + ETag string `json:"etag,omitempty"` +} + +type EncryptedSecretV3 struct { + ID string `json:"_id"` + Version int `json:"version"` + Workspace string `json:"workspace"` + Type string `json:"type"` + Tags []struct { + ID string `json:"_id"` + Name string `json:"name"` + Slug string `json:"slug"` + Workspace string `json:"workspace"` + } `json:"tags"` + Environment string `json:"environment"` + SecretKeyCiphertext string `json:"secretKeyCiphertext"` + SecretKeyIV string `json:"secretKeyIV"` + SecretKeyTag string `json:"secretKeyTag"` + SecretValueCiphertext string `json:"secretValueCiphertext"` + SecretValueIV string `json:"secretValueIV"` + SecretValueTag string `json:"secretValueTag"` + SecretCommentCiphertext string `json:"secretCommentCiphertext"` + SecretCommentIV string `json:"secretCommentIV"` + SecretCommentTag string `json:"secretCommentTag"` + Algorithm string `json:"algorithm"` + KeyEncoding string `json:"keyEncoding"` + Folder string `json:"folder"` + V int `json:"__v"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` +} + +type ImportedSecretV3 struct { + Environment string `json:"environment"` + FolderId string `json:"folderId"` + SecretPath string `json:"secretPath"` + Secrets []EncryptedSecretV3 `json:"secrets"` } type GetEncryptedSecretsV3Response struct { - Secrets []struct { - ID string `json:"_id"` - Version int `json:"version"` - Workspace string `json:"workspace"` - Type string `json:"type"` - Tags []struct { - ID string `json:"_id"` - Name string `json:"name"` - Slug string `json:"slug"` - Workspace string `json:"workspace"` - } `json:"tags"` - Environment string `json:"environment"` - SecretKeyCiphertext string `json:"secretKeyCiphertext"` - SecretKeyIV string `json:"secretKeyIV"` - SecretKeyTag string `json:"secretKeyTag"` - SecretValueCiphertext string `json:"secretValueCiphertext"` - SecretValueIV string `json:"secretValueIV"` - SecretValueTag string `json:"secretValueTag"` - SecretCommentCiphertext string `json:"secretCommentCiphertext"` - SecretCommentIV string `json:"secretCommentIV"` - SecretCommentTag string `json:"secretCommentTag"` - Algorithm string `json:"algorithm"` - KeyEncoding string `json:"keyEncoding"` - Folder string `json:"folder"` - V int `json:"__v"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - } `json:"secrets"` - Modified bool `json:"modified,omitempty"` - ETag string `json:"ETag,omitempty"` + Secrets []EncryptedSecretV3 `json:"secrets"` + ImportedSecrets []ImportedSecretV3 `json:"imports,omitempty"` + Modified bool `json:"modified,omitempty"` + ETag string `json:"ETag,omitempty"` } type GetServiceTokenDetailsResponse struct { diff --git a/k8-operator/packages/util/secrets.go b/k8-operator/packages/util/secrets.go index 28ba47253..d3e13f536 100644 --- a/k8-operator/packages/util/secrets.go +++ b/k8-operator/packages/util/secrets.go @@ -89,13 +89,18 @@ func GetPlainTextSecretsViaServiceToken(fullServiceToken string, etag string, en return nil, api.GetEncryptedSecretsV3Response{}, fmt.Errorf("unable to decrypt the required workspace key") } - plainTextSecrets, err := GetPlainTextSecrets(plainTextWorkspaceKey, encryptedSecretsResponse) + plainTextSecrets, err := GetPlainTextSecrets(plainTextWorkspaceKey, encryptedSecretsResponse.Secrets) if err != nil { return nil, api.GetEncryptedSecretsV3Response{}, fmt.Errorf("unable to decrypt your secrets [err=%v]", err) } + plainTextSecretsMergedWithImports, err := InjectImportedSecret(plainTextWorkspaceKey, plainTextSecrets, encryptedSecretsResponse.ImportedSecrets) + if err != nil { + return nil, api.GetEncryptedSecretsV3Response{}, err + } + // expand secrets that are referenced - expandedSecrets := ExpandSecrets(plainTextSecrets, fullServiceToken) + expandedSecrets := ExpandSecrets(plainTextSecretsMergedWithImports, fullServiceToken) return expandedSecrets, encryptedSecretsResponse, nil } @@ -163,7 +168,7 @@ func GetPlainTextSecretsViaServiceAccount(serviceAccountCreds model.ServiceAccou return nil, api.GetEncryptedSecretsV3Response{}, fmt.Errorf("unable to fetch secrets because [err=%v]", err) } - plainTextSecrets, err := GetPlainTextSecrets(plainTextWorkspaceKey, encryptedSecretsResponse) + plainTextSecrets, err := GetPlainTextSecrets(plainTextWorkspaceKey, encryptedSecretsResponse.Secrets) if err != nil { return nil, api.GetEncryptedSecretsV3Response{}, fmt.Errorf("GetPlainTextSecretsViaServiceAccount: unable to get plain text secrets because [err=%v]", err) } @@ -200,9 +205,9 @@ func GetBase64DecodedSymmetricEncryptionDetails(key string, cipher string, IV st }, nil } -func GetPlainTextSecrets(key []byte, encryptedSecretsResponse api.GetEncryptedSecretsV3Response) ([]model.SingleEnvironmentVariable, error) { +func GetPlainTextSecrets(key []byte, encryptedSecrets []api.EncryptedSecretV3) ([]model.SingleEnvironmentVariable, error) { plainTextSecrets := []model.SingleEnvironmentVariable{} - for _, secret := range encryptedSecretsResponse.Secrets { + for _, secret := range encryptedSecrets { // Decrypt key key_iv, err := base64.StdEncoding.DecodeString(secret.SecretKeyIV) if err != nil { @@ -332,7 +337,7 @@ func ExpandSecrets(secrets []model.SingleEnvironmentVariable, infisicalToken str // if not in cross reference cache, fetch it from server refSecs, _, err := GetPlainTextSecretsViaServiceToken(infisicalToken, "", env, secPath) if err != nil { - fmt.Println("HELLO===>", "MOO", err) + fmt.Printf("Could not fetch secrets in environment: %s secret-path: %s", env, secPath) // HandleError(err, fmt.Sprintf("Could not fetch secrets in environment: %s secret-path: %s", env, secPath), "If you are using a service token to fetch secrets, please ensure it is valid") } refSecsByKey := getSecretsByKeys(refSecs) @@ -358,3 +363,32 @@ func getSecretsByKeys(secrets []model.SingleEnvironmentVariable) map[string]mode return secretMapByName } + +func InjectImportedSecret(plainTextWorkspaceKey []byte, secrets []model.SingleEnvironmentVariable, importedSecrets []api.ImportedSecretV3) ([]model.SingleEnvironmentVariable, error) { + if importedSecrets == nil { + return secrets, nil + } + + hasOverriden := make(map[string]bool) + for _, sec := range secrets { + hasOverriden[sec.Key] = true + } + + for i := len(importedSecrets) - 1; i >= 0; i-- { + importSec := importedSecrets[i] + plainTextImportedSecrets, err := GetPlainTextSecrets(plainTextWorkspaceKey, importSec.Secrets) + + if err != nil { + return nil, fmt.Errorf("unable to decrypt your imported secrets [err=%v]", err) + } + + for _, sec := range plainTextImportedSecrets { + if _, ok := hasOverriden[sec.Key]; !ok { + secrets = append(secrets, sec) + hasOverriden[sec.Key] = true + } + } + } + + return secrets, nil +}