Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"rad credential register aws" command changes for irsa #7750

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
165 changes: 165 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,165 @@
/*
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)
Comment on lines +121 to +124
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to print the empty AccessKey and AccessKeyID here? I mean why do we need %q here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the exisitng code for access-key type. we moved it to different file

}

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{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: extra line before this

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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we have access key credential configured, and run rad credential register, then we would just overwrite it, since we store exactly one credential which is "default" correct?

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
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to add any other tests here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we havent changed anything for the access-key type. the tests were copied from the previously added tests.

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)
vishwahiremat marked this conversation as resolved.
Show resolved Hide resolved
cmd.AddCommand(irsa)

return nil
return cmd
}
Loading