Skip to content

Commit 17ca55f

Browse files
authored
Fix order of AWS CLI credentials for all cluster commands (#1403)
1 parent 8314b5a commit 17ca55f

File tree

4 files changed

+77
-68
lines changed

4 files changed

+77
-68
lines changed

cli/cmd/cluster.go

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -141,26 +141,29 @@ var _upCmd = &cobra.Command{
141141
}
142142
}
143143

144-
awsCreds, err := awsCredentialsForCreatingCluster(_flagClusterDisallowPrompt)
144+
accessConfig, err := getNewClusterAccessConfig(_flagClusterDisallowPrompt)
145145
if err != nil {
146146
exit.Error(err)
147147
}
148148

149-
clusterConfig, err := getInstallClusterConfig(awsCreds, _flagClusterEnv, _flagClusterDisallowPrompt)
149+
awsCreds, err := awsCredentialsForManagingCluster(*accessConfig, _flagClusterDisallowPrompt)
150150
if err != nil {
151151
exit.Error(err)
152152
}
153153

154-
accessConfig := clusterConfig.ToAccessConfig()
155-
156154
awsClient, err := newAWSClient(*accessConfig.Region, awsCreds)
157155
if err != nil {
158156
exit.Error(err)
159157
}
160158

161-
cacheAWSCredentials(awsCreds, accessConfig)
159+
cacheAWSCredentials(awsCreds, *accessConfig)
160+
161+
clusterConfig, err := getInstallClusterConfig(awsCreds, *accessConfig, _flagClusterEnv, _flagClusterDisallowPrompt)
162+
if err != nil {
163+
exit.Error(err)
164+
}
162165

163-
clusterState, err := clusterstate.GetClusterState(awsClient, &accessConfig)
166+
clusterState, err := clusterstate.GetClusterState(awsClient, accessConfig)
164167
if err != nil {
165168
exit.Error(err)
166169
}
@@ -322,7 +325,7 @@ var _configureCmd = &cobra.Command{
322325
}
323326
}
324327

325-
accessConfig, err := getClusterAccessConfig(_flagClusterDisallowPrompt)
328+
accessConfig, err := getClusterAccessConfigWithCache(_flagClusterDisallowPrompt)
326329
if err != nil {
327330
exit.Error(err)
328331
}
@@ -332,13 +335,13 @@ var _configureCmd = &cobra.Command{
332335
exit.Error(err)
333336
}
334337

335-
cacheAWSCredentials(awsCreds, *accessConfig)
336-
337338
awsClient, err := newAWSClient(*accessConfig.Region, awsCreds)
338339
if err != nil {
339340
exit.Error(err)
340341
}
341342

343+
cacheAWSCredentials(awsCreds, *accessConfig)
344+
342345
clusterState, err := clusterstate.GetClusterState(awsClient, accessConfig)
343346
if err != nil {
344347
exit.Error(err)
@@ -390,7 +393,7 @@ var _infoCmd = &cobra.Command{
390393
}
391394
}
392395

393-
accessConfig, err := getClusterAccessConfig(_flagClusterDisallowPrompt)
396+
accessConfig, err := getClusterAccessConfigWithCache(_flagClusterDisallowPrompt)
394397
if err != nil {
395398
exit.Error(err)
396399
}
@@ -428,7 +431,7 @@ var _downCmd = &cobra.Command{
428431
}
429432
}
430433

431-
accessConfig, err := getClusterAccessConfig(_flagClusterDisallowPrompt)
434+
accessConfig, err := getClusterAccessConfigWithCache(_flagClusterDisallowPrompt)
432435
if err != nil {
433436
exit.Error(err)
434437
}
@@ -559,7 +562,7 @@ var _exportCmd = &cobra.Command{
559562
}
560563
}
561564

562-
accessConfig, err := getClusterAccessConfig(_flagClusterDisallowPrompt)
565+
accessConfig, err := getClusterAccessConfigWithCache(_flagClusterDisallowPrompt)
563566
if err != nil {
564567
exit.Error(err)
565568
}

cli/cmd/lib_aws_creds.go

Lines changed: 21 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ func detectAWSCredsInConfigFile(cmd, path string) error {
130130
return nil
131131
}
132132

133-
func awsCredentialsForCreatingCluster(disallowPrompt bool) (AWSCredentials, error) {
133+
func awsCredentialsForManagingCluster(accessConfig clusterconfig.AccessConfig, disallowPrompt bool) (AWSCredentials, error) {
134134
awsCredentials, err := awsCredentialsFromFlags()
135135
if err != nil {
136136
return AWSCredentials{}, err
@@ -140,55 +140,26 @@ func awsCredentialsForCreatingCluster(disallowPrompt bool) (AWSCredentials, erro
140140
return *awsCredentials, nil
141141
}
142142

143-
awsCredentials, err = awsCredentialsFromEnvVars()
144-
if err != nil {
145-
return AWSCredentials{}, err
146-
}
147-
148-
if awsCredentials != nil {
149-
fmt.Println(fmt.Sprintf("using %s found in environment variables (to use different credentials, specify the --aws-key and --aws-secret flags)\n", awsCredentials.MaskedString()))
150-
return *awsCredentials, nil
151-
}
152-
153-
awsCredentials, err = awsCredentialsFromSharedCreds()
154-
if err != nil {
155-
return AWSCredentials{}, errors.Append(err, "\n\nit may be possible to avoid this error by specifying the --aws-key and --aws-secret flags")
156-
}
157-
143+
awsCredentials = awsCredentialsFromCache(accessConfig)
158144
if awsCredentials != nil {
159-
fmt.Println(fmt.Sprintf("using %s from the \"default\" profile configured via `aws configure` (to use different credentials, specify the --aws-key and --aws-secret flags)\n", awsCredentials.MaskedString()))
145+
fmt.Println(fmt.Sprintf("using %s from cache (to use different credentials, specify the --aws-key and --aws-secret flags)\n", awsCredentials.MaskedString()))
160146
return *awsCredentials, nil
161147
}
162148

163-
if disallowPrompt {
164-
return AWSCredentials{}, ErrorMissingAWSCredentials()
165-
}
166-
167-
awsCredentials, err = awsCredentialsPrompt()
168-
if err != nil {
169-
return AWSCredentials{}, errors.Append(err, "\n\nit may be possible to avoid this error by specifying the --aws-key and --aws-secret flags")
170-
}
171-
172-
return *awsCredentials, nil
173-
}
174-
175-
func awsCredentialsForManagingCluster(accessConfig clusterconfig.AccessConfig, disallowPrompt bool) (AWSCredentials, error) {
176-
awsCredentials, err := awsCredentialsFromFlags()
149+
awsCredentials, err = awsCredentialsFromEnvVars()
177150
if err != nil {
178151
return AWSCredentials{}, err
179152
}
180153

181154
if awsCredentials != nil {
155+
fmt.Println(fmt.Sprintf("using %s found in environment variables (to use different credentials, specify the --aws-key and --aws-secret flags)\n", awsCredentials.MaskedString()))
182156
return *awsCredentials, nil
183157
}
184158

185-
awsCredentials, err = getAWSCredentialsFromCache(accessConfig)
186-
if err != nil {
187-
return AWSCredentials{}, errors.Append(err, "\n\nit may be possible to avoid this error by specifying the --aws-key and --aws-secret flags")
188-
}
159+
awsCredentials = awsCredentialsFromSharedCreds()
189160

190161
if awsCredentials != nil {
191-
fmt.Println(fmt.Sprintf("using cached %s (to use different credentials, specify the --aws-key and --aws-secret flags)\n", awsCredentials.MaskedString()))
162+
fmt.Println(fmt.Sprintf("using %s from the \"default\" profile configured via `aws configure` (to use different credentials, specify the --aws-key and --aws-secret flags)\n", awsCredentials.MaskedString()))
192163
return *awsCredentials, nil
193164
}
194165

@@ -241,7 +212,7 @@ func awsCredentialsFromFlags() (*AWSCredentials, error) {
241212
}
242213

243214
credentials.ClusterAWSAccessKeyID = _flagClusterAWSAccessKeyID
244-
credentials.ClusterAWSSecretAccessKey = _flagClusterAWSAccessKeyID
215+
credentials.ClusterAWSSecretAccessKey = _flagClusterAWSSecretAccessKey
245216
} else {
246217
credentials.ClusterAWSAccessKeyID = credentials.AWSAccessKeyID
247218
credentials.ClusterAWSSecretAccessKey = credentials.AWSSecretAccessKey
@@ -289,19 +260,20 @@ func awsCredentialsFromEnvVars() (*AWSCredentials, error) {
289260
return &credentials, nil
290261
}
291262

292-
// Read from "default" profile from credentials specified by AWS_SHARED_CREDENTIALS_FILE (default path: ~/.aws/credentials)
293-
func awsCredentialsFromSharedCreds() (*AWSCredentials, error) {
263+
// Read from "default" profile from credentials specified by AWS_SHARED_CREDENTIALS_FILE (default path: ~/.aws/credentials).
264+
// Returns nil if an error is encountered.
265+
func awsCredentialsFromSharedCreds() *AWSCredentials {
294266
credentials := AWSCredentials{}
295267
accessKeyID, secretAccessKey, err := aws.GetCredentialsFromCLIConfigFile()
296268
if err != nil {
297-
return nil, err
269+
return nil
298270
}
299271

300272
credentials.AWSAccessKeyID = accessKeyID
301273
credentials.AWSSecretAccessKey = secretAccessKey
302274
credentials.ClusterAWSAccessKeyID = accessKeyID
303275
credentials.ClusterAWSSecretAccessKey = secretAccessKey
304-
return &credentials, nil
276+
return &credentials
305277
}
306278

307279
func awsCredentialsPrompt() (*AWSCredentials, error) {
@@ -322,26 +294,29 @@ func credentialsCachePath(accessConfig clusterconfig.AccessConfig) string {
322294
return filepath.Join(_credentialsCacheDir, fmt.Sprintf("%s-%s.json", *accessConfig.Region, *accessConfig.ClusterName))
323295
}
324296

325-
func getAWSCredentialsFromCache(accessConfig clusterconfig.AccessConfig) (*AWSCredentials, error) {
297+
// Read AWS credentials from cache.
298+
// Returns nil if not found or an error is encountered.
299+
func awsCredentialsFromCache(accessConfig clusterconfig.AccessConfig) *AWSCredentials {
300+
326301
credsPath := credentialsCachePath(accessConfig)
327302

328303
if !files.IsFile(credsPath) {
329-
return nil, nil
304+
return nil
330305
}
331306

332307
jsonBytes, err := files.ReadFileBytes(credsPath)
333308
if err != nil {
334-
return nil, err
309+
return nil
335310
}
336311

337312
credentials := AWSCredentials{}
338313

339314
err = libjson.Unmarshal(jsonBytes, &credentials)
340315
if err != nil {
341-
return nil, err
316+
return nil
342317
}
343318

344-
return &credentials, nil
319+
return &credentials
345320
}
346321

347322
func cacheAWSCredentials(awsCreds AWSCredentials, accessConfig clusterconfig.AccessConfig) error {

cli/cmd/lib_cluster_config.go

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,36 @@ func readUserClusterConfigFile(clusterConfig *clusterconfig.Config) error {
7676
return nil
7777
}
7878

79-
func getClusterAccessConfig(disallowPrompt bool) (*clusterconfig.AccessConfig, error) {
79+
func getNewClusterAccessConfig(disallowPrompt bool) (*clusterconfig.AccessConfig, error) {
80+
accessConfig, err := clusterconfig.DefaultAccessConfig()
81+
if err != nil {
82+
return nil, err
83+
}
84+
85+
if _flagClusterConfig != "" {
86+
errs := cr.ParseYAMLFile(accessConfig, clusterconfig.AccessValidation, _flagClusterConfig)
87+
if errors.HasError(errs) {
88+
return nil, errors.Append(errors.FirstError(errs...), fmt.Sprintf("\n\ncluster configuration schema can be found here: https://docs.cortex.dev/v/%s/cluster-management/config", consts.CortexVersionMinor))
89+
}
90+
}
91+
92+
if accessConfig.ClusterName != nil && accessConfig.Region != nil {
93+
return accessConfig, nil
94+
}
95+
96+
if disallowPrompt {
97+
return nil, ErrorClusterAccessConfigOrPromptsRequired()
98+
}
99+
100+
err = cr.ReadPrompt(accessConfig, clusterconfig.AccessPromptValidation)
101+
if err != nil {
102+
return nil, err
103+
}
104+
105+
return accessConfig, nil
106+
}
107+
108+
func getClusterAccessConfigWithCache(disallowPrompt bool) (*clusterconfig.AccessConfig, error) {
80109
accessConfig, err := clusterconfig.DefaultAccessConfig()
81110
if err != nil {
82111
return nil, err
@@ -127,7 +156,7 @@ func getClusterAccessConfig(disallowPrompt bool) (*clusterconfig.AccessConfig, e
127156
return accessConfig, nil
128157
}
129158

130-
func getInstallClusterConfig(awsCreds AWSCredentials, envName string, disallowPrompt bool) (*clusterconfig.Config, error) {
159+
func getInstallClusterConfig(awsCreds AWSCredentials, accessConfig clusterconfig.AccessConfig, envName string, disallowPrompt bool) (*clusterconfig.Config, error) {
131160
clusterConfig := &clusterconfig.Config{}
132161

133162
err := clusterconfig.SetDefaults(clusterConfig)
@@ -142,10 +171,8 @@ func getInstallClusterConfig(awsCreds AWSCredentials, envName string, disallowPr
142171
}
143172
}
144173

145-
err = clusterconfig.RegionPrompt(clusterConfig, disallowPrompt)
146-
if err != nil {
147-
return nil, err
148-
}
174+
clusterConfig.ClusterName = *accessConfig.ClusterName
175+
clusterConfig.Region = accessConfig.Region
149176

150177
awsClient, err := newAWSClient(*clusterConfig.Region, awsCreds)
151178
if err != nil {

docs/miscellaneous/security.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,17 @@ Cortex uses AWS credentials for 3 main purposes:
2828

2929
### Cluster spin-up
3030

31-
Spinning up Cortex on your AWS account requires more permissions than Cortex needs once it's running. You can specify different credentials for each purpose in two ways (in order of precedence):
31+
You can specify credentials for spinning up the cluster in four ways (in order of precedence):
3232

33-
1. You can specify `--aws-key` and `--aws-secret` flags with the command `cortex cluster up` to indicate the credentials that will be used to create your cluster. Optionally, you can specify `--cluster-aws-key` and `--cluster-aws-secret` to specify credentials which will be used by the cluster.
33+
1. You can specify `--aws-key` and `--aws-secret` flags with the command `cortex cluster up` to indicate the credentials that will be used to create your cluster. Optionally, you can specify `--cluster-aws-key` and `--cluster-aws-secret` to specify credentials which will be used by the cluster. When all four flags are specified, the credentials used when spinning up the cluster will not be used by the cluster itself. If `--cluster-aws-key` and `--cluster-aws-secret` flags are not specified, then they'll get set to the values of `--aws-key` and `--aws-secret` respectively.
3434

35-
2. You can export the environment variables `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` which will be used to create your cluster. Optionally, you can export `CLUSTER_AWS_ACCESS_KEY_ID` and `CLUSTER_AWS_SECRET_ACCESS_KEY` to specify credentials which will be used by the cluster.
35+
2. From your Cortex CLI cluster cache. If a cluster with the same name and region has existed before, the AWS credentials of that will now be used for the current creation of the cluster.
3636

37-
In either case, the credentials used when spinning up the cluster will not be used by the cluster itself, and can be safely revoked after the cluster is running. You may need credentials with similar access to run other `cortex cluster` commands, such as `cortex cluster configure`, `cortex cluster info`, and `cortex cluster down`.
37+
3. You can export the environment variables `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` which will be used to create your cluster. Optionally, you can export `CLUSTER_AWS_ACCESS_KEY_ID` and `CLUSTER_AWS_SECRET_ACCESS_KEY` to specify credentials which will be used by the cluster. When all four environment variables are set, the credentials used when spinning up the cluster will not be used by the cluster itself. If `CLUSTER_AWS_ACCESS_KEY_ID` and `CLUSTER_AWS_SECRET_ACCESS_KEY` environment variables are not set, then they'll get set to the values of `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` respectively.
38+
39+
4. You can configure the shared AWS credentials with `aws configure` which will then be used to create your cluster.
40+
41+
5. You can specify the AWS credentials `"aws access key id"` and `"aws secret access key"` at the CLI's prompt when requested.
3842

3943
It is recommended to use an IAM user with the `AdministratorAccess` policy to create your cluster, since the CLI requires many permissions for this step, and the list of permissions is evolving as Cortex adds new features. If it is not possible to use `AdministratorAccess` in your existing AWS account, you could create a separate AWS account for your Cortex cluster, or you could ask someone within your organization to create the Cortex cluster for you (since `AdministratorAccess` is not required to deploy APIs to your cluster; see [CLI](#cli) below).
4044

0 commit comments

Comments
 (0)