Skip to content

Onboard Secrets Manager user create and list commands #111

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

Merged
merged 10 commits into from
Mar 6, 2024
1 change: 1 addition & 0 deletions docs/stackit_secrets-manager.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ stackit secrets-manager [flags]

* [stackit](./stackit.md) - Manage STACKIT resources using the command line
* [stackit secrets-manager instance](./stackit_secrets-manager_instance.md) - Provides functionality for Secrets Manager instances
* [stackit secrets-manager user](./stackit_secrets-manager_user.md) - Provides functionality for Secrets Manager users

33 changes: 33 additions & 0 deletions docs/stackit_secrets-manager_user.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
## stackit secrets-manager user

Provides functionality for Secrets Manager users

### Synopsis

Provides functionality for Secrets Manager users.

```
stackit secrets-manager user [flags]
```

### Options

```
-h, --help Help for "stackit secrets-manager user"
```

### Options inherited from parent commands

```
-y, --assume-yes If set, skips all confirmation prompts
--async If set, runs the command asynchronously
-o, --output-format string Output format, one of ["json" "pretty"]
-p, --project-id string Project ID
```

### SEE ALSO

* [stackit secrets-manager](./stackit_secrets-manager.md) - Provides functionality for Secrets Manager
* [stackit secrets-manager user create](./stackit_secrets-manager_user_create.md) - Creates a Secrets Manager user
* [stackit secrets-manager user list](./stackit_secrets-manager_user_list.md) - Lists all Secrets Manager users

51 changes: 51 additions & 0 deletions docs/stackit_secrets-manager_user_create.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
## stackit secrets-manager user create

Creates a Secrets Manager user

### Synopsis

Creates a user for a Secrets Manager instance with generated username and password

```
stackit secrets-manager user create [flags]
```

### Examples

```
Create a Secrets Manager user for instance with ID "xxx"
$ stackit mongodbflex user create --instance-id xxx

Create a Secrets Manager user for instance with ID "xxx" and description "yyy"
$ stackit mongodbflex user create --instance-id xxx --description yyy

Create a Secrets Manager user for instance with ID "xxx" and doesn't display the password
$ stackit mongodbflex user create --instance-id xxx --hide-password

Create a Secrets Manager user for instance with ID "xxx" with write access to the secrets engine
$ stackit mongodbflex user create --instance-id xxx --write
```

### Options

```
--description string A user chosen description to differentiate between multiple users
-h, --help Help for "stackit secrets-manager user create"
--hide-password Hide password in output
--instance-id string ID of the instance
--write User write access to the secrets engine. If unset, user is read-only
```

### Options inherited from parent commands

```
-y, --assume-yes If set, skips all confirmation prompts
--async If set, runs the command asynchronously
-o, --output-format string Output format, one of ["json" "pretty"]
-p, --project-id string Project ID
```

### SEE ALSO

* [stackit secrets-manager user](./stackit_secrets-manager_user.md) - Provides functionality for Secrets Manager users

46 changes: 46 additions & 0 deletions docs/stackit_secrets-manager_user_list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
## stackit secrets-manager user list

Lists all Secrets Manager users

### Synopsis

Lists all Secrets Manager users.

```
stackit secrets-manager user list [flags]
```

### Examples

```
List all Secrets Manager users of instance with ID "xxx
$ stackit secrets-manager user list --instance-id xxx

List all Secrets Manager users in JSON format with ID "xxx
$ stackit secrets-manager user list --instance-id xxx --output-format json

List up to 10 Secrets Manager users with ID "xxx"
$ stackit secrets-manager user list --instance-id xxx --limit 10
```

### Options

```
-h, --help Help for "stackit secrets-manager user list"
--instance-id string Instance ID
--limit int Maximum number of entries to list
```

### Options inherited from parent commands

```
-y, --assume-yes If set, skips all confirmation prompts
--async If set, runs the command asynchronously
-o, --output-format string Output format, one of ["json" "pretty"]
-p, --project-id string Project ID
```

### SEE ALSO

* [stackit secrets-manager user](./stackit_secrets-manager_user.md) - Provides functionality for Secrets Manager users

2 changes: 2 additions & 0 deletions internal/cmd/secrets-manager/secrets_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package secretsmanager

import (
"github.com/stackitcloud/stackit-cli/internal/cmd/secrets-manager/instance"
"github.com/stackitcloud/stackit-cli/internal/cmd/secrets-manager/user"
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
"github.com/stackitcloud/stackit-cli/internal/pkg/utils"

Expand All @@ -22,4 +23,5 @@ func NewCmd() *cobra.Command {

func addSubcommands(cmd *cobra.Command) {
cmd.AddCommand(instance.NewCmd())
cmd.AddCommand(user.NewCmd())
}
141 changes: 141 additions & 0 deletions internal/cmd/secrets-manager/user/create/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package create

import (
"context"
"fmt"

"github.com/stackitcloud/stackit-cli/internal/pkg/args"
"github.com/stackitcloud/stackit-cli/internal/pkg/confirm"
"github.com/stackitcloud/stackit-cli/internal/pkg/errors"
"github.com/stackitcloud/stackit-cli/internal/pkg/examples"
"github.com/stackitcloud/stackit-cli/internal/pkg/flags"
"github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
"github.com/stackitcloud/stackit-cli/internal/pkg/services/secrets-manager/client"
secretsManagerUtils "github.com/stackitcloud/stackit-cli/internal/pkg/services/secrets-manager/utils"
"github.com/stackitcloud/stackit-cli/internal/pkg/utils"

"github.com/spf13/cobra"
"github.com/stackitcloud/stackit-sdk-go/services/secretsmanager"
)

const (
instanceIdFlag = "instance-id"
descriptionFlag = "description"
writeFlag = "write"
hidePasswordFlag = "hide-password"
)

type inputModel struct {
*globalflags.GlobalFlagModel

InstanceId string
Description *string
Write *bool
HidePassword bool
}

func NewCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create",
Short: "Creates a Secrets Manager user",
Long: fmt.Sprintf("%s\n%s\n%s",
"Creates a Secrets Manager user.",
"The username and password are auto-generated and provided upon creation.",
"A description can be provided to identify a user.",
),
Example: examples.Build(
examples.NewExample(
`Create a Secrets Manager user for instance with ID "xxx" and description "yyy"`,
"$ stackit secrets-manager user create --instance-id xxx --description yyy"),
examples.NewExample(
`Create a Secrets Manager user for instance with ID "xxx" and hides the generated password`,
"$ stackit secrets-manager user create --instance-id xxx --hide-password"),
examples.NewExample(
`Create a Secrets Manager user for instance with ID "xxx" with write access to the secrets engine`,
"$ stackit secrets-manager user create --instance-id xxx --write"),
),
Args: args.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background()
model, err := parseInput(cmd)
if err != nil {
return err
}

// Configure API client
apiClient, err := client.ConfigureClient(cmd)
if err != nil {
return err
}

instanceLabel, err := secretsManagerUtils.GetInstanceName(ctx, apiClient, model.ProjectId, model.InstanceId)
if err != nil {
instanceLabel = model.InstanceId
}

if !model.AssumeYes {
prompt := fmt.Sprintf("Are you sure you want to create a user for instance %q?", instanceLabel)
err = confirm.PromptForConfirmation(cmd, prompt)
if err != nil {
return err
}
}

// Call API
req := buildRequest(ctx, model, apiClient)
resp, err := req.Execute()
if err != nil {
return fmt.Errorf("create Secrets Manager user: %w", err)
}

cmd.Printf("Created user for instance %q. User ID: %s\n\n", instanceLabel, *resp.Id)
cmd.Printf("Username: %s\n", *resp.Username)
if model.HidePassword {
cmd.Printf("Password: <hidden>\n")
} else {
cmd.Printf("Password: %s\n", *resp.Password)
}
cmd.Printf("Description: %s\n", *resp.Description)
cmd.Printf("Write Access: %t\n", *resp.Write)

return nil
},
}

configureFlags(cmd)
return cmd
}

func configureFlags(cmd *cobra.Command) {
cmd.Flags().Var(flags.UUIDFlag(), instanceIdFlag, "ID of the instance")
cmd.Flags().String(descriptionFlag, "", "A user chosen description to differentiate between multiple users")
cmd.Flags().Bool(writeFlag, false, "User write access to the secrets engine. If unset, user is read-only")
cmd.Flags().Bool(hidePasswordFlag, false, "Hide password in output")

err := flags.MarkFlagsRequired(cmd, instanceIdFlag)
cobra.CheckErr(err)
}

func parseInput(cmd *cobra.Command) (*inputModel, error) {
globalFlags := globalflags.Parse(cmd)
if globalFlags.ProjectId == "" {
return nil, &errors.ProjectIdError{}
}

return &inputModel{
GlobalFlagModel: globalFlags,
InstanceId: flags.FlagToStringValue(cmd, instanceIdFlag),
Description: utils.Ptr(flags.FlagToStringValue(cmd, descriptionFlag)),
Write: utils.Ptr(flags.FlagToBoolValue(cmd, writeFlag)),
HidePassword: flags.FlagToBoolValue(cmd, hidePasswordFlag),
}, nil
}

func buildRequest(ctx context.Context, model *inputModel, apiClient *secretsmanager.APIClient) secretsmanager.ApiCreateUserRequest {
req := apiClient.CreateUser(ctx, model.ProjectId, model.InstanceId)
req = req.CreateUserPayload(secretsmanager.CreateUserPayload{
Description: model.Description,
Write: model.Write,
})
return req
}
Loading