From 9b950ec676fc3a9679def6b226e93bc947a3f154 Mon Sep 17 00:00:00 2001 From: Josh Mullins Date: Tue, 3 Jan 2023 15:45:11 -0500 Subject: [PATCH 1/7] Added new hologram console command --- cmd/hologram/main.go | 111 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/cmd/hologram/main.go b/cmd/hologram/main.go index f1542d7..87a93b9 100644 --- a/cmd/hologram/main.go +++ b/cmd/hologram/main.go @@ -16,10 +16,16 @@ package main import ( + "encoding/json" "flag" "fmt" + "io" "io/ioutil" + "net/http" + "net/url" "os" + "os/exec" + "runtime" "github.com/AdRoll/hologram/log" "github.com/AdRoll/hologram/protocol" @@ -53,9 +59,19 @@ func main() { case "me": err = me() break + case "console": + err = launchConsole() case "version": fmt.Println(Version) break + case "help": + fmt.Println("Usage: hologram ") + fmt.Println("Commands:") + fmt.Println(" use - Assume a role") + fmt.Println(" me - Get credentials for the current user") + fmt.Println(" console - Log into the AWS console via the default browser") + fmt.Println(" version - Print version") + fmt.Println(" help - Print this help message") default: fmt.Println("Usage: hologram use ") os.Exit(1) @@ -156,3 +172,98 @@ func request(req *protocol.AgentRequest) (*protocol.AgentResponse, error) { return response.GetAgentResponse(), nil } + +type HttpHologramCredentials struct { + Code string + LastUpdated string + Type string + AccessKeyId string + SecretAccessKey string + Token string + Expiration string +} + +type HttpAwsCredentials struct { + SessionId string `json:"sessionId"` + SessionKey string `json:"sessionKey"` + SessionToken string `json:"sessionToken"` +} + +type HttpFederationSigninToken struct { + SigninToken string +} + +func launchConsole() error { + federationUrlBase := "https://signin.aws.amazon.com/federation" + profileUrl := "http://169.254.169.254/latest/meta-data/iam/security-credentials/" + awsConsoleUrl := "https://console.aws.amazon.com/" + + // Get the profile name from the metadata service + response, err := http.Get(profileUrl) + defer response.Body.Close() + if err != nil { + return err + } + profileBytes, err := io.ReadAll(response.Body) + if err != nil { + return err + } + profile := string(profileBytes) + + // Get the credentials from the metadata service + metadataUrl := fmt.Sprintf("%v%v", profileUrl, profile) + response, err = http.Get(metadataUrl) + defer response.Body.Close() + if err != nil { + return err + } + if response.StatusCode != 200 { + return fmt.Errorf("error getting credentials. Try running 'hologram me'") + } + metadataBytes, err := io.ReadAll(response.Body) + if err != nil { + return err + } + credentials := HttpHologramCredentials{} + err = json.Unmarshal(metadataBytes, &credentials) + if err != nil { + // TODO add SyntaxError handling for when hologram me hasn't run yet + return err + } + + // Get the federation signin token + awsCreds := HttpAwsCredentials{ + SessionId: credentials.AccessKeyId, + SessionKey: credentials.SecretAccessKey, + SessionToken: credentials.Token, + } + awsCredsJson, err := json.Marshal(awsCreds) + signinTokenUrl := fmt.Sprintf("%v?Action=getSigninToken&SessionDuration=43200&Session=%v", federationUrlBase, url.QueryEscape(string(awsCredsJson))) + response, err = http.Get(signinTokenUrl) + defer response.Body.Close() + if err != nil { + return err + } + signinToken_bytes, err := io.ReadAll(response.Body) + if err != nil { + return err + } + signinToken := HttpFederationSigninToken{} + err = json.Unmarshal(signinToken_bytes, &signinToken) + if err != nil { + return err + } + + // Get the federation login URL + federationUrl := fmt.Sprintf("%v?Action=login&Issuer=Hologram&Destination=%v&SigninToken=%v", federationUrlBase, url.QueryEscape(awsConsoleUrl), signinToken.SigninToken) + + // Open the URL in the browser + switch runtime.GOOS { + case "darwin": + err = exec.Command("open", federationUrl).Start() + default: + return fmt.Errorf("unsupported OS: %v", runtime.GOOS) + } + + return err +} From 2de62e904a89265a7f0721ffe093ce3b0ed2a3c4 Mon Sep 17 00:00:00 2001 From: Josh Mullins Date: Tue, 3 Jan 2023 15:45:47 -0500 Subject: [PATCH 2/7] Updated to golang 1.19.4 --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index d4e0f7a..d441f61 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.17.5 +FROM golang:1.19.4 RUN echo 'deb http://deb.debian.org/debian stretch main' >> /etc/apt/sources.list @@ -26,7 +26,7 @@ RUN cd /tmp && wget https://github.com/google/protobuf/releases/download/v2.6.1/ WORKDIR /tmp # Get dependencies for building hologram -RUN go get github.com/jteeuwen/go-bindata/... +RUN go install github.com/jteeuwen/go-bindata/... RUN git clone https://github.com/pote/gpm.git && cd gpm && ./configure && make install && rm -rf /tmp/gpm RUN wget https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/xar/xar-1.5.2.tar.gz && tar xf xar-1.5.2.tar.gz && cd xar-1.5.2 && ./configure && make && make install && rm -rf /tmp/xar-1.5.2 RUN git clone https://github.com/hogliux/bomutils.git > /dev/null && cd bomutils && make > /dev/null && make install > /dev/null && rm -rf /tmp/bomutils From 7d97005b8c2cf81828d8baedf9059b028b299b0b Mon Sep 17 00:00:00 2001 From: Josh Mullins Date: Tue, 3 Jan 2023 15:45:59 -0500 Subject: [PATCH 3/7] Updated deps --- go.mod | 24 ++++++++++++------------ go.sum | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 7e84266..e7105e3 100644 --- a/go.mod +++ b/go.mod @@ -3,20 +3,20 @@ module github.com/AdRoll/hologram go 1.17 require ( - github.com/aws/aws-sdk-go v1.4.21-0.20161031215218-ed981a1d5ee7 - github.com/aybabtme/rgbterm v0.0.0-20151029041548-c9a1bdb3761d - github.com/go-ini/ini v1.66.2 // indirect + github.com/aws/aws-sdk-go v1.44.160 + github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 + github.com/go-ini/ini v1.67.0 // indirect github.com/golang/protobuf v1.5.2 github.com/gopherjs/gopherjs v0.0.0-20220104163920-15ed2e8cf2bd // indirect - github.com/howeyc/gopass v0.0.0-20161003130900-f5387c492211 + github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/mitchellh/go-homedir v1.0.0 - github.com/nmcclain/asn1-ber v0.0.0-20140416010459-ec51d5ed2137 // indirect - github.com/nmcclain/ldap v0.0.0-20160601145537-6e14e8271933 - github.com/peterbourgon/g2s v0.0.0-20160722085717-5767a0b20786 + github.com/mitchellh/go-homedir v1.1.0 + github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484 // indirect + github.com/nmcclain/ldap v0.0.0-20210720162743-7f8d1e44eeba + github.com/peterbourgon/g2s v0.0.0-20170223122336-d4e7ad98afea github.com/smartystreets/goconvey v1.6.4 - golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 - golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect + golang.org/x/crypto v0.4.0 + golang.org/x/sys v0.3.0 // indirect ) require ( @@ -24,8 +24,8 @@ require ( github.com/jtolds/gls v4.20.0+incompatible // indirect github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect github.com/stretchr/testify v1.7.0 // indirect - golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect - google.golang.org/protobuf v1.26.0 // indirect + golang.org/x/term v0.3.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) diff --git a/go.sum b/go.sum index 49cf022..b02fc70 100644 --- a/go.sum +++ b/go.sum @@ -45,8 +45,12 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aws/aws-sdk-go v1.4.21-0.20161031215218-ed981a1d5ee7 h1:ivJK51kDsa1rpmWUEVHbfUCYsOkmoHs3Psn9XZqdT7k= github.com/aws/aws-sdk-go v1.4.21-0.20161031215218-ed981a1d5ee7/go.mod h1:ZRmQr0FajVIyZ4ZzBYKG5P3ZqPz9IHG41ZoMu1ADI3k= +github.com/aws/aws-sdk-go v1.44.160 h1:F41sWUel1CJ69ezoBGCg8sDyu9kyeKEpwmDrLXbCuyA= +github.com/aws/aws-sdk-go v1.44.160/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aybabtme/rgbterm v0.0.0-20151029041548-c9a1bdb3761d h1:3Lbj1S1Gx5zRB1wSKWW0+2tX96JecE6Q9AlKP3DkdwQ= github.com/aybabtme/rgbterm v0.0.0-20151029041548-c9a1bdb3761d/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= +github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= +github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -78,6 +82,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ini/ini v1.66.2 h1:IxZmi/R4Yo7inPSXdoPtbL3rGyWaAm+Wy+QoornDenQ= github.com/go-ini/ini v1.66.2/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= +github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -170,6 +176,8 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/howeyc/gopass v0.0.0-20161003130900-f5387c492211 h1:IDxI/EaCdmlyCtkiwK0hqqN4Wp+QAP5nFZGAj7w7nWY= github.com/howeyc/gopass v0.0.0-20161003130900-f5387c492211/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= +github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef h1:A9HsByNhogrvm9cWb28sjiS3i7tcKCkflWFEkHfuAgM= +github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -195,6 +203,8 @@ github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3N github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= @@ -208,13 +218,20 @@ github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJE github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/nmcclain/asn1-ber v0.0.0-20140416010459-ec51d5ed2137 h1:qf83gL84qBpNhsNxj+NPWSZKC7E+oUf1Ses0hg4s47U= github.com/nmcclain/asn1-ber v0.0.0-20140416010459-ec51d5ed2137/go.mod h1:O1EljZ+oHprtxDDPHiMWVo/5dBT6PlvWX5PSwj80aBA= +github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484 h1:D9EvfGQvlkKaDr2CRKN++7HbSXbefUNDrPq60T+g24s= +github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484/go.mod h1:O1EljZ+oHprtxDDPHiMWVo/5dBT6PlvWX5PSwj80aBA= github.com/nmcclain/ldap v0.0.0-20160601145537-6e14e8271933 h1:0Fd8aTYHbLx4Wx2aT048Z8KT93VgzY9XmCV6DjHFDPw= github.com/nmcclain/ldap v0.0.0-20160601145537-6e14e8271933/go.mod h1:YtrVB1/v9Td9SyjXpjYVmbdKgj9B0nPTBsdGUxy0i8U= +github.com/nmcclain/ldap v0.0.0-20210720162743-7f8d1e44eeba h1:DO8NFYdcRv1dnyAINJIBm6Bw2XibtLvQniNFGzf2W8E= +github.com/nmcclain/ldap v0.0.0-20210720162743-7f8d1e44eeba/go.mod h1:4S0XndRL8HNOaQBfdViJ2F/GPCgL524xlXRuXFH12/U= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/g2s v0.0.0-20160722085717-5767a0b20786 h1:OfKbTJrjtnlYr/07QQ5lmxnLiPOEfM8WncWyYqCIIkA= github.com/peterbourgon/g2s v0.0.0-20160722085717-5767a0b20786/go.mod h1:1VcHEd3ro4QMoHfiNl/j7Jkln9+KQuorp0PItHMJYNg= +github.com/peterbourgon/g2s v0.0.0-20170223122336-d4e7ad98afea h1:sKwxy1H95npauwu8vtF95vG/syrL0p8fSZo/XlDg5gk= +github.com/peterbourgon/g2s v0.0.0-20170223122336-d4e7ad98afea/go.mod h1:1VcHEd3ro4QMoHfiNl/j7Jkln9+KQuorp0PItHMJYNg= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -253,6 +270,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= @@ -275,6 +293,9 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8= +golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -310,6 +331,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -346,6 +368,8 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -369,6 +393,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -414,8 +439,17 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -423,6 +457,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -478,6 +514,7 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -586,6 +623,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= From c535d46d0fe4b729311483c34e9c3e4aa0017917 Mon Sep 17 00:00:00 2001 From: Josh Mullins Date: Wed, 4 Jan 2023 15:18:02 -0500 Subject: [PATCH 4/7] Added additional console command flags --- cmd/hologram/main.go | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/cmd/hologram/main.go b/cmd/hologram/main.go index 87a93b9..317b014 100644 --- a/cmd/hologram/main.go +++ b/cmd/hologram/main.go @@ -26,6 +26,7 @@ import ( "os" "os/exec" "runtime" + "time" "github.com/AdRoll/hologram/log" "github.com/AdRoll/hologram/protocol" @@ -198,6 +199,16 @@ func launchConsole() error { profileUrl := "http://169.254.169.254/latest/meta-data/iam/security-credentials/" awsConsoleUrl := "https://console.aws.amazon.com/" + // Parse optional flags + cmd := flag.NewFlagSet("console", flag.ExitOnError) + newSession := cmd.Bool("new-session", false, "Start a new Google Chrome session. This allows use of multiple roles simultaneously.") + showUrl := cmd.Bool("show-url", false, "Show the federation URL used for sign-in.") + noLaunch := cmd.Bool("no-launch", false, "Don't launch the browser.") + err := cmd.Parse(os.Args[2:]) + if err != nil { + return err + } + // Get the profile name from the metadata service response, err := http.Get(profileUrl) defer response.Body.Close() @@ -257,10 +268,34 @@ func launchConsole() error { // Get the federation login URL federationUrl := fmt.Sprintf("%v?Action=login&Issuer=Hologram&Destination=%v&SigninToken=%v", federationUrlBase, url.QueryEscape(awsConsoleUrl), signinToken.SigninToken) + // if --show-url is set, print the URL + if *showUrl { + fmt.Println(federationUrl) + } + // if --no-launch is set, stop here + if *noLaunch { + return nil + } + // Open the URL in the browser + var openArgs []string switch runtime.GOOS { case "darwin": - err = exec.Command("open", federationUrl).Start() + if *newSession { + dateSeconds := time.Now().Unix() + userDataDir := fmt.Sprintf("/tmp/hologram_session_%v/", dateSeconds) + err := os.MkdirAll(userDataDir, 0755) + if err != nil { + return err + } + _, err = os.Create(fmt.Sprintf("%v/First Run", userDataDir)) + if err != nil { + return err + } + openArgs = append(openArgs, "-na", "Google Chrome", "--args", "--user-data-dir="+userDataDir) + } + openArgs = append(openArgs, federationUrl) + err = exec.Command("open", openArgs...).Run() default: return fmt.Errorf("unsupported OS: %v", runtime.GOOS) } From f0b4cb9149d59f3de30baaca8fec5d5a11693ea5 Mon Sep 17 00:00:00 2001 From: Josh Mullins Date: Thu, 5 Jan 2023 16:39:12 -0500 Subject: [PATCH 5/7] Refactoring and switching from flag to cobra --- cmd/hologram/console.go | 158 +++++++++++++++++++++ cmd/hologram/helpers.go | 57 ++++++++ cmd/hologram/main.go | 305 ++-------------------------------------- cmd/hologram/me.go | 46 ++++++ cmd/hologram/use.go | 53 +++++++ cmd/hologram/version.go | 35 +++++ go.mod | 5 +- go.sum | 10 ++ 8 files changed, 378 insertions(+), 291 deletions(-) create mode 100644 cmd/hologram/console.go create mode 100644 cmd/hologram/helpers.go create mode 100644 cmd/hologram/me.go create mode 100644 cmd/hologram/use.go create mode 100644 cmd/hologram/version.go diff --git a/cmd/hologram/console.go b/cmd/hologram/console.go new file mode 100644 index 0000000..5b189d1 --- /dev/null +++ b/cmd/hologram/console.go @@ -0,0 +1,158 @@ +package main + +import ( + "encoding/json" + "fmt" + "github.com/AdRoll/hologram/log" + "github.com/spf13/cobra" + "io" + "net/http" + "net/url" + "os" + "os/exec" + "runtime" + "time" +) + +func init() { + consoleCmd.Flags().Bool("new-session", false, "Start a new Google Chrome session. This allows use of multiple roles simultaneously.") + consoleCmd.Flags().Bool("show-url", false, "Show the federation URL used for sign-in.") + consoleCmd.Flags().Bool("no-launch", false, "Don't launch the browser.") + rootCmd.AddCommand(consoleCmd) +} + +var consoleCmd = &cobra.Command{ + Use: "console", + Short: "Open the AWS console in the default browser", + Run: func(cmd *cobra.Command, args []string) { + newSession, err := cmd.Flags().GetBool("new-session") + showUrl, err := cmd.Flags().GetBool("show-url") + noLaunch, err := cmd.Flags().GetBool("no-launch") + if err == nil { + err = launchConsole(newSession, showUrl, noLaunch) + } + + if err != nil { + log.Errorf("%s", err) + os.Exit(1) + } + }, +} + +type HttpHologramCredentials struct { + Code string + LastUpdated string + Type string + AccessKeyId string + SecretAccessKey string + Token string + Expiration string +} + +type HttpAwsCredentials struct { + SessionId string `json:"sessionId"` + SessionKey string `json:"sessionKey"` + SessionToken string `json:"sessionToken"` +} + +type HttpFederationSigninToken struct { + SigninToken string +} + +func launchConsole(newSession bool, showUrl bool, noLaunch bool) error { + federationUrlBase := "https://signin.aws.amazon.com/federation" + profileUrl := "http://169.254.169.254/latest/meta-data/iam/security-credentials/" + awsConsoleUrl := "https://console.aws.amazon.com/" + + // Get the profile name from the metadata service + response, err := http.Get(profileUrl) + defer response.Body.Close() + if err != nil { + return err + } + profileBytes, err := io.ReadAll(response.Body) + if err != nil { + return err + } + profile := string(profileBytes) + + // Get the credentials from the metadata service + metadataUrl := fmt.Sprintf("%v%v", profileUrl, profile) + response, err = http.Get(metadataUrl) + defer response.Body.Close() + if err != nil { + return err + } + if response.StatusCode != 200 { + return fmt.Errorf("error getting credentials. Try running 'hologram me'") + } + metadataBytes, err := io.ReadAll(response.Body) + if err != nil { + return err + } + credentials := HttpHologramCredentials{} + err = json.Unmarshal(metadataBytes, &credentials) + if err != nil { + return err + } + + // Get the federation signin token + awsCreds := HttpAwsCredentials{ + SessionId: credentials.AccessKeyId, + SessionKey: credentials.SecretAccessKey, + SessionToken: credentials.Token, + } + awsCredsJson, err := json.Marshal(awsCreds) + signinTokenUrl := fmt.Sprintf("%v?Action=getSigninToken&SessionDuration=43200&Session=%v", federationUrlBase, url.QueryEscape(string(awsCredsJson))) + response, err = http.Get(signinTokenUrl) + defer response.Body.Close() + if err != nil { + return err + } + signinToken_bytes, err := io.ReadAll(response.Body) + if err != nil { + return err + } + signinToken := HttpFederationSigninToken{} + err = json.Unmarshal(signinToken_bytes, &signinToken) + if err != nil { + return err + } + + // Get the federation login URL + federationUrl := fmt.Sprintf("%v?Action=login&Issuer=Hologram&Destination=%v&SigninToken=%v", federationUrlBase, url.QueryEscape(awsConsoleUrl), signinToken.SigninToken) + + // if --show-url is set, print the URL + if showUrl { + fmt.Println(federationUrl) + } + // if --no-launch is set, stop here + if noLaunch { + return nil + } + + // Open the URL in the browser + var openArgs []string + switch runtime.GOOS { + case "darwin": + if newSession { + dateSeconds := time.Now().Unix() + userDataDir := fmt.Sprintf("/tmp/hologram_session_%v/", dateSeconds) + err := os.MkdirAll(userDataDir, 0755) + if err != nil { + return err + } + _, err = os.Create(fmt.Sprintf("%v/First Run", userDataDir)) + if err != nil { + return err + } + openArgs = append(openArgs, "-na", "Google Chrome", "--args", "--user-data-dir="+userDataDir) + } + openArgs = append(openArgs, federationUrl) + err = exec.Command("open", openArgs...).Run() + default: + return fmt.Errorf("unsupported OS: %v", runtime.GOOS) + } + + return err +} \ No newline at end of file diff --git a/cmd/hologram/helpers.go b/cmd/hologram/helpers.go new file mode 100644 index 0000000..d3ce0b0 --- /dev/null +++ b/cmd/hologram/helpers.go @@ -0,0 +1,57 @@ +package main + +import ( + "fmt" + "github.com/AdRoll/hologram/log" + "github.com/AdRoll/hologram/protocol" + "github.com/AdRoll/hologram/transport/local" + "github.com/mitchellh/go-homedir" + "io/ioutil" + "os" +) + +func request(req *protocol.AgentRequest) (*protocol.AgentResponse, error) { + client, err := local.NewClient("/var/run/hologram.sock") + if err != nil { + return nil, fmt.Errorf("Unable to connect to hologram socket. Is hologram-agent running? Error: %s", err.Error()) + } + + // Try to get to the user's SSH agent, for best compatibility. + // However, some agents are broken, so we should also try to + // include the ssh key contents. + sshAgentSock := os.Getenv("SSH_AUTH_SOCK") + req.SshAgentSock = &sshAgentSock + + // Send along the raw bytes of the SSH key. + // TODO(silversupreme): Add in logic for id_dsa, id_ecdsa, etc. + if sshDir, homeErr := homedir.Expand("~/.ssh"); homeErr == nil { + sshFilename := fmt.Sprintf("%s/id_rsa", sshDir) + if sshKeyBytes, keyReadErr := ioutil.ReadFile(sshFilename); keyReadErr == nil { + req.SshKeyFile = sshKeyBytes + } else { + log.Debug("Falling back on DSA key.") + // Fallback on a user's DSA key if they have one. + sshFilename := fmt.Sprintf("%s/id_dsa", sshDir) + if sshKeyBytes, keyReadErr := ioutil.ReadFile(sshFilename); keyReadErr == nil { + req.SshKeyFile = sshKeyBytes + } + } + } + + msg := &protocol.Message{ + AgentRequest: req, + } + + err = client.Write(msg) + if err != nil { + return nil, err + } + + response, err := client.Read() + + if response.GetAgentResponse() == nil { + return nil, fmt.Errorf("unexpected response type: %v", response) + } + + return response.GetAgentResponse(), nil +} diff --git a/cmd/hologram/main.go b/cmd/hologram/main.go index 317b014..9fbc69e 100644 --- a/cmd/hologram/main.go +++ b/cmd/hologram/main.go @@ -1,304 +1,29 @@ -// Copyright 2014 AdRoll, 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. - -// Hologram workstation CLI. package main import ( - "encoding/json" - "flag" "fmt" - "io" - "io/ioutil" - "net/http" - "net/url" + "github.com/spf13/cobra" "os" - "os/exec" - "runtime" - "time" - - "github.com/AdRoll/hologram/log" - "github.com/AdRoll/hologram/protocol" - "github.com/AdRoll/hologram/transport/local" - "github.com/mitchellh/go-homedir" ) // Version will be linked at compile time var Version = "Unknown - Not built using standard process" -func main() { - flag.Parse() - - args := flag.Args() - - var err error - - if len(args) < 1 { - fmt.Println("Usage: hologram ") - os.Exit(1) - } - - switch args[0] { - case "use": - if len(args) < 2 { - fmt.Println("Usage: hologram use ") - os.Exit(1) - } - err = use(args[1]) - break - case "me": - err = me() - break - case "console": - err = launchConsole() - case "version": - fmt.Println(Version) - break - case "help": - fmt.Println("Usage: hologram ") - fmt.Println("Commands:") - fmt.Println(" use - Assume a role") - fmt.Println(" me - Get credentials for the current user") - fmt.Println(" console - Log into the AWS console via the default browser") - fmt.Println(" version - Print version") - fmt.Println(" help - Print this help message") - default: - fmt.Println("Usage: hologram use ") - os.Exit(1) - } - - if err != nil { - log.Errorf(err.Error()) - os.Exit(1) - } -} - -func use(role string) error { - response, err := request(&protocol.AgentRequest{ - AssumeRole: &protocol.AssumeRole{ - Role: &role, - }, - }) - if err != nil { - return err - } - - if response.GetFailure() != nil { - return fmt.Errorf(response.GetFailure().GetErrorMessage()) - } - - if response.GetSuccess() != nil { - output := fmt.Sprintf("Successfully got credentials for role '%s'", role) - log.Info(output) - return nil - } - - return fmt.Errorf("Unexpected response type: %v", response) -} - -func me() error { - response, err := request(&protocol.AgentRequest{ - GetUserCredentials: &protocol.GetUserCredentials{}, - }) - - if err != nil { - return err - } - - if response.GetFailure() != nil { - return fmt.Errorf("Error from server: %s", response.GetFailure().GetErrorMessage()) - } - - if response.GetSuccess() != nil { - log.Info("Successfully loaded credentials for you") - return nil - } - - return fmt.Errorf("Unexpected response type: %v", response) -} - -func request(req *protocol.AgentRequest) (*protocol.AgentResponse, error) { - client, err := local.NewClient("/var/run/hologram.sock") - if err != nil { - return nil, fmt.Errorf("Unable to connect to hologram socket. Is hologram-agent running? Error: %s", err.Error()) - } - - // Try to get to the user's SSH agent, for best compatibility. - // However, some agents are broken, so we should also try to - // include the ssh key contents. - sshAgentSock := os.Getenv("SSH_AUTH_SOCK") - req.SshAgentSock = &sshAgentSock - - // Send along the raw bytes of the SSH key. - // TODO(silversupreme): Add in logic for id_dsa, id_ecdsa, etc. - if sshDir, homeErr := homedir.Expand("~/.ssh"); homeErr == nil { - sshFilename := fmt.Sprintf("%s/id_rsa", sshDir) - if sshKeyBytes, keyReadErr := ioutil.ReadFile(sshFilename); keyReadErr == nil { - req.SshKeyFile = sshKeyBytes - } else { - log.Debug("Falling back on DSA key.") - // Fallback on a user's DSA key if they have one. - sshFilename := fmt.Sprintf("%s/id_dsa", sshDir) - if sshKeyBytes, keyReadErr := ioutil.ReadFile(sshFilename); keyReadErr == nil { - req.SshKeyFile = sshKeyBytes - } - } - } - - msg := &protocol.Message{ - AgentRequest: req, - } - - err = client.Write(msg) - if err != nil { - return nil, err - } - - response, err := client.Read() - - if response.GetAgentResponse() == nil { - return nil, fmt.Errorf("Unexpected response type: %v", response) - } - - return response.GetAgentResponse(), nil -} - -type HttpHologramCredentials struct { - Code string - LastUpdated string - Type string - AccessKeyId string - SecretAccessKey string - Token string - Expiration string +var rootCmd = &cobra.Command{ + Use: "hologram", + Short: "Easy, painless AWS credentials on developer laptops.", + Run: func(cmd *cobra.Command, args []string) { + _ = cmd.Help() + }, + CompletionOptions: cobra.CompletionOptions{ + HiddenDefaultCmd: true, + }, } -type HttpAwsCredentials struct { - SessionId string `json:"sessionId"` - SessionKey string `json:"sessionKey"` - SessionToken string `json:"sessionToken"` -} - -type HttpFederationSigninToken struct { - SigninToken string -} - -func launchConsole() error { - federationUrlBase := "https://signin.aws.amazon.com/federation" - profileUrl := "http://169.254.169.254/latest/meta-data/iam/security-credentials/" - awsConsoleUrl := "https://console.aws.amazon.com/" - - // Parse optional flags - cmd := flag.NewFlagSet("console", flag.ExitOnError) - newSession := cmd.Bool("new-session", false, "Start a new Google Chrome session. This allows use of multiple roles simultaneously.") - showUrl := cmd.Bool("show-url", false, "Show the federation URL used for sign-in.") - noLaunch := cmd.Bool("no-launch", false, "Don't launch the browser.") - err := cmd.Parse(os.Args[2:]) - if err != nil { - return err - } - - // Get the profile name from the metadata service - response, err := http.Get(profileUrl) - defer response.Body.Close() - if err != nil { - return err - } - profileBytes, err := io.ReadAll(response.Body) - if err != nil { - return err - } - profile := string(profileBytes) - - // Get the credentials from the metadata service - metadataUrl := fmt.Sprintf("%v%v", profileUrl, profile) - response, err = http.Get(metadataUrl) - defer response.Body.Close() - if err != nil { - return err - } - if response.StatusCode != 200 { - return fmt.Errorf("error getting credentials. Try running 'hologram me'") - } - metadataBytes, err := io.ReadAll(response.Body) - if err != nil { - return err - } - credentials := HttpHologramCredentials{} - err = json.Unmarshal(metadataBytes, &credentials) - if err != nil { - // TODO add SyntaxError handling for when hologram me hasn't run yet - return err - } - - // Get the federation signin token - awsCreds := HttpAwsCredentials{ - SessionId: credentials.AccessKeyId, - SessionKey: credentials.SecretAccessKey, - SessionToken: credentials.Token, - } - awsCredsJson, err := json.Marshal(awsCreds) - signinTokenUrl := fmt.Sprintf("%v?Action=getSigninToken&SessionDuration=43200&Session=%v", federationUrlBase, url.QueryEscape(string(awsCredsJson))) - response, err = http.Get(signinTokenUrl) - defer response.Body.Close() - if err != nil { - return err - } - signinToken_bytes, err := io.ReadAll(response.Body) - if err != nil { - return err - } - signinToken := HttpFederationSigninToken{} - err = json.Unmarshal(signinToken_bytes, &signinToken) - if err != nil { - return err - } - - // Get the federation login URL - federationUrl := fmt.Sprintf("%v?Action=login&Issuer=Hologram&Destination=%v&SigninToken=%v", federationUrlBase, url.QueryEscape(awsConsoleUrl), signinToken.SigninToken) - - // if --show-url is set, print the URL - if *showUrl { - fmt.Println(federationUrl) - } - // if --no-launch is set, stop here - if *noLaunch { - return nil - } - - // Open the URL in the browser - var openArgs []string - switch runtime.GOOS { - case "darwin": - if *newSession { - dateSeconds := time.Now().Unix() - userDataDir := fmt.Sprintf("/tmp/hologram_session_%v/", dateSeconds) - err := os.MkdirAll(userDataDir, 0755) - if err != nil { - return err - } - _, err = os.Create(fmt.Sprintf("%v/First Run", userDataDir)) - if err != nil { - return err - } - openArgs = append(openArgs, "-na", "Google Chrome", "--args", "--user-data-dir="+userDataDir) - } - openArgs = append(openArgs, federationUrl) - err = exec.Command("open", openArgs...).Run() - default: - return fmt.Errorf("unsupported OS: %v", runtime.GOOS) +func main() { + (*rootCmd).SetHelpCommand(&cobra.Command{Hidden: true}) + if err := rootCmd.Execute(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) } - - return err } diff --git a/cmd/hologram/me.go b/cmd/hologram/me.go new file mode 100644 index 0000000..ffb20a6 --- /dev/null +++ b/cmd/hologram/me.go @@ -0,0 +1,46 @@ +package main + +import ( + "fmt" + "github.com/AdRoll/hologram/log" + "github.com/AdRoll/hologram/protocol" + "github.com/spf13/cobra" + "os" +) + +func init() { + rootCmd.AddCommand(meCmd) +} + +var meCmd = &cobra.Command{ + Use: "me", + Short: "Assumes the default role", + Run: func(cmd *cobra.Command, args []string) { + err := me() + if err != nil { + log.Errorf("%s", err) + os.Exit(1) + } + }, +} + +func me() error { + response, err := request(&protocol.AgentRequest{ + GetUserCredentials: &protocol.GetUserCredentials{}, + }) + + if err != nil { + return err + } + + if response.GetFailure() != nil { + return fmt.Errorf("error from server: %s", response.GetFailure().GetErrorMessage()) + } + + if response.GetSuccess() != nil { + log.Info("Successfully loaded credentials for you") + return nil + } + + return fmt.Errorf("unexpected response type: %v", response) +} diff --git a/cmd/hologram/use.go b/cmd/hologram/use.go new file mode 100644 index 0000000..332a393 --- /dev/null +++ b/cmd/hologram/use.go @@ -0,0 +1,53 @@ +package main + +import ( + "fmt" + "github.com/AdRoll/hologram/log" + "github.com/AdRoll/hologram/protocol" + "github.com/spf13/cobra" + "os" +) + +func init() { + rootCmd.AddCommand(useCmd) +} + +var useCmd = &cobra.Command{ + Use: "use", + Short: " - Assumes the specified role", + Run: func(cmd *cobra.Command, args []string) { + var err error + if len(args) > 0 { + err = use(args[0]) + } else { + err = fmt.Errorf("usage: hologram use ") + } + if err != nil { + log.Errorf("%s", err) + os.Exit(1) + } + }, +} + +func use(role string) error { + response, err := request(&protocol.AgentRequest{ + AssumeRole: &protocol.AssumeRole{ + Role: &role, + }, + }) + if err != nil { + return err + } + + if response.GetFailure() != nil { + return fmt.Errorf(response.GetFailure().GetErrorMessage()) + } + + if response.GetSuccess() != nil { + output := fmt.Sprintf("Successfully got credentials for role '%s'", role) + log.Info(output) + return nil + } + + return fmt.Errorf("unexpected response type: %v", response) +} \ No newline at end of file diff --git a/cmd/hologram/version.go b/cmd/hologram/version.go new file mode 100644 index 0000000..cf833c7 --- /dev/null +++ b/cmd/hologram/version.go @@ -0,0 +1,35 @@ +package main + +import ( + "fmt" + "github.com/spf13/cobra" + "os" +) + +func init() { + rootCmd.AddCommand(versionCmd) + + rootCmd.PersistentFlags().BoolP("version", "v", false, "print the application version") + rootCmd.PreRunE = func(cmd *cobra.Command, args []string) error { + version, err := cmd.Flags().GetBool("version") + if err != nil { + return err + } + if version { + fmt.Println(Version) + os.Exit(0) + } + return nil + } +} + +// Legacy support +var versionCmd = &cobra.Command{ + Use: "version", + Hidden: true, + Short: "print the application version", + Run: func(cmd *cobra.Command, args []string) { + fmt.Println(Version) + os.Exit(0) + }, +} diff --git a/go.mod b/go.mod index e7105e3..670d8c0 100644 --- a/go.mod +++ b/go.mod @@ -21,11 +21,14 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jtolds/gls v4.20.0+incompatible // indirect github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect + github.com/spf13/cobra v1.6.1 // indirect + github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/testify v1.7.0 // indirect golang.org/x/term v0.3.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index b02fc70..fe58817 100644 --- a/go.sum +++ b/go.sum @@ -64,6 +64,7 @@ github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnht github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -181,6 +182,9 @@ github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef/go.mod h1:lADxMC39cJ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -240,6 +244,7 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= @@ -253,7 +258,10 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9 github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= +github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= +github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -637,6 +645,8 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From a13f5bcdf35b7c583ddbd8362e52b93f02e212a5 Mon Sep 17 00:00:00 2001 From: Josh Mullins Date: Thu, 5 Jan 2023 17:09:37 -0500 Subject: [PATCH 6/7] Changed version flag to only exist at root --- cmd/hologram/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/hologram/version.go b/cmd/hologram/version.go index cf833c7..0e6e1b0 100644 --- a/cmd/hologram/version.go +++ b/cmd/hologram/version.go @@ -9,7 +9,7 @@ import ( func init() { rootCmd.AddCommand(versionCmd) - rootCmd.PersistentFlags().BoolP("version", "v", false, "print the application version") + rootCmd.Flags().BoolP("version", "v", false, "print the application version") rootCmd.PreRunE = func(cmd *cobra.Command, args []string) error { version, err := cmd.Flags().GetBool("version") if err != nil { From 5147c044506c22c7e33c9673efa261a412e29a80 Mon Sep 17 00:00:00 2001 From: Josh Mullins Date: Tue, 14 Feb 2023 13:28:00 -0500 Subject: [PATCH 7/7] Adding linux support for new console command --- cmd/hologram/console.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmd/hologram/console.go b/cmd/hologram/console.go index 5b189d1..dda2614 100644 --- a/cmd/hologram/console.go +++ b/cmd/hologram/console.go @@ -150,6 +150,12 @@ func launchConsole(newSession bool, showUrl bool, noLaunch bool) error { } openArgs = append(openArgs, federationUrl) err = exec.Command("open", openArgs...).Run() + case "linux": + if newSession { + fmt.Println("Warning: --new-session is not currently supported on Linux") + } + openArgs = append(openArgs, federationUrl) + err = exec.Command("xdg-open", openArgs...).Run() default: return fmt.Errorf("unsupported OS: %v", runtime.GOOS) }