mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-03 04:25:46 +00:00
add auto redeploy, new secrets api, and new service token
This commit is contained in:
+50
-147
@@ -1,177 +1,80 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/Infisical/infisical/k8-operator/packages/crypto"
|
||||
"github.com/Infisical/infisical/k8-operator/packages/models"
|
||||
"github.com/go-resty/resty/v2"
|
||||
"golang.org/x/crypto/nacl/box"
|
||||
)
|
||||
|
||||
func GetAllEnvironmentVariables(projectId string, envName string, infisicalToken string, hostAPI string) ([]models.SingleEnvironmentVariable, error) {
|
||||
envsFromApi, err := GetSecretsFromAPIUsingInfisicalToken(infisicalToken, envName, projectId, hostAPI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
const USER_AGENT_NAME = "k8-operator"
|
||||
|
||||
return SubstituteSecrets(envsFromApi), nil
|
||||
}
|
||||
|
||||
func GetSecretsFromAPIUsingInfisicalToken(infisicalToken string, envName string, projectId string, hostAPI string) ([]models.SingleEnvironmentVariable, error) {
|
||||
if infisicalToken == "" || projectId == "" || envName == "" {
|
||||
return nil, errors.New("infisical token, project id and or environment name cannot be empty")
|
||||
}
|
||||
|
||||
splitToken := strings.Split(infisicalToken, ",")
|
||||
JTWToken := splitToken[0]
|
||||
temPrivateKey := splitToken[1]
|
||||
|
||||
// create http client
|
||||
httpClient := resty.New().
|
||||
SetAuthToken(JTWToken).
|
||||
SetHeader("Accept", "application/json")
|
||||
|
||||
var pullSecretsByInfisicalTokenResponse models.PullSecretsByInfisicalTokenResponse
|
||||
func CallGetEncryptedWorkspaceKey(httpClient *resty.Client, request GetEncryptedWorkspaceKeyRequest) (GetEncryptedWorkspaceKeyResponse, error) {
|
||||
endpoint := fmt.Sprintf("%v/v2/workspace/%v/encrypted-key", API_HOST_URL, request.WorkspaceId)
|
||||
var result GetEncryptedWorkspaceKeyResponse
|
||||
response, err := httpClient.
|
||||
R().
|
||||
SetQueryParam("environment", envName).
|
||||
SetQueryParam("channel", "cli").
|
||||
SetResult(&pullSecretsByInfisicalTokenResponse).
|
||||
Get(fmt.Sprintf("%v/v1/secret/%v/service-token", hostAPI, projectId))
|
||||
SetResult(&result).
|
||||
SetHeader("User-Agent", USER_AGENT_NAME).
|
||||
Get(endpoint)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return GetEncryptedWorkspaceKeyResponse{}, fmt.Errorf("CallGetEncryptedWorkspaceKey: Unable to complete api request [err=%s]", err)
|
||||
}
|
||||
|
||||
if response.StatusCode() > 299 {
|
||||
return nil, fmt.Errorf(response.Status())
|
||||
return GetEncryptedWorkspaceKeyResponse{}, fmt.Errorf("CallGetEncryptedWorkspaceKey: Unsuccessful response: [response=%s]", response)
|
||||
}
|
||||
|
||||
// Get workspace key
|
||||
workspaceKey, err := base64.StdEncoding.DecodeString(pullSecretsByInfisicalTokenResponse.Key.EncryptedKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nonce, err := base64.StdEncoding.DecodeString(pullSecretsByInfisicalTokenResponse.Key.Nonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
senderPublicKey, err := base64.StdEncoding.DecodeString(pullSecretsByInfisicalTokenResponse.Key.Sender.PublicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
currentUsersPrivateKey, err := base64.StdEncoding.DecodeString(temPrivateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
workspaceKeyInBytes, _ := box.Open(nil, workspaceKey, (*[24]byte)(nonce), (*[32]byte)(senderPublicKey), (*[32]byte)(currentUsersPrivateKey))
|
||||
var listOfEnv []models.SingleEnvironmentVariable
|
||||
|
||||
for _, secret := range pullSecretsByInfisicalTokenResponse.Secrets {
|
||||
key_iv, _ := base64.StdEncoding.DecodeString(secret.SecretKey.Iv)
|
||||
key_tag, _ := base64.StdEncoding.DecodeString(secret.SecretKey.Tag)
|
||||
key_ciphertext, _ := base64.StdEncoding.DecodeString(secret.SecretKey.Ciphertext)
|
||||
|
||||
plainTextKey, err := crypto.DecryptSymmetric(workspaceKeyInBytes, key_ciphertext, key_tag, key_iv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
value_iv, _ := base64.StdEncoding.DecodeString(secret.SecretValue.Iv)
|
||||
value_tag, _ := base64.StdEncoding.DecodeString(secret.SecretValue.Tag)
|
||||
value_ciphertext, _ := base64.StdEncoding.DecodeString(secret.SecretValue.Ciphertext)
|
||||
|
||||
plainTextValue, err := crypto.DecryptSymmetric(workspaceKeyInBytes, value_ciphertext, value_tag, value_iv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
env := models.SingleEnvironmentVariable{
|
||||
Key: string(plainTextKey),
|
||||
Value: string(plainTextValue),
|
||||
}
|
||||
|
||||
listOfEnv = append(listOfEnv, env)
|
||||
}
|
||||
|
||||
return listOfEnv, nil
|
||||
return result, 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
|
||||
func CallGetServiceTokenDetailsV2(httpClient *resty.Client) (GetServiceTokenDetailsResponse, error) {
|
||||
var tokenDetailsResponse GetServiceTokenDetailsResponse
|
||||
response, err := httpClient.
|
||||
R().
|
||||
SetResult(&tokenDetailsResponse).
|
||||
SetHeader("User-Agent", USER_AGENT_NAME).
|
||||
Get(fmt.Sprintf("%v/v2/service-token", API_HOST_URL))
|
||||
|
||||
if err != nil {
|
||||
return GetServiceTokenDetailsResponse{}, fmt.Errorf("CallGetServiceTokenDetails: Unable to complete api request [err=%s]", err)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
if response.IsError() {
|
||||
return GetServiceTokenDetailsResponse{}, fmt.Errorf("CallGetServiceTokenDetails: Unsuccessful response: [response=%s]", response)
|
||||
}
|
||||
|
||||
return "${" + variableWeAreLookingFor + "}"
|
||||
return tokenDetailsResponse, nil
|
||||
}
|
||||
|
||||
func SubstituteSecrets(secrets []models.SingleEnvironmentVariable) []models.SingleEnvironmentVariable {
|
||||
hashMapOfCompleteVariables := make(map[string]string)
|
||||
hashMapOfSelfRefs := make(map[string]string)
|
||||
expandedSecrets := []models.SingleEnvironmentVariable{}
|
||||
|
||||
for _, secret := range secrets {
|
||||
expandedVariable := getExpandedEnvVariable(secrets, secret.Key, hashMapOfCompleteVariables, hashMapOfSelfRefs)
|
||||
expandedSecrets = append(expandedSecrets, models.SingleEnvironmentVariable{
|
||||
Key: secret.Key,
|
||||
Value: expandedVariable,
|
||||
})
|
||||
func CallGetSecretsV2(httpClient *resty.Client, request GetEncryptedSecretsV2Request) (GetEncryptedSecretsV2Response, error) {
|
||||
var secretsResponse GetEncryptedSecretsV2Response = GetEncryptedSecretsV2Response{}
|
||||
createHttpRequest := httpClient.
|
||||
R().
|
||||
SetResult(&secretsResponse.Secrets).
|
||||
SetQueryParam("environment", request.EnvironmentName).
|
||||
SetHeader("User-Agent", USER_AGENT_NAME)
|
||||
|
||||
if request.ETag != "" {
|
||||
createHttpRequest.SetHeader("If-None-Match", request.ETag)
|
||||
}
|
||||
|
||||
return expandedSecrets
|
||||
response, err := createHttpRequest.Get(fmt.Sprintf("%v/v2/secret/workspace/%v", API_HOST_URL, request.WorkspaceId))
|
||||
if err != nil {
|
||||
return GetEncryptedSecretsV2Response{}, fmt.Errorf("CallGetSecretsV2: Unable to complete api request [err=%s]", err)
|
||||
}
|
||||
|
||||
if response.IsError() {
|
||||
return GetEncryptedSecretsV2Response{}, fmt.Errorf("CallGetSecretsV2: Unsuccessful response: [response=%s]", response)
|
||||
}
|
||||
|
||||
if response.StatusCode() == 304 {
|
||||
secretsResponse.Modified = false
|
||||
} else {
|
||||
secretsResponse.Modified = true
|
||||
}
|
||||
|
||||
secretsResponse.ETag = response.Header().Get("etag")
|
||||
|
||||
return secretsResponse, nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package api
|
||||
|
||||
import "time"
|
||||
|
||||
type GetEncryptedWorkspaceKeyRequest struct {
|
||||
WorkspaceId string `json:"workspaceId"`
|
||||
}
|
||||
|
||||
type GetEncryptedWorkspaceKeyResponse struct {
|
||||
ID string `json:"_id"`
|
||||
EncryptedKey string `json:"encryptedKey"`
|
||||
Nonce string `json:"nonce"`
|
||||
Sender struct {
|
||||
ID string `json:"_id"`
|
||||
Email string `json:"email"`
|
||||
RefreshVersion int `json:"refreshVersion"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
V int `json:"__v"`
|
||||
FirstName string `json:"firstName"`
|
||||
LastName string `json:"lastName"`
|
||||
PublicKey string `json:"publicKey"`
|
||||
} `json:"sender"`
|
||||
Receiver string `json:"receiver"`
|
||||
Workspace string `json:"workspace"`
|
||||
V int `json:"__v"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type GetEncryptedSecretsV2Request struct {
|
||||
EnvironmentName string `json:"environmentName"`
|
||||
WorkspaceId string `json:"workspaceId"`
|
||||
ETag string `json:"etag,omitempty"`
|
||||
}
|
||||
|
||||
type GetEncryptedSecretsV2Response struct {
|
||||
Secrets []struct {
|
||||
ID string `json:"_id"`
|
||||
Version int `json:"version"`
|
||||
Workspace string `json:"workspace"`
|
||||
Type string `json:"type"`
|
||||
Environment string `json:"environment"`
|
||||
SecretKeyCiphertext string `json:"secretKeyCiphertext"`
|
||||
SecretKeyIV string `json:"secretKeyIV"`
|
||||
SecretKeyTag string `json:"secretKeyTag"`
|
||||
SecretKeyHash string `json:"secretKeyHash"`
|
||||
SecretValueCiphertext string `json:"secretValueCiphertext"`
|
||||
SecretValueIV string `json:"secretValueIV"`
|
||||
SecretValueTag string `json:"secretValueTag"`
|
||||
SecretValueHash string `json:"secretValueHash"`
|
||||
SecretCommentCiphertext string `json:"secretCommentCiphertext"`
|
||||
SecretCommentIV string `json:"secretCommentIV"`
|
||||
SecretCommentTag string `json:"secretCommentTag"`
|
||||
SecretCommentHash string `json:"secretCommentHash"`
|
||||
V int `json:"__v"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
User string `json:"user,omitempty"`
|
||||
}
|
||||
|
||||
Modified bool `json:"modified,omitempty"`
|
||||
ETag string `json:"ETag,omitempty"`
|
||||
}
|
||||
|
||||
type GetServiceTokenDetailsResponse struct {
|
||||
ID string `json:"_id"`
|
||||
Name string `json:"name"`
|
||||
Workspace string `json:"workspace"`
|
||||
Environment string `json:"environment"`
|
||||
User string `json:"user"`
|
||||
EncryptedKey string `json:"encryptedKey"`
|
||||
Iv string `json:"iv"`
|
||||
Tag string `json:"tag"`
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package api
|
||||
|
||||
var API_HOST_URL string = "https://app.infisical.com/api"
|
||||
@@ -1,51 +0,0 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
type PullSecretsByInfisicalTokenResponse struct {
|
||||
Secrets []struct {
|
||||
ID string `json:"_id"`
|
||||
Workspace string `json:"workspace"`
|
||||
Type string `json:"type"`
|
||||
Environment string `json:"environment"`
|
||||
SecretKey struct {
|
||||
Workspace string `json:"workspace"`
|
||||
Ciphertext string `json:"ciphertext"`
|
||||
Iv string `json:"iv"`
|
||||
Tag string `json:"tag"`
|
||||
Hash string `json:"hash"`
|
||||
} `json:"secretKey"`
|
||||
SecretValue struct {
|
||||
Workspace string `json:"workspace"`
|
||||
Ciphertext string `json:"ciphertext"`
|
||||
Iv string `json:"iv"`
|
||||
Tag string `json:"tag"`
|
||||
Hash string `json:"hash"`
|
||||
} `json:"secretValue"`
|
||||
} `json:"secrets"`
|
||||
Key struct {
|
||||
EncryptedKey string `json:"encryptedKey"`
|
||||
Nonce string `json:"nonce"`
|
||||
Sender struct {
|
||||
PublicKey string `json:"publicKey"`
|
||||
} `json:"sender"`
|
||||
Receiver struct {
|
||||
RefreshVersion int `json:"refreshVersion"`
|
||||
ID string `json:"_id"`
|
||||
Email string `json:"email"`
|
||||
CustomerID string `json:"customerId"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
V int `json:"__v"`
|
||||
FirstName string `json:"firstName"`
|
||||
LastName string `json:"lastName"`
|
||||
PublicKey string `json:"publicKey"`
|
||||
} `json:"receiver"`
|
||||
Workspace string `json:"workspace"`
|
||||
} `json:"key"`
|
||||
}
|
||||
|
||||
type SingleEnvironmentVariable struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/Infisical/infisical/k8-operator/packages/api"
|
||||
"github.com/Infisical/infisical/k8-operator/packages/crypto"
|
||||
"github.com/go-resty/resty/v2"
|
||||
)
|
||||
|
||||
type SingleEnvironmentVariable struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
Type string `json:"type"`
|
||||
ID string `json:"_id"`
|
||||
}
|
||||
|
||||
type DecodedSymmetricEncryptionDetails = struct {
|
||||
Cipher []byte
|
||||
IV []byte
|
||||
Tag []byte
|
||||
Key []byte
|
||||
}
|
||||
|
||||
func VerifyServiceToken(serviceToken string) (string, error) {
|
||||
serviceTokenParts := strings.SplitN(serviceToken, ".", 4)
|
||||
if len(serviceTokenParts) < 4 {
|
||||
return "", fmt.Errorf("invalid service token entered. Please double check your service token and try again")
|
||||
}
|
||||
|
||||
serviceToken = fmt.Sprintf("%v.%v.%v", serviceTokenParts[0], serviceTokenParts[1], serviceTokenParts[2])
|
||||
return serviceToken, nil
|
||||
}
|
||||
|
||||
func GetServiceTokenDetails(infisicalToken string) (api.GetServiceTokenDetailsResponse, error) {
|
||||
serviceTokenParts := strings.SplitN(infisicalToken, ".", 4)
|
||||
if len(serviceTokenParts) < 4 {
|
||||
return api.GetServiceTokenDetailsResponse{}, fmt.Errorf("invalid service token entered. Please double check your service token and try again")
|
||||
}
|
||||
|
||||
serviceToken := fmt.Sprintf("%v.%v.%v", serviceTokenParts[0], serviceTokenParts[1], serviceTokenParts[2])
|
||||
|
||||
httpClient := resty.New()
|
||||
httpClient.SetAuthToken(serviceToken).
|
||||
SetHeader("Accept", "application/json")
|
||||
|
||||
serviceTokenDetails, err := api.CallGetServiceTokenDetailsV2(httpClient)
|
||||
if err != nil {
|
||||
return api.GetServiceTokenDetailsResponse{}, fmt.Errorf("unable to get service token details. [err=%v]", err)
|
||||
}
|
||||
|
||||
return serviceTokenDetails, nil
|
||||
}
|
||||
|
||||
func GetPlainTextSecretsViaServiceToken(fullServiceToken string, etag string) ([]SingleEnvironmentVariable, api.GetEncryptedSecretsV2Response, error) {
|
||||
serviceTokenParts := strings.SplitN(fullServiceToken, ".", 4)
|
||||
if len(serviceTokenParts) < 4 {
|
||||
return nil, api.GetEncryptedSecretsV2Response{}, fmt.Errorf("invalid service token entered. Please double check your service token and try again")
|
||||
}
|
||||
|
||||
serviceToken := fmt.Sprintf("%v.%v.%v", serviceTokenParts[0], serviceTokenParts[1], serviceTokenParts[2])
|
||||
|
||||
httpClient := resty.New()
|
||||
httpClient.SetAuthToken(serviceToken).
|
||||
SetHeader("Accept", "application/json")
|
||||
|
||||
serviceTokenDetails, err := api.CallGetServiceTokenDetailsV2(httpClient)
|
||||
if err != nil {
|
||||
return nil, api.GetEncryptedSecretsV2Response{}, fmt.Errorf("unable to get service token details. [err=%v]", err)
|
||||
}
|
||||
|
||||
encryptedSecretsResponse, err := api.CallGetSecretsV2(httpClient, api.GetEncryptedSecretsV2Request{
|
||||
WorkspaceId: serviceTokenDetails.Workspace,
|
||||
EnvironmentName: serviceTokenDetails.Environment,
|
||||
ETag: etag,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, api.GetEncryptedSecretsV2Response{}, err
|
||||
}
|
||||
|
||||
decodedSymmetricEncryptionDetails, err := GetBase64DecodedSymmetricEncryptionDetails(serviceTokenParts[3], serviceTokenDetails.EncryptedKey, serviceTokenDetails.Iv, serviceTokenDetails.Tag)
|
||||
if err != nil {
|
||||
return nil, api.GetEncryptedSecretsV2Response{}, fmt.Errorf("unable to decode symmetric encryption details [err=%v]", err)
|
||||
}
|
||||
|
||||
plainTextWorkspaceKey, err := crypto.DecryptSymmetric([]byte(serviceTokenParts[3]), decodedSymmetricEncryptionDetails.Cipher, decodedSymmetricEncryptionDetails.Tag, decodedSymmetricEncryptionDetails.IV)
|
||||
if err != nil {
|
||||
return nil, api.GetEncryptedSecretsV2Response{}, fmt.Errorf("unable to decrypt the required workspace key")
|
||||
}
|
||||
|
||||
plainTextSecrets, err := GetPlainTextSecrets(plainTextWorkspaceKey, encryptedSecretsResponse)
|
||||
if err != nil {
|
||||
return nil, api.GetEncryptedSecretsV2Response{}, fmt.Errorf("unable to decrypt your secrets [err=%v]", err)
|
||||
}
|
||||
|
||||
return plainTextSecrets, encryptedSecretsResponse, nil
|
||||
}
|
||||
|
||||
func GetBase64DecodedSymmetricEncryptionDetails(key string, cipher string, IV string, tag string) (DecodedSymmetricEncryptionDetails, error) {
|
||||
cipherx, err := base64.StdEncoding.DecodeString(cipher)
|
||||
if err != nil {
|
||||
return DecodedSymmetricEncryptionDetails{}, fmt.Errorf("Base64DecodeSymmetricEncryptionDetails: Unable to decode cipher text [err=%v]", err)
|
||||
}
|
||||
|
||||
keyx, err := base64.StdEncoding.DecodeString(key)
|
||||
if err != nil {
|
||||
return DecodedSymmetricEncryptionDetails{}, fmt.Errorf("Base64DecodeSymmetricEncryptionDetails: Unable to decode key [err=%v]", err)
|
||||
}
|
||||
|
||||
IVx, err := base64.StdEncoding.DecodeString(IV)
|
||||
if err != nil {
|
||||
return DecodedSymmetricEncryptionDetails{}, fmt.Errorf("Base64DecodeSymmetricEncryptionDetails: Unable to decode IV [err=%v]", err)
|
||||
}
|
||||
|
||||
tagx, err := base64.StdEncoding.DecodeString(tag)
|
||||
if err != nil {
|
||||
return DecodedSymmetricEncryptionDetails{}, fmt.Errorf("Base64DecodeSymmetricEncryptionDetails: Unable to decode tag [err=%v]", err)
|
||||
}
|
||||
|
||||
return DecodedSymmetricEncryptionDetails{
|
||||
Key: keyx,
|
||||
Cipher: cipherx,
|
||||
IV: IVx,
|
||||
Tag: tagx,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func GetPlainTextSecrets(key []byte, encryptedSecretsResponse api.GetEncryptedSecretsV2Response) ([]SingleEnvironmentVariable, error) {
|
||||
plainTextSecrets := []SingleEnvironmentVariable{}
|
||||
for _, secret := range encryptedSecretsResponse.Secrets {
|
||||
// Decrypt key
|
||||
key_iv, err := base64.StdEncoding.DecodeString(secret.SecretKeyIV)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to decode secret IV for secret key")
|
||||
}
|
||||
|
||||
key_tag, err := base64.StdEncoding.DecodeString(secret.SecretKeyTag)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to decode secret authentication tag for secret key")
|
||||
}
|
||||
|
||||
key_ciphertext, err := base64.StdEncoding.DecodeString(secret.SecretKeyCiphertext)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to decode secret cipher text for secret key")
|
||||
}
|
||||
|
||||
plainTextKey, err := crypto.DecryptSymmetric(key, key_ciphertext, key_tag, key_iv)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to symmetrically decrypt secret key")
|
||||
}
|
||||
|
||||
// Decrypt value
|
||||
value_iv, err := base64.StdEncoding.DecodeString(secret.SecretValueIV)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to decode secret IV for secret value")
|
||||
}
|
||||
|
||||
value_tag, err := base64.StdEncoding.DecodeString(secret.SecretValueTag)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to decode secret authentication tag for secret value")
|
||||
}
|
||||
|
||||
value_ciphertext, _ := base64.StdEncoding.DecodeString(secret.SecretValueCiphertext)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to decode secret cipher text for secret key")
|
||||
}
|
||||
|
||||
plainTextValue, err := crypto.DecryptSymmetric(key, value_ciphertext, value_tag, value_iv)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to symmetrically decrypt secret value")
|
||||
}
|
||||
|
||||
plainTextSecret := SingleEnvironmentVariable{
|
||||
Key: string(plainTextKey),
|
||||
Value: string(plainTextValue),
|
||||
Type: string(secret.Type),
|
||||
ID: secret.ID,
|
||||
}
|
||||
|
||||
plainTextSecrets = append(plainTextSecrets, plainTextSecret)
|
||||
}
|
||||
|
||||
return plainTextSecrets, nil
|
||||
}
|
||||
Reference in New Issue
Block a user