mirror of
https://github.com/passbolt/go-passbolt-cli.git
synced 2025-05-07 17:18:21 +00:00
Feature: adding support for exposing secrets to subprocesses (#68)
Some checks failed
Go / build (push) Has been cancelled
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:
parent
6033d6bbb3
commit
1183813dcb
2 changed files with 116 additions and 0 deletions
13
README.md
13
README.md
|
@ -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
103
cmd/exec.go
Normal 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
|
||||
}
|
Loading…
Add table
Reference in a new issue