From 500ac598d71ba86de19a4d0a477cc24544fccf9b Mon Sep 17 00:00:00 2001 From: Vishwanath Hiremath Date: Fri, 19 Jul 2024 15:21:16 -0700 Subject: [PATCH 1/3] rad credential register command changes for irsa Signed-off-by: Vishwanath Hiremath --- .github/workflows/functional-test.yaml | 2 +- .github/workflows/long-running-azure.yaml | 2 +- pkg/cli/cmd/credential/credential.go | 6 +- .../register/aws/accesskey/accesskey.go | 166 ++++++++++++++++++ .../accesskey_test.go} | 2 +- pkg/cli/cmd/credential/register/aws/aws.go | 146 ++------------- .../cmd/credential/register/aws/irsa/irsa.go | 153 ++++++++++++++++ .../credential/register/aws/irsa/irsa_test.go | 138 +++++++++++++++ pkg/cli/cmd/credential/register/register.go | 8 +- 9 files changed, 483 insertions(+), 140 deletions(-) create mode 100644 pkg/cli/cmd/credential/register/aws/accesskey/accesskey.go rename pkg/cli/cmd/credential/register/aws/{aws_test.go => accesskey/accesskey_test.go} (99%) create mode 100644 pkg/cli/cmd/credential/register/aws/irsa/irsa.go create mode 100644 pkg/cli/cmd/credential/register/aws/irsa/irsa_test.go diff --git a/.github/workflows/functional-test.yaml b/.github/workflows/functional-test.yaml index bcf12e2b91..f3123a506a 100644 --- a/.github/workflows/functional-test.yaml +++ b/.github/workflows/functional-test.yaml @@ -527,7 +527,7 @@ jobs: echo "*** Configuring AWS provider ***" rad env update kind-radius --aws-region ${{ env.AWS_REGION }} --aws-account-id ${{ secrets.FUNCTEST_AWS_ACCOUNT_ID }} - rad credential register aws \ + rad credential register aws access-key \ --access-key-id ${{ secrets.FUNCTEST_AWS_ACCESS_KEY_ID }} --secret-access-key ${{ secrets.FUNCTEST_AWS_SECRET_ACCESS_KEY }} - uses: marocchino/sticky-pull-request-comment@v2 if: failure() && env.PR_NUMBER != '' diff --git a/.github/workflows/long-running-azure.yaml b/.github/workflows/long-running-azure.yaml index b1f242ce30..eb52846ef3 100644 --- a/.github/workflows/long-running-azure.yaml +++ b/.github/workflows/long-running-azure.yaml @@ -429,7 +429,7 @@ jobs: echo "*** Configuring AWS provider ***" rad env update ${{ env.RADIUS_TEST_ENVIRONMENT_NAME }} --aws-region ${{ env.AWS_REGION }} --aws-account-id ${{ secrets.FUNCTEST_AWS_ACCOUNT_ID }} - rad credential register aws \ + rad credential register aws access-key \ --access-key-id ${{ secrets.FUNCTEST_AWS_ACCESS_KEY_ID }} --secret-access-key ${{ secrets.FUNCTEST_AWS_SECRET_ACCESS_KEY }} - name: Log radius installation status (failure) if: failure() diff --git a/pkg/cli/cmd/credential/credential.go b/pkg/cli/cmd/credential/credential.go index a019e536cb..f8f40e4bc7 100644 --- a/pkg/cli/cmd/credential/credential.go +++ b/pkg/cli/cmd/credential/credential.go @@ -45,8 +45,10 @@ rad credential list rad credential register azure sp --client-id --client-secret --tenant-id # Register (Add or Update) cloud provider credential for Azure with workload identity authentication rad credential register azure wi --client-id --tenant-id -# Register (Add or Update) cloud provider credential for AWS with IAM authentication -rad credential register aws --access-key-id --secret-access-key +# Register (Add or update) cloud provider credential for AWS with access key authentication. +rad credential register aws access-key --access-key-id --secret-access-key +# Register (Add or update) cloud provider credential for AWS with IRSA. +rad credential register aws irsa --iam-role # Show cloud provider credential details for Azure rad credential show azure diff --git a/pkg/cli/cmd/credential/register/aws/accesskey/accesskey.go b/pkg/cli/cmd/credential/register/aws/accesskey/accesskey.go new file mode 100644 index 0000000000..e4385525ff --- /dev/null +++ b/pkg/cli/cmd/credential/register/aws/accesskey/accesskey.go @@ -0,0 +1,166 @@ +/* +Copyright 2023 The Radius Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package accesskey + +import ( + "context" + + v1 "github.com/radius-project/radius/pkg/armrpc/api/v1" + "github.com/radius-project/radius/pkg/cli" + "github.com/radius-project/radius/pkg/cli/clierrors" + "github.com/radius-project/radius/pkg/cli/cmd/commonflags" + "github.com/radius-project/radius/pkg/cli/cmd/credential/common" + "github.com/radius-project/radius/pkg/cli/connections" + cli_credential "github.com/radius-project/radius/pkg/cli/credential" + "github.com/radius-project/radius/pkg/cli/framework" + "github.com/radius-project/radius/pkg/cli/output" + "github.com/radius-project/radius/pkg/cli/workspaces" + "github.com/radius-project/radius/pkg/to" + ucp "github.com/radius-project/radius/pkg/ucp/api/v20231001preview" + "github.com/spf13/cobra" +) + +func NewCommand(factory framework.Factory) (*cobra.Command, framework.Runner) { + runner := NewRunner(factory) + + cmd := &cobra.Command{ + Use: "access-key", + Short: "Register (Add or update) AWS cloud provider credential for a Radius installation.", + Long: `Register (Add or update) AWS cloud provider credential for a Radius installation.. + +This command is intended for scripting or advanced use-cases. See 'rad init' for a user-friendly way +to configure these settings. + +Radius will use the provided IAM credential for all interactions with AWS. +` + common.LongDescriptionBlurb, + Example: ` +# Register (Add or update) cloud provider credential for AWS with IAM authentication +rad credential register aws access-key --access-key-id --secret-access-key +`, + Args: cobra.ExactArgs(0), + RunE: framework.RunCommand(runner), + } + + commonflags.AddOutputFlag(cmd) + commonflags.AddWorkspaceFlag(cmd) + + cmd.Flags().String("access-key-id", "", "The AWS IAM access key id.") + _ = cmd.MarkFlagRequired("access-key-id") + + cmd.Flags().String("secret-access-key", "", "The AWS IAM secret access key.") + _ = cmd.MarkFlagRequired("secret-access-key") + + return cmd, runner +} + +// Runner is the runner implementation for the `rad credential register aws` command. +type Runner struct { + ConfigHolder *framework.ConfigHolder + ConnectionFactory connections.Factory + Output output.Interface + Format string + Workspace *workspaces.Workspace + + AccessKeyID string + SecretAccessKey string + KubeContext string +} + +// NewRunner creates a new instance of the `rad credential register aws` runner. +func NewRunner(factory framework.Factory) *Runner { + return &Runner{ + ConfigHolder: factory.GetConfigHolder(), + ConnectionFactory: factory.GetConnectionFactory(), + Output: factory.GetOutput(), + } +} + +// Validate runs validation for the `rad credential register aws` command. +// + +// Validate() checks if the required workspace, output format, access key ID and secret access key are present, and if not, returns an error. +func (r *Runner) Validate(cmd *cobra.Command, args []string) error { + workspace, err := cli.RequireWorkspace(cmd, r.ConfigHolder.Config, r.ConfigHolder.DirectoryConfig) + if err != nil { + return err + } + r.Workspace = workspace + + format, err := cli.RequireOutput(cmd) + if err != nil { + return err + } + r.Format = format + + accessKeyID, err := cmd.Flags().GetString("access-key-id") + if err != nil { + return err + } + secretAccessKey, err := cmd.Flags().GetString("secret-access-key") + if err != nil { + return err + } + r.AccessKeyID = accessKeyID + r.SecretAccessKey = secretAccessKey + + if r.AccessKeyID == "" { + return clierrors.Message("Access Key id %q cannot be empty.", r.AccessKeyID) + } + if r.SecretAccessKey == "" { + return clierrors.Message("Secret Access Key %q cannot be empty.", r.SecretAccessKey) + } + + kubeContext, ok := r.Workspace.KubernetesContext() + if !ok { + return clierrors.Message("A Kubernetes connection is required.") + } + r.KubeContext = kubeContext + return nil +} + +// Run runs the `rad credential register aws access-key` command. +// + +// Run() registers an AWS credential with the given context and workspace, and returns an error if unsuccessful. +func (r *Runner) Run(ctx context.Context) error { + + r.Output.LogInfo("Registering credential for %q cloud provider in Radius installation %q...", "aws", r.Workspace.FmtConnection()) + client, err := r.ConnectionFactory.CreateCredentialManagementClient(ctx, *r.Workspace) + if err != nil { + return err + } + credential := ucp.AwsCredentialResource{ + Location: to.Ptr(v1.LocationGlobal), + Type: to.Ptr(cli_credential.AWSCredential), + Properties: &ucp.AwsAccessKeyCredentialProperties{ + Storage: &ucp.CredentialStorageProperties{ + Kind: to.Ptr(ucp.CredentialStorageKindInternal), + }, + AccessKeyID: &r.AccessKeyID, + SecretAccessKey: &r.SecretAccessKey, + }, + } + + err = client.PutAWS(ctx, credential) + if err != nil { + return err + } + + r.Output.LogInfo("Successfully registered credential for %q cloud provider. Tokens may take up to 30 seconds to refresh.", "aws") + + return nil +} diff --git a/pkg/cli/cmd/credential/register/aws/aws_test.go b/pkg/cli/cmd/credential/register/aws/accesskey/accesskey_test.go similarity index 99% rename from pkg/cli/cmd/credential/register/aws/aws_test.go rename to pkg/cli/cmd/credential/register/aws/accesskey/accesskey_test.go index 2455a3c0bf..da48a28084 100644 --- a/pkg/cli/cmd/credential/register/aws/aws_test.go +++ b/pkg/cli/cmd/credential/register/aws/accesskey/accesskey_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package aws +package accesskey import ( "context" diff --git a/pkg/cli/cmd/credential/register/aws/aws.go b/pkg/cli/cmd/credential/register/aws/aws.go index 244ab9fb67..6bbb5ade26 100644 --- a/pkg/cli/cmd/credential/register/aws/aws.go +++ b/pkg/cli/cmd/credential/register/aws/aws.go @@ -17,20 +17,10 @@ limitations under the License. package aws import ( - "context" - - v1 "github.com/radius-project/radius/pkg/armrpc/api/v1" - "github.com/radius-project/radius/pkg/cli" - "github.com/radius-project/radius/pkg/cli/clierrors" - "github.com/radius-project/radius/pkg/cli/cmd/commonflags" "github.com/radius-project/radius/pkg/cli/cmd/credential/common" - "github.com/radius-project/radius/pkg/cli/connections" - cli_credential "github.com/radius-project/radius/pkg/cli/credential" + "github.com/radius-project/radius/pkg/cli/cmd/credential/register/aws/accesskey" + "github.com/radius-project/radius/pkg/cli/cmd/credential/register/aws/irsa" "github.com/radius-project/radius/pkg/cli/framework" - "github.com/radius-project/radius/pkg/cli/output" - "github.com/radius-project/radius/pkg/cli/workspaces" - "github.com/radius-project/radius/pkg/to" - ucp "github.com/radius-project/radius/pkg/ucp/api/v20231001preview" "github.com/spf13/cobra" ) @@ -39,133 +29,25 @@ import ( // NewCommand creates a new cobra command for registering AWS cloud provider credentials with IAM authentication, and // returns a Runner to execute the command. -func NewCommand(factory framework.Factory) (*cobra.Command, framework.Runner) { - runner := NewRunner(factory) - +func NewCommand(factory framework.Factory) *cobra.Command { + // This command is not runnable, and thus has no runner. cmd := &cobra.Command{ Use: "aws", Short: "Register (Add or update) AWS cloud provider credential for a Radius installation.", - Long: `Register (Add or update) AWS cloud provider credential for a Radius installation.. - -This command is intended for scripting or advanced use-cases. See 'rad init' for a user-friendly way -to configure these settings. - -Radius will use the provided IAM credential for all interactions with AWS. -` + common.LongDescriptionBlurb, + Long: "Register (Add or update) AWS cloud provider credential for a Radius installation.." + common.LongDescriptionBlurb, Example: ` -# Register (Add or update) cloud provider credential for AWS with IAM authentication -rad credential register aws --access-key-id --secret-access-key +# Register (Add or update) cloud provider credential for AWS with access key authentication. +rad credential register aws access-key --access-key-id --secret-access-key +# Register (Add or update) cloud provider credential for AWS with IRSA. +rad credential register aws irsa --iam-role `, - Args: cobra.ExactArgs(0), - RunE: framework.RunCommand(runner), - } - - commonflags.AddOutputFlag(cmd) - commonflags.AddWorkspaceFlag(cmd) - - cmd.Flags().String("access-key-id", "", "The AWS IAM access key id.") - _ = cmd.MarkFlagRequired("access-key-id") - - cmd.Flags().String("secret-access-key", "", "The AWS IAM secret access key.") - _ = cmd.MarkFlagRequired("secret-access-key") - - return cmd, runner -} - -// Runner is the runner implementation for the `rad credential register aws` command. -type Runner struct { - ConfigHolder *framework.ConfigHolder - ConnectionFactory connections.Factory - Output output.Interface - Format string - Workspace *workspaces.Workspace - - AccessKeyID string - SecretAccessKey string - KubeContext string -} - -// NewRunner creates a new instance of the `rad credential register aws` runner. -func NewRunner(factory framework.Factory) *Runner { - return &Runner{ - ConfigHolder: factory.GetConfigHolder(), - ConnectionFactory: factory.GetConnectionFactory(), - Output: factory.GetOutput(), - } -} - -// Validate runs validation for the `rad credential register aws` command. -// - -// Validate() checks if the required workspace, output format, access key ID and secret access key are present, and if not, returns an error. -func (r *Runner) Validate(cmd *cobra.Command, args []string) error { - workspace, err := cli.RequireWorkspace(cmd, r.ConfigHolder.Config, r.ConfigHolder.DirectoryConfig) - if err != nil { - return err } - r.Workspace = workspace - format, err := cli.RequireOutput(cmd) - if err != nil { - return err - } - r.Format = format - - accessKeyID, err := cmd.Flags().GetString("access-key-id") - if err != nil { - return err - } - secretAccessKey, err := cmd.Flags().GetString("secret-access-key") - if err != nil { - return err - } - r.AccessKeyID = accessKeyID - r.SecretAccessKey = secretAccessKey - - if r.AccessKeyID == "" { - return clierrors.Message("Access Key id %q cannot be empty.", r.AccessKeyID) - } - if r.SecretAccessKey == "" { - return clierrors.Message("Secret Access Key %q cannot be empty.", r.SecretAccessKey) - } - - kubeContext, ok := r.Workspace.KubernetesContext() - if !ok { - return clierrors.Message("A Kubernetes connection is required.") - } - r.KubeContext = kubeContext - return nil -} - -// Run runs the `rad credential register aws` command. -// - -// Run() registers an AWS credential with the given context and workspace, and returns an error if unsuccessful. -func (r *Runner) Run(ctx context.Context) error { - - r.Output.LogInfo("Registering credential for %q cloud provider in Radius installation %q...", "aws", r.Workspace.FmtConnection()) - client, err := r.ConnectionFactory.CreateCredentialManagementClient(ctx, *r.Workspace) - if err != nil { - return err - } - credential := ucp.AwsCredentialResource{ - Location: to.Ptr(v1.LocationGlobal), - Type: to.Ptr(cli_credential.AWSCredential), - Properties: &ucp.AwsAccessKeyCredentialProperties{ - Storage: &ucp.CredentialStorageProperties{ - Kind: to.Ptr(ucp.CredentialStorageKindInternal), - }, - AccessKeyID: &r.AccessKeyID, - SecretAccessKey: &r.SecretAccessKey, - }, - } - - err = client.PutAWS(ctx, credential) - if err != nil { - return err - } + accesskey, _ := accesskey.NewCommand(factory) + cmd.AddCommand(accesskey) - r.Output.LogInfo("Successfully registered credential for %q cloud provider. Tokens may take up to 30 seconds to refresh.", "aws") + irsa, _ := irsa.NewCommand(factory) + cmd.AddCommand(irsa) - return nil + return cmd } diff --git a/pkg/cli/cmd/credential/register/aws/irsa/irsa.go b/pkg/cli/cmd/credential/register/aws/irsa/irsa.go new file mode 100644 index 0000000000..00bd06523e --- /dev/null +++ b/pkg/cli/cmd/credential/register/aws/irsa/irsa.go @@ -0,0 +1,153 @@ +/* +Copyright 2023 The Radius Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package irsa + +import ( + "context" + + v1 "github.com/radius-project/radius/pkg/armrpc/api/v1" + "github.com/radius-project/radius/pkg/cli" + "github.com/radius-project/radius/pkg/cli/clierrors" + "github.com/radius-project/radius/pkg/cli/cmd/commonflags" + "github.com/radius-project/radius/pkg/cli/cmd/credential/common" + "github.com/radius-project/radius/pkg/cli/connections" + cli_credential "github.com/radius-project/radius/pkg/cli/credential" + "github.com/radius-project/radius/pkg/cli/framework" + "github.com/radius-project/radius/pkg/cli/output" + "github.com/radius-project/radius/pkg/cli/workspaces" + "github.com/radius-project/radius/pkg/to" + ucp "github.com/radius-project/radius/pkg/ucp/api/v20231001preview" + "github.com/spf13/cobra" +) + +func NewCommand(factory framework.Factory) (*cobra.Command, framework.Runner) { + runner := NewRunner(factory) + + cmd := &cobra.Command{ + Use: "irsa", + Short: "Register (Add or update) AWS cloud provider credential for a Radius installation.", + Long: `Register (Add or update) AWS cloud provider credential for a Radius installation.. + +This command is intended for scripting or advanced use-cases. See 'rad init' for a user-friendly way +to configure these settings. + +Radius will use the provided IAM credential for all interactions with AWS. +` + common.LongDescriptionBlurb, + Example: ` +# Register (Add or update) cloud provider credential for AWS with IAM authentication +rad credential register aws irsa --iam-role +`, + Args: cobra.ExactArgs(0), + RunE: framework.RunCommand(runner), + } + + commonflags.AddOutputFlag(cmd) + commonflags.AddWorkspaceFlag(cmd) + + cmd.Flags().String("iam-role", "", "RoleARN for AWS IRSA identity.") + _ = cmd.MarkFlagRequired("iam-role") + + return cmd, runner +} + +// Runner is the runner implementation for the `rad credential register aws` command. +type Runner struct { + ConfigHolder *framework.ConfigHolder + ConnectionFactory connections.Factory + Output output.Interface + Format string + Workspace *workspaces.Workspace + + IAMRole string + KubeContext string +} + +// NewRunner creates a new instance of the `rad credential register aws` runner. +func NewRunner(factory framework.Factory) *Runner { + return &Runner{ + ConfigHolder: factory.GetConfigHolder(), + ConnectionFactory: factory.GetConnectionFactory(), + Output: factory.GetOutput(), + } +} + +// Validate runs validation for the `rad credential register aws` command. +// + +// Validate() checks if the required workspace, output format, access key ID and secret access key are present, and if not, returns an error. +func (r *Runner) Validate(cmd *cobra.Command, args []string) error { + workspace, err := cli.RequireWorkspace(cmd, r.ConfigHolder.Config, r.ConfigHolder.DirectoryConfig) + if err != nil { + return err + } + r.Workspace = workspace + + format, err := cli.RequireOutput(cmd) + if err != nil { + return err + } + r.Format = format + + iamRole, err := cmd.Flags().GetString("iam-role") + if err != nil { + return err + } + + r.IAMRole = iamRole + if r.IAMRole == "" { + return clierrors.Message("IAM Role %q cannot be empty.", r.IAMRole) + } + + kubeContext, ok := r.Workspace.KubernetesContext() + if !ok { + return clierrors.Message("A Kubernetes connection is required.") + } + r.KubeContext = kubeContext + return nil +} + +// Run runs the `rad credential register aws irsa` command. +// + +// Run() registers an AWS credential with the given context and workspace, and returns an error if unsuccessful. +func (r *Runner) Run(ctx context.Context) error { + + r.Output.LogInfo("Registering credential for %q cloud provider in Radius installation %q...", "aws", r.Workspace.FmtConnection()) + client, err := r.ConnectionFactory.CreateCredentialManagementClient(ctx, *r.Workspace) + if err != nil { + return err + } + credential := ucp.AwsCredentialResource{ + Location: to.Ptr(v1.LocationGlobal), + Type: to.Ptr(cli_credential.AWSCredential), + Properties: &ucp.AwsIRSACredentialProperties{ + Storage: &ucp.CredentialStorageProperties{ + Kind: to.Ptr(ucp.CredentialStorageKindInternal), + }, + RoleARN: &r.IAMRole, + }, + } + + err = client.PutAWS(ctx, credential) + if err != nil { + return err + } + + r.Output.LogInfo("Successfully registered credential for %q cloud provider. Tokens may take up to 30 seconds to refresh.", "aws") + + return nil +} diff --git a/pkg/cli/cmd/credential/register/aws/irsa/irsa_test.go b/pkg/cli/cmd/credential/register/aws/irsa/irsa_test.go new file mode 100644 index 0000000000..e3881101c4 --- /dev/null +++ b/pkg/cli/cmd/credential/register/aws/irsa/irsa_test.go @@ -0,0 +1,138 @@ +/* +Copyright 2023 The Radius Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package irsa + +import ( + "context" + "testing" + + "go.uber.org/mock/gomock" + + v1 "github.com/radius-project/radius/pkg/armrpc/api/v1" + "github.com/radius-project/radius/pkg/cli/connections" + cli_credential "github.com/radius-project/radius/pkg/cli/credential" + "github.com/radius-project/radius/pkg/cli/framework" + "github.com/radius-project/radius/pkg/cli/output" + "github.com/radius-project/radius/pkg/cli/workspaces" + "github.com/radius-project/radius/pkg/to" + ucp "github.com/radius-project/radius/pkg/ucp/api/v20231001preview" + "github.com/radius-project/radius/test/radcli" + "github.com/stretchr/testify/require" +) + +const ( + roleARN = "role-arn" +) + +func Test_CommandValidation(t *testing.T) { + radcli.SharedCommandValidation(t, NewCommand) +} + +func Test_Validate(t *testing.T) { + configWithWorkspace := radcli.LoadConfigWithWorkspace(t) + testcases := []radcli.ValidateInput{ + { + Name: "Valid AWS command", + Input: []string{ + "--iam-role", roleARN, + }, + ExpectedValid: true, + ConfigHolder: framework.ConfigHolder{Config: configWithWorkspace}, + }, + { + Name: "AWS command with fallback workspace", + Input: []string{ + "--iam-role", roleARN, + }, + ExpectedValid: true, + ConfigHolder: framework.ConfigHolder{Config: radcli.LoadEmptyConfig(t)}, + }, + { + Name: "AWS command with too many positional args", + Input: []string{ + "letsgoooooo", + "--iam-role", roleARN, + }, + ExpectedValid: false, + ConfigHolder: framework.ConfigHolder{Config: configWithWorkspace}, + }, + { + Name: "AWS command without role ARN", + Input: []string{ + "--iam-role", "", + }, + ExpectedValid: false, + ConfigHolder: framework.ConfigHolder{Config: configWithWorkspace}, + }, + } + radcli.SharedValidateValidation(t, NewCommand, testcases) +} + +func Test_Run(t *testing.T) { + t.Run("Create aws provider", func(t *testing.T) { + t.Run("Success", func(t *testing.T) { + ctrl := gomock.NewController(t) + expectedPut := ucp.AwsCredentialResource{ + Location: to.Ptr(v1.LocationGlobal), + Type: to.Ptr(cli_credential.AWSCredential), + Properties: &ucp.AwsIRSACredentialProperties{ + Storage: &ucp.CredentialStorageProperties{ + Kind: to.Ptr(ucp.CredentialStorageKindInternal), + }, + RoleARN: to.Ptr(roleARN), + }, + } + + client := cli_credential.NewMockCredentialManagementClient(ctrl) + client.EXPECT(). + PutAWS(gomock.Any(), expectedPut). + Return(nil). + Times(1) + + outputSink := &output.MockOutput{} + + runner := &Runner{ + ConnectionFactory: &connections.MockFactory{CredentialManagementClient: client}, + Output: outputSink, + Workspace: &workspaces.Workspace{ + Connection: map[string]any{ + "kind": workspaces.KindKubernetes, + "context": "my-context", + }, + Source: workspaces.SourceUserConfig, + }, + Format: "table", + IAMRole: roleARN, + KubeContext: "my-context", + } + err := runner.Run(context.Background()) + require.NoError(t, err) + + expected := []any{ + output.LogOutput{ + Format: "Registering credential for %q cloud provider in Radius installation %q...", + Params: []any{"aws", "Kubernetes (context=my-context)"}, + }, + output.LogOutput{ + Format: "Successfully registered credential for %q cloud provider. Tokens may take up to 30 seconds to refresh.", + Params: []any{"aws"}, + }, + } + require.Equal(t, expected, outputSink.Writes) + }) + }) +} diff --git a/pkg/cli/cmd/credential/register/register.go b/pkg/cli/cmd/credential/register/register.go index b8b340ffe7..72d41b6e30 100644 --- a/pkg/cli/cmd/credential/register/register.go +++ b/pkg/cli/cmd/credential/register/register.go @@ -39,15 +39,17 @@ func NewCommand(factory framework.Factory) *cobra.Command { rad credential register azure sp --client-id --client-secret --tenant-id # Register (Add or update) cloud provider credential for Azure with workload identity authentication rad credential register azure wi --client-id --tenant-id -# Register (Add or Update) cloud provider credential for AWS with IAM authentication -rad credential register aws --access-key-id --secret-access-key +# Register (Add or update) cloud provider credential for AWS with access key authentication. +rad credential register aws access-key --access-key-id --secret-access-key +# Register (Add or update) cloud provider credential for AWS with IRSA. +rad credential register aws irsa --iam-role `, } azure := credential_register_azure.NewCommand(factory) cmd.AddCommand(azure) - aws, _ := credential_register_aws.NewCommand(factory) + aws := credential_register_aws.NewCommand(factory) cmd.AddCommand(aws) return cmd From 6c60fb1c19e24a84e6af88de3190caf2b87523c1 Mon Sep 17 00:00:00 2001 From: Vishwanath Hiremath Date: Thu, 25 Jul 2024 16:25:01 -0700 Subject: [PATCH 2/3] addressing comments Signed-off-by: Vishwanath Hiremath --- pkg/cli/cmd/credential/credential.go | 2 +- pkg/cli/cmd/credential/register/aws/accesskey/accesskey.go | 3 +-- pkg/cli/cmd/credential/register/register.go | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/pkg/cli/cmd/credential/credential.go b/pkg/cli/cmd/credential/credential.go index f8f40e4bc7..db10a4efec 100644 --- a/pkg/cli/cmd/credential/credential.go +++ b/pkg/cli/cmd/credential/credential.go @@ -47,7 +47,7 @@ rad credential register azure sp --client-id --client-secret --tenant-id # Register (Add or update) cloud provider credential for AWS with access key authentication. rad credential register aws access-key --access-key-id --secret-access-key -# Register (Add or update) cloud provider credential for AWS with IRSA. +# Register (Add or update) cloud provider credential for AWS with IRSA (IAM Roles for Service Accounts). rad credential register aws irsa --iam-role # Show cloud provider credential details for Azure diff --git a/pkg/cli/cmd/credential/register/aws/accesskey/accesskey.go b/pkg/cli/cmd/credential/register/aws/accesskey/accesskey.go index e4385525ff..29ce5ab6b7 100644 --- a/pkg/cli/cmd/credential/register/aws/accesskey/accesskey.go +++ b/pkg/cli/cmd/credential/register/aws/accesskey/accesskey.go @@ -135,9 +135,8 @@ func (r *Runner) Validate(cmd *cobra.Command, args []string) error { // Run runs the `rad credential register aws access-key` command. // -// Run() registers an AWS credential with the given context and workspace, and returns an error if unsuccessful. +// Run registers an AWS credential with the given context and workspace, and returns an error if unsuccessful. func (r *Runner) Run(ctx context.Context) error { - r.Output.LogInfo("Registering credential for %q cloud provider in Radius installation %q...", "aws", r.Workspace.FmtConnection()) client, err := r.ConnectionFactory.CreateCredentialManagementClient(ctx, *r.Workspace) if err != nil { diff --git a/pkg/cli/cmd/credential/register/register.go b/pkg/cli/cmd/credential/register/register.go index 72d41b6e30..36ec9fcb98 100644 --- a/pkg/cli/cmd/credential/register/register.go +++ b/pkg/cli/cmd/credential/register/register.go @@ -41,8 +41,8 @@ rad credential register azure sp --client-id --client-secret --tenant-id # Register (Add or update) cloud provider credential for AWS with access key authentication. rad credential register aws access-key --access-key-id --secret-access-key -# Register (Add or update) cloud provider credential for AWS with IRSA. -rad credential register aws irsa --iam-role +# Register (Add or update) cloud provider credential for AWS with IRSA (IAM Roles for service Accounts). +rad credential register aws irsa --iam-role `, } From 2d4dcc9a03b4e6ea3024f2ebd8409acd29a55730 Mon Sep 17 00:00:00 2001 From: Vishwanath Hiremath Date: Fri, 26 Jul 2024 13:22:31 -0700 Subject: [PATCH 3/3] addressing comments Signed-off-by: Vishwanath Hiremath --- pkg/cli/cmd/credential/register/aws/accesskey/accesskey.go | 1 + pkg/cli/cmd/credential/register/aws/irsa/irsa.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/cli/cmd/credential/register/aws/accesskey/accesskey.go b/pkg/cli/cmd/credential/register/aws/accesskey/accesskey.go index 29ce5ab6b7..e3df1f26bd 100644 --- a/pkg/cli/cmd/credential/register/aws/accesskey/accesskey.go +++ b/pkg/cli/cmd/credential/register/aws/accesskey/accesskey.go @@ -142,6 +142,7 @@ func (r *Runner) Run(ctx context.Context) error { if err != nil { return err } + credential := ucp.AwsCredentialResource{ Location: to.Ptr(v1.LocationGlobal), Type: to.Ptr(cli_credential.AWSCredential), diff --git a/pkg/cli/cmd/credential/register/aws/irsa/irsa.go b/pkg/cli/cmd/credential/register/aws/irsa/irsa.go index 00bd06523e..184a6e6a0e 100644 --- a/pkg/cli/cmd/credential/register/aws/irsa/irsa.go +++ b/pkg/cli/cmd/credential/register/aws/irsa/irsa.go @@ -48,7 +48,7 @@ to configure these settings. Radius will use the provided IAM credential for all interactions with AWS. ` + common.LongDescriptionBlurb, Example: ` -# Register (Add or update) cloud provider credential for AWS with IAM authentication +# Register (Add or update) cloud provider credential for AWS with IRSA (IAM roles for service accounts) authentication rad credential register aws irsa --iam-role `, Args: cobra.ExactArgs(0),