github.com/dahs81/otto@v0.2.1-0.20160126165905-6400716cf085/builtin/infra/aws/infra.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "strings" 8 9 "github.com/hashicorp/otto/helper/bindata" 10 "github.com/hashicorp/otto/helper/sshagent" 11 "github.com/hashicorp/otto/helper/terraform" 12 "github.com/hashicorp/otto/infrastructure" 13 "github.com/hashicorp/otto/ui" 14 "github.com/mitchellh/go-homedir" 15 ) 16 17 //go:generate go-bindata -pkg=aws -nomemcopy -nometadata ./data/... 18 19 // Infra returns the infrastructure.Infrastructure implementation. 20 // This function is a infrastructure.Factory. 21 func Infra() (infrastructure.Infrastructure, error) { 22 return &terraform.Infrastructure{ 23 CredsFunc: creds, 24 VerifyCredsFunc: verifyCreds, 25 Bindata: &bindata.Data{ 26 Asset: Asset, 27 AssetDir: AssetDir, 28 }, 29 Variables: map[string]string{ 30 "aws_region": "us-east-1", 31 }, 32 }, nil 33 } 34 35 func creds(ctx *infrastructure.Context) (map[string]string, error) { 36 fields := []*ui.InputOpts{ 37 &ui.InputOpts{ 38 Id: "aws_access_key", 39 Query: "AWS Access Key", 40 Description: "AWS access key used for API calls.", 41 EnvVars: []string{"AWS_ACCESS_KEY_ID"}, 42 }, 43 &ui.InputOpts{ 44 Id: "aws_secret_key", 45 Query: "AWS Secret Key", 46 Description: "AWS secret key used for API calls.", 47 EnvVars: []string{"AWS_SECRET_ACCESS_KEY"}, 48 }, 49 &ui.InputOpts{ 50 Id: "ssh_public_key_path", 51 Query: "SSH Public Key Path", 52 Description: "Path to an SSH public key that will be granted access to EC2 instances", 53 Default: "~/.ssh/id_rsa.pub", 54 EnvVars: []string{"AWS_SSH_PUBLIC_KEY_PATH"}, 55 }, 56 } 57 58 result := make(map[string]string, len(fields)) 59 for _, f := range fields { 60 value, err := ctx.Ui.Input(f) 61 if err != nil { 62 return nil, err 63 } 64 65 result[f.Id] = value 66 } 67 68 // Load SSH public key contents 69 sshPath, err := homedir.Expand(result["ssh_public_key_path"]) 70 if err != nil { 71 return nil, fmt.Errorf("Error expanding homedir for SSH key: %s", err) 72 } 73 74 sshKey, err := ioutil.ReadFile(sshPath) 75 if err != nil { 76 return nil, fmt.Errorf("Error reading SSH key: %s", err) 77 } 78 result["ssh_public_key"] = string(sshKey) 79 80 return result, nil 81 } 82 83 func verifyCreds(ctx *infrastructure.Context) error { 84 found, err := sshagent.HasKey(ctx.InfraCreds["ssh_public_key"]) 85 if err != nil { 86 return sshAgentError(err) 87 } 88 if !found { 89 ok, _ := guessAndLoadPrivateKey( 90 ctx.Ui, ctx.InfraCreds["ssh_public_key_path"]) 91 if ok { 92 ctx.Ui.Message( 93 "A private key was found and loaded. Otto will now check\n" + 94 "the SSH Agent again and continue if the correct key is loaded") 95 96 found, err = sshagent.HasKey(ctx.InfraCreds["ssh_public_key"]) 97 if err != nil { 98 return sshAgentError(err) 99 } 100 } 101 } 102 103 if !found { 104 return sshAgentError(fmt.Errorf( 105 "You specified an SSH public key of: %q, but the private key from this\n"+ 106 "keypair is not loaded the SSH Agent. To load it, run:\n\n"+ 107 " ssh-add [PATH_TO_PRIVATE_KEY]", 108 ctx.InfraCreds["ssh_public_key_path"])) 109 } 110 return nil 111 } 112 113 func sshAgentError(err error) error { 114 return fmt.Errorf( 115 "Otto uses your SSH Agent to authenticate with instances created in\n"+ 116 "AWS, but it could not verify that your SSH key is loaded into the agent.\n"+ 117 "The error message follows:\n\n%s", err) 118 } 119 120 // guessAndLoadPrivateKey takes a path to a public key and determines if a 121 // private key exists by just stripping ".pub" from the end of it. if so, 122 // it attempts to load that key into the agent. 123 func guessAndLoadPrivateKey(ui ui.Ui, pubKeyPath string) (bool, error) { 124 fullPath, err := homedir.Expand(pubKeyPath) 125 if err != nil { 126 return false, err 127 } 128 if !strings.HasSuffix(fullPath, ".pub") { 129 return false, fmt.Errorf("No .pub suffix, cannot guess path.") 130 } 131 privKeyGuess := strings.TrimSuffix(fullPath, ".pub") 132 if _, err := os.Stat(privKeyGuess); os.IsNotExist(err) { 133 return false, fmt.Errorf("No file at guessed path.") 134 } 135 136 ui.Header("Loading key into SSH Agent") 137 ui.Message(fmt.Sprintf( 138 "The key you provided (%s) was not found in your SSH Agent.", pubKeyPath)) 139 ui.Message(fmt.Sprintf( 140 "However, Otto found a private key here: %s", privKeyGuess)) 141 ui.Message(fmt.Sprintf( 142 "Automatically running 'ssh-add %s'.", privKeyGuess)) 143 ui.Message("If your SSH key has a passphrase, you will be prompted for it.") 144 ui.Message("") 145 146 if err := sshagent.Add(ui, privKeyGuess); err != nil { 147 return false, err 148 } 149 150 return true, nil 151 }