mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 09:28:06 +00:00
Merge pull request #1538 from Infisical/daniel/agent-template-func
Feat: Agent secret referencing support
This commit is contained in:
@@ -228,7 +228,9 @@ func secretTemplateFunction(accessToken string, existingEtag string, currentEtag
|
|||||||
*currentEtag = res.Etag
|
*currentEtag = res.Etag
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.Secrets, nil
|
expandedSecrets := util.ExpandSecrets(res.Secrets, models.ExpandSecretsAuthentication{UniversalAuthAccessToken: accessToken}, "")
|
||||||
|
|
||||||
|
return expandedSecrets, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -622,7 +624,7 @@ var agentCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !FileExists(configPath) && agentConfigInBase64 == "" {
|
if !FileExists(configPath) && agentConfigInBase64 == "" {
|
||||||
log.Error().Msgf("No agent config file provided. Please provide a agent config file", configPath)
|
log.Error().Msgf("No agent config file provided at %v. Please provide a agent config file", configPath)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,9 @@ var exportCmd = &cobra.Command{
|
|||||||
|
|
||||||
var output string
|
var output string
|
||||||
if shouldExpandSecrets {
|
if shouldExpandSecrets {
|
||||||
secrets = util.ExpandSecrets(secrets, infisicalToken, "")
|
secrets = util.ExpandSecrets(secrets, models.ExpandSecretsAuthentication{
|
||||||
|
InfisicalToken: infisicalToken,
|
||||||
|
}, "")
|
||||||
}
|
}
|
||||||
secrets = util.FilterSecretsByTag(secrets, tagSlugs)
|
secrets = util.FilterSecretsByTag(secrets, tagSlugs)
|
||||||
output, err = formatEnvs(secrets, format)
|
output, err = formatEnvs(secrets, format)
|
||||||
|
|||||||
@@ -110,7 +110,9 @@ var runCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if shouldExpandSecrets {
|
if shouldExpandSecrets {
|
||||||
secrets = util.ExpandSecrets(secrets, infisicalToken, projectConfigDir)
|
secrets = util.ExpandSecrets(secrets, models.ExpandSecretsAuthentication{
|
||||||
|
InfisicalToken: infisicalToken,
|
||||||
|
}, projectConfigDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
secretsByKey := getSecretsByKeys(secrets)
|
secretsByKey := getSecretsByKeys(secrets)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -39,6 +40,11 @@ var secretsCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
infisicalToken, err := cmd.Flags().GetString("token")
|
infisicalToken, err := cmd.Flags().GetString("token")
|
||||||
|
|
||||||
|
if infisicalToken == "" {
|
||||||
|
infisicalToken = os.Getenv(util.INFISICAL_TOKEN_NAME)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.HandleError(err, "Unable to parse flag")
|
util.HandleError(err, "Unable to parse flag")
|
||||||
}
|
}
|
||||||
@@ -80,7 +86,9 @@ var secretsCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if shouldExpandSecrets {
|
if shouldExpandSecrets {
|
||||||
secrets = util.ExpandSecrets(secrets, infisicalToken, "")
|
secrets = util.ExpandSecrets(secrets, models.ExpandSecretsAuthentication{
|
||||||
|
InfisicalToken: infisicalToken,
|
||||||
|
}, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
visualize.PrintAllSecretDetails(secrets)
|
visualize.PrintAllSecretDetails(secrets)
|
||||||
|
|||||||
@@ -21,11 +21,12 @@ type LoggedInUser struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SingleEnvironmentVariable struct {
|
type SingleEnvironmentVariable struct {
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
Value string `json:"value"`
|
WorkspaceId string `json:"workspace"`
|
||||||
Type string `json:"type"`
|
Value string `json:"value"`
|
||||||
ID string `json:"_id"`
|
Type string `json:"type"`
|
||||||
Tags []struct {
|
ID string `json:"_id"`
|
||||||
|
Tags []struct {
|
||||||
ID string `json:"_id"`
|
ID string `json:"_id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Slug string `json:"slug"`
|
Slug string `json:"slug"`
|
||||||
@@ -68,6 +69,7 @@ type GetAllSecretsParameters struct {
|
|||||||
Environment string
|
Environment string
|
||||||
EnvironmentPassedViaFlag bool
|
EnvironmentPassedViaFlag bool
|
||||||
InfisicalToken string
|
InfisicalToken string
|
||||||
|
UniversalAuthAccessToken string
|
||||||
TagSlugs string
|
TagSlugs string
|
||||||
WorkspaceId string
|
WorkspaceId string
|
||||||
SecretsPath string
|
SecretsPath string
|
||||||
@@ -96,3 +98,8 @@ type DeleteFolderParameters struct {
|
|||||||
FolderPath string
|
FolderPath string
|
||||||
InfisicalToken string
|
InfisicalToken string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ExpandSecretsAuthentication struct {
|
||||||
|
InfisicalToken string
|
||||||
|
UniversalAuthAccessToken string
|
||||||
|
}
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ func GetPlainTextSecretsViaMachineIdentity(accessToken string, workspaceId strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, secret := range rawSecrets.Secrets {
|
for _, secret := range rawSecrets.Secrets {
|
||||||
plainTextSecrets = append(plainTextSecrets, models.SingleEnvironmentVariable{Key: secret.SecretKey, Value: secret.SecretValue})
|
plainTextSecrets = append(plainTextSecrets, models.SingleEnvironmentVariable{Key: secret.SecretKey, Value: secret.SecretValue, WorkspaceId: secret.Workspace})
|
||||||
}
|
}
|
||||||
|
|
||||||
// if includeImports {
|
// if includeImports {
|
||||||
@@ -248,11 +248,8 @@ func FilterSecretsByTag(plainTextSecrets []models.SingleEnvironmentVariable, tag
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetAllEnvironmentVariables(params models.GetAllSecretsParameters, projectConfigFilePath string) ([]models.SingleEnvironmentVariable, error) {
|
func GetAllEnvironmentVariables(params models.GetAllSecretsParameters, projectConfigFilePath string) ([]models.SingleEnvironmentVariable, error) {
|
||||||
var infisicalToken string
|
|
||||||
if params.InfisicalToken == "" {
|
if params.InfisicalToken == "" {
|
||||||
infisicalToken = os.Getenv(INFISICAL_TOKEN_NAME)
|
params.InfisicalToken = os.Getenv(INFISICAL_TOKEN_NAME)
|
||||||
} else {
|
|
||||||
infisicalToken = params.InfisicalToken
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isConnected := CheckIsConnectedToInternet()
|
isConnected := CheckIsConnectedToInternet()
|
||||||
@@ -260,7 +257,7 @@ func GetAllEnvironmentVariables(params models.GetAllSecretsParameters, projectCo
|
|||||||
// var serviceTokenDetails api.GetServiceTokenDetailsResponse
|
// var serviceTokenDetails api.GetServiceTokenDetailsResponse
|
||||||
var errorToReturn error
|
var errorToReturn error
|
||||||
|
|
||||||
if infisicalToken == "" {
|
if params.InfisicalToken == "" && params.UniversalAuthAccessToken == "" {
|
||||||
if isConnected {
|
if isConnected {
|
||||||
log.Debug().Msg("GetAllEnvironmentVariables: Connected to internet, checking logged in creds")
|
log.Debug().Msg("GetAllEnvironmentVariables: Connected to internet, checking logged in creds")
|
||||||
|
|
||||||
@@ -306,12 +303,6 @@ func GetAllEnvironmentVariables(params models.GetAllSecretsParameters, projectCo
|
|||||||
infisicalDotJson.WorkspaceId = params.WorkspaceId
|
infisicalDotJson.WorkspaceId = params.WorkspaceId
|
||||||
}
|
}
|
||||||
|
|
||||||
// // Verify environment
|
|
||||||
// err = ValidateEnvironmentName(params.Environment, workspaceFile.WorkspaceId, loggedInUserDetails.UserCredentials)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, fmt.Errorf("unable to validate environment name because [err=%s]", err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
secretsToReturn, errorToReturn = GetPlainTextSecretsViaJTW(loggedInUserDetails.UserCredentials.JTWToken, loggedInUserDetails.UserCredentials.PrivateKey, infisicalDotJson.WorkspaceId,
|
secretsToReturn, errorToReturn = GetPlainTextSecretsViaJTW(loggedInUserDetails.UserCredentials.JTWToken, loggedInUserDetails.UserCredentials.PrivateKey, infisicalDotJson.WorkspaceId,
|
||||||
params.Environment, params.TagSlugs, params.SecretsPath, params.IncludeImport)
|
params.Environment, params.TagSlugs, params.SecretsPath, params.IncludeImport)
|
||||||
log.Debug().Msgf("GetAllEnvironmentVariables: Trying to fetch secrets JTW token [err=%s]", errorToReturn)
|
log.Debug().Msgf("GetAllEnvironmentVariables: Trying to fetch secrets JTW token [err=%s]", errorToReturn)
|
||||||
@@ -332,91 +323,19 @@ func GetAllEnvironmentVariables(params models.GetAllSecretsParameters, projectCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
log.Debug().Msg("Trying to fetch secrets using service token")
|
if params.InfisicalToken != "" {
|
||||||
secretsToReturn, _, errorToReturn = GetPlainTextSecretsViaServiceToken(infisicalToken, params.Environment, params.SecretsPath, params.IncludeImport)
|
log.Debug().Msg("Trying to fetch secrets using service token")
|
||||||
}
|
secretsToReturn, _, errorToReturn = GetPlainTextSecretsViaServiceToken(params.InfisicalToken, params.Environment, params.SecretsPath, params.IncludeImport)
|
||||||
|
} else if params.UniversalAuthAccessToken != "" {
|
||||||
|
log.Debug().Msg("Trying to fetch secrets using universal auth")
|
||||||
|
res, err := GetPlainTextSecretsViaMachineIdentity(params.UniversalAuthAccessToken, params.WorkspaceId, params.Environment, params.SecretsPath, params.IncludeImport)
|
||||||
|
|
||||||
return secretsToReturn, errorToReturn
|
errorToReturn = err
|
||||||
}
|
secretsToReturn = res.Secrets
|
||||||
|
|
||||||
// func ValidateEnvironmentName(environmentName string, workspaceId string, userLoggedInDetails models.UserCredentials) error {
|
|
||||||
// httpClient := resty.New()
|
|
||||||
// httpClient.SetAuthToken(userLoggedInDetails.JTWToken).
|
|
||||||
// SetHeader("Accept", "application/json")
|
|
||||||
|
|
||||||
// response, err := api.CallGetAccessibleEnvironments(httpClient, api.GetAccessibleEnvironmentsRequest{WorkspaceId: workspaceId})
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// listOfEnvSlugs := []string{}
|
|
||||||
// mapOfEnvSlugs := make(map[string]interface{})
|
|
||||||
|
|
||||||
// for _, environment := range response.AccessibleEnvironments {
|
|
||||||
// listOfEnvSlugs = append(listOfEnvSlugs, environment.Slug)
|
|
||||||
// mapOfEnvSlugs[environment.Slug] = environment
|
|
||||||
// }
|
|
||||||
|
|
||||||
// _, exists := mapOfEnvSlugs[environmentName]
|
|
||||||
// if !exists {
|
|
||||||
// HandleError(fmt.Errorf("the environment [%s] does not exist in project with [id=%s]. Only [%s] are available", environmentName, workspaceId, strings.Join(listOfEnvSlugs, ",")))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return nil
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
func getExpandedEnvVariable(secrets []models.SingleEnvironmentVariable, variableWeAreLookingFor string, hashMapOfCompleteVariables map[string]string, hashMapOfSelfRefs map[string]string) string {
|
|
||||||
if value, found := hashMapOfCompleteVariables[variableWeAreLookingFor]; found {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, secret := range secrets {
|
|
||||||
if secret.Key == variableWeAreLookingFor {
|
|
||||||
regex := regexp.MustCompile(`\${([^\}]*)}`)
|
|
||||||
variablesToPopulate := regex.FindAllString(secret.Value, -1)
|
|
||||||
|
|
||||||
// case: variable is a constant so return its value
|
|
||||||
if len(variablesToPopulate) == 0 {
|
|
||||||
return secret.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
valueToEdit := secret.Value
|
|
||||||
for _, variableWithSign := range variablesToPopulate {
|
|
||||||
variableWithoutSign := strings.Trim(variableWithSign, "}")
|
|
||||||
variableWithoutSign = strings.Trim(variableWithoutSign, "${")
|
|
||||||
|
|
||||||
// case: reference to self
|
|
||||||
if variableWithoutSign == secret.Key {
|
|
||||||
hashMapOfSelfRefs[variableWithoutSign] = variableWithoutSign
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
var expandedVariableValue string
|
|
||||||
|
|
||||||
if preComputedVariable, found := hashMapOfCompleteVariables[variableWithoutSign]; found {
|
|
||||||
expandedVariableValue = preComputedVariable
|
|
||||||
} else {
|
|
||||||
expandedVariableValue = getExpandedEnvVariable(secrets, variableWithoutSign, hashMapOfCompleteVariables, hashMapOfSelfRefs)
|
|
||||||
hashMapOfCompleteVariables[variableWithoutSign] = expandedVariableValue
|
|
||||||
}
|
|
||||||
|
|
||||||
// If after expanding all the vars above, is the current var a self ref? if so no replacement needed for it
|
|
||||||
if _, found := hashMapOfSelfRefs[variableWithoutSign]; found {
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
valueToEdit = strings.ReplaceAll(valueToEdit, variableWithSign, expandedVariableValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return valueToEdit
|
|
||||||
|
|
||||||
} else {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "${" + variableWeAreLookingFor + "}"
|
return secretsToReturn, errorToReturn
|
||||||
}
|
}
|
||||||
|
|
||||||
var secRefRegex = regexp.MustCompile(`\${([^\}]*)}`)
|
var secRefRegex = regexp.MustCompile(`\${([^\}]*)}`)
|
||||||
@@ -428,7 +347,7 @@ func recursivelyExpandSecret(expandedSecs map[string]string, interpolatedSecs ma
|
|||||||
|
|
||||||
interpolatedVal, ok := interpolatedSecs[key]
|
interpolatedVal, ok := interpolatedSecs[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
HandleError(fmt.Errorf("Could not find refered secret - %s", key), "Kindly check whether its provided")
|
HandleError(fmt.Errorf("could not find refered secret - %s", key), "Kindly check whether its provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
refs := secRefRegex.FindAllStringSubmatch(interpolatedVal, -1)
|
refs := secRefRegex.FindAllStringSubmatch(interpolatedVal, -1)
|
||||||
@@ -467,7 +386,7 @@ func getSecretsByKeys(secrets []models.SingleEnvironmentVariable) map[string]mod
|
|||||||
return secretMapByName
|
return secretMapByName
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExpandSecrets(secrets []models.SingleEnvironmentVariable, infisicalToken string, projectConfigPathDir string) []models.SingleEnvironmentVariable {
|
func ExpandSecrets(secrets []models.SingleEnvironmentVariable, auth models.ExpandSecretsAuthentication, projectConfigPathDir string) []models.SingleEnvironmentVariable {
|
||||||
expandedSecs := make(map[string]string)
|
expandedSecs := make(map[string]string)
|
||||||
interpolatedSecs := make(map[string]string)
|
interpolatedSecs := make(map[string]string)
|
||||||
// map[env.secret-path][keyname]Secret
|
// map[env.secret-path][keyname]Secret
|
||||||
@@ -499,8 +418,18 @@ func ExpandSecrets(secrets []models.SingleEnvironmentVariable, infisicalToken st
|
|||||||
uniqKey := fmt.Sprintf("%s.%s", env, secPathDot)
|
uniqKey := fmt.Sprintf("%s.%s", env, secPathDot)
|
||||||
|
|
||||||
if crossRefSec, ok := crossEnvRefSecs[uniqKey]; !ok {
|
if crossRefSec, ok := crossEnvRefSecs[uniqKey]; !ok {
|
||||||
|
|
||||||
|
var refSecs []models.SingleEnvironmentVariable
|
||||||
|
var err error
|
||||||
|
|
||||||
// if not in cross reference cache, fetch it from server
|
// if not in cross reference cache, fetch it from server
|
||||||
refSecs, err := GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: env, InfisicalToken: infisicalToken, SecretsPath: secPath}, projectConfigPathDir)
|
if auth.InfisicalToken != "" {
|
||||||
|
refSecs, err = GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: env, InfisicalToken: auth.InfisicalToken, SecretsPath: secPath}, projectConfigPathDir)
|
||||||
|
} else if auth.UniversalAuthAccessToken != "" {
|
||||||
|
refSecs, err = GetAllEnvironmentVariables((models.GetAllSecretsParameters{Environment: env, UniversalAuthAccessToken: auth.UniversalAuthAccessToken, SecretsPath: secPath, WorkspaceId: sec.WorkspaceId}), projectConfigPathDir)
|
||||||
|
} else {
|
||||||
|
HandleError(errors.New("no authentication provided"), "Please provide authentication to fetch secrets")
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
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")
|
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")
|
||||||
}
|
}
|
||||||
@@ -508,6 +437,7 @@ func ExpandSecrets(secrets []models.SingleEnvironmentVariable, infisicalToken st
|
|||||||
// save it to avoid calling api again for same environment and folder path
|
// save it to avoid calling api again for same environment and folder path
|
||||||
crossEnvRefSecs[uniqKey] = refSecsByKey
|
crossEnvRefSecs[uniqKey] = refSecsByKey
|
||||||
return refSecsByKey[secKey].Value
|
return refSecsByKey[secKey].Value
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return crossRefSec[secKey].Value
|
return crossRefSec[secKey].Value
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user