-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[PLAT-14809][YBA CLI]Support Master Key Rotation
Summary: Support MKR in the universe security operations Security sub command in universe: ``` ./yba universe security Error: required flag(s) "name" not set Usage: yba universe security [flags] yba universe security [command] Available Commands: ear Encryption-at-rest settings for a universe Flags: -f, --force [Optional] Bypass the prompt for non-interactive usage. -n, --name string [Required] The name of the universe for the operation. -s, --skip-validations [Optional] Skip validations before running the CLI command. -h, --help help for security Global Flags: -a, --apiToken string YugabyteDB Anywhere api token. --config string Config file, defaults to $HOME/.yba-cli.yaml --debug Use debug mode, same as --logLevel debug. --disable-color Disable colors in output. (default false) -H, --host string YugabyteDB Anywhere Host (default "http://localhost:9000") -l, --logLevel string Select the desired log level format. Allowed values: debug, info, warn, error, fatal. (default "info") -o, --output string Select the desired output format. Allowed values: table, json, pretty. (default "table") --timeout duration Wait command timeout, example: 5m, 1h. (default 168h0m0s) --wait Wait until the task is completed, otherwise it will exit immediately. (default true) ``` EAR command for universe: ``` ./yba universe security ear -h Encryption-at-rest settings for a universe Usage: yba universe security ear [flags] Aliases: ear, encryption-at-rest, kms Flags: --operation string [Required] Enable or disable encryption-at-rest in a universe. Allowed values: enable, disable, rotate-universe-key, rotate-kms-config. --config-name string [Optional] Key management service configuration name for master key. Required for enable and rotate-kms-config operations, ignored otherwise. -h, --help help for ear Global Flags: -a, --apiToken string YugabyteDB Anywhere api token. --config string Config file, defaults to $HOME/.yba-cli.yaml --debug Use debug mode, same as --logLevel debug. --disable-color Disable colors in output. (default false) -f, --force [Optional] Bypass the prompt for non-interactive usage. -H, --host string YugabyteDB Anywhere Host (default "http://localhost:9000") -l, --logLevel string Select the desired log level format. Allowed values: debug, info, warn, error, fatal. (default "info") -n, --name string [Required] The name of the universe for the operation. -o, --output string Select the desired output format. Allowed values: table, json, pretty. (default "table") -s, --skip-validations [Optional] Skip validations before running the CLI command. --timeout duration Wait command timeout, example: 5m, 1h. (default 168h0m0s) --wait Wait until the task is completed, otherwise it will exit immediately. (default true) ``` Changes to go-client: yugabyte/platform-go-client@c3a4e13 Test Plan: Tested out commands: To change Master Key config of the universe `./yba universe security ear --name dkumar --operation rotate-kms-config --config-name dkumar-aws-cli ` Enable EAR on a universe which has it disabled: `./yba universe security ear --name dkumar --operation enable --config-name dkumar-aws-cli ` Disable EAR `./yba universe security ear --name dkumar --operation disable ` Rotate universe key `/yba universe security ear --name dkumar --operation rotate-universe-key` Reviewers: #yba-api-review!, sneelakantan, skurapati Reviewed By: skurapati Subscribers: yugaware Differential Revision: https://phorge.dev.yugabyte.com/D37835
- Loading branch information
Showing
19 changed files
with
429 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,259 @@ | ||
/* | ||
* Copyright (c) YugaByte, Inc. | ||
*/ | ||
|
||
package security | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/sirupsen/logrus" | ||
"github.com/spf13/cobra" | ||
"github.com/spf13/viper" | ||
ybaclient "github.com/yugabyte/platform-go-client" | ||
"github.com/yugabyte/yugabyte-db/managed/yba-cli/cmd/universe/upgrade" | ||
"github.com/yugabyte/yugabyte-db/managed/yba-cli/cmd/util" | ||
"github.com/yugabyte/yugabyte-db/managed/yba-cli/internal/client" | ||
"github.com/yugabyte/yugabyte-db/managed/yba-cli/internal/formatter" | ||
) | ||
|
||
// encryptionAtRestCmd represents the universe security encryption-at-rest command | ||
var encryptionAtRestCmd = &cobra.Command{ | ||
Use: "ear", | ||
Aliases: []string{"encryption-at-rest", "kms"}, | ||
Short: "Encryption-at-rest settings for a universe", | ||
Long: "Encryption-at-rest settings for a universe", | ||
PreRun: func(cmd *cobra.Command, args []string) { | ||
viper.BindPFlag("force", cmd.Flags().Lookup("force")) | ||
universeName, err := cmd.Flags().GetString("name") | ||
if err != nil { | ||
logrus.Fatalf(formatter.Colorize(err.Error()+"\n", formatter.RedColor)) | ||
} | ||
if len(universeName) == 0 { | ||
cmd.Help() | ||
logrus.Fatalln( | ||
formatter.Colorize("No universe name found to change settings\n", | ||
formatter.RedColor)) | ||
} | ||
|
||
// Validations before gflags upgrade operation | ||
skipValidations, err := cmd.Flags().GetBool("skip-validations") | ||
if err != nil { | ||
logrus.Fatalf(formatter.Colorize(err.Error()+"\n", formatter.RedColor)) | ||
} | ||
if !skipValidations { | ||
_, _, err := upgrade.Validations(cmd, util.SecurityOperation) | ||
if err != nil { | ||
logrus.Fatalf( | ||
formatter.Colorize(err.Error()+"\n", formatter.RedColor), | ||
) | ||
} | ||
|
||
} | ||
err = util.ConfirmCommand( | ||
fmt.Sprintf("Are you sure you want to change encryption at rest configuration for %s: %s", | ||
util.UniverseType, universeName), | ||
viper.GetBool("force")) | ||
if err != nil { | ||
logrus.Fatal(formatter.Colorize(err.Error()+"\n", formatter.RedColor)) | ||
} | ||
}, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
authAPI, universe, err := upgrade.Validations(cmd, util.UpgradeOperation) | ||
if err != nil { | ||
logrus.Fatalf( | ||
formatter.Colorize(err.Error()+"\n", formatter.RedColor)) | ||
} | ||
|
||
universeName := universe.GetName() | ||
universeUUID := universe.GetUniverseUUID() | ||
universeDetails := universe.GetUniverseDetails() | ||
earConfig := universeDetails.GetEncryptionAtRestConfig() | ||
|
||
operation, err := cmd.Flags().GetString("operation") | ||
if err != nil { | ||
logrus.Fatalf(formatter.Colorize(err.Error()+"\n", formatter.RedColor)) | ||
} | ||
configName, err := cmd.Flags().GetString("config-name") | ||
if err != nil { | ||
logrus.Fatalf(formatter.Colorize(err.Error()+"\n", formatter.RedColor)) | ||
} | ||
|
||
operation = strings.ToUpper(operation) | ||
if strings.Compare(operation, util.EnableKMSOpType) != 0 && | ||
strings.Compare(operation, util.DisableKMSOpType) != 0 && | ||
strings.Compare(operation, util.RotateKMSConfigKMSOpType) != 0 && | ||
strings.Compare(operation, util.RotateUniverseKeyKMSOpType) != 0 { | ||
logrus.Fatalf( | ||
formatter.Colorize( | ||
"Invalid operation. "+ | ||
"Allowed values: enable, disable,"+ | ||
" rotate-universe-key, rotate-kms-config\n", formatter.RedColor)) | ||
} | ||
var requestBody ybaclient.EncryptionAtRestConfig | ||
switch operation { | ||
case util.EnableKMSOpType, util.RotateKMSConfigKMSOpType: | ||
requestBody, err = earEnableRequest(authAPI, earConfig, configName, operation) | ||
if err != nil { | ||
logrus.Fatalf( | ||
formatter.Colorize(err.Error()+"\n", formatter.RedColor)) | ||
} | ||
case util.DisableKMSOpType: | ||
requestBody, err = earDisableRequest(earConfig) | ||
if err != nil { | ||
logrus.Fatalf( | ||
formatter.Colorize(err.Error()+"\n", formatter.RedColor)) | ||
} | ||
case util.RotateUniverseKeyKMSOpType: | ||
if earConfig.GetEncryptionAtRestEnabled() || | ||
strings.Compare(earConfig.GetOpType(), util.EnableKMSOpType) == 0 { | ||
requestBody = ybaclient.EncryptionAtRestConfig{ | ||
KmsConfigUUID: util.GetStringPointer(earConfig.GetKmsConfigUUID()), | ||
OpType: util.GetStringPointer(util.EnableKMSOpType), | ||
} | ||
} else { | ||
logrus.Fatal( | ||
formatter.Colorize( | ||
"Cannot rotate universe key if encryption at rest is not enabled", | ||
formatter.RedColor)) | ||
} | ||
|
||
} | ||
|
||
earAPICall(authAPI, universeName, universeUUID, requestBody) | ||
|
||
}, | ||
} | ||
|
||
func init() { | ||
encryptionAtRestCmd.Flags().SortFlags = false | ||
|
||
encryptionAtRestCmd.Flags().String("operation", "", | ||
"[Required] Enable or disable encryption-at-rest in a universe. "+ | ||
"Allowed values: enable, disable, rotate-universe-key, rotate-kms-config.") | ||
encryptionAtRestCmd.MarkFlagRequired("operation") | ||
encryptionAtRestCmd.Flags().String("config-name", "", | ||
fmt.Sprintf("[Optional] Key management service configuration name for master key. %s.", | ||
formatter.Colorize("Required for enable and rotate-kms-config operations, "+ | ||
"ignored otherwise", formatter.GreenColor))) | ||
|
||
} | ||
|
||
func earEnableRequest( | ||
authAPI *client.AuthAPIClient, | ||
earConfig ybaclient.EncryptionAtRestConfig, | ||
configName, operation string) ( | ||
ybaclient.EncryptionAtRestConfig, | ||
error, | ||
) { | ||
if earConfig.GetEncryptionAtRestEnabled() || | ||
strings.Compare(earConfig.GetOpType(), util.EnableKMSOpType) == 0 { | ||
if strings.Compare(operation, util.EnableKMSOpType) == 0 { | ||
logrus.Fatalf( | ||
formatter.Colorize("Encryption at rest is already enabled\n", | ||
formatter.RedColor)) | ||
} | ||
} else { | ||
if strings.Compare(operation, util.RotateKMSConfigKMSOpType) == 0 { | ||
logrus.Fatalf( | ||
formatter.Colorize("Encryption at rest is not enabled, cannot rotate KMS configuration\n", | ||
formatter.RedColor)) | ||
} | ||
} | ||
|
||
if len(strings.TrimSpace(configName)) == 0 { | ||
logrus.Fatalf( | ||
formatter.Colorize( | ||
"Configuration name is required to enable encryption at rest "+ | ||
"or to rotate KMS configuration.\n", | ||
formatter.RedColor)) | ||
} | ||
|
||
configUUID, err := getKMSConfigUUID(authAPI, configName) | ||
if err != nil { | ||
logrus.Fatalf( | ||
formatter.Colorize(err.Error()+"\n", formatter.RedColor)) | ||
} | ||
|
||
if strings.Compare(operation, util.RotateKMSConfigKMSOpType) == 0 && | ||
strings.Compare(configUUID, earConfig.GetKmsConfigUUID()) == 0 { | ||
logrus.Fatal( | ||
formatter.Colorize( | ||
fmt.Sprintf("Universe encryption at rest is already using configuration: %s (%s)\n", | ||
configName, configUUID), | ||
formatter.RedColor, | ||
), | ||
) | ||
} | ||
{ | ||
} | ||
|
||
return ybaclient.EncryptionAtRestConfig{ | ||
KmsConfigUUID: util.GetStringPointer(configUUID), | ||
OpType: util.GetStringPointer(util.EnableKMSOpType), | ||
}, nil | ||
|
||
} | ||
|
||
func earDisableRequest( | ||
earConfig ybaclient.EncryptionAtRestConfig) ( | ||
ybaclient.EncryptionAtRestConfig, | ||
error, | ||
) { | ||
if !earConfig.GetEncryptionAtRestEnabled() || | ||
strings.Compare(earConfig.GetOpType(), util.DisableKMSOpType) == 0 { | ||
logrus.Fatalf( | ||
formatter.Colorize("Encryption at rest is already disabled\n", | ||
formatter.RedColor)) | ||
} | ||
|
||
return ybaclient.EncryptionAtRestConfig{ | ||
OpType: util.GetStringPointer(util.DisableKMSOpType), | ||
}, nil | ||
} | ||
|
||
func getKMSConfigUUID(authAPI *client.AuthAPIClient, configName string) (string, error) { | ||
r, response, err := authAPI.ListKMSConfigs().Execute() | ||
if err != nil { | ||
errMessage := util.ErrorFromHTTPResponse( | ||
response, err, "Universe", "Master Key Rotation - List") | ||
logrus.Fatalf(formatter.Colorize(errMessage.Error()+"\n", formatter.RedColor)) | ||
} | ||
for _, k := range r { | ||
kmsConfig, err := util.ConvertToKMSConfig(k) | ||
if err != nil { | ||
logrus.Fatalf(formatter.Colorize(err.Error()+"\n", formatter.RedColor)) | ||
} | ||
if strings.Compare(kmsConfig.Name, configName) == 0 { | ||
return kmsConfig.ConfigUUID, nil | ||
} | ||
|
||
} | ||
return "", fmt.Errorf("No configurations with name: %s found\n", configName) | ||
} | ||
|
||
func earAPICall( | ||
authAPI *client.AuthAPIClient, | ||
universeName string, | ||
universeUUID string, | ||
requestBody ybaclient.EncryptionAtRestConfig, | ||
) { | ||
r, response, err := authAPI.SetUniverseKey( | ||
universeUUID).SetUniverseKeyRequest(requestBody).Execute() | ||
if err != nil { | ||
errMessage := util.ErrorFromHTTPResponse( | ||
response, err, "Universe", "Master Key Rotation") | ||
logrus.Fatalf(formatter.Colorize(errMessage.Error()+"\n", formatter.RedColor)) | ||
} | ||
|
||
taskUUID := r.GetTaskUUID() | ||
logrus.Info( | ||
fmt.Sprintf("Setting encryption at rest configuration in universe %s (%s)\n", | ||
formatter.Colorize(universeName, formatter.GreenColor), | ||
universeUUID, | ||
)) | ||
|
||
upgrade.WaitForUpgradeUniverseTask(authAPI, universeName, universeUUID, taskUUID) | ||
|
||
} |
32 changes: 32 additions & 0 deletions
32
managed/yba-cli/cmd/universe/security/security_universe.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/* | ||
* Copyright (c) YugaByte, Inc. | ||
*/ | ||
|
||
package security | ||
|
||
import "github.com/spf13/cobra" | ||
|
||
// SecurityUniverseCmd represents the universe security command | ||
var SecurityUniverseCmd = &cobra.Command{ | ||
Use: "security", | ||
Short: "Manage security settings for a universe", | ||
Long: "Manage security settings for a universe", | ||
Run: func(cmd *cobra.Command, args []string) { | ||
cmd.Help() | ||
}, | ||
} | ||
|
||
func init() { | ||
SecurityUniverseCmd.Flags().SortFlags = false | ||
|
||
SecurityUniverseCmd.AddCommand(encryptionAtRestCmd) | ||
|
||
SecurityUniverseCmd.PersistentFlags().StringP("name", "n", "", | ||
"[Required] The name of the universe for the operation.") | ||
SecurityUniverseCmd.MarkPersistentFlagRequired("name") | ||
SecurityUniverseCmd.PersistentFlags().BoolP("force", "f", false, | ||
"[Optional] Bypass the prompt for non-interactive usage.") | ||
SecurityUniverseCmd.PersistentFlags().BoolP("skip-validations", "s", false, | ||
"[Optional] Skip validations before running the CLI command.") | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.