diff --git a/internal/openbao/bootstrap.go b/internal/openbao/bootstrap.go index 108e863..701e97c 100644 --- a/internal/openbao/bootstrap.go +++ b/internal/openbao/bootstrap.go @@ -2,6 +2,7 @@ package openbao import ( "bytes" + "context" "encoding/base64" "encoding/json" "errors" @@ -45,6 +46,8 @@ var decryptRecovery = func(identityPath, bundlePath string) ([]byte, error) { var openBaoStatus = getStatus +var commandTimeout = time.Minute + func EnsureRecoveryIdentity(identityPath string) (string, error) { if _, err := os.Stat(identityPath); os.IsNotExist(err) { if err := os.MkdirAll(filepath.Dir(identityPath), 0700); err != nil { @@ -251,7 +254,7 @@ func waitForPod(kubeconfig string) error { func getStatus(kubeconfig string) (status, error) { command := []string{"--kubeconfig", kubeconfig, "-n", "openbao", "exec", "openbao-0", "--", "bao", "status", "-format=json"} - output, err := exec.Command("kubectl", command...).Output() + output, err := commandOutput(nil, "kubectl", command...) if err != nil && !json.Valid(output) { return status{}, fmt.Errorf("get OpenBao status: %w", err) } @@ -411,17 +414,27 @@ func encryptRecovery(recipient, bundlePath string, plaintext []byte) error { var execInPod = func(kubeconfig string, input []byte, args ...string) ([]byte, error) { command := append([]string{"--kubeconfig", kubeconfig, "-n", "openbao", "exec", "-i", "openbao-0", "--"}, args...) - cmd := exec.Command("kubectl", command...) - cmd.Stdin = bytes.NewReader(input) - return cmd.CombinedOutput() + return commandOutput(input, "kubectl", command...) } var execInUnsealController = func(kubeconfig, script string) ([]byte, error) { command := []string{"--kubeconfig", kubeconfig, "-n", "openbao", "exec", "deployment/openbao-unseal", "--", "sh", "-ec", script} - return exec.Command("kubectl", command...).CombinedOutput() + return commandOutput(nil, "kubectl", command...) } var kubectlOutput = func(kubeconfig string, args ...string) ([]byte, error) { command := append([]string{"--kubeconfig", kubeconfig}, args...) - return exec.Command("kubectl", command...).Output() + return commandOutput(nil, "kubectl", command...) +} + +func commandOutput(input []byte, name string, args ...string) ([]byte, error) { + ctx, cancel := context.WithTimeout(context.Background(), commandTimeout) + defer cancel() + cmd := exec.CommandContext(ctx, name, args...) + cmd.Stdin = bytes.NewReader(input) + output, err := cmd.CombinedOutput() + if errors.Is(ctx.Err(), context.DeadlineExceeded) { + return output, fmt.Errorf("%s timed out after %s", name, commandTimeout) + } + return output, err }