Skip to content

Commit

Permalink
feat: adding option to specify an aws profile to use by the argocd-se…
Browse files Browse the repository at this point in the history
…rver when adding a EKS cluster (argoproj#16767)

useful for argocd-servers which are not running in AWS and want to add multiple EKS clusters using
separate keys instead of assuming roles

argoproj#16766

Signed-off-by: Isaac Gaskin <isaac.gaskin@circle.com>
Co-authored-by: Soumya Ghosh Dastidar <44349253+gdsoumya@users.noreply.github.com>
  • Loading branch information
2 people authored and clement-heetch committed Feb 12, 2024
1 parent 2fada95 commit d336b7a
Show file tree
Hide file tree
Showing 13 changed files with 770 additions and 698 deletions.
4 changes: 4 additions & 0 deletions assets/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -5664,6 +5664,10 @@
"type": "string",
"title": "ClusterName contains AWS cluster name"
},
"profile": {
"description": "Profile contains optional role ARN. If set then AWS IAM Authenticator uses the profile to perform cluster operations instead of the default AWS credential provider chain.",
"type": "string"
},
"roleARN": {
"description": "RoleARN contains optional role ARN. If set then AWS IAM Authenticator assume a role to perform cluster operations instead of the default AWS credential provider chain.",
"type": "string"
Expand Down
16 changes: 10 additions & 6 deletions cmd/argocd-k8s-auth/commands/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,14 @@ func newAWSCommand() *cobra.Command {
var (
clusterName string
roleARN string
profile string
)
var command = &cobra.Command{
Use: "aws",
Run: func(c *cobra.Command, args []string) {
ctx := c.Context()

presignedURLString, err := getSignedRequestWithRetry(ctx, time.Minute, 5*time.Second, clusterName, roleARN, getSignedRequest)
presignedURLString, err := getSignedRequestWithRetry(ctx, time.Minute, 5*time.Second, clusterName, roleARN, profile, getSignedRequest)
errors.CheckError(err)
token := v1Prefix + base64.RawURLEncoding.EncodeToString([]byte(presignedURLString))
// Set token expiration to 1 minute before the presigned URL expires for some cushion
Expand All @@ -53,16 +54,17 @@ func newAWSCommand() *cobra.Command {
}
command.Flags().StringVar(&clusterName, "cluster-name", "", "AWS Cluster name")
command.Flags().StringVar(&roleARN, "role-arn", "", "AWS Role ARN")
command.Flags().StringVar(&profile, "profile", "", "AWS Profile")
return command
}

type getSignedRequestFunc func(clusterName, roleARN string) (string, error)
type getSignedRequestFunc func(clusterName, roleARN string, profile string) (string, error)

func getSignedRequestWithRetry(ctx context.Context, timeout, interval time.Duration, clusterName, roleARN string, fn getSignedRequestFunc) (string, error) {
func getSignedRequestWithRetry(ctx context.Context, timeout, interval time.Duration, clusterName, roleARN string, profile string, fn getSignedRequestFunc) (string, error) {
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
for {
signed, err := fn(clusterName, roleARN)
signed, err := fn(clusterName, roleARN, profile)
if err == nil {
return signed, nil
}
Expand All @@ -74,8 +76,10 @@ func getSignedRequestWithRetry(ctx context.Context, timeout, interval time.Durat
}
}

func getSignedRequest(clusterName, roleARN string) (string, error) {
sess, err := session.NewSession()
func getSignedRequest(clusterName, roleARN string, profile string) (string, error) {
sess, err := session.NewSessionWithOptions(session.Options{
Profile: profile,
})
if err != nil {
return "", fmt.Errorf("error creating new AWS session: %s", err)
}
Expand Down
8 changes: 4 additions & 4 deletions cmd/argocd-k8s-auth/commands/aws_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func TestGetSignedRequestWithRetry(t *testing.T) {
}

// when
signed, err := getSignedRequestWithRetry(ctx, time.Second, time.Millisecond, "cluster-name", "", mock.getSignedRequestMock)
signed, err := getSignedRequestWithRetry(ctx, time.Second, time.Millisecond, "cluster-name", "", "", mock.getSignedRequestMock)

// then
assert.NoError(t, err)
Expand All @@ -41,7 +41,7 @@ func TestGetSignedRequestWithRetry(t *testing.T) {
}

// when
signed, err := getSignedRequestWithRetry(ctx, time.Second, time.Millisecond, "cluster-name", "", mock.getSignedRequestMock)
signed, err := getSignedRequestWithRetry(ctx, time.Second, time.Millisecond, "cluster-name", "", "", mock.getSignedRequestMock)

// then
assert.NoError(t, err)
Expand All @@ -57,7 +57,7 @@ func TestGetSignedRequestWithRetry(t *testing.T) {
}

// when
signed, err := getSignedRequestWithRetry(ctx, time.Second, time.Millisecond, "cluster-name", "", mock.getSignedRequestMock)
signed, err := getSignedRequestWithRetry(ctx, time.Second, time.Millisecond, "cluster-name", "", "", mock.getSignedRequestMock)

// then
assert.Error(t, err)
Expand All @@ -70,7 +70,7 @@ type signedRequestMock struct {
returnFunc func(m *signedRequestMock) (string, error)
}

func (m *signedRequestMock) getSignedRequestMock(clusterName, roleARN string) (string, error) {
func (m *signedRequestMock) getSignedRequestMock(clusterName, roleARN string, profile string) (string, error) {
m.getSignedRequestCalls++
return m.returnFunc(m)
}
1 change: 1 addition & 0 deletions cmd/argocd/commands/admin/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,7 @@ func NewGenClusterConfigCommand(pathOpts *clientcmd.PathOptions) *cobra.Command
awsAuthConf = &argoappv1.AWSAuthConfig{
ClusterName: clusterOpts.AwsClusterName,
RoleARN: clusterOpts.AwsRoleArn,
Profile: clusterOpts.AwsProfile,
}
} else if clusterOpts.ExecProviderCommand != "" {
execProviderConf = &argoappv1.ExecProviderConfig{
Expand Down
1 change: 1 addition & 0 deletions cmd/argocd/commands/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clie
awsAuthConf = &argoappv1.AWSAuthConfig{
ClusterName: clusterOpts.AwsClusterName,
RoleARN: clusterOpts.AwsRoleArn,
Profile: clusterOpts.AwsProfile,
}
} else if clusterOpts.ExecProviderCommand != "" {
execProviderConf = &argoappv1.ExecProviderConfig{
Expand Down
2 changes: 2 additions & 0 deletions cmd/util/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ type ClusterOptions struct {
Upsert bool
ServiceAccount string
AwsRoleArn string
AwsProfile string
AwsClusterName string
SystemNamespace string
Namespaces []string
Expand All @@ -169,6 +170,7 @@ func AddClusterFlags(command *cobra.Command, opts *ClusterOptions) {
command.Flags().BoolVar(&opts.InCluster, "in-cluster", false, "Indicates Argo CD resides inside this cluster and should connect using the internal k8s hostname (kubernetes.default.svc)")
command.Flags().StringVar(&opts.AwsClusterName, "aws-cluster-name", "", "AWS Cluster name if set then aws cli eks token command will be used to access cluster")
command.Flags().StringVar(&opts.AwsRoleArn, "aws-role-arn", "", "Optional AWS role arn. If set then AWS IAM Authenticator assumes a role to perform cluster operations instead of the default AWS credential provider chain.")
command.Flags().StringVar(&opts.AwsProfile, "aws-profile", "", "Optional AWS profile. If set then AWS IAM Authenticator uses this profile to perform cluster operations instead of the default AWS credential provider chain.")
command.Flags().StringArrayVar(&opts.Namespaces, "namespace", nil, "List of namespaces which are allowed to manage")
command.Flags().BoolVar(&opts.ClusterResources, "cluster-resources", false, "Indicates if cluster level resources should be managed. The setting is used only if list of managed namespaces is not empty.")
command.Flags().StringVar(&opts.Name, "name", "", "Overwrite the cluster name")
Expand Down
1 change: 1 addition & 0 deletions docs/operator-manual/declarative-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,7 @@ bearerToken: string
awsAuthConfig:
clusterName: string
roleARN: string
profile: string
# Configure external command to supply client credentials
# See https://godoc.org/k8s.io/client-go/tools/clientcmd/api#ExecConfig
execProviderConfig:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ argocd admin cluster generate-spec CONTEXT [flags]
```
--annotation stringArray Set metadata annotations (e.g. --annotation key=value)
--aws-cluster-name string AWS Cluster name if set then aws cli eks token command will be used to access cluster
--aws-profile string Optional AWS profile. If set then AWS IAM Authenticator uses this profile to perform cluster operations instead of the default AWS credential provider chain.
--aws-role-arn string Optional AWS role arn. If set then AWS IAM Authenticator assumes a role to perform cluster operations instead of the default AWS credential provider chain.
--bearer-token string Authentication token that should be used to access K8S API server
--cluster-endpoint string Cluster endpoint to use. Can be one of the following: 'kubeconfig', 'kube-public', or 'internal'.
Expand Down
1 change: 1 addition & 0 deletions docs/user-guide/commands/argocd_cluster_add.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ argocd cluster add CONTEXT [flags]
```
--annotation stringArray Set metadata annotations (e.g. --annotation key=value)
--aws-cluster-name string AWS Cluster name if set then aws cli eks token command will be used to access cluster
--aws-profile string Optional AWS profile. If set then AWS IAM Authenticator uses this profile to perform cluster operations instead of the default AWS credential provider chain.
--aws-role-arn string Optional AWS role arn. If set then AWS IAM Authenticator assumes a role to perform cluster operations instead of the default AWS credential provider chain.
--cluster-endpoint string Cluster endpoint to use. Can be one of the following: 'kubeconfig', 'kube-public', or 'internal'.
--cluster-resources Indicates if cluster level resources should be managed. The setting is used only if list of managed namespaces is not empty.
Expand Down
Loading

0 comments on commit d336b7a

Please sign in to comment.