cli/cli.go (94 lines of code) (raw):

/* * Copyright (c) 2018 Uber Technologies, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Package cli is reponsible for cli interaction package cli import ( "fmt" "io" "os" "os/exec" "syscall" assumerole "github.com/uber/assume-role-cli" ) // credentialsToEnv takes credentials and outputs them as a list of environment // variables. func credentialsToEnv(creds *assumerole.TemporaryCredentials) (envVars []string) { envVars = append(envVars, fmt.Sprintf("%s=%s", "AWS_ACCESS_KEY_ID", creds.AccessKeyID), fmt.Sprintf("%s=%s", "AWS_SECRET_ACCESS_KEY", creds.SecretAccessKey), fmt.Sprintf("%s=%s", "AWS_SESSION_TOKEN", creds.SessionToken), ) return envVars } // execute will act like "exec <cmd> [args ...]" in a shell, first searching // for cmd in the path and then ecxecuting it, replacing the current running // process. func execute(cmd string, args []string, env []string) error { binary, err := exec.LookPath(cmd) if err != nil { return err } // execve will replace the current running process on success return syscall.Exec(binary, args, env) } func loadApp(stdin io.Reader, stdout io.Writer, stderr io.Writer) (*assumerole.App, error) { appOpts := []assumerole.Option{ assumerole.WithStdin(stdin), assumerole.WithStderr(stderr), } configFile, err := findConfigFile() if err != nil { return nil, err } if configFile != "" { config, err := assumerole.LoadConfig(configFile) if err != nil { return nil, err } appOpts = append(appOpts, assumerole.WithConfig(config)) } return assumerole.NewApp(appOpts...) } func printHelp(out io.Writer) { fmt.Fprint(out, `Assume an AWS role and run the specified command. Usage: assume-role [options] <command> [args ...] Options: --help Help for assume-role -f, --force-refresh Forces credentials refresh irrespective of their expiry --role string Name of the role to assume --role-session-name string Name of the session for the assumed role `) } func printVars(vars []string, out io.Writer) { for _, x := range vars { fmt.Fprintf(out, "%s\n", x) } } // Main is the main entry point into the CLI program. func Main(stdin io.Reader, stdout io.Writer, stderr io.Writer, args []string) (exitCode int) { if len(args) == 1 && (args[0] == "-h" || args[0] == "--help") { printHelp(stdout) return 0 } app, err := loadApp(stdin, stdout, stderr) if err != nil { fmt.Fprintf(stderr, "ERROR: %v\n", err) return 1 } userOpts, err := parseOptions(args) if err != nil { fmt.Fprintf(stderr, "ERROR: %v\n", err) return 1 } credentials, err := app.AssumeRole(assumerole.AssumeRoleParameters{ ForceRefresh: userOpts.forceRefresh, UserRole: userOpts.role, RoleSessionName: userOpts.roleSessionName, }) if err != nil { fmt.Fprintf(stderr, "ERROR: %v\n", err) return 1 } vars := credentialsToEnv(credentials) if len(userOpts.args) == 0 { // Print vars to stdout printVars(vars, stdout) } else { // Add AWS credentials to the environment env := append(os.Environ(), vars...) // execve will replace the current running process on success if err := execute(userOpts.args[0], userOpts.args, env); err != nil { fmt.Fprintf(stderr, "ERROR: Could not execute command: %v\n", err) return 127 } } return 0 }