2022-03-14 06:55:09 +00:00
|
|
|
package key
|
|
|
|
|
|
|
|
import (
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/spf13/viper"
|
|
|
|
"sigs.k8s.io/yaml"
|
|
|
|
|
2022-04-26 23:01:45 +00:00
|
|
|
"github.com/zitadel/zitadel/internal/crypto"
|
|
|
|
cryptoDB "github.com/zitadel/zitadel/internal/crypto/database"
|
|
|
|
"github.com/zitadel/zitadel/internal/database"
|
2023-12-20 16:13:04 +00:00
|
|
|
"github.com/zitadel/zitadel/internal/database/dialect"
|
|
|
|
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
2022-03-14 06:55:09 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2022-04-04 08:10:57 +00:00
|
|
|
flagKeyFile = "file"
|
2022-03-14 06:55:09 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Config struct {
|
|
|
|
Database database.Config
|
|
|
|
}
|
|
|
|
|
|
|
|
func New() *cobra.Command {
|
|
|
|
cmd := &cobra.Command{
|
|
|
|
Use: "keys",
|
|
|
|
Short: "manage encryption keys",
|
|
|
|
}
|
2022-04-04 08:10:57 +00:00
|
|
|
AddMasterKeyFlag(cmd)
|
2022-03-14 06:55:09 +00:00
|
|
|
cmd.AddCommand(newKey())
|
|
|
|
return cmd
|
|
|
|
}
|
|
|
|
|
|
|
|
func newKey() *cobra.Command {
|
|
|
|
cmd := &cobra.Command{
|
|
|
|
Use: "new [keyID=key]... [-f file]",
|
|
|
|
Short: "create new encryption key(s)",
|
|
|
|
Long: `create new encryption key(s) (encrypted by the provided master key)
|
|
|
|
provide key(s) by YAML file and/or by argument
|
|
|
|
Requirements:
|
|
|
|
- cockroachdb`,
|
|
|
|
Example: `new -f keys.yaml
|
|
|
|
new key1=somekey key2=anotherkey
|
|
|
|
new -f keys.yaml key2=anotherkey`,
|
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
keys, err := keysFromArgs(args)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
filePath, _ := cmd.Flags().GetString(flagKeyFile)
|
|
|
|
if filePath != "" {
|
|
|
|
file, err := openFile(filePath)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
yamlKeys, err := keysFromYAML(file)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
keys = append(keys, yamlKeys...)
|
|
|
|
}
|
|
|
|
config := new(Config)
|
|
|
|
if err := viper.Unmarshal(config); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-04-04 08:10:57 +00:00
|
|
|
masterKey, err := MasterKey(cmd)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-03-14 06:55:09 +00:00
|
|
|
storage, err := keyStorage(config.Database, masterKey)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return storage.CreateKeys(keys...)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
cmd.PersistentFlags().StringP(flagKeyFile, "f", "", "path to keys file")
|
|
|
|
return cmd
|
|
|
|
}
|
|
|
|
|
|
|
|
func keysFromArgs(args []string) ([]*crypto.Key, error) {
|
|
|
|
keys := make([]*crypto.Key, len(args))
|
|
|
|
for i, arg := range args {
|
|
|
|
key := strings.Split(arg, "=")
|
|
|
|
if len(key) != 2 {
|
|
|
|
return nil, caos_errs.ThrowInternal(nil, "KEY-JKd82", "argument is not in the valid format [keyID=key]")
|
|
|
|
}
|
|
|
|
keys[i] = &crypto.Key{
|
|
|
|
ID: key[0],
|
|
|
|
Value: key[1],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return keys, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func keysFromYAML(file io.Reader) ([]*crypto.Key, error) {
|
|
|
|
data, err := io.ReadAll(file)
|
|
|
|
if err != nil {
|
|
|
|
return nil, caos_errs.ThrowInternal(err, "KEY-ajGFr", "unable to extract keys from file")
|
|
|
|
}
|
|
|
|
keysYAML := make(map[string]string)
|
|
|
|
if err = yaml.Unmarshal(data, &keysYAML); err != nil {
|
|
|
|
return nil, caos_errs.ThrowInternal(err, "KEY-sd34K", "unable to extract keys from file")
|
|
|
|
}
|
|
|
|
keys := make([]*crypto.Key, 0, len(keysYAML))
|
|
|
|
for id, key := range keysYAML {
|
|
|
|
keys = append(keys, &crypto.Key{
|
|
|
|
ID: id,
|
|
|
|
Value: key,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return keys, nil
|
|
|
|
}
|
|
|
|
|
2022-04-04 08:10:57 +00:00
|
|
|
func openFile(fileName string) (io.Reader, error) {
|
2022-03-14 06:55:09 +00:00
|
|
|
file, err := os.Open(fileName)
|
|
|
|
if err != nil {
|
|
|
|
return nil, caos_errs.ThrowInternalf(err, "KEY-asGr2", "failed to open file: %s", fileName)
|
|
|
|
}
|
|
|
|
return file, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func keyStorage(config database.Config, masterKey string) (crypto.KeyStorage, error) {
|
2023-12-20 16:13:04 +00:00
|
|
|
db, err := database.Connect(config, false, dialect.DBPurposeQuery)
|
2022-03-14 06:55:09 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-08-22 12:49:02 +00:00
|
|
|
return cryptoDB.NewKeyStorage(db, masterKey)
|
2022-03-14 06:55:09 +00:00
|
|
|
}
|