-
Notifications
You must be signed in to change notification settings - Fork 37
Expand file tree
/
Copy pathimportKey.go
More file actions
162 lines (136 loc) · 5.49 KB
/
importKey.go
File metadata and controls
162 lines (136 loc) · 5.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package importKey
import (
"context"
"encoding/base64"
"fmt"
"github.com/stackitcloud/stackit-cli/internal/pkg/types"
"github.com/spf13/cobra"
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
cliErr "github.com/stackitcloud/stackit-cli/internal/pkg/errors"
"github.com/stackitcloud/stackit-cli/internal/pkg/services/kms/client"
kmsUtils "github.com/stackitcloud/stackit-cli/internal/pkg/services/kms/utils"
"github.com/stackitcloud/stackit-cli/internal/pkg/utils"
"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/print"
"github.com/stackitcloud/stackit-sdk-go/services/kms"
)
const (
keyIdArg = "KEY_ID"
keyRingIdFlag = "keyring-id"
wrappedKeyFlag = "wrapped-key"
wrappingKeyIdFlag = "wrapping-key-id"
)
type inputModel struct {
*globalflags.GlobalFlagModel
KeyRingId string
KeyId string
WrappedKey *string
WrappingKeyId *string
}
func NewCmd(params *types.CmdParams) *cobra.Command {
cmd := &cobra.Command{
Use: fmt.Sprintf("import %s", keyIdArg),
Short: "Import a KMS key",
Long: "After encrypting the secret with the wrapping key’s public key and Base64-encoding it, import it as a new version of the specified KMS key.",
Args: args.SingleArg(keyIdArg, utils.ValidateUUID),
Example: examples.Build(
examples.NewExample(
`Import a new version for the given KMS key "MY_KEY_ID" from literal value`,
`$ stackit kms key import "MY_KEY_ID" --keyring-id "my-keyring-id" --wrapped-key "BASE64_VALUE" --wrapping-key-id "MY_WRAPPING_KEY_ID"`),
examples.NewExample(
`Import from a file`,
`$ stackit kms key import "MY_KEY_ID" --keyring-id "my-keyring-id" --wrapped-key "@path/to/wrapped.key.b64" --wrapping-key-id "MY_WRAPPING_KEY_ID"`,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background()
model, err := parseInput(params.Printer, cmd, args)
if err != nil {
return err
}
// Configure API client
apiClient, err := client.ConfigureClient(params.Printer, params.CliVersion)
if err != nil {
return err
}
keyName, err := kmsUtils.GetKeyName(ctx, apiClient, model.ProjectId, model.Region, model.KeyRingId, model.KeyId)
if err != nil {
params.Printer.Debug(print.ErrorLevel, "get key name: %v", err)
keyName = model.KeyId
}
keyRingName, err := kmsUtils.GetKeyRingName(ctx, apiClient, model.ProjectId, model.KeyRingId, model.Region)
if err != nil {
params.Printer.Debug(print.ErrorLevel, "get key ring name: %v", err)
keyRingName = model.KeyRingId
}
prompt := fmt.Sprintf("Are you sure you want to import a new version for the KMS Key %q inside the key ring %q?", keyName, keyRingName)
err = params.Printer.PromptForConfirmation(prompt)
if err != nil {
return err
}
// Call API
req, _ := buildRequest(ctx, model, apiClient)
resp, err := req.Execute()
if err != nil {
return fmt.Errorf("import KMS key: %w", err)
}
return outputResult(params.Printer, model.OutputFormat, keyRingName, keyName, resp)
},
}
configureFlags(cmd)
return cmd
}
func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inputModel, error) {
keyId := inputArgs[0]
globalFlags := globalflags.Parse(p, cmd)
if globalFlags.ProjectId == "" {
return nil, &cliErr.ProjectIdError{}
}
// WrappedKey needs to be base64 encoded
var wrappedKey = flags.FlagToStringPointer(p, cmd, wrappedKeyFlag)
_, err := base64.StdEncoding.DecodeString(*wrappedKey)
if err != nil || *wrappedKey == "" {
return nil, &cliErr.FlagValidationError{
Flag: wrappedKeyFlag,
Details: "The 'wrappedKey' argument is required and needs to be base64 encoded (whether provided inline or via file).",
}
}
model := inputModel{
GlobalFlagModel: globalFlags,
KeyId: keyId,
KeyRingId: flags.FlagToStringValue(p, cmd, keyRingIdFlag),
WrappedKey: wrappedKey,
WrappingKeyId: flags.FlagToStringPointer(p, cmd, wrappingKeyIdFlag),
}
p.DebugInputModel(model)
return &model, nil
}
type kmsKeyClient interface {
ImportKey(ctx context.Context, projectId string, regionId string, keyRingId string, keyId string) kms.ApiImportKeyRequest
}
func buildRequest(ctx context.Context, model *inputModel, apiClient kmsKeyClient) (kms.ApiImportKeyRequest, error) {
req := apiClient.ImportKey(ctx, model.ProjectId, model.Region, model.KeyRingId, model.KeyId)
req = req.ImportKeyPayload(kms.ImportKeyPayload{
WrappedKey: model.WrappedKey,
WrappingKeyId: model.WrappingKeyId,
})
return req, nil
}
func outputResult(p *print.Printer, outputFormat, keyRingName, keyName string, resp *kms.Version) error {
if resp == nil {
return fmt.Errorf("response is nil")
}
return p.OutputResult(outputFormat, resp, func() error {
p.Outputf("Imported a new version for the key %q inside the key ring %q\n", keyName, keyRingName)
return nil
})
}
func configureFlags(cmd *cobra.Command) {
cmd.Flags().Var(flags.UUIDFlag(), keyRingIdFlag, "ID of the KMS key ring")
cmd.Flags().Var(flags.ReadFromFileFlag(), wrappedKeyFlag, "The wrapped key material to be imported. Base64-encoded. Pass the value directly or a file path (e.g. @path/to/wrapped.key.b64)")
cmd.Flags().Var(flags.UUIDFlag(), wrappingKeyIdFlag, "The unique id of the wrapping key the key material has been wrapped with")
err := flags.MarkFlagsRequired(cmd, keyRingIdFlag, wrappedKeyFlag, wrappingKeyIdFlag)
cobra.CheckErr(err)
}