Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/gitpod-cli/cmd/idp-login-aws.go
3603 views
1
// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
2
// Licensed under the GNU Affero General Public License (AGPL).
3
// See License.AGPL.txt in the project root for license information.
4
5
package cmd
6
7
import (
8
"context"
9
"encoding/json"
10
"fmt"
11
"os"
12
"os/exec"
13
"time"
14
15
"github.com/gitpod-io/gitpod/gitpod-cli/pkg/gitpod"
16
"github.com/spf13/cobra"
17
)
18
19
const (
20
idpAudienceAWS = "sts.amazonaws.com"
21
)
22
23
var idpLoginAwsOpts struct {
24
RoleARN string
25
Profile string
26
DurationSeconds int
27
Audience []string
28
}
29
30
var idpLoginAwsCmd = &cobra.Command{
31
Use: "aws",
32
Short: "Login to AWS",
33
Long: "Obtains credentials to access AWS. The command delegates to `aws sts assume-role-with-web-identity`, see https://docs.aws.amazon.com/cli/latest/reference/sts/assume-role-with-web-identity.html for more details.",
34
RunE: func(cmd *cobra.Command, args []string) error {
35
cmd.SilenceUsage = true
36
if idpLoginAwsOpts.RoleARN == "" {
37
return fmt.Errorf("missing --role-arn or IDP_AWS_ROLE_ARN env var")
38
}
39
if idpLoginAwsOpts.DurationSeconds <= 0 {
40
return fmt.Errorf("invalid --duration-seconds: %d, must be a positive integer", idpLoginAwsOpts.DurationSeconds)
41
}
42
43
ctx, cancel := context.WithTimeout(cmd.Context(), 5*time.Second)
44
defer cancel()
45
46
tkn, err := idpToken(ctx, idpLoginAwsOpts.Audience, idpLoginOpts.Scope)
47
if err != nil {
48
return err
49
}
50
51
wsInfo, err := gitpod.GetWSInfo(ctx)
52
if err != nil {
53
return err
54
}
55
56
awsCmd := exec.Command("aws", "sts", "assume-role-with-web-identity",
57
"--role-arn", idpLoginAwsOpts.RoleARN,
58
"--role-session-name", fmt.Sprintf("%s-%d", wsInfo.WorkspaceId, time.Now().Unix()),
59
"--web-identity-token", tkn,
60
"--duration-seconds", fmt.Sprintf("%d", idpLoginAwsOpts.DurationSeconds),
61
)
62
out, err := awsCmd.CombinedOutput()
63
if err != nil {
64
return fmt.Errorf("%w: %s", err, string(out))
65
}
66
67
var result struct {
68
Credentials struct {
69
AccessKeyId string
70
SecretAccessKey string
71
SessionToken string
72
}
73
}
74
err = json.Unmarshal(out, &result)
75
if err != nil {
76
return err
77
}
78
79
vars := map[string]string{
80
"aws_access_key_id": result.Credentials.AccessKeyId,
81
"aws_secret_access_key": result.Credentials.SecretAccessKey,
82
"aws_session_token": result.Credentials.SessionToken,
83
}
84
for k, v := range vars {
85
awsCmd := exec.Command("aws", "configure", "set", "--profile", idpLoginAwsOpts.Profile, k, v)
86
out, err := awsCmd.CombinedOutput()
87
if err != nil {
88
return fmt.Errorf("%w: %s", err, string(out))
89
}
90
}
91
92
return nil
93
},
94
}
95
96
func init() {
97
idpLoginCmd.AddCommand(idpLoginAwsCmd)
98
99
idpLoginAwsCmd.Flags().StringVar(&idpLoginAwsOpts.RoleARN, "role-arn", os.Getenv("IDP_AWS_ROLE_ARN"), "AWS role to assume (defaults to IDP_AWS_ROLE_ARN env var)")
100
idpLoginAwsCmd.Flags().StringArrayVar(&idpLoginAwsOpts.Audience, "audience", []string{idpAudienceAWS}, "audience of the ID token")
101
idpLoginAwsCmd.Flags().StringVarP(&idpLoginAwsOpts.Profile, "profile", "p", "default", "AWS profile to configure")
102
idpLoginAwsCmd.Flags().IntVarP(&idpLoginAwsOpts.DurationSeconds, "duration-seconds", "d", 3600, "Duration in seconds for which the credentials will be valid (defaults to 3600), upper bound is controlled by the AWS maximum session duration. See https://docs.aws.amazon.com/cli/latest/reference/sts/assume-role-with-web-identity.html")
103
_ = idpLoginAwsCmd.MarkFlagFilename("profile")
104
}
105
106