forked from 99designs/aws-vault
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserver.go
121 lines (99 loc) · 2.99 KB
/
server.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"net"
"net/http"
"os"
"os/exec"
"time"
)
const (
metadataBind = "169.254.169.254:80"
awsTimeFormat = "2006-01-02T15:04:05Z"
localServerUrl = "http://127.0.0.1:9099"
localServerBind = "127.0.0.1:9099"
)
type ServerCommandInput struct {
}
func ServerCommand(ui Ui, input ServerCommandInput) {
if output, err := installNetworkAlias(); err != nil {
ui.Error.Println(string(output))
ui.Error.Fatal(err)
}
router := http.NewServeMux()
router.HandleFunc("/latest/meta-data/iam/security-credentials/", indexHandler)
router.HandleFunc("/latest/meta-data/iam/security-credentials/local-credentials", credentialsHandler)
l, err := net.Listen("tcp", metadataBind)
if err != nil {
ui.Error.Fatal(err)
}
ui.Debug.Printf("Local instance role server running on %s", l.Addr())
ui.Println(http.Serve(l, router))
}
type metadataHandler struct {
http.Handler
}
func indexHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "local-credentials")
}
func credentialsHandler(w http.ResponseWriter, r *http.Request) {
resp, err := http.Get(localServerUrl)
if err != nil {
http.Error(w, err.Error(), http.StatusGatewayTimeout)
return
}
defer resp.Body.Close()
log.Printf("Fetched credentials from %s", localServerUrl)
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
io.Copy(w, resp.Body)
}
func installNetworkAlias() ([]byte, error) {
return exec.Command("ifconfig", "lo0", "alias", "169.254.169.254").CombinedOutput()
}
func checkServerRunning(bind string) bool {
_, err := net.DialTimeout("tcp", bind, time.Millisecond*10)
return err == nil
}
func startCredentialsServer(ui Ui, creds *VaultCredentials) error {
if !checkServerRunning(metadataBind) {
ui.Error.Println("Starting `aws-vault server` as root in the background")
cmd := exec.Command("sudo", "-b", os.Args[0], "server")
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return err
}
}
l, err := net.Listen("tcp", localServerBind)
if err != nil {
return err
}
log.Printf("Local instance role server running on %s", l.Addr())
go http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("Credentials.IsExpired() = %#v", creds.IsExpired())
val, err := creds.Get()
if err != nil {
http.Error(w, err.Error(), http.StatusGatewayTimeout)
return
}
log.Printf("Serving credentials via http ****************%s, expiration of %s (%s)",
val.AccessKeyID[len(val.AccessKeyID)-4:],
creds.Expires().Format(awsTimeFormat),
creds.Expires().Sub(time.Now()).String())
json.NewEncoder(w).Encode(map[string]interface{}{
"Code": "Success",
"LastUpdated": time.Now().Format(awsTimeFormat),
"Type": "AWS-HMAC",
"AccessKeyId": val.AccessKeyID,
"SecretAccessKey": val.SecretAccessKey,
"Token": val.SessionToken,
"Expiration": creds.Expires().Format(awsTimeFormat),
})
}))
return nil
}