Skip to content

Commit

Permalink
Add option to use AWS authentication
Browse files Browse the repository at this point in the history
instead of AppPack.io OIDC.
  • Loading branch information
ipmb committed Oct 9, 2021
1 parent 510a339 commit 1fc9d63
Show file tree
Hide file tree
Showing 13 changed files with 82 additions and 36 deletions.
12 changes: 10 additions & 2 deletions app/app.go
Expand Up @@ -1150,7 +1150,7 @@ func (a *App) ValidateCronString(rule string) error {
}

// Init will pull in app settings from DyanmoDB and provide helper
func Init(name string) (*App, error) {
func Init(name string, awsCredentials bool) (*App, error) {
var reviewApp *string
if strings.Contains(name, ":") {
parts := strings.Split(name, ":")
Expand All @@ -1159,7 +1159,15 @@ func Init(name string) (*App, error) {
} else {
reviewApp = nil
}
sess, appRole, err := auth.AwsSession(name)
var sess *session.Session
var err error
var appRole *auth.AppRole
if awsCredentials {
sess = session.Must(session.NewSession())
appRole, err = auth.AppRoleFromAWS(sess, name)
} else {
sess, appRole, err = auth.AwsSession(name)
}
if err != nil {
return nil, err
}
Expand Down
37 changes: 33 additions & 4 deletions auth/auth.go
Expand Up @@ -16,6 +16,8 @@ import (
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
"github.com/aws/aws-sdk-go/service/sts"
awsconsoleurl "github.com/jkueh/go-aws-console-url"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -58,11 +60,11 @@ type UserInfo struct {
}

type AppRole struct {
RoleARN string `json:"role_arn"`
RoleARN string `json:"role_arn" dynamodbav:"role_arn"`
AccountID string `json:"account_id"`
AppName string `json:"name"`
Region string `json:"region"`
Pipeline bool `json:"pipeline"`
AppName string `json:"name" dynamodbav:"secondary_id"`
Region string `json:"region" dynamodbav:"region"`
Pipeline bool `json:"pipeline" dynamodbav:"pipeline"`
}

func getAppRole(IDToken, name string) (*AppRole, error) {
Expand Down Expand Up @@ -338,6 +340,33 @@ func tokenRequest(url string, jsonData []byte) (*Tokens, error) {
return &tokens, nil
}

func AppRoleFromAWS(sess *session.Session, appName string) (*AppRole, error) {
stsSvc := sts.New(sess)
resp, err := stsSvc.GetCallerIdentity(&sts.GetCallerIdentityInput{})
if err != nil {
return nil, err
}
accountID := resp.Account
ddbSvc := dynamodb.New(sess)
item, err := ddbSvc.GetItem(&dynamodb.GetItemInput{
TableName: aws.String("apppack"),
Key: map[string]*dynamodb.AttributeValue{
"primary_id": {S: aws.String(fmt.Sprintf("APP#%s", *accountID))},
"secondary_id": {S: &appName},
},
})
if err != nil {
return nil, err
}
a := AppRole{}
err = dynamodbattribute.UnmarshalMap(item.Item, &a)
if err != nil {
return nil, err
}
a.AccountID = *accountID
return &a, nil
}

func LoginComplete(deviceCode string) (*UserInfo, error) {
reqBody, err := json.Marshal(map[string]string{
"grant_type": grantType, "device_code": deviceCode, "client_id": clientID,
Expand Down
2 changes: 1 addition & 1 deletion cmd/aws_exec.go
Expand Up @@ -165,7 +165,7 @@ var awsExecCmd = &cobra.Command{
Short: "run a local command with AWS credentials",
DisableFlagsInUseLine: true,
Run: func(cmd *cobra.Command, args []string) {
a, err := app.Init(AppName)
a, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
if len(args) < 1 {
checkErr(fmt.Errorf("provide an executable to run as an argument"))
Expand Down
7 changes: 4 additions & 3 deletions cmd/build.go
Expand Up @@ -584,7 +584,7 @@ var buildStartCmd = &cobra.Command{
DisableFlagsInUseLine: true,
Run: func(cmd *cobra.Command, args []string) {
startSpinner()
a, err := app.Init(AppName)
a, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
build, err := a.StartBuild(false)
checkErr(err)
Expand Down Expand Up @@ -616,7 +616,7 @@ var buildWatchCmd = &cobra.Command{
DisableFlagsInUseLine: true,
Run: func(cmd *cobra.Command, args []string) {
startSpinner()
a, err := app.Init(AppName)
a, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
build, err := a.LastBuild()
checkErr(err)
Expand All @@ -636,7 +636,7 @@ var buildListCmd = &cobra.Command{
DisableFlagsInUseLine: true,
Run: func(cmd *cobra.Command, args []string) {
startSpinner()
a, err := app.Init(AppName)
a, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
builds, err := a.ListBuilds()
checkErr(err)
Expand All @@ -658,6 +658,7 @@ func init() {
rootCmd.AddCommand(buildCmd)
buildCmd.PersistentFlags().StringVarP(&AppName, "app-name", "a", "", "app name (required)")
buildCmd.MarkPersistentFlagRequired("app-name")
buildCmd.PersistentFlags().BoolVar(&UseAWSCredentials, "aws-credentials", false, "use AWS credentials instead of AppPack.io federation")

buildCmd.AddCommand(buildStartCmd)
buildStartCmd.Flags().BoolVarP(&watchBuildFlag, "watch", "w", false, "watch build process")
Expand Down
13 changes: 7 additions & 6 deletions cmd/config.go
Expand Up @@ -49,7 +49,7 @@ var getCmd = &cobra.Command{
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
startSpinner()
a, err := app.Init(AppName)
a, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
svc := ssm.New(a.Session)
resp, err := svc.GetParameter(&ssm.GetParameterInput{
Expand Down Expand Up @@ -77,7 +77,7 @@ var setCmd = &cobra.Command{
name := parts[0]
value := parts[1]
startSpinner()
a, err := app.Init(AppName)
a, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
err = a.SetConfig(name, value, true)
checkErr(err)
Expand All @@ -95,7 +95,7 @@ var unsetCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
startSpinner()
name := args[0]
a, err := app.Init(AppName)
a, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
svc := ssm.New(a.Session)
_, err = svc.DeleteParameter(&ssm.DeleteParameterInput{
Expand All @@ -118,7 +118,7 @@ var listCmd = &cobra.Command{
// minwidth, tabwidth, padding, padchar, flags
w.Init(os.Stdout, 8, 8, 0, '\t', 0)
startSpinner()
a, err := app.Init(AppName)
a, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
parameters, err := a.GetConfig()
checkErr(err)
Expand Down Expand Up @@ -174,7 +174,7 @@ var configExportCmd = &cobra.Command{
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
startSpinner()
a, err := app.Init(AppName)
a, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
parameters, err := a.GetConfig()
checkErr(err)
Expand Down Expand Up @@ -211,7 +211,7 @@ var configImportCmd = &cobra.Command{
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
startSpinner()
a, err := app.Init(AppName)
a, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
data, err := ioutil.ReadFile(args[0])
if err != nil {
Expand Down Expand Up @@ -250,6 +250,7 @@ func init() {
rootCmd.AddCommand(configCmd)
configCmd.PersistentFlags().StringVarP(&AppName, "app-name", "a", "", "app name (required)")
configCmd.MarkPersistentFlagRequired("app-name")
configCmd.PersistentFlags().BoolVar(&UseAWSCredentials, "aws-credentials", false, "use AWS credentials instead of AppPack.io federation")

configCmd.AddCommand(getCmd)
configCmd.AddCommand(setCmd)
Expand Down
7 changes: 4 additions & 3 deletions cmd/db.go
Expand Up @@ -69,7 +69,7 @@ var dbShellCmd = &cobra.Command{
DisableFlagsInUseLine: true,
Run: func(cmd *cobra.Command, args []string) {
startSpinner()
a, err := app.Init(AppName)
a, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
family, exec, err := a.DBShellTaskInfo()
checkErr(err)
Expand All @@ -85,7 +85,7 @@ var dbDumpCmd = &cobra.Command{
DisableFlagsInUseLine: true,
Run: func(cmd *cobra.Command, args []string) {
startSpinner()
app, err := app.Init(AppName)
app, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
err = app.LoadSettings()
checkErr(err)
Expand Down Expand Up @@ -164,7 +164,7 @@ WARNING: This is a destructive action which will delete the contents of your rem
Run: func(cmd *cobra.Command, args []string) {
var remoteFile string
startSpinner()
app, err := app.Init(AppName)
app, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
Spinner.Stop()
confirmAction("This will destroy any data that is currently in the database.", AppName)
Expand Down Expand Up @@ -219,6 +219,7 @@ func init() {

dbCmd.PersistentFlags().StringVarP(&AppName, "app-name", "a", "", "app name (required)")
dbCmd.MarkPersistentFlagRequired("app-name")
dbCmd.PersistentFlags().BoolVar(&UseAWSCredentials, "aws-credentials", false, "use AWS credentials instead of AppPack.io federation")
dbCmd.AddCommand(dbShellCmd)
dbCmd.AddCommand(dbDumpCmd)
dbCmd.AddCommand(dbLoadCmd)
Expand Down
5 changes: 3 additions & 2 deletions cmd/logs.go
Expand Up @@ -54,7 +54,7 @@ var logsCmd = &cobra.Command{
DisableFlagsInUseLine: true,
Run: func(cmd *cobra.Command, args []string) {
startSpinner()
a, err := app.Init(AppName)
a, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
err = a.LoadSettings()
checkErr(err)
Expand Down Expand Up @@ -92,7 +92,7 @@ var logsOpenCmd = &cobra.Command{
Long: `Generates a presigned URL and opens a web browser to Cloudwatch Insights in the AWS web console`,
DisableFlagsInUseLine: true,
Run: func(cmd *cobra.Command, args []string) {
a, err := app.Init(AppName)
a, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
a.LoadSettings()
checkErr(err)
Expand All @@ -116,6 +116,7 @@ func init() {
rootCmd.AddCommand(logsCmd)
logsCmd.PersistentFlags().StringVarP(&AppName, "app-name", "a", "", "app name (required)")
logsCmd.MarkPersistentFlagRequired("app-name")
logsCmd.PersistentFlags().BoolVar(&UseAWSCredentials, "aws-credentials", false, "use AWS credentials instead of AppPack.io federation")

logsCmd.AddCommand(logsOpenCmd)
logsCmd.Flags().StringVar(&sawConfig.Prefix, "prefix", "", `log group prefix filter
Expand Down
7 changes: 4 additions & 3 deletions cmd/open.go
Expand Up @@ -26,10 +26,10 @@ import (

// openCmd represents the open command
var openCmd = &cobra.Command{
Use: "open",
Short: "open the app in a browser",
Use: "open",
Short: "open the app in a browser",
Run: func(cmd *cobra.Command, args []string) {
a, err := app.Init(AppName)
a, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
u, err := a.URL(nil)
checkErr(err)
Expand All @@ -42,4 +42,5 @@ func init() {
rootCmd.AddCommand(openCmd)
openCmd.PersistentFlags().StringVarP(&AppName, "app-name", "a", "", "app name (required)")
openCmd.MarkPersistentFlagRequired("app-name")
openCmd.PersistentFlags().BoolVar(&UseAWSCredentials, "aws-credentials", false, "use AWS credentials instead of AppPack.io federation")
}
9 changes: 5 additions & 4 deletions cmd/ps.go
Expand Up @@ -72,7 +72,7 @@ var psCmd = &cobra.Command{
DisableFlagsInUseLine: true,
Run: func(cmd *cobra.Command, args []string) {
startSpinner()
a, err := app.Init(AppName)
a, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
if a.Pipeline && !a.IsReviewApp() {
checkErr(fmt.Errorf("pipelines don't directly run processes"))
Expand Down Expand Up @@ -161,7 +161,7 @@ var psResizeCmd = &cobra.Command{
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
processType := args[0]
a, err := app.Init(AppName)
a, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
size, err := humanToECSSizeConfiguration(scaleCPU, scaleMemory)
checkErr(err)
Expand Down Expand Up @@ -192,7 +192,7 @@ apppack -a my-app ps scale worker 1-4 # autoscale worker service from 1 to 4 pr
minMaxProcs := strings.Split(args[1], "-")
minProcesses, err := strconv.Atoi(minMaxProcs[0])
checkErr(err)
a, err := app.Init(AppName)
a, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
if a.IsReviewApp() {
checkErr(fmt.Errorf("scaling is not supported for review apps"))
Expand Down Expand Up @@ -223,7 +223,7 @@ Requires installation of Amazon's SSM Session Manager. https://docs.aws.amazon.c
DisableFlagsInUseLine: true,
Run: func(cmd *cobra.Command, args []string) {
startSpinner()
a, err := app.Init(AppName)
a, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
interactiveCmd(a, strings.Join(args, " "))
},
Expand All @@ -236,6 +236,7 @@ func init() {
rootCmd.AddCommand(psCmd)
psCmd.PersistentFlags().StringVarP(&AppName, "app-name", "a", "", "app name (required)")
psCmd.MarkPersistentFlagRequired("app-name")
psCmd.PersistentFlags().BoolVar(&UseAWSCredentials, "aws-credentials", false, "use AWS credentials instead of AppPack.io federation")

psCmd.AddCommand(psResizeCmd)
psResizeCmd.Flags().Float64Var(&scaleCPU, "cpu", 0.5, "CPU cores available for process")
Expand Down
7 changes: 4 additions & 3 deletions cmd/reviewapps.go
Expand Up @@ -52,7 +52,7 @@ var reviewappsCmd = &cobra.Command{
DisableFlagsInUseLine: true,
Run: func(cmd *cobra.Command, args []string) {
startSpinner()
a, err := app.Init(args[0])
a, err := app.Init(args[0], UseAWSCredentials)
checkErr(err)
reviewApps, err := a.GetReviewApps()
checkErr(err)
Expand Down Expand Up @@ -174,7 +174,7 @@ var reviewappsCreateCmd = &cobra.Command{
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
startSpinner()
a, err := app.Init(args[0])
a, err := app.Init(args[0], UseAWSCredentials)
checkErr(err)
if !a.IsReviewApp() { // TODO: validate
checkErr(fmt.Errorf("no pull request number set"))
Expand Down Expand Up @@ -233,7 +233,7 @@ var reviewappsDestroyCmd = &cobra.Command{
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
startSpinner()
a, err := app.Init(args[0])
a, err := app.Init(args[0], UseAWSCredentials)
checkErr(err)
if !a.IsReviewApp() { // TODO: validate
checkErr(fmt.Errorf("no pull request number set"))
Expand All @@ -250,6 +250,7 @@ var reviewappsDestroyCmd = &cobra.Command{

func init() {
rootCmd.AddCommand(reviewappsCmd)
reviewappsCmd.PersistentFlags().BoolVar(&UseAWSCredentials, "aws-credentials", false, "use AWS credentials instead of AppPack.io federation")
reviewappsCmd.AddCommand(reviewappsCreateCmd)
reviewappsCreateCmd.Flags().StringVar(&release, "release", "", "Specify a specific pre-release stack")
upgradeCmd.PersistentFlags().MarkHidden("release")
Expand Down
1 change: 1 addition & 0 deletions cmd/root.go
Expand Up @@ -38,6 +38,7 @@ const (

// AppName is used to hold the `--app-name` flag
var AppName string
var UseAWSCredentials bool = false

// Spinner is the loading animation to use for all commands
var Spinner *spinner.Spinner = spinner.New(spinner.CharSets[14], 50*time.Millisecond)
Expand Down
8 changes: 4 additions & 4 deletions cmd/scheduledTasks.go
Expand Up @@ -45,7 +45,7 @@ var scheduledTasksCmd = &cobra.Command{
DisableFlagsInUseLine: true,
Run: func(cmd *cobra.Command, args []string) {
startSpinner()
a, err := app.Init(AppName)
a, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
if a.IsReviewApp() {
checkErr(fmt.Errorf("review apps do not currently support scheduled tasks"))
Expand Down Expand Up @@ -76,7 +76,7 @@ Be sure to wrap your command and schedule in quotes to ensure they are read as a
}
command := strings.Join(args, " ")
startSpinner()
a, err := app.Init(AppName)
a, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
if a.IsReviewApp() {
checkErr(fmt.Errorf("review apps do not currently support scheduled tasks"))
Expand All @@ -100,7 +100,7 @@ If no index is provided, an interactive prompt will be provided to choose the ta
DisableFlagsInUseLine: true,
Run: func(cmd *cobra.Command, args []string) {
startSpinner()
a, err := app.Init(AppName)
a, err := app.Init(AppName, UseAWSCredentials)
checkErr(err)
if a.IsReviewApp() {
checkErr(fmt.Errorf("review apps do not currently support scheduled tasks"))
Expand Down Expand Up @@ -143,7 +143,7 @@ If no index is provided, an interactive prompt will be provided to choose the ta
func init() {
rootCmd.AddCommand(scheduledTasksCmd)
scheduledTasksCmd.PersistentFlags().StringVarP(&AppName, "app-name", "a", "", "app name (required)")
scheduledTasksCmd.MarkPersistentFlagRequired("app-name")
scheduledTasksCmd.PersistentFlags().BoolVar(&UseAWSCredentials, "aws-credentials", false, "use AWS credentials instead of AppPack.io federation")

scheduledTasksCmd.AddCommand(scheduledTasksCreateCmd)
scheduledTasksCreateCmd.Flags().StringVarP(&schedule, "schedule", "s", "", "cron-like schedule. See https://docs.aws.amazon.com/eventbridge/latest/userguide/scheduled-events.html#cron-expressions")
Expand Down

0 comments on commit 1fc9d63

Please sign in to comment.