Skip to content

Commit

Permalink
App list API and regions
Browse files Browse the repository at this point in the history
  • Loading branch information
ipmb committed Dec 29, 2020
1 parent cfc931a commit 0e336f9
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 31 deletions.
4 changes: 2 additions & 2 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ func (a *App) ConnectToTask(task *ecs.Task, cmd *string) error {
})
ssmSvc := ssm.New(a.Session)
documentName := "AWS-StartInteractiveCommand"
region := "us-east-1" //TODO get from auth info
region := a.Session.Config.Region
err = a.LoadSettings()
if err != nil {
return err
Expand All @@ -343,7 +343,7 @@ func (a *App) ConnectToTask(task *ecs.Task, cmd *string) error {
}
// session-manager-plugin isn't documented
// args were determined from here: https://github.com/aws/aws-cli/blob/84f751b71131489afcb5401d8297bb5b3faa29cb/awscli/customizations/sessionmanager.py#L83-L89
err = syscall.Exec(binaryPath, []string{"session-manager-plugin", string(arg1), region, "StartSession", "", string(arg2), fmt.Sprintf("https://ssm.%s.amazonaws.com", region)}, os.Environ())
err = syscall.Exec(binaryPath, []string{"session-manager-plugin", string(arg1), *region, "StartSession", "", string(arg2), fmt.Sprintf("https://ssm.%s.amazonaws.com", region)}, os.Environ())
if err != nil {
return err
}
Expand Down
95 changes: 68 additions & 27 deletions auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const (
deviceCodeURL = "https://auth.apppack.io/oauth/device/code"
oauthTokenURL = "https://auth.apppack.io/oauth/token"
userInfoURL = "https://auth.apppack.io/userinfo"
appListURL = "https://api.apppack.io/apps"
clientID = "x15zAd2hgdbugNWSZz2mP2k5jcZfNFk3"
scope = "openid profile email offline_access"
audience = "https://paaws.lloop.us"
Expand All @@ -51,35 +52,48 @@ type DeviceCodeResp struct {
}

type UserInfo struct {
Email string `json:"email"`
AwsRoles map[string]string `json:"https://paaws.lloop.us/aws_roles"`
Email string `json:"email"`
Apps []AppRole `json:"https://apppack.io/apps"`
}

func getCredentials(appName string) (*sts.Credentials, error) {
tokens, userInfo, err := verifyAuth()
type AppRole struct {
RoleARN string `json:"role_arn"`
AccountID string `json:"account_id"`
AppName string `json:"name"`
Region string `json:"region"`
}

func getAppRole(IDToken string, name string) (*AppRole, error) {
appList, err := getAppListWithIDToken(IDToken)
if err != nil {
return nil, err
}
roleArn, ok := (*userInfo).AwsRoles[appName]
if !ok {
tokens, err = refreshTokens()
tokens, err := refreshTokens()
appList, err = getAppListWithIDToken(tokens.IDToken)
if err != nil {
return nil, err
}
userInfo, err := getUserInfoWithAccessToken(tokens.AccessToken)
if err != nil {
return nil, err
}
roleArn, ok = (*userInfo).AwsRoles[appName]
if !ok {
return nil, fmt.Errorf("You don't have access to the app %s", appName)
}
for _, appRole := range appList {
if appRole.AppName == name {
return appRole, nil
}
}
return nil, fmt.Errorf("app not found in user info")
}

func getCredentials(appName string) (*sts.Credentials, *string, error) {
tokens, userInfo, err := verifyAuth()
if err != nil {
return nil, nil, err
}
appRole, err := getAppRole(tokens.IDToken, appName)
if err != nil {
return nil, nil, err
}
sess := session.Must(session.NewSession())
svc := sts.New(sess)
duration := int64(900)
resp, err := svc.AssumeRoleWithWebIdentity(&sts.AssumeRoleWithWebIdentityInput{
RoleArn: &roleArn,
RoleArn: &appRole.RoleARN,
WebIdentityToken: &tokens.IDToken,
RoleSessionName: &userInfo.Email,
DurationSeconds: &duration,
Expand All @@ -89,25 +103,23 @@ func getCredentials(appName string) (*sts.Credentials, error) {
if aerr.Code() == sts.ErrCodeExpiredTokenException {
tokens, err = refreshTokens()
if err != nil {
return nil, err
return nil, nil, err
}
resp, err = svc.AssumeRoleWithWebIdentity(&sts.AssumeRoleWithWebIdentityInput{
RoleArn: &roleArn,
RoleArn: &appRole.RoleARN,
WebIdentityToken: &tokens.IDToken,
RoleSessionName: &userInfo.Email,
DurationSeconds: &duration,
})
if err != nil {
return nil, err
return nil, nil, err
}
}
} else {
if err != nil {
return nil, err
}
return nil, nil, err
}
return nil, nil, err
}
return resp.Credentials, nil
return resp.Credentials, &appRole.Region, nil
}

func writeToUserCache(name string, data []byte) error {
Expand Down Expand Up @@ -221,6 +233,35 @@ func getUserInfoWithAccessToken(accessToken string) (*UserInfo, error) {
return &userInfo, nil
}

func getAppListWithIDToken(IDToken string) ([]*AppRole, error) {
req, err := http.NewRequest("GET", appListURL, nil)
if err != nil {
return nil, err
}
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", IDToken))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
contents, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("Unable to retrieve app list. Status code %d", resp.StatusCode)
}
//err = writeToUserCache("apps", contents)
//if err != nil {
// return err
//}
var appList []*AppRole

if err = json.Unmarshal(contents, &appList); err != nil {
return nil, err
}
return appList, nil
}

func verifyAuth() (*Tokens, *UserInfo, error) {
tokens, err := readTokensFromUserCache()
if err != nil {
Expand Down Expand Up @@ -328,7 +369,7 @@ func Logout() error {
}

func AwsSession(appName string) (*session.Session, error) {
creds, err := getCredentials(appName)
creds, region, err := getCredentials(appName)
if err != nil {
return nil, err
}
Expand All @@ -341,7 +382,7 @@ func AwsSession(appName string) (*session.Session, error) {
*creds.SecretAccessKey,
*creds.SessionToken,
),
).WithRegion("us-east-1"), // TODO: configure region
).WithRegion(*region),
},
),
), nil
Expand Down
3 changes: 1 addition & 2 deletions cmd/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,7 @@ var logsOpenCmd = &cobra.Command{
checkErr(err)
logGroupParam := strings.ReplaceAll(url.QueryEscape(a.Settings.LogGroup.Name), "%", "*")
queryParam := strings.ReplaceAll(url.QueryEscape("fields @timestamp, @message\n| sort @timestamp desc\n| limit 200"), "%", "*")
// TODO remove hard-coded region
region := "us-east-1"
region := *a.Session.Config.Region
destinationURL := fmt.Sprintf("https://console.aws.amazon.com/cloudwatch/home?region=%s#logsV2:logs-insights$3FqueryDetail$3D~(editorString~'%s~source~(~'%s))", region, queryParam, logGroupParam)
signinURL, err := a.GetConsoleURL(destinationURL)
checkErr(err)
Expand Down

0 comments on commit 0e336f9

Please sign in to comment.