Skip to content

Commit

Permalink
Add info command (#54)
Browse files Browse the repository at this point in the history
  • Loading branch information
patricksanders authored Mar 31, 2021
1 parent 9958376 commit d5f836b
Show file tree
Hide file tree
Showing 11 changed files with 165 additions and 32 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
FROM scratch
ENV USER=docker
EXPOSE 9090
EXPOSE 9091
COPY weep /
ENTRYPOINT ["/weep"]
3 changes: 1 addition & 2 deletions cmd/credential_process.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import (

func init() {
CredentialProcessCmd.PersistentFlags().BoolVarP(&generate, "generate", "g", false, "generate ~/.aws/config with credential process config")
CredentialProcessCmd.PersistentFlags().BoolVarP(&showAll, "all", "a", false, "include all roles (console and application)")
CredentialProcessCmd.PersistentFlags().StringVarP(&destinationConfig, "output", "o", getDefaultAwsConfigFile(), "output file for AWS config")
rootCmd.AddCommand(CredentialProcessCmd)
}
Expand Down Expand Up @@ -81,7 +80,7 @@ func generateCredentialProcessConfig(destination string) error {
if err != nil {
return err
}
roles, err := client.Roles(showAll)
roles, err := client.Roles()
if err != nil {
return err
}
Expand Down
108 changes: 108 additions & 0 deletions cmd/info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package cmd

import (
"compress/zlib"
"encoding/base64"
"fmt"
"io"
"os"
"strings"

"gopkg.in/yaml.v2"

"github.com/netflix/weep/metadata"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

func init() {
infoCmd.PersistentFlags().BoolVarP(&infoDecode, "decode", "d", false, "decode weep info output")
infoCmd.PersistentFlags().BoolVarP(&infoRaw, "raw", "R", false, "print raw info output")
rootCmd.AddCommand(infoCmd)
}

var infoCmd = &cobra.Command{
Use: "info",
Short: infoShortHelp,
Long: infoLongHelp,
Hidden: true,
RunE: func(cmd *cobra.Command, args []string) error {
if infoDecode {
return DecodeWeepInfo(args, cmd.OutOrStdout())
} else {
return PrintWeepInfo(cmd.OutOrStdout())
}
},
}

func marshalStruct(obj interface{}) []byte {
out, err := yaml.Marshal(obj)
if err != nil {
log.Errorf("failed to marshal struct: %v", err)
return nil
}
return out
}

func isInputFromPipe() bool {
fileInfo, _ := os.Stdin.Stat()
return fileInfo.Mode()&os.ModeCharDevice == 0
}

func PrintWeepInfo(w io.Writer) error {
var writer io.Writer
if infoRaw {
writer = w
} else {
b64encoder := base64.NewEncoder(base64.StdEncoding, w)
defer b64encoder.Close()
writer = zlib.NewWriter(b64encoder)
}
if closeable, ok := writer.(io.WriteCloser); ok {
defer closeable.Close()
}

roles, err := roleList(true)
if err != nil {
log.Errorf("failed to retrieve role list from ConsoleMe: %v", err)
} else {
_, _ = writer.Write([]byte(roles))
}

// We're ignoring errors here in the interest of best-effort information gathering
_, _ = writer.Write([]byte("\nVersion\n"))
_, _ = writer.Write(marshalStruct(metadata.GetVersion()))

_, _ = writer.Write([]byte("\nConfiguration\n"))
_, _ = writer.Write(marshalStruct(viper.AllSettings()))

_, _ = writer.Write([]byte("\nHost Info\n"))
_, _ = writer.Write(marshalStruct(metadata.GetInstanceInfo()))

return nil
}

func DecodeWeepInfo(args []string, w io.Writer) error {
var r io.Reader
if isInputFromPipe() {
// Input is being piped in to weep
r = os.Stdin
} else {
// Input should be the first arg, but we can't trust that
if len(args) > 0 {
r = strings.NewReader(args[0])
} else {
return fmt.Errorf("must pass arg") // TODO: handle error better
}
}
b64decoder := base64.NewDecoder(base64.StdEncoding, r)
zreader, err := zlib.NewReader(b64decoder)
defer zreader.Close()
if err != nil {
return err
}

io.Copy(w, zreader)

return nil
}
31 changes: 23 additions & 8 deletions cmd/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,13 @@
package cmd

import (
"fmt"
"strings"

"github.com/netflix/weep/creds"
"github.com/spf13/cobra"
)

func init() {
listCmd.PersistentFlags().BoolVarP(&showAll, "all", "a", false, "include all roles (console and application)")
rootCmd.AddCommand(listCmd)
}

Expand All @@ -35,18 +34,34 @@ var listCmd = &cobra.Command{
RunE: runList,
}

func runList(cmd *cobra.Command, args []string) error {
func roleList(all bool) (string, error) {
client, err := creds.GetClient(region)
if err != nil {
return err
return "", err
}
roles, err := client.Roles(showAll)
roles, err := client.Roles()
if err != nil {
return err
return "", err
}
var sb strings.Builder
if all {
sb.WriteString("Available Roles\n")
} else {
sb.WriteString("Available Console Roles\n")
}
fmt.Println("Roles:")
for i := range roles {
fmt.Println(" ", roles[i])
sb.WriteString("\t")
sb.WriteString(roles[i])
sb.WriteString("\n")
}
return sb.String(), nil
}

func runList(cmd *cobra.Command, args []string) error {
roles, err := roleList(showAll)
if err != nil {
return err
}
cmd.Print(roles)
return nil
}
2 changes: 1 addition & 1 deletion cmd/setup_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ func PrintSetup() {
fmt.Println("Please run the following commands to setup routing for the meta-data service:")
fmt.Println("")
fmt.Println("\tsudo ifconfig lo0 169.254.169.254 alias")
fmt.Println("\techo \"rdr pass on lo0 inet proto tcp from any to 169.254.169.254 port 80 -> 127.0.0.1 port 9090\" | sudo pfctl -ef -")
fmt.Println("\techo \"rdr pass on lo0 inet proto tcp from any to 169.254.169.254 port 80 -> 127.0.0.1 port 9091\" | sudo pfctl -ef -")
fmt.Println("")
}
2 changes: 1 addition & 1 deletion cmd/setup_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ import (
func PrintSetup() {
fmt.Println("Please run the following commands to setup routing for the meta-data service:")
fmt.Println("")
fmt.Println("\tsudo iptables -t nat -A OUTPUT -p tcp --dport 80 -d 169.254.169.254 -j DNAT --to 127.0.0.1:9090")
fmt.Println("\tsudo iptables -t nat -A OUTPUT -p tcp --dport 80 -d 169.254.169.254 -j DNAT --to 127.0.0.1:9091")
fmt.Println("")
}
28 changes: 20 additions & 8 deletions cmd/vars.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,25 @@ import "os"

var (
assumeRole []string
profileName string
autoRefresh bool
cfgFile string
destination string
destinationConfig string
done chan int
force bool
autoRefresh bool
generate bool
noIpRestrict bool
showAll bool
region string
infoDecode bool
infoRaw bool
listenAddr string
listenPort int
cfgFile string
logLevel string
logFile string
logFormat string
logLevel string
noIpRestrict bool
profileName string
region string
showAll bool
shutdown chan os.Signal
done chan int
)

var completionShortHelp = "Generate completion script"
Expand Down Expand Up @@ -71,6 +73,16 @@ every hour to get new credentials.
More information: https://hawkins.gitbook.io/consoleme/weep-cli/commands/credential-file
`

var infoShortHelp = "Print info for support and troubleshooting"
var infoLongHelp = `The info command prints a compressed and base64-encoded dump of Weep's configuration,
available roles according to ConsoleMe, and basic system information. The raw output can be viewed by
running the command with the --raw/-R flag.
The command also has a --decode/-d flag to decode output, which allows folks to do fun things like this:
weep info | weep info -d
`

var listShortHelp = "List available roles"
var listLongHelp = `The list command prints out all of the roles you have access to via ConsoleMe. By default,
this command will only show console roles. Use the --all flag to also include application
Expand Down
6 changes: 2 additions & 4 deletions creds/consoleme.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,17 +144,15 @@ func (c *Client) CloseIdleConnections() {

// accounts returns all accounts, and allows you to filter the accounts by sub-resources
// like: /accounts/service/support
func (c *Client) Roles(showAll bool) ([]string, error) {
func (c *Client) Roles() ([]string, error) {
req, err := c.buildRequest(http.MethodGet, "/get_roles", nil)
if err != nil {
return nil, errors.Wrap(err, "failed to build request")
}

// Add URL Parameters
q := url.Values{}
if showAll {
q.Add("all", "true")
}
q.Add("all", "true")
req.URL.RawQuery = q.Encode()

resp, err := c.Do(req)
Expand Down
2 changes: 1 addition & 1 deletion extras/com.user.weep.plist
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<array>
<string>/bin/bash</string>
<string>-c</string>
<string>echo "rdr pass on lo0 inet proto tcp from any to 169.254.169.254 port 80 -> 127.0.0.1 port 9090" | sudo pfctl -ef -</string>
<string>echo "rdr pass on lo0 inet proto tcp from any to 169.254.169.254 port 80 -> 127.0.0.1 port 9091" | sudo pfctl -ef -</string>
</array>
<key>RunAtLoad</key> <true/>
<key>Nice</key>
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ require (
golang.org/x/sys v0.0.0-20210317225723-c4fcb01b228e // indirect
golang.org/x/text v0.3.5 // indirect
gopkg.in/ini.v1 v1.62.0
gopkg.in/yaml.v2 v2.4.0
)
12 changes: 6 additions & 6 deletions metadata/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
package metadata

type InstanceInfo struct {
Hostname string `json:"hostname"`
Username string `json:"username"`
CertAgeSeconds int `json:"cert_age_seconds,omitempty"`
CertFingerprintSHA256 string `json:"cert_fingerprint_sha256,omitempty"`
WeepVersion string `json:"weep_version"`
WeepMethod string `json:"weep_method"`
Hostname string `json:"hostname" yaml:"hostname"`
Username string `json:"username" yaml:"username"`
CertAgeSeconds int `json:"cert_age_seconds,omitempty" yaml:"cert_age_seconds"`
CertFingerprintSHA256 string `json:"cert_fingerprint_sha256,omitempty" yaml:"cert_fingerprint_sha256"`
WeepVersion string `json:"weep_version" yaml:"weep_version"`
WeepMethod string `json:"weep_method" yaml:"weep_method"`
}

0 comments on commit d5f836b

Please sign in to comment.