feat(vault-tui): implement KV client and service for managing secrets

- Added internal/vault/client.go for creating a Vault client with configuration settings.
- Introduced internal/vault/errors.go to classify Vault API errors for better UI handling.
- Created internal/vault/kv.go to manage KV secrets, including listing, reading, writing, and deleting operations.
- Implemented internal/vault/mounts.go to list and describe secret engine mounts.
- Developed internal/vault/service.go to provide a unified entry point for Vault operations.
- Added internal/vault/kv_test.go for comprehensive testing of KV operations.
- Introduced internal/ui/toast.go for transient notifications in the UI.
- Added renovate.json for dependency management and updates.
This commit is contained in:
2026-08-14 11:09:03 +02:00
commit ae30ba1240
85 changed files with 9413 additions and 0 deletions
+110
View File
@@ -0,0 +1,110 @@
//go:build cloud
package auth
import (
"context"
"github.com/hashicorp/vault/api"
awsauth "github.com/hashicorp/vault/api/auth/aws"
azureauth "github.com/hashicorp/vault/api/auth/azure"
gcpauth "github.com/hashicorp/vault/api/auth/gcp"
)
// Cloud auth methods (AWS/Azure/GCP) are gated behind the `cloud` build
// tag: their SDKs transitively pull in tens of MB of dependencies
// (aws-sdk-go, google.golang.org/api, the Azure SDK) that a typical
// OIDC/userpass/LDAP-only deployment never needs. Build with `-tags cloud`
// to include them; see m_cloud_stub.go for the default (excluded) build,
// which lists these names in the picker greyed out with a reason instead
// of letting them silently vanish.
func init() {
register(awsMethod{}, azureMethod{}, gcpMethod{})
}
type awsMethod struct{}
func (awsMethod) Name() string { return "aws" }
func (awsMethod) DisplayName() string { return "AWS" }
func (awsMethod) DefaultMount() string { return "aws" }
func (awsMethod) Fields() []Field {
return []Field{
{Name: "role", Label: "Role", Kind: FieldText, Required: true, EnvFallback: []string{"VAULT_AUTH_AWS_ROLE"}},
{Name: "type", Label: "Auth type", Kind: FieldSelect, Options: []string{"iam", "ec2"}, Default: "iam"},
{Name: "region", Label: "AWS region (optional)", Kind: FieldText},
}
}
func (awsMethod) Login(ctx context.Context, c *api.Client, req Request) (*api.Secret, error) {
opts := []awsauth.LoginOption{awsauth.WithMountPath(mountOf(req, "aws"))}
if r := req.Creds.Get("role"); r != "" {
opts = append(opts, awsauth.WithRole(r))
}
if r := req.Creds.Get("region"); r != "" {
opts = append(opts, awsauth.WithRegion(r))
}
if req.Creds.Get("type") == "ec2" {
opts = append(opts, awsauth.WithEC2Auth())
} else {
opts = append(opts, awsauth.WithIAMAuth())
}
a, err := awsauth.NewAWSAuth(opts...)
if err != nil {
return nil, err
}
return a.Login(ctx, c)
}
type azureMethod struct{}
func (azureMethod) Name() string { return "azure" }
func (azureMethod) DisplayName() string { return "Azure" }
func (azureMethod) DefaultMount() string { return "azure" }
func (azureMethod) Fields() []Field {
return []Field{
{Name: "role", Label: "Role", Kind: FieldText, Required: true, EnvFallback: []string{"VAULT_AUTH_AZURE_ROLE"}},
{Name: "resource", Label: "Resource URL (optional)", Kind: FieldText},
}
}
func (azureMethod) Login(ctx context.Context, c *api.Client, req Request) (*api.Secret, error) {
opts := []azureauth.LoginOption{azureauth.WithMountPath(mountOf(req, "azure"))}
if r := req.Creds.Get("resource"); r != "" {
opts = append(opts, azureauth.WithResource(r))
}
a, err := azureauth.NewAzureAuth(req.Creds.Get("role"), opts...)
if err != nil {
return nil, err
}
return a.Login(ctx, c)
}
type gcpMethod struct{}
func (gcpMethod) Name() string { return "gcp" }
func (gcpMethod) DisplayName() string { return "GCP" }
func (gcpMethod) DefaultMount() string { return "gcp" }
func (gcpMethod) Fields() []Field {
return []Field{
{Name: "role", Label: "Role", Kind: FieldText, Required: true, EnvFallback: []string{"VAULT_AUTH_GCP_ROLE"}},
{Name: "type", Label: "Auth type", Kind: FieldSelect, Options: []string{"iam", "gce"}, Default: "iam"},
{Name: "service_account", Label: "Service account email (iam only)", Kind: FieldText},
}
}
func (gcpMethod) Login(ctx context.Context, c *api.Client, req Request) (*api.Secret, error) {
opts := []gcpauth.LoginOption{gcpauth.WithMountPath(mountOf(req, "gcp"))}
if req.Creds.Get("type") == "gce" {
opts = append(opts, gcpauth.WithGCEAuth())
} else {
opts = append(opts, gcpauth.WithIAMAuth(req.Creds.Get("service_account")))
}
a, err := gcpauth.NewGCPAuth(req.Creds.Get("role"), opts...)
if err != nil {
return nil, err
}
return a.Login(ctx, c)
}