Skip to content

Commit

Permalink
"rad credential register aws" command changes for irsa (#7750)
Browse files Browse the repository at this point in the history
# Description

Updating the existing `rad credential register aws command`:

`rad credential register aws --access-key-id <access-key-id>
--secret-access-key <secret-access-key>` should be replaced with `rad
credential register aws access-key --access-key-id <access-key-id>
--secret-access-key <secret-access-key>`

`rad credential register aws irsa --iam-role <roleARN>` should be
supported.

## Type of change

<!--

Please select **one** of the following options that describes your
change and delete the others. Clearly identifying the type of change you
are making will help us review your PR faster, and is used in authoring
release notes.

If you are making a bug fix or functionality change to Radius and do not
have an associated issue link please create one now.

-->

- This pull request fixes a bug in Radius and has an approved issue
(issue link required).
- This pull request adds or changes features of Radius and has an
approved issue (issue link required).
- This pull request is a minor refactor, code cleanup, test improvement,
or other maintenance task and doesn't change the functionality of Radius
(issue link optional).

<!--

Please update the following to link the associated issue. This is
required for some kinds of changes (see above).

-->

Fixes: #issue_number

---------

Signed-off-by: Vishwanath Hiremath <[email protected]>
  • Loading branch information
vishwahiremat authored Jul 30, 2024
1 parent 81b89fd commit 9b564db
Show file tree
Hide file tree
Showing 9 changed files with 483 additions and 140 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/functional-test-cloud.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/long-running-azure.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
6 changes: 4 additions & 2 deletions pkg/cli/cmd/credential/credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ rad credential list
rad credential register azure sp --client-id <client id> --client-secret <client secret> --tenant-id <tenant id>
# Register (Add or Update) cloud provider credential for Azure with workload identity authentication
rad credential register azure wi --client-id <client id> --tenant-id <tenant id>
# Register (Add or Update) cloud provider credential for AWS with IAM authentication
rad credential register aws --access-key-id <access-key-id> --secret-access-key <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 <access-key-id> --secret-access-key <secret-access-key>
# Register (Add or update) cloud provider credential for AWS with IRSA (IAM Roles for Service Accounts).
rad credential register aws irsa --iam-role <roleARN>
# Show cloud provider credential details for Azure
rad credential show azure
Expand Down
166 changes: 166 additions & 0 deletions pkg/cli/cmd/credential/register/aws/accesskey/accesskey.go
Original file line number Diff line number Diff line change
@@ -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 <access-key-id> --secret-access-key <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
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package aws
package accesskey

import (
"context"
Expand Down
146 changes: 14 additions & 132 deletions pkg/cli/cmd/credential/register/aws/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand All @@ -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 <access-key-id> --secret-access-key <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 <access-key-id> --secret-access-key <secret-access-key>
# Register (Add or update) cloud provider credential for AWS with IRSA.
rad credential register aws irsa --iam-role <roleARN>
`,
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
}
Loading

0 comments on commit 9b564db

Please sign in to comment.