Skip to content

Commit

Permalink
Embed application config instead of just mTLS (#6)
Browse files Browse the repository at this point in the history
* embed application config instead of just mtls

* override embedded config with file

* update embedded config instructions in readme

* bump version
  • Loading branch information
patricksanders authored Oct 16, 2020
1 parent 7657ec8 commit 7a143a5
Show file tree
Hide file tree
Showing 16 changed files with 224 additions and 234 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
GOFMT_FILES?=$$(find . -name '*.go' | grep -v vendor)
BINARY_NAME=weep
VERSION=0.1.1
VERSION=0.1.2
REGISTRY=$(REGISTRY)
BRANCH=$(shell git rev-parse --abbrev-ref HEAD)

Expand Down
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,20 +132,21 @@ AWS_PROFILE=role1 aws s3 ls
In most cases, `weep` can be built by running the `make` command in the repository root. `make release` (requires
[`upx`](https://upx.github.io/)) will build and compress the binary for distribution.

### Embedding mTLS configuration
### Embedded configuration

`weep` binaries can be shipped with an embedded mutual TLS (mTLS) configuration to
avoid making users set this configuration. An example of such a configuration is included
in [mtls/mtls_paths.yaml](mtls/mtls_paths.yaml).
`weep` binaries can be shipped with an embedded configuration to allow shipping an "all-in-one" binary.
An example of such a configuration is included in [example-config.yaml](example-config.yaml).

To compile with an embedded config, set the `MTLS_CONFIG_FILE` environment variable at
To compile with an embedded config, set the `EMBEDDED_CONFIG_FILE` environment variable at
build time. The value of this variable MUST be the **absolute path** of the configuration
file **relative to the root of the module**:

```bash
MTLS_CONFIG_FILE=/mtls/mtls_paths.yaml make
EMBEDDED_CONFIG_FILE=/example-config.yaml make
```

Note that the embedded configuration can be overridden by a configuration file in the locations listed above.

### Docker

#### Building and Running
Expand Down
46 changes: 25 additions & 21 deletions challenge/challenge.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ import (
"strings"
"time"

"github.com/spf13/viper"

"github.com/golang/glog"
"github.com/netflix/weep/config"
"github.com/netflix/weep/util"
log "github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -57,9 +58,6 @@ func NewHTTPClient(consolemeUrl string) (*http.Client, error) {
return nil, err
}
jar.SetCookies(consoleMeUrlParsed, cookies)
if err != nil {
return nil, err
}
client := &http.Client{
Jar: jar,
}
Expand All @@ -79,8 +77,6 @@ func isWSL() bool {
}

func poll(pollingUrl string) (*ConsolemeChallengeResponse, error) {
var pollResponse ConsolemeChallengeResponse
var pollResponseBody []byte
timeout := time.After(2 * time.Minute)
tick := time.Tick(3 * time.Second)
req, err := http.NewRequest("GET", pollingUrl, nil)
Expand All @@ -95,25 +91,30 @@ func poll(pollingUrl string) (*ConsolemeChallengeResponse, error) {
case <-timeout:
return nil, errors.New("*** Unable to validate Challenge Response after 2 minutes. Quitting. ***")
case <-tick:
resp, err := client.Do(req)
pollResponse, err := pollRequest(client, req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.Body != nil {
pollResponseBody, err = ioutil.ReadAll(resp.Body)
err := json.Unmarshal(pollResponseBody, &pollResponse)
if err != nil {
return nil, err
}
if pollResponse.Status == "success" {
return &pollResponse, nil
}
if pollResponse.Status == "success" {
return pollResponse, nil
}
}
}
}

func pollRequest(c *http.Client, r *http.Request) (*ConsolemeChallengeResponse, error) {
var pollResponse ConsolemeChallengeResponse
var pollResponseBody []byte
resp, err := c.Do(r)
if err != nil {
return nil, err
}
defer resp.Body.Close()
pollResponseBody, err = ioutil.ReadAll(resp.Body)
err = json.Unmarshal(pollResponseBody, &pollResponse)
return &pollResponse, err
}

func getCredentialsPath() (string, error) {
currentUser, err := user.Current()
if err != nil {
Expand Down Expand Up @@ -158,18 +159,21 @@ func RefreshChallenge() error {
return nil
}
// Step 1: Make unauthed request to ConsoleMe challenge endpoint and get a challenge challenge
if config.Config.ChallengeSettings.User == "" {
if viper.GetString("challenge_settings.user") == "" {
log.Fatalf(
"Invalid configuration. You must define challenge_settings.user as the user you wish to authenticate as.",
)
}
var consoleMeChallengeGeneratorEndpoint string = fmt.Sprintf(
var consoleMeChallengeGeneratorEndpoint = fmt.Sprintf(
"%s/noauth/v1/challenge_generator/%s",
config.Config.ConsoleMeUrl,
config.Config.ChallengeSettings.User,
viper.GetString("consoleme_url"),
viper.GetString("challenge_settings.user"),
)
var challenge ConsolemeChallenge
req, err := http.NewRequest("GET", consoleMeChallengeGeneratorEndpoint, nil)
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
Expand Down
20 changes: 14 additions & 6 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,22 @@ func initConfig() {
viper.AddConfigPath(home + "/.config/weep/")
}

err := viper.ReadInConfig()
if err == nil {
log.Debug("Found config")
err = viper.Unmarshal(&config.Config)
if err != nil {
log.Fatalf("unable to decode into struct, %v", err)
if err := config.ReadEmbeddedConfig(); err != nil {
log.Errorf("unable to read embedded config: %v; falling back to config file", err)
}

if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok && config.EmbeddedConfigFile != "" {
log.Debug("no config file found, trying to use embedded config")
} else {
log.Fatalf("unable to read config file: %v", err)
}
}

log.Debug("Found config")
if err := viper.Unmarshal(&config.Config); err != nil {
log.Fatalf("unable to decode config into struct: %v", err)
}
}

func initLogging() {
Expand Down
14 changes: 0 additions & 14 deletions config.yml

This file was deleted.

11 changes: 7 additions & 4 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ type MetaDataConfig struct {
}

type MtlsSettings struct {
Cert string `mapstructure:"cert"`
Key string `mapstructure:"key"`
CATrust string `mapstructure:"catrust"`
Insecure bool `mapstructure:"insecure"`
Cert string `mapstructure:"cert"`
Key string `mapstructure:"key"`
CATrust string `mapstructure:"catrust"`
Insecure bool `mapstructure:"insecure"`
Darwin []string `mapstructure:"darwin"`
Linux []string `mapstructure:"linux"`
Windows []string `mapstructure:"windows"`
}

type ChallengeSettings struct {
Expand Down
29 changes: 29 additions & 0 deletions config/embedded.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package config

import (
"github.com/markbates/pkger"
"github.com/pkg/errors"
"github.com/spf13/viper"
)

var (
EmbeddedConfigFile string // To be set by ldflags at compile time
)

// ReadEmbeddedConfig attempts to read the embedded mTLS config and create a tls.Config
func ReadEmbeddedConfig() error {
if EmbeddedConfigFile == "" {
return EmbeddedConfigDisabledError
}
f, err := pkger.Open(EmbeddedConfigFile)
if err != nil {
return errors.Wrap(err, "could not open embedded config")
}
defer f.Close()

err = viper.ReadConfig(f)
if err != nil {
return errors.Wrap(err, "could not read embedded config")
}
return nil
}
11 changes: 11 additions & 0 deletions config/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package config

type Error string

func (e Error) Error() string { return string(e) }

const ClientCertificatesNotFoundError = Error("could not find client certificates")
const EmbeddedConfigDisabledError = Error("embedded config is disabled")
const HomeDirectoryError = Error("could not resolve user's home directory")
const MissingTLSConfigError = Error("missing required mTLS configuration")
const UnsupportedOSError = Error("running on unsupported operating system")
7 changes: 4 additions & 3 deletions consoleme/consoleme.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import (
"syscall"
"time"

"github.com/spf13/viper"

"github.com/netflix/weep/challenge"
"github.com/netflix/weep/config"
"github.com/netflix/weep/mtls"
log "github.com/sirupsen/logrus"

Expand Down Expand Up @@ -44,8 +45,8 @@ type Client struct {
// GetClient creates an authenticated ConsoleMe client
func GetClient() (*Client, error) {
var client *Client
consoleMeUrl := config.Config.ConsoleMeUrl
authenticationMethod := config.Config.AuthenticationMethod
consoleMeUrl := viper.GetString("consoleme_url")
authenticationMethod := viper.GetString("authentication_method")

if authenticationMethod == "mtls" {
mtlsClient, err := mtls.NewHTTPClient()
Expand Down
29 changes: 29 additions & 0 deletions example-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
consoleme_url: https://path_to_consoleme:port
authentication_method: mtls # challenge or mtls
mtls_settings:
cert: mtls.crt
key: mtls.key
cafile: mtlsCA.pem
insecure: false
darwin: # weep will look in platform-specific directories for the three files specified above
- "/run/mtls/certificates"
- "/mtls/certificates"
- "$HOME/.mtls/certificates"
- "$HOME/.mtls"
linux:
- "/run/mtls/certificates"
- "/mtls/certificates"
- "$HOME/.mtls/certificates"
- "$HOME/.mtls"
windows:
- "C:\\run\\mtls\\certificates"
- "C:\\mtls\\certificates"
- "$HOME\\.mtls\\certificates"
- "$HOME\\.mtls"
metadata:
routes:
- path: latest/user-data
- path: latest/meta-data/local-ipv4
data: "127.0.0.1"
- path: latest/meta-data/local-hostname
data: ip-127-0-0-1.us-west-2.compute.internal
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,4 @@ require (
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc // indirect
golang.org/x/sys v0.0.0-20200828081204-131dc92a58d5 // indirect
gopkg.in/ini.v1 v1.62.0
gopkg.in/yaml.v2 v2.3.0
)
6 changes: 3 additions & 3 deletions handlers/customHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ func CustomHandler(w http.ResponseWriter, r *http.Request) {

path := mux.Vars(r)["path"]

for i := range config.Config.MetaData.Routes {
if config.Config.MetaData.Routes[i].Path == path {
fmt.Fprintln(w, config.Config.MetaData.Routes[i].Data)
for _, configRoute := range config.Config.MetaData.Routes {
if configRoute.Path == path {
fmt.Fprintln(w, configRoute.Path)
}
}
}
Loading

0 comments on commit 7a143a5

Please sign in to comment.