Feature: adding support for exposing secrets to subprocesses (#68)
Some checks failed
Go / build (push) Has been cancelled

* adding support for exposing secrets to subprocesses

* updating readme

* wip 3

* wip 4

* wip 56
This commit is contained in:
Nelson Isioma 2025-02-23 15:56:48 +01:00 committed by GitHub
parent 6033d6bbb3
commit 1183813dcb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 116 additions and 0 deletions

View file

@ -105,6 +105,19 @@ For Scripting we have a -j or --json flag to convert the Output for the create,
Note: The JSON Output does not cover Error Messages, you can detect Errors by checking if the Exitcode is not 0
# Exposing Secrets to Subprocesses
The `exec` command allows you to execute another command with environment variables that reference secrets stored in Passbolt.
Any environment variables containing `passbolt://` references are automatically resolved to their corresponding secret values
before the specified command is executed. This ensures that secrets are securely injected into the child process's environment
without exposing them to the parent shell.
For example:
```bash
export GITHUB_TOKEN=passbolt://<PASSBOLT_RESOURCE_ID_HERE>
passbolt exec -- gh auth login
```
This would resolve the passbolt:// reference in GITHUB_TOKEN to its actual secret value and pass it to the gh process.
# Documentation
Usage for all Subcommands is [here](https://github.com/passbolt/go-passbolt-cli/wiki/passbolt).
And is also available via `man passbolt`

103
cmd/exec.go Normal file
View file

@ -0,0 +1,103 @@
package cmd
import (
"context"
"fmt"
"os"
"os/exec"
"strings"
"github.com/passbolt/go-passbolt-cli/util"
"github.com/passbolt/go-passbolt/api"
"github.com/passbolt/go-passbolt/helper"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
const PassboltPrefix = "passbolt://"
// execCmd represents the exec command
var execCmd = &cobra.Command{
Use: "exec -- command [args...]",
Short: "Run a command with secrets injected into the environment.",
Long: `The command allows you to execute another command with environment variables that reference secrets stored in Passbolt.
Any environment variables containing passbolt:// references are automatically resolved to their corresponding secret values
before the specified command is executed. This ensures that secrets are securely injected into the child process's environment
without exposing them to the parent shell.
For example:
export GITHUB_TOKEN=passbolt://<PASSBOLT_RESOURCE_ID_HERE>
passbolt exec -- gh auth login
This would resolve the passbolt:// reference in GITHUB_TOKEN to its actual secret value and pass it to the gh process.
`,
Args: cobra.MinimumNArgs(1),
RunE: execAction,
}
func init() {
rootCmd.AddCommand(execCmd)
}
func execAction(_ *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
client, err := util.GetClient(ctx)
if err != nil {
return fmt.Errorf("Creating client: %w", err)
}
envVars, err := resolveEnvironmentSecrets(ctx, client)
if err != nil {
return fmt.Errorf("Resolving secrets: %w", err)
}
if err = client.Logout(ctx); err != nil {
return fmt.Errorf("Logging out client: %w", err)
}
subCmd := exec.Command(args[0], args[1:]...)
subCmd.Stdin = os.Stdin
subCmd.Stdout = os.Stdout
subCmd.Stderr = os.Stderr
subCmd.Env = envVars
if err = subCmd.Run(); err != nil {
return fmt.Errorf("Running command: %w", err)
}
return nil
}
func resolveEnvironmentSecrets(ctx context.Context, client *api.Client) ([]string, error) {
envVars := os.Environ()
for i, envVar := range envVars {
splitIndex := strings.Index(envVar, "=")
if splitIndex == -1 {
continue
}
key := envVar[:splitIndex]
value := envVar[splitIndex+1:]
if !strings.HasPrefix(value, PassboltPrefix) {
continue
}
resourceId := strings.TrimPrefix(value, PassboltPrefix)
_, _, _, _, secret, _, err := helper.GetResource(ctx, client, resourceId)
if err != nil {
return nil, fmt.Errorf("Getting resource: %w", err)
}
envVars[i] = key + "=" + secret
if viper.GetBool("debug") {
fmt.Fprintf(os.Stdout, "%v env var populated with resource id %v\n", key, resourceId)
}
}
return envVars, nil
}