Skip to content

Commit

Permalink
Added support to read jwt and mysql password from a file (#141)
Browse files Browse the repository at this point in the history
The current implementation of FleetDM doesn't support Docker secrets for supplying the MySQL password and JWT key. This PR provides the ability for a file path to read in secrets. The goal of this PR is to avoid storing secrets in a static config or in an environment variable. 

Example config for Docker:
```yaml
mysql:
  address: mysql:3306
  database: fleet
  username: fleet
  password_path: /run/secrets/mysql-fleetdm-password
redis:
  address: redis:6379
server:
  address: 0.0.0.0:8080
  cert: /run/secrets/fleetdm-tls-cert
  key: /run/secrets/fleetdm-tls-key
auth:
  jwt_key_path: /run/secrets/fleetdm-jwt-key
filesystem:
  status_log_file: /var/log/osquery/status.log
  result_log_file: /var/log/osquery/result.log
  enable_log_rotation: true
logging:
  json: true
```
  • Loading branch information
CptOfEvilMinions authored Jan 4, 2021
1 parent 522bff0 commit 626429c
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 8 deletions.
5 changes: 2 additions & 3 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
*
!build/binary-bundle/linux/fleet
!build/binary-bundle/linux/fleetctl
!build/binary-bundle/linux/fleet
!build/binary-bundle/linux/fleet
16 changes: 14 additions & 2 deletions cmd/fleet/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,14 +163,26 @@ the way that the Fleet server works.
os.Exit(1)
}

if config.Auth.JwtKey == "" {
if config.Auth.JwtKey != "" && config.Auth.JwtKeyPath != "" {
initFatal(err, "A JWT key and a JWT key file were provided - please specify only one")
}

if config.Auth.JwtKeyPath != "" {
fileContents, err := ioutil.ReadFile(config.Auth.JwtKeyPath)
if err != nil {
initFatal(err, "Could not read the JWT Key file provided")
}
config.Auth.JwtKey = strings.TrimSpace(string(fileContents))
}

if config.Auth.JwtKey == "" && config.Auth.JwtKeyPath == "" {
jwtKey, err := kolide.RandomText(24)
if err != nil {
initFatal(err, "generating sample jwt key")
}
fmt.Printf("################################################################################\n"+
"# ERROR:\n"+
"# A value must be supplied for --auth_jwt_key. This value is used to create\n"+
"# A value must be supplied for --auth_jwt_key or --auth_jwt_key_path. This value is used to create\n"+
"# session tokens for users.\n"+
"#\n"+
"# Consider using the following randomly generated key:\n"+
Expand Down
29 changes: 27 additions & 2 deletions docs/2-Deployment/2-Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,20 @@ The password to use when connecting to the MySQL instance.
password: kolide
```

###### `mysql_tls_ca`
##### `mysql_password_path`

File path to a file that contains the password to use when connecting to the MySQL instance.

- Default value: `""`
- Config file format:

```
mysql:
password_path: '/run/secrets/fleetdm-mysql-password
```


##### `mysql_tls_ca`

The path to a PEM encoded certificate of MYSQL's CA for client certificate authentication.

Expand Down Expand Up @@ -418,7 +431,19 @@ The [JWT](https://jwt.io/) key to use when signing and validating session keys.
jwt_key: JVnKw7CaUdJjZwYAqDgUHVYP
```

###### `auth_bcrypt_cost`
##### `auth_jwt_key_path`

File path to a file that contains the [JWT](https://jwt.io/) key to use when signing and validating session keys.

- Default value: `""`
- Config file format:

```
auth:
jwt_key_path: '/run/secrets/fleetdm-jwt-token
```

##### `auth_bcrypt_cost`

The bcrypt cost to use when hashing user passwords.

Expand Down
10 changes: 9 additions & 1 deletion server/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type MysqlConfig struct {
Address string
Username string
Password string
PasswordPath string `yaml:"password_path"`
Database string
TLSCert string `yaml:"tls_cert"`
TLSKey string `yaml:"tls_key"`
Expand Down Expand Up @@ -59,6 +60,7 @@ type ServerConfig struct {
// AuthConfig defines configs related to user authorization
type AuthConfig struct {
JwtKey string `yaml:"jwt_key"`
JwtKeyPath string `yaml:"jwt_key_path"`
BcryptCost int `yaml:"bcrypt_cost"`
SaltKeySize int `yaml:"salt_key_size"`
}
Expand Down Expand Up @@ -168,8 +170,10 @@ func (man Manager) addConfigs() {
"MySQL server address (host:port)")
man.addConfigString("mysql.username", "kolide",
"MySQL server username")
man.addConfigString("mysql.password", "kolide",
man.addConfigString("mysql.password", "",
"MySQL server password (prefer env variable for security)")
man.addConfigString("mysql.password_path", "",
"Path to file containg MySQL server password")
man.addConfigString("mysql.database", "kolide",
"MySQL database name")
man.addConfigString("mysql.tls_cert", "",
Expand Down Expand Up @@ -213,6 +217,8 @@ func (man Manager) addConfigs() {
// Auth
man.addConfigString("auth.jwt_key", "",
"JWT session token key (required)")
man.addConfigString("auth.jwt_key_path", "",
"Path to file containg JWT session token key")
man.addConfigInt("auth.bcrypt_cost", 12,
"Bcrypt iterations")
man.addConfigInt("auth.salt_key_size", 24,
Expand Down Expand Up @@ -314,6 +320,7 @@ func (man Manager) LoadConfig() KolideConfig {
Address: man.getConfigString("mysql.address"),
Username: man.getConfigString("mysql.username"),
Password: man.getConfigString("mysql.password"),
PasswordPath: man.getConfigString("mysql.password_path"),
Database: man.getConfigString("mysql.database"),
TLSCert: man.getConfigString("mysql.tls_cert"),
TLSKey: man.getConfigString("mysql.tls_key"),
Expand All @@ -340,6 +347,7 @@ func (man Manager) LoadConfig() KolideConfig {
},
Auth: AuthConfig{
JwtKey: man.getConfigString("auth.jwt_key"),
JwtKeyPath: man.getConfigString("auth.jwt_key_path"),
BcryptCost: man.getConfigInt("auth.bcrypt_cost"),
SaltKeySize: man.getConfigInt("auth.salt_key_size"),
},
Expand Down
16 changes: 16 additions & 0 deletions server/datastore/mysql/mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"io/ioutil"
"net/url"
"regexp"
"strings"
"time"

"github.com/WatchBeam/clock"
Expand Down Expand Up @@ -109,6 +110,21 @@ func New(config config.MysqlConfig, c clock.Clock, opts ...DBOption) (*Datastore
setOpt(options)
}

if config.PasswordPath != "" && config.Password != "" {
return nil, errors.New("A MySQL password and a MySQL password file were provided - please specify only one")
}

// Check to see if the flag is populated
// Check if file exists on disk
// If file exists read contents
if config.PasswordPath != "" {
fileContents, err := ioutil.ReadFile(config.PasswordPath)
if err != nil {
return nil, err
}
config.Password = strings.TrimSpace(string(fileContents))
}

if config.TLSConfig != "" {
err := registerTLS(config)
if err != nil {
Expand Down

0 comments on commit 626429c

Please sign in to comment.