Path: blob/main/components/gitpod-cli/cmd/idp-login-aws.go
3603 views
// Copyright (c) 2022 Gitpod GmbH. All rights reserved.1// Licensed under the GNU Affero General Public License (AGPL).2// See License.AGPL.txt in the project root for license information.34package cmd56import (7"context"8"encoding/json"9"fmt"10"os"11"os/exec"12"time"1314"github.com/gitpod-io/gitpod/gitpod-cli/pkg/gitpod"15"github.com/spf13/cobra"16)1718const (19idpAudienceAWS = "sts.amazonaws.com"20)2122var idpLoginAwsOpts struct {23RoleARN string24Profile string25DurationSeconds int26Audience []string27}2829var idpLoginAwsCmd = &cobra.Command{30Use: "aws",31Short: "Login to AWS",32Long: "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.",33RunE: func(cmd *cobra.Command, args []string) error {34cmd.SilenceUsage = true35if idpLoginAwsOpts.RoleARN == "" {36return fmt.Errorf("missing --role-arn or IDP_AWS_ROLE_ARN env var")37}38if idpLoginAwsOpts.DurationSeconds <= 0 {39return fmt.Errorf("invalid --duration-seconds: %d, must be a positive integer", idpLoginAwsOpts.DurationSeconds)40}4142ctx, cancel := context.WithTimeout(cmd.Context(), 5*time.Second)43defer cancel()4445tkn, err := idpToken(ctx, idpLoginAwsOpts.Audience, idpLoginOpts.Scope)46if err != nil {47return err48}4950wsInfo, err := gitpod.GetWSInfo(ctx)51if err != nil {52return err53}5455awsCmd := exec.Command("aws", "sts", "assume-role-with-web-identity",56"--role-arn", idpLoginAwsOpts.RoleARN,57"--role-session-name", fmt.Sprintf("%s-%d", wsInfo.WorkspaceId, time.Now().Unix()),58"--web-identity-token", tkn,59"--duration-seconds", fmt.Sprintf("%d", idpLoginAwsOpts.DurationSeconds),60)61out, err := awsCmd.CombinedOutput()62if err != nil {63return fmt.Errorf("%w: %s", err, string(out))64}6566var result struct {67Credentials struct {68AccessKeyId string69SecretAccessKey string70SessionToken string71}72}73err = json.Unmarshal(out, &result)74if err != nil {75return err76}7778vars := map[string]string{79"aws_access_key_id": result.Credentials.AccessKeyId,80"aws_secret_access_key": result.Credentials.SecretAccessKey,81"aws_session_token": result.Credentials.SessionToken,82}83for k, v := range vars {84awsCmd := exec.Command("aws", "configure", "set", "--profile", idpLoginAwsOpts.Profile, k, v)85out, err := awsCmd.CombinedOutput()86if err != nil {87return fmt.Errorf("%w: %s", err, string(out))88}89}9091return nil92},93}9495func init() {96idpLoginCmd.AddCommand(idpLoginAwsCmd)9798idpLoginAwsCmd.Flags().StringVar(&idpLoginAwsOpts.RoleARN, "role-arn", os.Getenv("IDP_AWS_ROLE_ARN"), "AWS role to assume (defaults to IDP_AWS_ROLE_ARN env var)")99idpLoginAwsCmd.Flags().StringArrayVar(&idpLoginAwsOpts.Audience, "audience", []string{idpAudienceAWS}, "audience of the ID token")100idpLoginAwsCmd.Flags().StringVarP(&idpLoginAwsOpts.Profile, "profile", "p", "default", "AWS profile to configure")101idpLoginAwsCmd.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")102_ = idpLoginAwsCmd.MarkFlagFilename("profile")103}104105106