Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[chore] Fix missing context, add timeout #164

Merged
merged 2 commits into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Table of Contents
- [Prerequisites](#prerequisites)
- [Building Steps](#building-steps)
- [Examples](#examples)
- [Raw Mode](#raw-mode)
- [Contributing](#contributing)
- [License](#license)

Expand All @@ -52,6 +53,7 @@ The `SealedSecret` will be printed to `STDOUT`. You can run it as is, as part of
| `-l`, `--labels` | Sets k8s labels. KV pairs, comma separated. | | `[]string` |
| `--raw` | Use Kubeseal raw mode. | | `bool` |
| | | | |
| `-t`, `--timeout` | Set timeout to the secret fetch. Default: 30 | | `int` |
| `-d`, `--debug` | Run in debug mode. | | `bool` |
| `-h`, `--help` | Display help. | | `none` |
| `-v`, `--version` | Display version. | | `none` |
Expand Down Expand Up @@ -82,7 +84,7 @@ If not, `kubeseal-convert` will try to extract the project ID from the default c

* Go version 1.22+
* `make` command installed
* `kubeseal` command installed, and a valid communication to the sealed secrets controller.
* `kubeseal` command installed, and a valid communication to the Sealed Secrets controller.

### Building Steps

Expand Down
2 changes: 1 addition & 1 deletion cmd/kubeseal-convert/azurekeyvault.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ var azureKeyVaultCmd = &cobra.Command{
PreRun: toggleDebug,
Run: func(cmd *cobra.Command, args []string) {
secretVal := domain.SecretValues{
Data: AzureKeyVault.GetSecrets(args[0]),
Data: AzureKeyVault.GetSecrets(args[0], timeout),
Name: ParseStringFlag(cmd, "name"),
Namespace: ParseStringFlag(cmd, "namespace"),
Labels: ParseLabels(cmd),
Expand Down
2 changes: 1 addition & 1 deletion cmd/kubeseal-convert/azurekeyvault_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestAzureKeyVaultCmd(t *testing.T) {

// mock azurekeyvault
mockAzureKeyVault := mocks.NewAzureKeyVault(t)
mockAzureKeyVault.On("GetSecrets", mock.Anything).Return(map[string]interface{}{
mockAzureKeyVault.On("GetSecrets", mock.Anything, mock.AnythingOfType("int")).Return(map[string]interface{}{
"key": "value",
}, nil)
AzureKeyVault = mockAzureKeyVault
Expand Down
2 changes: 1 addition & 1 deletion cmd/kubeseal-convert/gcpsecretsmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ var gcpSecretsmanagerCmd = &cobra.Command{
PreRun: toggleDebug,
Run: func(cmd *cobra.Command, args []string) {
secretVal := domain.SecretValues{
Data: GcpSecretsManager.GetSecret(args[0]),
Data: GcpSecretsManager.GetSecret(args[0], timeout),
Name: ParseStringFlag(cmd, "name"),
Namespace: ParseStringFlag(cmd, "namespace"),
Labels: ParseLabels(cmd),
Expand Down
4 changes: 3 additions & 1 deletion cmd/kubeseal-convert/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ var (
secretName string
secretNamespace string
rawMode bool
timeout int

version = "3.2.0"
version = "3.3.0"
rootCmd = &cobra.Command{
Use: "kubeseal-convert",
Short: "kubeseal-convert - a simple CLI to transform external secrets into Sealed Secrets",
Expand Down Expand Up @@ -54,4 +55,5 @@ func init() {
rootCmd.PersistentFlags().StringToStringP("labels", "l", map[string]string{}, "Set k8s labels")
rootCmd.PersistentFlags().BoolVar(&rawMode, "raw", false, "[optional] use raw mode")
rootCmd.PersistentFlags().BoolVarP(&debug, "debug", "d", false, "[optional] debug logging")
rootCmd.PersistentFlags().IntVarP(&timeout, "timeout", "t", 30, "[optional] get secret timeout")
}
2 changes: 1 addition & 1 deletion cmd/kubeseal-convert/secretsmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ var secretsmanagerCmd = &cobra.Command{
PreRun: toggleDebug,
Run: func(cmd *cobra.Command, args []string) {
secretVal := domain.SecretValues{
Data: SecretsManager.GetSecret(args[0]),
Data: SecretsManager.GetSecret(args[0], timeout),
Name: ParseStringFlag(cmd, "name"),
Namespace: ParseStringFlag(cmd, "namespace"),
Labels: ParseLabels(cmd),
Expand Down
2 changes: 1 addition & 1 deletion cmd/kubeseal-convert/secretsmanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func TestSecretManagerCmd(t *testing.T) {
// mock secretsmanager
mockSecretsManager := mocks.NewSecretsManager(t)

mockSecretsManager.On("GetSecret", mock.Anything).Return(map[string]interface{}{"key": "value"}, nil)
mockSecretsManager.On("GetSecret", mock.Anything, mock.AnythingOfType("int")).Return(map[string]interface{}{"key": "value"}, nil)
SecretsManager = mockSecretsManager

// test sm command
Expand Down
4 changes: 2 additions & 2 deletions cmd/kubeseal-convert/vault.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ var vaultCmd = &cobra.Command{
PreRun: toggleDebug,
Run: func(cmd *cobra.Command, args []string) {
secretVal := domain.SecretValues{
Data: Vault.GetSecret(args[0]),
Data: Vault.GetSecret(args[0], timeout),
Name: ParseStringFlag(cmd, "name"),
Namespace: ParseStringFlag(cmd, "namespace"),
Labels: ParseLabels(cmd),
Annotations: ParseAnnotations(cmd),
}
log.Debugf("secret values: %v", secretVal)
KubeSeal.BuildSecretFile(secretVal, false)
KubeSeal.BuildSecretFile(secretVal, rawMode)
},
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/kubeseal-convert/vault_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestVaultCmd(t *testing.T) {

// mock vault
mockVault := mocks.NewVault(t)
mockVault.On("GetSecret", mock.Anything).Return(map[string]interface{}{
mockVault.On("GetSecret", mock.Anything, mock.AnythingOfType("int")).Return(map[string]interface{}{
"key": "value",
}, nil)
Vault = mockVault
Expand Down
10 changes: 5 additions & 5 deletions mocks/AzureKeyVault.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions mocks/GcpSecretsManager.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions mocks/SecretsManager.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions mocks/Vault.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 30 additions & 15 deletions pkg/kubeseal-convert/handlers/azurekeyvault/azurekeyvault.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package azurekeyvault
import (
"context"
"fmt"
"time"

log "github.com/sirupsen/logrus"

Expand All @@ -12,47 +13,49 @@ import (
"github.com/eladleev/kubeseal-convert/pkg/kubeseal-convert/interfaces"
)

func createClient(vaultName string) *secrets.Client {
// see https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#readme-defaultazurecredential: this allows getting credentials
// via either environment variables, managed identity, or 'az login'
func createClient(vaultName string) (*secrets.Client, error) {
/*
see https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#readme-defaultazurecredential: this allows getting credentials
via either environment variables, managed identity, or 'az login'
*/
cred, err := identity.NewDefaultAzureCredential(nil)
log.Debugf("Azure identity: %v", cred)
if err != nil {
log.Fatalf("Failed to obtain a credential needed to login to the azure vault: %v", err)
return nil, fmt.Errorf("failed to obtain a credential needed to login to the azure vault: %v", err)
}

vaultURI := fmt.Sprintf("https://%s.vault.azure.net", vaultName)
log.Debugf("vaultURI: %v", vaultURI)
client, err := secrets.NewClient(vaultURI, cred, nil)
if err != nil {
log.Fatalf("Failed to connect to vault '%s': %v", vaultURI, err)
return nil, fmt.Errorf("failed to connect to vault '%s': %v", vaultURI, err)
}
return client
return client, nil
}

// retrieve secret by name with the client
func getSecrets(client *secrets.Client, vaultName string) map[string]interface{} {
func getSecrets(ctx context.Context, client *secrets.Client, vaultName string) (map[string]interface{}, error) {
mp := make(map[string]interface{})

pager := client.NewListSecretsPager(&secrets.ListSecretsOptions{})

for pager.More() {
log.Debugf("pager: %v", pager)
page, err := pager.NextPage(context.TODO())
page, err := pager.NextPage(ctx)
if err != nil {
log.Fatalf("Failed to retrieve secrets from vault '%s': %v", vaultName, err)
return nil, fmt.Errorf("failed to retrieve secrets from vault '%s': %v", vaultName, err)
}
for _, secret := range page.Value {
value, err := client.GetSecret(context.TODO(), secret.ID.Name(), secret.ID.Version(), &secrets.GetSecretOptions{})
value, err := client.GetSecret(ctx, secret.ID.Name(), secret.ID.Version(), &secrets.GetSecretOptions{})
log.Debugf("secret value: %v", value)
if err != nil {
log.Fatalf("Failed to retrieve secret '%s' from vault '%s': %v", secret.ID.Name(), vaultName, err)
return nil, fmt.Errorf("failed to retrieve secret '%s' from vault '%s': %v", secret.ID.Name(), vaultName, err)
}
mp[secret.ID.Name()] = *value.Value
}
}

return mp
return mp, nil
}

type AzureKeyVaultImp struct {
Expand All @@ -62,8 +65,20 @@ func New() interfaces.AzureKeyVault {
return &AzureKeyVaultImp{}
}

func (*AzureKeyVaultImp) GetSecrets(vaultName string) map[string]interface{} {
func (*AzureKeyVaultImp) GetSecrets(vaultName string, timeout int) map[string]interface{} {
log.Debugf("Getting secrets from vault %v", vaultName)
cli := createClient(vaultName)
return getSecrets(cli, vaultName)
// Create a context with a timeout
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
defer cancel()

cli, err := createClient(vaultName)
if err != nil {
log.Fatalf("failed to create client: %v", err)
}

secret, err := getSecrets(ctx, cli, vaultName)
if err != nil {
log.Fatalf("failed to get secret: %v", err)
}
return secret
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"strings"
"time"

log "github.com/sirupsen/logrus"

Expand Down Expand Up @@ -37,14 +38,13 @@ func buildSecretId(ctx context.Context, secretName string) string {
return secretName
}

func getSecret(secretName string) map[string]interface{} {
func getSecret(ctx context.Context, secretName string) (map[string]interface{}, error) {
mp := make(map[string]interface{})
ctx := context.Background()

client, err := secretmanager.NewClient(ctx)
log.Debugf("client: %v", client)
if err != nil {
log.Fatalf("failed to setup client: %v", err)
return nil, fmt.Errorf("failed to setup client: %v", err)
}

defer func(client *secretmanager.Client) {
Expand All @@ -59,11 +59,11 @@ func getSecret(secretName string) map[string]interface{} {
result, err := client.AccessSecretVersion(ctx, accessRequest)
log.Debugf("result: %v", result)
if err != nil {
log.Fatalf("failed to access secret version: %v", err)
return nil, fmt.Errorf("failed to access secret version: %v", err)
}

mp[cleanSecretName] = string(result.Payload.Data)
return mp
return mp, nil
}

type GcpSecretsManagerImp struct {
Expand All @@ -73,6 +73,13 @@ func New() interfaces.SecretsManager {
return &GcpSecretsManagerImp{}
}

func (*GcpSecretsManagerImp) GetSecret(secretName string) map[string]interface{} {
return getSecret(secretName)
func (*GcpSecretsManagerImp) GetSecret(secretName string, timeout int) map[string]interface{} {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
defer cancel()

secret, err := getSecret(ctx, secretName)
if err != nil {
log.Errorf("failed to get secret: %v", err)
}
return secret
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func Test_getSecret(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := getSecret(tt.args.secretName); !reflect.DeepEqual(got, tt.want) {
if got, _ := getSecret(context.TODO(), tt.args.secretName); !reflect.DeepEqual(got, tt.want) {
t.Errorf("getSecret() = %v, want %v", got, tt.want)
}
})
Expand Down
Loading
Loading