2015-03-12 22:21:11 +00:00
package command
import (
2018-01-19 06:44:44 +00:00
"context"
2018-03-28 21:36:55 +00:00
"crypto/sha256"
2016-08-15 20:01:15 +00:00
"encoding/base64"
2018-03-28 21:36:55 +00:00
"encoding/hex"
2015-03-12 22:30:07 +00:00
"fmt"
2018-03-28 21:36:55 +00:00
"io"
2017-07-31 15:28:06 +00:00
"io/ioutil"
2015-03-13 17:09:38 +00:00
"net"
"net/http"
2015-05-02 22:57:40 +00:00
"net/url"
2015-04-04 19:06:41 +00:00
"os"
2017-07-31 15:28:06 +00:00
"path/filepath"
2015-10-28 17:05:56 +00:00
"runtime"
2015-04-04 19:06:41 +00:00
"sort"
2015-05-02 22:57:40 +00:00
"strconv"
2015-03-12 22:21:11 +00:00
"strings"
2016-07-30 17:17:29 +00:00
"sync"
2015-04-15 01:44:09 +00:00
"time"
2015-03-12 22:21:11 +00:00
2019-08-20 21:47:08 +00:00
monitoring "cloud.google.com/go/monitoring/apiv3"
2019-10-04 07:29:51 +00:00
"github.com/armon/go-metrics"
2016-07-22 19:49:23 +00:00
"github.com/armon/go-metrics/circonus"
2017-06-17 03:51:46 +00:00
"github.com/armon/go-metrics/datadog"
2019-02-14 20:46:59 +00:00
"github.com/armon/go-metrics/prometheus"
2019-08-20 21:47:08 +00:00
stackdriver "github.com/google/go-metrics-stackdriver"
2016-04-04 14:44:22 +00:00
"github.com/hashicorp/errwrap"
2018-04-03 00:46:59 +00:00
log "github.com/hashicorp/go-hclog"
2019-10-04 07:29:51 +00:00
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-sockaddr"
2015-04-05 01:07:53 +00:00
"github.com/hashicorp/vault/audit"
2015-03-12 22:30:07 +00:00
"github.com/hashicorp/vault/command/server"
2018-09-18 03:03:00 +00:00
serverseal "github.com/hashicorp/vault/command/server/seal"
2018-11-07 01:21:24 +00:00
"github.com/hashicorp/vault/helper/builtinplugins"
2019-01-09 00:48:57 +00:00
gatedwriter "github.com/hashicorp/vault/helper/gated-writer"
2019-10-04 07:29:51 +00:00
"github.com/hashicorp/vault/helper/metricsutil"
2019-04-13 07:44:06 +00:00
"github.com/hashicorp/vault/helper/namespace"
"github.com/hashicorp/vault/helper/reload"
vaulthttp "github.com/hashicorp/vault/http"
2019-04-12 21:54:35 +00:00
"github.com/hashicorp/vault/sdk/helper/jsonutil"
"github.com/hashicorp/vault/sdk/helper/logging"
"github.com/hashicorp/vault/sdk/helper/mlock"
"github.com/hashicorp/vault/sdk/helper/parseutil"
2019-08-20 21:47:08 +00:00
"github.com/hashicorp/vault/sdk/helper/useragent"
2019-04-12 21:54:35 +00:00
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/sdk/physical"
2019-04-13 07:44:06 +00:00
"github.com/hashicorp/vault/sdk/version"
2015-03-13 17:09:38 +00:00
"github.com/hashicorp/vault/vault"
2018-10-29 13:30:24 +00:00
vaultseal "github.com/hashicorp/vault/vault/seal"
2019-06-20 19:14:58 +00:00
shamirseal "github.com/hashicorp/vault/vault/seal/shamir"
2018-10-31 18:11:45 +00:00
"github.com/mitchellh/cli"
2019-10-04 07:29:51 +00:00
"github.com/mitchellh/go-testing-interface"
2018-10-31 18:11:45 +00:00
"github.com/posener/complete"
2019-11-07 16:54:34 +00:00
"go.uber.org/atomic"
2019-10-04 07:29:51 +00:00
"golang.org/x/net/http/httpproxy"
2019-08-20 21:47:08 +00:00
"google.golang.org/api/option"
2018-10-31 18:11:45 +00:00
"google.golang.org/grpc/grpclog"
2015-03-12 22:21:11 +00:00
)
2017-09-08 02:03:44 +00:00
var _ cli . Command = ( * ServerCommand ) ( nil )
var _ cli . CommandAutocomplete = ( * ServerCommand ) ( nil )
2018-10-31 18:11:45 +00:00
var memProfilerEnabled = false
2019-08-23 15:53:18 +00:00
var enableFourClusterDev = func ( c * ServerCommand , base * vault . CoreConfig , info map [ string ] string , infoKeys [ ] string , devListenAddress , tempDir string ) int {
c . logger . Error ( "-dev-four-cluster only supported in enterprise Vault" )
return 1
}
2018-10-23 06:34:02 +00:00
const storageMigrationLock = "core/migration"
2018-09-25 23:18:22 +00:00
2015-03-12 22:21:11 +00:00
type ServerCommand struct {
2017-09-22 00:51:12 +00:00
* BaseCommand
2015-04-05 01:07:53 +00:00
AuditBackends map [ string ] audit . Factory
2015-04-01 22:48:13 +00:00
CredentialBackends map [ string ] logical . Factory
LogicalBackends map [ string ] logical . Factory
2017-08-03 17:24:27 +00:00
PhysicalBackends map [ string ] physical . Factory
2015-03-20 18:32:18 +00:00
2016-03-14 18:05:47 +00:00
ShutdownCh chan struct { }
SighupCh chan struct { }
2019-03-15 13:27:53 +00:00
SigUSR2Ch chan struct { }
2016-03-11 21:46:56 +00:00
2016-07-30 17:17:29 +00:00
WaitGroup * sync . WaitGroup
2018-06-15 18:47:37 +00:00
logWriter io . Writer
logGate * gatedwriter . Writer
logger log . Logger
2016-06-02 16:40:25 +00:00
2016-10-10 17:18:19 +00:00
cleanupGuard sync . Once
2016-09-30 04:06:40 +00:00
reloadFuncsLock * sync . RWMutex
2017-07-31 15:28:06 +00:00
reloadFuncs * map [ string ] [ ] reload . ReloadFunc
2017-09-08 02:03:44 +00:00
startedCh chan ( struct { } ) // for tests
reloadedCh chan ( struct { } ) // for tests
// new stuff
2019-07-24 16:41:28 +00:00
flagConfigs [ ] string
flagLogLevel string
flagLogFormat string
2019-10-15 04:55:31 +00:00
flagRecovery bool
2019-07-24 16:41:28 +00:00
flagDev bool
flagDevRootTokenID string
flagDevListenAddr string
flagDevNoStoreToken bool
2017-09-08 02:03:44 +00:00
flagDevPluginDir string
2018-03-28 21:36:55 +00:00
flagDevPluginInit bool
2017-09-08 02:03:44 +00:00
flagDevHA bool
2017-09-20 20:05:00 +00:00
flagDevLatency int
flagDevLatencyJitter int
2017-09-08 02:03:44 +00:00
flagDevLeasedKV bool
2018-12-12 20:07:18 +00:00
flagDevKVV1 bool
2017-09-22 00:51:12 +00:00
flagDevSkipInit bool
2017-09-08 02:03:44 +00:00
flagDevThreeNode bool
2018-02-22 05:23:37 +00:00
flagDevFourCluster bool
2017-09-22 00:51:12 +00:00
flagDevTransactional bool
2018-10-29 13:30:24 +00:00
flagDevAutoSeal bool
2017-09-08 02:03:44 +00:00
flagTestVerifyOnly bool
2018-06-15 18:47:37 +00:00
flagCombineLogs bool
2019-05-10 17:41:42 +00:00
flagTestServerConfig bool
2019-06-24 17:29:47 +00:00
flagDevConsul bool
2017-09-08 02:03:44 +00:00
}
2018-04-17 22:52:09 +00:00
type ServerListener struct {
net . Listener
2019-10-04 07:29:51 +00:00
config map [ string ] interface { }
maxRequestSize int64
maxRequestDuration time . Duration
unauthenticatedMetricsAccess bool
2018-04-17 22:52:09 +00:00
}
2017-09-08 02:03:44 +00:00
func ( c * ServerCommand ) Synopsis ( ) string {
return "Start a Vault server"
}
func ( c * ServerCommand ) Help ( ) string {
helpText := `
Usage : vault server [ options ]
This command starts a Vault server that responds to API requests . By default ,
Vault will start in a "sealed" state . The Vault cluster must be initialized
2018-06-07 04:11:21 +00:00
before use , usually by the "vault operator init" command . Each Vault server must
also be unsealed using the "vault operator unseal" command or the API before the
server can respond to requests .
2017-09-08 02:03:44 +00:00
Start a server with a configuration file :
$ vault server - config = / etc / vault / config . hcl
Run in "dev" mode :
$ vault server - dev - dev - root - token - id = "root"
For a full list of examples , please see the documentation .
` + c . Flags ( ) . Help ( )
return strings . TrimSpace ( helpText )
}
func ( c * ServerCommand ) Flags ( ) * FlagSets {
set := c . flagSet ( FlagSetHTTP )
f := set . NewFlagSet ( "Command Options" )
f . StringSliceVar ( & StringSliceVar {
Name : "config" ,
Target : & c . flagConfigs ,
Completion : complete . PredictOr (
complete . PredictFiles ( "*.hcl" ) ,
complete . PredictFiles ( "*.json" ) ,
complete . PredictDirs ( "*" ) ,
) ,
Usage : "Path to a configuration file or directory of configuration " +
"files. This flag can be specified multiple times to load multiple " +
"configurations. If the path is a directory, all files which end in " +
".hcl or .json are loaded." ,
} )
f . StringVar ( & StringVar {
Name : "log-level" ,
Target : & c . flagLogLevel ,
2018-09-05 19:52:54 +00:00
Default : notSetValue ,
2018-01-03 19:02:31 +00:00
EnvVar : "VAULT_LOG_LEVEL" ,
2017-09-08 02:03:44 +00:00
Completion : complete . PredictSet ( "trace" , "debug" , "info" , "warn" , "err" ) ,
Usage : "Log verbosity level. Supported values (in order of detail) are " +
"\"trace\", \"debug\", \"info\", \"warn\", and \"err\"." ,
} )
2019-07-18 19:59:27 +00:00
f . StringVar ( & StringVar {
Name : "log-format" ,
Target : & c . flagLogFormat ,
Default : notSetValue ,
// EnvVar can't be just "VAULT_LOG_FORMAT", because more than one env var name is supported
// for backwards compatibility reasons.
// See github.com/hashicorp/vault/sdk/helper/logging.ParseEnvLogFormat()
Completion : complete . PredictSet ( "standard" , "json" ) ,
Usage : ` Log format. Supported values are "standard" and "json". ` ,
} )
2019-10-15 04:55:31 +00:00
f . BoolVar ( & BoolVar {
Name : "recovery" ,
Target : & c . flagRecovery ,
Usage : "Enable recovery mode. In this mode, Vault is used to perform recovery actions." +
"Using a recovery operation token, \"sys/raw\" API can be used to manipulate the storage." ,
} )
2017-09-08 02:03:44 +00:00
f = set . NewFlagSet ( "Dev Options" )
f . BoolVar ( & BoolVar {
Name : "dev" ,
Target : & c . flagDev ,
Usage : "Enable development mode. In this mode, Vault runs in-memory and " +
"starts unsealed. As the name implies, do not run \"dev\" mode in " +
"production." ,
} )
f . StringVar ( & StringVar {
Name : "dev-root-token-id" ,
Target : & c . flagDevRootTokenID ,
Default : "" ,
EnvVar : "VAULT_DEV_ROOT_TOKEN_ID" ,
Usage : "Initial root token. This only applies when running in \"dev\" " +
"mode." ,
} )
f . StringVar ( & StringVar {
Name : "dev-listen-address" ,
Target : & c . flagDevListenAddr ,
Default : "127.0.0.1:8200" ,
EnvVar : "VAULT_DEV_LISTEN_ADDRESS" ,
Usage : "Address to bind to in \"dev\" mode." ,
} )
2019-07-24 16:41:07 +00:00
f . BoolVar ( & BoolVar {
Name : "dev-no-store-token" ,
Target : & c . flagDevNoStoreToken ,
Default : false ,
Usage : "Do not persist the dev root token to the token helper " +
"(usually the local filesystem) for use in future requests. " +
"The token will only be displayed in the command output." ,
} )
2017-09-08 02:03:44 +00:00
// Internal-only flags to follow.
//
// Why hello there little source code reader! Welcome to the Vault source
// code. The remaining options are intentionally undocumented and come with
2019-03-19 13:32:45 +00:00
// no warranty or backwards-compatibility promise. Do not use these flags
2017-09-08 02:03:44 +00:00
// in production. Do not build automation using these flags. Unless you are
// developing against Vault, you should not need any of these flags.
f . StringVar ( & StringVar {
Name : "dev-plugin-dir" ,
Target : & c . flagDevPluginDir ,
Default : "" ,
Completion : complete . PredictDirs ( "*" ) ,
Hidden : true ,
} )
2018-03-28 21:36:55 +00:00
f . BoolVar ( & BoolVar {
Name : "dev-plugin-init" ,
Target : & c . flagDevPluginInit ,
Default : true ,
Hidden : true ,
} )
2017-09-08 02:03:44 +00:00
f . BoolVar ( & BoolVar {
Name : "dev-ha" ,
Target : & c . flagDevHA ,
Default : false ,
Hidden : true ,
} )
f . BoolVar ( & BoolVar {
Name : "dev-transactional" ,
Target : & c . flagDevTransactional ,
Default : false ,
Hidden : true ,
} )
2017-09-20 20:05:00 +00:00
f . IntVar ( & IntVar {
Name : "dev-latency" ,
Target : & c . flagDevLatency ,
Hidden : true ,
} )
f . IntVar ( & IntVar {
Name : "dev-latency-jitter" ,
Target : & c . flagDevLatencyJitter ,
Hidden : true ,
} )
2017-09-08 02:03:44 +00:00
f . BoolVar ( & BoolVar {
2017-09-20 20:05:00 +00:00
Name : "dev-leased-kv" ,
2017-09-08 02:03:44 +00:00
Target : & c . flagDevLeasedKV ,
Default : false ,
Hidden : true ,
} )
2018-12-12 20:07:18 +00:00
f . BoolVar ( & BoolVar {
Name : "dev-kv-v1" ,
Target : & c . flagDevKVV1 ,
Default : false ,
Hidden : true ,
} )
2018-10-29 13:30:24 +00:00
f . BoolVar ( & BoolVar {
Name : "dev-auto-seal" ,
Target : & c . flagDevAutoSeal ,
Default : false ,
Hidden : true ,
} )
2017-09-22 00:51:12 +00:00
f . BoolVar ( & BoolVar {
Name : "dev-skip-init" ,
Target : & c . flagDevSkipInit ,
Default : false ,
Hidden : true ,
} )
2017-09-08 02:03:44 +00:00
f . BoolVar ( & BoolVar {
Name : "dev-three-node" ,
Target : & c . flagDevThreeNode ,
Default : false ,
Hidden : true ,
} )
2018-02-22 05:23:37 +00:00
f . BoolVar ( & BoolVar {
Name : "dev-four-cluster" ,
Target : & c . flagDevFourCluster ,
Default : false ,
Hidden : true ,
} )
2019-06-24 17:29:47 +00:00
f . BoolVar ( & BoolVar {
Name : "dev-consul" ,
Target : & c . flagDevConsul ,
Default : false ,
Hidden : true ,
} )
2018-06-15 18:47:37 +00:00
// TODO: should the below flags be public?
f . BoolVar ( & BoolVar {
Name : "combine-logs" ,
Target : & c . flagCombineLogs ,
Default : false ,
Hidden : true ,
} )
2017-09-08 02:03:44 +00:00
f . BoolVar ( & BoolVar {
Name : "test-verify-only" ,
Target : & c . flagTestVerifyOnly ,
Default : false ,
Hidden : true ,
} )
2019-05-10 17:41:42 +00:00
f . BoolVar ( & BoolVar {
Name : "test-server-config" ,
Target : & c . flagTestServerConfig ,
Default : false ,
Hidden : true ,
} )
2017-09-08 02:03:44 +00:00
// End internal-only flags.
return set
}
func ( c * ServerCommand ) AutocompleteArgs ( ) complete . Predictor {
return complete . PredictNothing
}
func ( c * ServerCommand ) AutocompleteFlags ( ) complete . Flags {
return c . Flags ( ) . Completions ( )
2015-03-12 22:21:11 +00:00
}
2019-10-15 04:55:31 +00:00
func ( c * ServerCommand ) parseConfig ( ) ( * server . Config , error ) {
2015-03-12 22:21:11 +00:00
// Load the configuration
2015-03-12 22:30:07 +00:00
var config * server . Config
2017-09-22 00:51:12 +00:00
for _ , path := range c . flagConfigs {
2019-07-18 19:59:27 +00:00
current , err := server . LoadConfig ( path )
2015-03-12 22:30:07 +00:00
if err != nil {
2019-10-15 04:55:31 +00:00
return nil , errwrap . Wrapf ( fmt . Sprintf ( "error loading configuration from %s: {{err}}" , path ) , err )
2015-03-12 22:30:07 +00:00
}
if config == nil {
config = current
} else {
config = config . Merge ( current )
}
}
2019-10-15 04:55:31 +00:00
return config , nil
}
func ( c * ServerCommand ) runRecoveryMode ( ) int {
config , err := c . parseConfig ( )
if err != nil {
c . UI . Error ( err . Error ( ) )
return 1
}
2015-03-12 22:30:07 +00:00
2016-02-13 00:39:28 +00:00
// Ensure at least one config was found.
if config == nil {
2017-09-22 00:51:12 +00:00
c . UI . Output ( wrapAtLength (
"No configuration files found. Please provide configurations with the " +
2019-07-24 16:58:48 +00:00
"-config flag. If you are supplying the path to a directory, please " +
2017-09-22 00:51:12 +00:00
"ensure the directory contains files with the .hcl or .json " +
"extension." ) )
2016-02-13 00:39:28 +00:00
return 1
}
2019-10-15 04:55:31 +00:00
level , logLevelString , logLevelWasNotSet , logFormat , err := c . processLogLevelAndFormat ( config )
if err != nil {
c . UI . Error ( err . Error ( ) )
return 1
}
c . logger = log . New ( & log . LoggerOptions {
Output : c . logWriter ,
Level : level ,
// Note that if logFormat is either unspecified or standard, then
// the resulting logger's format will be standard.
JSONFormat : logFormat == logging . JSONFormat ,
} )
logLevelStr , err := c . adjustLogLevel ( config , logLevelWasNotSet )
if err != nil {
c . UI . Error ( err . Error ( ) )
return 1
}
if logLevelStr != "" {
logLevelString = logLevelStr
}
// create GRPC logger
namedGRPCLogFaker := c . logger . Named ( "grpclogfaker" )
grpclog . SetLogger ( & grpclogFaker {
logger : namedGRPCLogFaker ,
log : os . Getenv ( "VAULT_GRPC_LOGGING" ) != "" ,
} )
if config . Storage == nil {
c . UI . Output ( "A storage backend must be specified" )
return 1
}
if config . DefaultMaxRequestDuration != 0 {
vault . DefaultMaxRequestDuration = config . DefaultMaxRequestDuration
}
proxyCfg := httpproxy . FromEnvironment ( )
c . logger . Info ( "proxy environment" , "http_proxy" , proxyCfg . HTTPProxy ,
"https_proxy" , proxyCfg . HTTPSProxy , "no_proxy" , proxyCfg . NoProxy )
// Initialize the storage backend
factory , exists := c . PhysicalBackends [ config . Storage . Type ]
if ! exists {
c . UI . Error ( fmt . Sprintf ( "Unknown storage type %s" , config . Storage . Type ) )
return 1
}
if config . Storage . Type == "raft" {
if envCA := os . Getenv ( "VAULT_CLUSTER_ADDR" ) ; envCA != "" {
config . ClusterAddr = envCA
}
if len ( config . ClusterAddr ) == 0 {
c . UI . Error ( "Cluster address must be set when using raft storage" )
return 1
}
}
namedStorageLogger := c . logger . Named ( "storage." + config . Storage . Type )
backend , err := factory ( config . Storage . Config , namedStorageLogger )
if err != nil {
c . UI . Error ( fmt . Sprintf ( "Error initializing storage of type %s: %s" , config . Storage . Type , err ) )
return 1
}
infoKeys := make ( [ ] string , 0 , 10 )
info := make ( map [ string ] string )
info [ "log level" ] = logLevelString
infoKeys = append ( infoKeys , "log level" )
var barrierSeal vault . Seal
var sealConfigError error
if len ( config . Seals ) == 0 {
config . Seals = append ( config . Seals , & server . Seal { Type : vaultseal . Shamir } )
}
if len ( config . Seals ) > 1 {
c . UI . Error ( "Only one seal block is accepted in recovery mode" )
return 1
}
configSeal := config . Seals [ 0 ]
sealType := vaultseal . Shamir
if ! configSeal . Disabled && os . Getenv ( "VAULT_SEAL_TYPE" ) != "" {
sealType = os . Getenv ( "VAULT_SEAL_TYPE" )
configSeal . Type = sealType
} else {
sealType = configSeal . Type
}
var seal vault . Seal
sealLogger := c . logger . Named ( sealType )
seal , sealConfigError = serverseal . ConfigureSeal ( configSeal , & infoKeys , & info , sealLogger , vault . NewDefaultSeal ( shamirseal . NewSeal ( c . logger . Named ( "shamir" ) ) ) )
if sealConfigError != nil {
if ! errwrap . ContainsType ( sealConfigError , new ( logical . KeyNotFoundError ) ) {
c . UI . Error ( fmt . Sprintf (
"Error parsing Seal configuration: %s" , sealConfigError ) )
return 1
}
}
if seal == nil {
c . UI . Error ( fmt . Sprintf (
"After configuring seal nil returned, seal type was %s" , sealType ) )
return 1
}
barrierSeal = seal
// Ensure that the seal finalizer is called, even if using verify-only
defer func ( ) {
err = seal . Finalize ( context . Background ( ) )
if err != nil {
c . UI . Error ( fmt . Sprintf ( "Error finalizing seals: %v" , err ) )
}
} ( )
coreConfig := & vault . CoreConfig {
Physical : backend ,
StorageType : config . Storage . Type ,
Seal : barrierSeal ,
Logger : c . logger ,
DisableMlock : config . DisableMlock ,
RecoveryMode : c . flagRecovery ,
ClusterAddr : config . ClusterAddr ,
}
core , newCoreError := vault . NewCore ( coreConfig )
if newCoreError != nil {
if vault . IsFatalError ( newCoreError ) {
c . UI . Error ( fmt . Sprintf ( "Error initializing core: %s" , newCoreError ) )
return 1
}
}
if err := core . InitializeRecovery ( context . Background ( ) ) ; err != nil {
c . UI . Error ( fmt . Sprintf ( "Error initializing core in recovery mode: %s" , err ) )
return 1
}
// Compile server information for output later
infoKeys = append ( infoKeys , "storage" )
info [ "storage" ] = config . Storage . Type
if coreConfig . ClusterAddr != "" {
info [ "cluster address" ] = coreConfig . ClusterAddr
infoKeys = append ( infoKeys , "cluster address" )
}
// Initialize the listeners
lns := make ( [ ] ServerListener , 0 , len ( config . Listeners ) )
for _ , lnConfig := range config . Listeners {
ln , _ , _ , err := server . NewListener ( lnConfig . Type , lnConfig . Config , c . logWriter , c . UI )
if err != nil {
c . UI . Error ( fmt . Sprintf ( "Error initializing listener of type %s: %s" , lnConfig . Type , err ) )
return 1
}
lns = append ( lns , ServerListener {
Listener : ln ,
config : lnConfig . Config ,
} )
}
listenerCloseFunc := func ( ) {
for _ , ln := range lns {
ln . Listener . Close ( )
}
}
defer c . cleanupGuard . Do ( listenerCloseFunc )
infoKeys = append ( infoKeys , "version" )
verInfo := version . GetVersion ( )
info [ "version" ] = verInfo . FullVersionNumber ( false )
if verInfo . Revision != "" {
info [ "version sha" ] = strings . Trim ( verInfo . Revision , "'" )
infoKeys = append ( infoKeys , "version sha" )
}
infoKeys = append ( infoKeys , "recovery mode" )
info [ "recovery mode" ] = "true"
// Server configuration output
padding := 24
sort . Strings ( infoKeys )
c . UI . Output ( "==> Vault server configuration:\n" )
for _ , k := range infoKeys {
c . UI . Output ( fmt . Sprintf (
"%s%s: %s" ,
strings . Repeat ( " " , padding - len ( k ) ) ,
strings . Title ( k ) ,
info [ k ] ) )
}
c . UI . Output ( "" )
for _ , ln := range lns {
handler := vaulthttp . Handler ( & vault . HandlerProperties {
Core : core ,
MaxRequestSize : ln . maxRequestSize ,
MaxRequestDuration : ln . maxRequestDuration ,
DisablePrintableCheck : config . DisablePrintableCheck ,
RecoveryMode : c . flagRecovery ,
RecoveryToken : atomic . NewString ( "" ) ,
} )
server := & http . Server {
Handler : handler ,
ReadHeaderTimeout : 10 * time . Second ,
ReadTimeout : 30 * time . Second ,
IdleTimeout : 5 * time . Minute ,
ErrorLog : c . logger . StandardLogger ( nil ) ,
}
go server . Serve ( ln . Listener )
}
if sealConfigError != nil {
init , err := core . Initialized ( context . Background ( ) )
if err != nil {
c . UI . Error ( fmt . Sprintf ( "Error checking if core is initialized: %v" , err ) )
return 1
}
if init {
c . UI . Error ( "Vault is initialized but no Seal key could be loaded" )
return 1
}
}
if newCoreError != nil {
c . UI . Warn ( wrapAtLength (
"WARNING! A non-fatal error occurred during initialization. Please " +
"check the logs for more information." ) )
c . UI . Warn ( "" )
}
if ! c . flagCombineLogs {
c . UI . Output ( "==> Vault server started! Log data will stream in below:\n" )
}
c . logGate . Flush ( )
for {
select {
case <- c . ShutdownCh :
c . UI . Output ( "==> Vault shutdown triggered" )
c . cleanupGuard . Do ( listenerCloseFunc )
if err := core . Shutdown ( ) ; err != nil {
c . UI . Error ( fmt . Sprintf ( "Error with core shutdown: %s" , err ) )
}
return 0
case <- c . SigUSR2Ch :
buf := make ( [ ] byte , 32 * 1024 * 1024 )
n := runtime . Stack ( buf [ : ] , true )
c . logger . Info ( "goroutine trace" , "stack" , string ( buf [ : n ] ) )
}
}
return 0
}
func ( c * ServerCommand ) adjustLogLevel ( config * server . Config , logLevelWasNotSet bool ) ( string , error ) {
var logLevelString string
if config . LogLevel != "" && logLevelWasNotSet {
configLogLevel := strings . ToLower ( strings . TrimSpace ( config . LogLevel ) )
logLevelString = configLogLevel
switch configLogLevel {
case "trace" :
c . logger . SetLevel ( log . Trace )
case "debug" :
c . logger . SetLevel ( log . Debug )
case "notice" , "info" , "" :
c . logger . SetLevel ( log . Info )
case "warn" , "warning" :
c . logger . SetLevel ( log . Warn )
case "err" , "error" :
c . logger . SetLevel ( log . Error )
default :
return "" , fmt . Errorf ( "unknown log level: %s" , config . LogLevel )
}
}
return logLevelString , nil
}
func ( c * ServerCommand ) processLogLevelAndFormat ( config * server . Config ) ( log . Level , string , bool , logging . LogFormat , error ) {
2019-07-18 19:59:27 +00:00
// Create a logger. We wrap it in a gated writer so that it doesn't
// start logging too early.
c . logGate = & gatedwriter . Writer { Writer : os . Stderr }
c . logWriter = c . logGate
if c . flagCombineLogs {
c . logWriter = os . Stdout
}
var level log . Level
var logLevelWasNotSet bool
2019-10-15 04:55:31 +00:00
logFormat := logging . UnspecifiedFormat
2019-07-18 19:59:27 +00:00
logLevelString := c . flagLogLevel
c . flagLogLevel = strings . ToLower ( strings . TrimSpace ( c . flagLogLevel ) )
switch c . flagLogLevel {
case notSetValue , "" :
logLevelWasNotSet = true
logLevelString = "info"
level = log . Info
case "trace" :
level = log . Trace
case "debug" :
level = log . Debug
case "notice" , "info" :
level = log . Info
case "warn" , "warning" :
level = log . Warn
case "err" , "error" :
level = log . Error
default :
2019-10-15 04:55:31 +00:00
return level , logLevelString , logLevelWasNotSet , logFormat , fmt . Errorf ( "unknown log level: %s" , c . flagLogLevel )
2019-07-18 19:59:27 +00:00
}
if c . flagLogFormat != notSetValue {
var err error
logFormat , err = logging . ParseLogFormat ( c . flagLogFormat )
if err != nil {
2019-10-15 04:55:31 +00:00
return level , logLevelString , logLevelWasNotSet , logFormat , err
2019-07-18 19:59:27 +00:00
}
}
if logFormat == logging . UnspecifiedFormat {
logFormat = logging . ParseEnvLogFormat ( )
}
if logFormat == logging . UnspecifiedFormat {
var err error
logFormat , err = logging . ParseLogFormat ( config . LogFormat )
if err != nil {
2019-10-15 04:55:31 +00:00
return level , logLevelString , logLevelWasNotSet , logFormat , err
}
}
return level , logLevelString , logLevelWasNotSet , logFormat , nil
}
func ( c * ServerCommand ) Run ( args [ ] string ) int {
f := c . Flags ( )
if err := f . Parse ( args ) ; err != nil {
c . UI . Error ( err . Error ( ) )
return 1
}
if c . flagRecovery {
return c . runRecoveryMode ( )
}
// Automatically enable dev mode if other dev flags are provided.
2019-11-11 17:51:49 +00:00
if c . flagDevConsul || c . flagDevHA || c . flagDevTransactional || c . flagDevLeasedKV || c . flagDevThreeNode || c . flagDevFourCluster || c . flagDevAutoSeal || c . flagDevKVV1 {
2019-10-15 04:55:31 +00:00
c . flagDev = true
}
// Validation
if ! c . flagDev {
switch {
case len ( c . flagConfigs ) == 0 :
c . UI . Error ( "Must specify at least one config path using -config" )
2019-07-18 19:59:27 +00:00
return 1
2019-10-15 04:55:31 +00:00
case c . flagDevRootTokenID != "" :
c . UI . Warn ( wrapAtLength (
"You cannot specify a custom root token ID outside of \"dev\" mode. " +
"Your request has been ignored." ) )
c . flagDevRootTokenID = ""
2019-07-18 19:59:27 +00:00
}
}
2019-10-15 04:55:31 +00:00
// Load the configuration
var config * server . Config
if c . flagDev {
var devStorageType string
switch {
case c . flagDevConsul :
devStorageType = "consul"
case c . flagDevHA && c . flagDevTransactional :
devStorageType = "inmem_transactional_ha"
case ! c . flagDevHA && c . flagDevTransactional :
devStorageType = "inmem_transactional"
case c . flagDevHA && ! c . flagDevTransactional :
devStorageType = "inmem_ha"
default :
devStorageType = "inmem"
}
config = server . DevConfig ( devStorageType )
if c . flagDevListenAddr != "" {
config . Listeners [ 0 ] . Config [ "address" ] = c . flagDevListenAddr
}
}
parsedConfig , err := c . parseConfig ( )
if err != nil {
c . UI . Error ( err . Error ( ) )
return 1
}
if config == nil {
config = parsedConfig
} else {
config = config . Merge ( parsedConfig )
}
// Ensure at least one config was found.
if config == nil {
c . UI . Output ( wrapAtLength (
"No configuration files found. Please provide configurations with the " +
"-config flag. If you are supplying the path to a directory, please " +
"ensure the directory contains files with the .hcl or .json " +
"extension." ) )
return 1
}
level , logLevelString , logLevelWasNotSet , logFormat , err := c . processLogLevelAndFormat ( config )
if err != nil {
c . UI . Error ( err . Error ( ) )
return 1
}
2019-07-18 19:59:27 +00:00
if c . flagDevThreeNode || c . flagDevFourCluster {
c . logger = log . New ( & log . LoggerOptions {
Mutex : & sync . Mutex { } ,
Output : c . logWriter ,
Level : log . Trace ,
} )
} else {
c . logger = log . New ( & log . LoggerOptions {
Output : c . logWriter ,
Level : level ,
// Note that if logFormat is either unspecified or standard, then
// the resulting logger's format will be standard.
JSONFormat : logFormat == logging . JSONFormat ,
} )
}
allLoggers := [ ] log . Logger { c . logger }
2019-10-15 04:55:31 +00:00
logLevelStr , err := c . adjustLogLevel ( config , logLevelWasNotSet )
if err != nil {
c . UI . Error ( err . Error ( ) )
return 1
}
if logLevelStr != "" {
logLevelString = logLevelStr
2018-09-05 19:52:54 +00:00
}
2019-07-18 19:59:27 +00:00
// create GRPC logger
2018-09-05 19:52:54 +00:00
namedGRPCLogFaker := c . logger . Named ( "grpclogfaker" )
allLoggers = append ( allLoggers , namedGRPCLogFaker )
grpclog . SetLogger ( & grpclogFaker {
logger : namedGRPCLogFaker ,
log : os . Getenv ( "VAULT_GRPC_LOGGING" ) != "" ,
} )
2018-10-31 18:11:45 +00:00
if memProfilerEnabled {
c . startMemProfiler ( )
}
2015-05-21 00:49:16 +00:00
// Ensure that a backend is provided
2017-03-08 14:17:00 +00:00
if config . Storage == nil {
2017-09-22 00:51:12 +00:00
c . UI . Output ( "A storage backend must be specified" )
2015-05-19 03:47:57 +00:00
return 1
}
2018-07-24 21:50:49 +00:00
if config . DefaultMaxRequestDuration != 0 {
vault . DefaultMaxRequestDuration = config . DefaultMaxRequestDuration
}
2019-09-30 15:46:42 +00:00
// log proxy settings
proxyCfg := httpproxy . FromEnvironment ( )
c . logger . Info ( "proxy environment" , "http_proxy" , proxyCfg . HTTPProxy ,
"https_proxy" , proxyCfg . HTTPSProxy , "no_proxy" , proxyCfg . NoProxy )
2018-02-14 20:11:33 +00:00
// If mlockall(2) isn't supported, show a warning. We disable this in dev
// because it is quite scary to see when first using Vault. We also disable
// this if the user has explicitly disabled mlock in configuration.
if ! c . flagDev && ! config . DisableMlock && ! mlock . Supported ( ) {
2017-09-22 00:51:12 +00:00
c . UI . Warn ( wrapAtLength (
"WARNING! mlock is not supported on this system! An mlockall(2)-like " +
"syscall to prevent memory from being swapped to disk is not " +
"supported on this system. For better security, only run Vault on " +
"systems where this call is supported. If you are running Vault " +
"in a Docker container, provide the IPC_LOCK cap to the container." ) )
2015-04-28 22:04:40 +00:00
}
2019-02-14 20:46:59 +00:00
metricsHelper , err := c . setupTelemetry ( config )
if err != nil {
2017-09-22 00:51:12 +00:00
c . UI . Error ( fmt . Sprintf ( "Error initializing telemetry: %s" , err ) )
2015-12-17 21:38:17 +00:00
return 1
}
2015-03-13 17:09:38 +00:00
// Initialize the backend
2017-08-03 17:24:27 +00:00
factory , exists := c . PhysicalBackends [ config . Storage . Type ]
if ! exists {
2017-09-22 00:51:12 +00:00
c . UI . Error ( fmt . Sprintf ( "Unknown storage type %s" , config . Storage . Type ) )
2017-08-03 17:24:27 +00:00
return 1
}
2019-10-10 18:42:59 +00:00
if config . Storage . Type == "raft" {
if envCA := os . Getenv ( "VAULT_CLUSTER_ADDR" ) ; envCA != "" {
config . ClusterAddr = envCA
}
if len ( config . ClusterAddr ) == 0 {
c . UI . Error ( "Cluster address must be set when using raft storage" )
return 1
}
2019-06-20 19:14:58 +00:00
}
2019-10-10 18:42:59 +00:00
2018-09-05 19:52:54 +00:00
namedStorageLogger := c . logger . Named ( "storage." + config . Storage . Type )
allLoggers = append ( allLoggers , namedStorageLogger )
backend , err := factory ( config . Storage . Config , namedStorageLogger )
2015-03-13 17:09:38 +00:00
if err != nil {
2017-09-22 00:51:12 +00:00
c . UI . Error ( fmt . Sprintf ( "Error initializing storage of type %s: %s" , config . Storage . Type , err ) )
2015-03-13 17:09:38 +00:00
return 1
}
2018-10-01 21:35:35 +00:00
// Prevent server startup if migration is active
2018-10-23 06:34:02 +00:00
if c . storageMigrationActive ( backend ) {
2018-09-25 23:18:22 +00:00
return 1
}
2016-04-04 17:46:33 +00:00
infoKeys := make ( [ ] string , 0 , 10 )
info := make ( map [ string ] string )
2019-02-07 08:48:50 +00:00
info [ "log level" ] = logLevelString
2017-11-02 14:30:04 +00:00
infoKeys = append ( infoKeys , "log level" )
2016-04-04 17:46:33 +00:00
2019-03-04 22:11:56 +00:00
var barrierSeal vault . Seal
var unwrapSeal vault . Seal
2018-09-18 03:03:00 +00:00
2018-10-29 13:30:24 +00:00
var sealConfigError error
if c . flagDevAutoSeal {
2019-03-04 22:11:56 +00:00
barrierSeal = vault . NewAutoSeal ( vaultseal . NewTestSeal ( nil ) )
2018-10-29 13:30:24 +00:00
} else {
2019-03-04 22:11:56 +00:00
// Handle the case where no seal is provided
2019-03-25 23:50:58 +00:00
switch len ( config . Seals ) {
case 0 :
2019-03-04 22:11:56 +00:00
config . Seals = append ( config . Seals , & server . Seal { Type : vaultseal . Shamir } )
2019-03-25 23:50:58 +00:00
case 1 :
// If there's only one seal and it's disabled assume they want to
// migrate to a shamir seal and simply didn't provide it
if config . Seals [ 0 ] . Disabled {
config . Seals = append ( config . Seals , & server . Seal { Type : vaultseal . Shamir } )
}
2019-03-04 22:11:56 +00:00
}
for _ , configSeal := range config . Seals {
sealType := vaultseal . Shamir
if ! configSeal . Disabled && os . Getenv ( "VAULT_SEAL_TYPE" ) != "" {
sealType = os . Getenv ( "VAULT_SEAL_TYPE" )
2019-03-25 23:52:20 +00:00
configSeal . Type = sealType
2019-03-04 22:11:56 +00:00
} else {
sealType = configSeal . Type
}
var seal vault . Seal
sealLogger := c . logger . Named ( sealType )
allLoggers = append ( allLoggers , sealLogger )
2019-06-20 19:14:58 +00:00
seal , sealConfigError = serverseal . ConfigureSeal ( configSeal , & infoKeys , & info , sealLogger , vault . NewDefaultSeal ( shamirseal . NewSeal ( c . logger . Named ( "shamir" ) ) ) )
2019-03-04 22:11:56 +00:00
if sealConfigError != nil {
if ! errwrap . ContainsType ( sealConfigError , new ( logical . KeyNotFoundError ) ) {
c . UI . Error ( fmt . Sprintf (
"Error parsing Seal configuration: %s" , sealConfigError ) )
return 1
}
}
if seal == nil {
2018-10-29 13:30:24 +00:00
c . UI . Error ( fmt . Sprintf (
2019-03-04 22:11:56 +00:00
"After configuring seal nil returned, seal type was %s" , sealType ) )
2018-10-29 13:30:24 +00:00
return 1
}
2016-04-04 17:46:33 +00:00
2019-03-04 22:11:56 +00:00
if configSeal . Disabled {
unwrapSeal = seal
} else {
barrierSeal = seal
2016-12-05 17:28:12 +00:00
}
2019-03-04 22:11:56 +00:00
// Ensure that the seal finalizer is called, even if using verify-only
defer func ( ) {
err = seal . Finalize ( context . Background ( ) )
if err != nil {
c . UI . Error ( fmt . Sprintf ( "Error finalizing seals: %v" , err ) )
}
} ( )
2016-04-28 18:04:31 +00:00
}
2019-03-04 22:11:56 +00:00
}
2016-04-28 18:04:31 +00:00
2019-03-04 22:11:56 +00:00
if barrierSeal == nil {
c . UI . Error ( fmt . Sprintf ( "Could not create barrier seal! Most likely proper Seal configuration information was not set, but no error was generated." ) )
2016-12-05 17:28:12 +00:00
return 1
}
2019-10-17 17:33:00 +00:00
// prepare a secure random reader for core
secureRandomReader , err := createSecureRandomReaderFunc ( config , & barrierSeal )
if err != nil {
c . UI . Error ( err . Error ( ) )
return 1
}
2015-12-14 22:58:30 +00:00
coreConfig := & vault . CoreConfig {
2019-10-08 17:57:15 +00:00
RawConfig : config ,
2018-09-18 03:03:00 +00:00
Physical : backend ,
RedirectAddr : config . Storage . RedirectAddr ,
2019-09-18 19:07:18 +00:00
StorageType : config . Storage . Type ,
2018-09-18 03:03:00 +00:00
HAPhysical : nil ,
2019-03-04 22:11:56 +00:00
Seal : barrierSeal ,
2018-09-18 03:03:00 +00:00
AuditBackends : c . AuditBackends ,
CredentialBackends : c . CredentialBackends ,
LogicalBackends : c . LogicalBackends ,
Logger : c . logger ,
DisableCache : config . DisableCache ,
DisableMlock : config . DisableMlock ,
MaxLeaseTTL : config . MaxLeaseTTL ,
DefaultLeaseTTL : config . DefaultLeaseTTL ,
ClusterName : config . ClusterName ,
CacheSize : config . CacheSize ,
PluginDirectory : config . PluginDirectory ,
EnableUI : config . EnableUI ,
EnableRaw : config . EnableRawEndpoint ,
DisableSealWrap : config . DisableSealWrap ,
DisablePerformanceStandby : config . DisablePerformanceStandby ,
2018-10-23 19:03:17 +00:00
DisableIndexing : config . DisableIndexing ,
2018-09-18 03:03:00 +00:00
AllLoggers : allLoggers ,
2018-11-07 01:21:24 +00:00
BuiltinRegistry : builtinplugins . Registry ,
2018-11-19 21:13:16 +00:00
DisableKeyEncodingChecks : config . DisablePrintableCheck ,
2019-02-14 20:46:59 +00:00
MetricsHelper : metricsHelper ,
2019-10-17 17:33:00 +00:00
SecureRandomReader : secureRandomReader ,
2015-12-14 22:58:30 +00:00
}
2017-09-22 00:51:12 +00:00
if c . flagDev {
coreConfig . DevToken = c . flagDevRootTokenID
if c . flagDevLeasedKV {
2017-09-15 13:02:29 +00:00
coreConfig . LogicalBackends [ "kv" ] = vault . LeasedPassthroughBackendFactory
2017-06-21 14:42:50 +00:00
}
2017-09-22 00:51:12 +00:00
if c . flagDevPluginDir != "" {
coreConfig . PluginDirectory = c . flagDevPluginDir
2017-08-16 15:17:50 +00:00
}
2017-09-20 20:05:00 +00:00
if c . flagDevLatency > 0 {
injectLatency := time . Duration ( c . flagDevLatency ) * time . Millisecond
2017-09-11 18:49:08 +00:00
if _ , txnOK := backend . ( physical . Transactional ) ; txnOK {
2017-09-20 20:05:00 +00:00
coreConfig . Physical = physical . NewTransactionalLatencyInjector ( backend , injectLatency , c . flagDevLatencyJitter , c . logger )
2017-09-11 18:49:08 +00:00
} else {
2017-09-20 20:05:00 +00:00
coreConfig . Physical = physical . NewLatencyInjector ( backend , injectLatency , c . flagDevLatencyJitter , c . logger )
2017-09-11 18:49:08 +00:00
}
}
2017-02-16 21:29:30 +00:00
}
2015-12-11 20:58:10 +00:00
2017-09-22 00:51:12 +00:00
if c . flagDevThreeNode {
2018-01-03 19:02:31 +00:00
return c . enableThreeNodeDevCluster ( coreConfig , info , infoKeys , c . flagDevListenAddr , os . Getenv ( "VAULT_DEV_TEMP_DIR" ) )
2017-07-31 15:28:06 +00:00
}
2018-09-18 03:03:00 +00:00
if c . flagDevFourCluster {
2019-08-23 15:53:18 +00:00
return enableFourClusterDev ( c , coreConfig , info , infoKeys , c . flagDevListenAddr , os . Getenv ( "VAULT_DEV_TEMP_DIR" ) )
2018-09-18 03:03:00 +00:00
}
2016-08-15 13:42:42 +00:00
var disableClustering bool
2017-03-08 14:17:00 +00:00
// Initialize the separate HA storage backend, if it exists
2016-02-02 20:09:58 +00:00
var ok bool
2017-03-08 14:17:00 +00:00
if config . HAStorage != nil {
2017-08-03 17:24:27 +00:00
factory , exists := c . PhysicalBackends [ config . HAStorage . Type ]
if ! exists {
2017-09-22 00:51:12 +00:00
c . UI . Error ( fmt . Sprintf ( "Unknown HA storage type %s" , config . HAStorage . Type ) )
2017-08-03 17:24:27 +00:00
return 1
2017-09-22 00:51:12 +00:00
2017-08-03 17:24:27 +00:00
}
habackend , err := factory ( config . HAStorage . Config , c . logger )
2015-12-11 20:58:10 +00:00
if err != nil {
2017-09-22 00:51:12 +00:00
c . UI . Error ( fmt . Sprintf (
"Error initializing HA storage of type %s: %s" , config . HAStorage . Type , err ) )
2015-12-11 20:58:10 +00:00
return 1
2017-09-22 00:51:12 +00:00
2015-12-11 20:58:10 +00:00
}
2015-12-14 22:58:30 +00:00
if coreConfig . HAPhysical , ok = habackend . ( physical . HABackend ) ; ! ok {
2017-09-22 00:51:12 +00:00
c . UI . Error ( "Specified HA storage does not support HA" )
2015-12-11 20:58:10 +00:00
return 1
}
2016-07-18 17:19:58 +00:00
if ! coreConfig . HAPhysical . HAEnabled ( ) {
2017-09-22 00:51:12 +00:00
c . UI . Error ( "Specified HA storage has HA support disabled; please consult documentation" )
2016-07-18 17:19:58 +00:00
return 1
}
2017-03-08 14:17:00 +00:00
coreConfig . RedirectAddr = config . HAStorage . RedirectAddr
disableClustering = config . HAStorage . DisableClustering
2016-08-15 13:42:42 +00:00
if ! disableClustering {
2017-03-08 14:17:00 +00:00
coreConfig . ClusterAddr = config . HAStorage . ClusterAddr
2016-08-15 13:42:42 +00:00
}
2016-02-02 20:09:58 +00:00
} else {
if coreConfig . HAPhysical , ok = backend . ( physical . HABackend ) ; ok {
2017-03-08 14:17:00 +00:00
coreConfig . RedirectAddr = config . Storage . RedirectAddr
disableClustering = config . Storage . DisableClustering
2016-08-15 13:42:42 +00:00
if ! disableClustering {
2017-03-08 14:17:00 +00:00
coreConfig . ClusterAddr = config . Storage . ClusterAddr
2016-08-15 13:42:42 +00:00
}
2016-02-02 20:09:58 +00:00
}
2015-12-11 20:58:10 +00:00
}
2017-11-11 01:06:07 +00:00
if envRA := os . Getenv ( "VAULT_API_ADDR" ) ; envRA != "" {
coreConfig . RedirectAddr = envRA
} else if envRA := os . Getenv ( "VAULT_REDIRECT_ADDR" ) ; envRA != "" {
2016-08-15 13:42:42 +00:00
coreConfig . RedirectAddr = envRA
} else if envAA := os . Getenv ( "VAULT_ADVERTISE_ADDR" ) ; envAA != "" {
coreConfig . RedirectAddr = envAA
2015-12-15 02:22:55 +00:00
}
2016-08-15 13:42:42 +00:00
// Attempt to detect the redirect address, if possible
2018-10-10 18:52:00 +00:00
if coreConfig . RedirectAddr == "" {
c . logger . Warn ( "no `api_addr` value specified in config or in VAULT_API_ADDR; falling back to detection if possible, but this value should be manually set" )
}
2016-08-15 13:42:42 +00:00
var detect physical . RedirectDetect
2016-07-18 17:19:58 +00:00
if coreConfig . HAPhysical != nil && coreConfig . HAPhysical . HAEnabled ( ) {
2016-08-15 13:42:42 +00:00
detect , ok = coreConfig . HAPhysical . ( physical . RedirectDetect )
2015-12-15 02:13:17 +00:00
} else {
2016-08-15 13:42:42 +00:00
detect , ok = coreConfig . Physical . ( physical . RedirectDetect )
2015-12-15 02:13:17 +00:00
}
2016-08-15 13:42:42 +00:00
if ok && coreConfig . RedirectAddr == "" {
redirect , err := c . detectRedirect ( detect , config )
2015-05-02 22:57:40 +00:00
if err != nil {
2018-04-04 20:15:07 +00:00
c . UI . Error ( fmt . Sprintf ( "Error detecting api address: %s" , err ) )
2016-08-15 13:42:42 +00:00
} else if redirect == "" {
2018-04-04 20:15:07 +00:00
c . UI . Error ( "Failed to detect api address" )
2015-05-02 22:57:40 +00:00
} else {
2016-08-15 13:42:42 +00:00
coreConfig . RedirectAddr = redirect
2015-05-02 22:57:40 +00:00
}
}
2017-09-22 00:51:12 +00:00
if coreConfig . RedirectAddr == "" && c . flagDev {
2017-02-24 15:45:29 +00:00
coreConfig . RedirectAddr = fmt . Sprintf ( "http://%s" , config . Listeners [ 0 ] . Config [ "address" ] )
}
2015-05-02 22:57:40 +00:00
2016-08-15 13:42:42 +00:00
// After the redirect bits are sorted out, if no cluster address was
// explicitly given, derive one from the redirect addr
if disableClustering {
coreConfig . ClusterAddr = ""
} else if envCA := os . Getenv ( "VAULT_CLUSTER_ADDR" ) ; envCA != "" {
coreConfig . ClusterAddr = envCA
2017-02-24 15:45:29 +00:00
} else {
var addrToUse string
2017-02-24 17:50:26 +00:00
switch {
case coreConfig . ClusterAddr == "" && coreConfig . RedirectAddr != "" :
2017-02-24 15:45:29 +00:00
addrToUse = coreConfig . RedirectAddr
2017-09-22 00:51:12 +00:00
case c . flagDev :
2017-02-24 15:45:29 +00:00
addrToUse = fmt . Sprintf ( "http://%s" , config . Listeners [ 0 ] . Config [ "address" ] )
2017-02-24 17:50:26 +00:00
default :
goto CLUSTER_SYNTHESIS_COMPLETE
2017-02-24 15:45:29 +00:00
}
u , err := url . ParseRequestURI ( addrToUse )
2016-08-15 13:42:42 +00:00
if err != nil {
2017-09-22 00:51:12 +00:00
c . UI . Error ( fmt . Sprintf (
"Error parsing synthesized cluster address %s: %v" , addrToUse , err ) )
2016-04-04 14:44:22 +00:00
return 1
}
2016-08-15 13:42:42 +00:00
host , port , err := net . SplitHostPort ( u . Host )
2015-03-31 23:44:47 +00:00
if err != nil {
2017-02-08 18:50:17 +00:00
// This sucks, as it's a const in the function but not exported in the package
if strings . Contains ( err . Error ( ) , "missing port in address" ) {
host = u . Host
port = "443"
} else {
2018-04-04 20:15:07 +00:00
c . UI . Error ( fmt . Sprintf ( "Error parsing api address: %v" , err ) )
2017-02-08 18:50:17 +00:00
return 1
}
2016-08-15 13:42:42 +00:00
}
2017-02-08 18:50:17 +00:00
nPort , err := strconv . Atoi ( port )
if err != nil {
2017-09-22 00:51:12 +00:00
c . UI . Error ( fmt . Sprintf (
"Error parsing synthesized address; failed to convert %q to a numeric: %v" , port , err ) )
2015-03-31 23:44:47 +00:00
return 1
}
2016-08-15 13:42:42 +00:00
u . Host = net . JoinHostPort ( host , strconv . Itoa ( nPort + 1 ) )
// Will always be TLS-secured
u . Scheme = "https"
coreConfig . ClusterAddr = u . String ( )
}
2017-02-24 17:50:26 +00:00
CLUSTER_SYNTHESIS_COMPLETE :
2018-04-05 16:54:15 +00:00
if coreConfig . RedirectAddr == coreConfig . ClusterAddr && len ( coreConfig . RedirectAddr ) != 0 {
2018-04-04 20:15:07 +00:00
c . UI . Error ( fmt . Sprintf (
"Address %q used for both API and cluster addresses" , coreConfig . RedirectAddr ) )
return 1
}
2016-08-15 13:42:42 +00:00
if coreConfig . ClusterAddr != "" {
// Force https as we'll always be TLS-secured
u , err := url . ParseRequestURI ( coreConfig . ClusterAddr )
if err != nil {
2018-04-17 12:36:38 +00:00
c . UI . Error ( fmt . Sprintf ( "Error parsing cluster address %s: %v" , coreConfig . ClusterAddr , err ) )
2017-09-22 00:51:12 +00:00
return 11
2015-10-22 07:48:46 +00:00
}
2016-08-15 13:42:42 +00:00
u . Scheme = "https"
coreConfig . ClusterAddr = u . String ( )
}
2015-10-22 07:48:46 +00:00
2018-03-27 20:23:33 +00:00
// Override the UI enabling config by the environment variable
if enableUI := os . Getenv ( "VAULT_UI" ) ; enableUI != "" {
var err error
coreConfig . EnableUI , err = strconv . ParseBool ( enableUI )
if err != nil {
c . UI . Output ( "Error parsing the environment variable VAULT_UI" )
return 1
}
}
2016-08-15 13:42:42 +00:00
// Initialize the core
core , newCoreError := vault . NewCore ( coreConfig )
if newCoreError != nil {
2019-01-23 21:34:34 +00:00
if vault . IsFatalError ( newCoreError ) {
2017-09-22 00:51:12 +00:00
c . UI . Error ( fmt . Sprintf ( "Error initializing core: %s" , newCoreError ) )
2016-08-15 13:42:42 +00:00
return 1
}
2015-03-31 23:44:47 +00:00
}
2016-09-30 04:06:40 +00:00
// Copy the reload funcs pointers back
c . reloadFuncs = coreConfig . ReloadFuncs
c . reloadFuncsLock = coreConfig . ReloadFuncsLock
2015-04-04 19:06:41 +00:00
// Compile server information for output later
2017-03-08 14:17:00 +00:00
info [ "storage" ] = config . Storage . Type
2015-04-28 22:11:39 +00:00
info [ "mlock" ] = fmt . Sprintf (
"supported: %v, enabled: %v" ,
2016-11-22 17:56:36 +00:00
mlock . Supported ( ) , ! config . DisableMlock && mlock . Supported ( ) )
2017-11-02 14:30:04 +00:00
infoKeys = append ( infoKeys , "mlock" , "storage" )
2015-04-04 19:06:41 +00:00
2017-02-24 15:45:29 +00:00
if coreConfig . ClusterAddr != "" {
info [ "cluster address" ] = coreConfig . ClusterAddr
infoKeys = append ( infoKeys , "cluster address" )
}
if coreConfig . RedirectAddr != "" {
2018-04-04 20:15:07 +00:00
info [ "api address" ] = coreConfig . RedirectAddr
infoKeys = append ( infoKeys , "api address" )
2017-02-24 15:45:29 +00:00
}
2017-03-08 14:17:00 +00:00
if config . HAStorage != nil {
info [ "HA storage" ] = config . HAStorage . Type
infoKeys = append ( infoKeys , "HA storage" )
2015-12-11 20:58:10 +00:00
} else {
2017-03-08 14:17:00 +00:00
// If the storage supports HA, then note it
2015-12-14 22:58:30 +00:00
if coreConfig . HAPhysical != nil {
2016-07-18 17:19:58 +00:00
if coreConfig . HAPhysical . HAEnabled ( ) {
2017-03-08 14:17:00 +00:00
info [ "storage" ] += " (HA available)"
2016-07-18 17:19:58 +00:00
} else {
2017-03-08 14:17:00 +00:00
info [ "storage" ] += " (HA disabled)"
2016-07-18 17:19:58 +00:00
}
2015-12-11 20:58:10 +00:00
}
2015-04-17 17:50:37 +00:00
}
2016-08-19 15:03:53 +00:00
clusterAddrs := [ ] * net . TCPAddr { }
2016-08-15 13:42:42 +00:00
2015-03-12 22:30:07 +00:00
// Initialize the listeners
2018-04-17 22:52:09 +00:00
lns := make ( [ ] ServerListener , 0 , len ( config . Listeners ) )
2016-09-30 04:06:40 +00:00
c . reloadFuncsLock . Lock ( )
2015-04-04 19:06:41 +00:00
for i , lnConfig := range config . Listeners {
2018-06-15 18:47:37 +00:00
ln , props , reloadFunc , err := server . NewListener ( lnConfig . Type , lnConfig . Config , c . logWriter , c . UI )
2015-03-13 17:09:38 +00:00
if err != nil {
2017-09-22 00:51:12 +00:00
c . UI . Error ( fmt . Sprintf ( "Error initializing listener of type %s: %s" , lnConfig . Type , err ) )
2015-03-13 17:09:38 +00:00
return 1
}
2016-08-15 13:42:42 +00:00
if reloadFunc != nil {
2016-09-30 04:06:40 +00:00
relSlice := ( * c . reloadFuncs ) [ "listener|" + lnConfig . Type ]
2016-08-15 13:42:42 +00:00
relSlice = append ( relSlice , reloadFunc )
2016-09-30 04:06:40 +00:00
( * c . reloadFuncs ) [ "listener|" + lnConfig . Type ] = relSlice
2016-08-15 13:42:42 +00:00
}
if ! disableClustering && lnConfig . Type == "tcp" {
2017-06-22 19:29:53 +00:00
var addrRaw interface { }
2016-08-15 13:42:42 +00:00
var addr string
var ok bool
2017-06-22 19:29:53 +00:00
if addrRaw , ok = lnConfig . Config [ "cluster_address" ] ; ok {
addr = addrRaw . ( string )
2016-08-19 15:03:53 +00:00
tcpAddr , err := net . ResolveTCPAddr ( "tcp" , addr )
if err != nil {
2017-09-22 00:51:12 +00:00
c . UI . Error ( fmt . Sprintf ( "Error resolving cluster_address: %s" , err ) )
2016-08-19 15:03:53 +00:00
return 1
}
clusterAddrs = append ( clusterAddrs , tcpAddr )
2016-08-15 13:42:42 +00:00
} else {
tcpAddr , ok := ln . Addr ( ) . ( * net . TCPAddr )
if ! ok {
2017-09-22 00:51:12 +00:00
c . UI . Error ( "Failed to parse tcp listener" )
2016-08-15 13:42:42 +00:00
return 1
}
2017-02-24 15:45:29 +00:00
clusterAddr := & net . TCPAddr {
2016-08-19 15:03:53 +00:00
IP : tcpAddr . IP ,
Port : tcpAddr . Port + 1 ,
2017-02-24 15:45:29 +00:00
}
clusterAddrs = append ( clusterAddrs , clusterAddr )
addr = clusterAddr . String ( )
2016-08-15 13:42:42 +00:00
}
props [ "cluster address" ] = addr
}
2018-07-06 19:44:56 +00:00
var maxRequestSize int64 = vaulthttp . DefaultMaxRequestSize
if valRaw , ok := lnConfig . Config [ "max_request_size" ] ; ok {
val , err := parseutil . ParseInt ( valRaw )
if err != nil {
c . UI . Error ( fmt . Sprintf ( "Could not parse max_request_size value %v" , valRaw ) )
return 1
}
if val >= 0 {
maxRequestSize = val
}
}
props [ "max_request_size" ] = fmt . Sprintf ( "%d" , maxRequestSize )
2019-10-08 17:57:15 +00:00
maxRequestDuration := vault . DefaultMaxRequestDuration
2018-07-24 21:50:49 +00:00
if valRaw , ok := lnConfig . Config [ "max_request_duration" ] ; ok {
val , err := parseutil . ParseDurationSecond ( valRaw )
if err != nil {
c . UI . Error ( fmt . Sprintf ( "Could not parse max_request_duration value %v" , valRaw ) )
return 1
}
if val >= 0 {
maxRequestDuration = val
}
}
props [ "max_request_duration" ] = fmt . Sprintf ( "%s" , maxRequestDuration . String ( ) )
2019-10-04 07:29:51 +00:00
var unauthenticatedMetricsAccess bool
if telemetryRaw , ok := lnConfig . Config [ "telemetry" ] ; ok {
telemetry , ok := telemetryRaw . ( [ ] map [ string ] interface { } )
if ! ok {
c . UI . Error ( fmt . Sprintf ( "Could not parse telemetry sink value %v" , telemetryRaw ) )
return 1
}
for _ , item := range telemetry {
if valRaw , ok := item [ "unauthenticated_metrics_access" ] ; ok {
unauthenticatedMetricsAccess , err = parseutil . ParseBool ( valRaw )
if err != nil {
c . UI . Error ( fmt . Sprintf ( "Could not parse unauthenticated_metrics_access value %v" , valRaw ) )
return 1
}
}
}
}
2018-07-06 19:44:56 +00:00
lns = append ( lns , ServerListener {
2019-10-04 07:29:51 +00:00
Listener : ln ,
config : lnConfig . Config ,
maxRequestSize : maxRequestSize ,
maxRequestDuration : maxRequestDuration ,
unauthenticatedMetricsAccess : unauthenticatedMetricsAccess ,
2018-07-06 19:44:56 +00:00
} )
2015-04-04 19:06:41 +00:00
// Store the listener props for output later
key := fmt . Sprintf ( "listener %d" , i + 1 )
propsList := make ( [ ] string , 0 , len ( props ) )
for k , v := range props {
propsList = append ( propsList , fmt . Sprintf (
"%s: %q" , k , v ) )
}
sort . Strings ( propsList )
infoKeys = append ( infoKeys , key )
info [ key ] = fmt . Sprintf (
"%s (%s)" , lnConfig . Type , strings . Join ( propsList , ", " ) )
2016-08-15 13:42:42 +00:00
}
2016-09-30 04:06:40 +00:00
c . reloadFuncsLock . Unlock ( )
2016-08-15 13:42:42 +00:00
if ! disableClustering {
2018-04-03 00:46:59 +00:00
if c . logger . IsDebug ( ) {
c . logger . Debug ( "cluster listener addresses synthesized" , "cluster_addresses" , clusterAddrs )
2016-08-19 20:45:17 +00:00
}
2015-03-13 17:09:38 +00:00
}
2016-06-02 16:40:25 +00:00
// Make sure we close all listeners from this point on
2016-10-10 17:18:19 +00:00
listenerCloseFunc := func ( ) {
2016-06-02 16:40:25 +00:00
for _ , ln := range lns {
2018-04-17 22:52:09 +00:00
ln . Listener . Close ( )
2016-06-02 16:40:25 +00:00
}
2016-10-10 17:18:19 +00:00
}
defer c . cleanupGuard . Do ( listenerCloseFunc )
2016-06-02 16:40:25 +00:00
2016-11-28 00:16:44 +00:00
infoKeys = append ( infoKeys , "version" )
2016-11-22 21:43:05 +00:00
verInfo := version . GetVersion ( )
2016-11-28 00:28:35 +00:00
info [ "version" ] = verInfo . FullVersionNumber ( false )
2016-11-28 00:16:44 +00:00
if verInfo . Revision != "" {
2016-11-28 00:28:35 +00:00
info [ "version sha" ] = strings . Trim ( verInfo . Revision , "'" )
infoKeys = append ( infoKeys , "version sha" )
}
infoKeys = append ( infoKeys , "cgo" )
info [ "cgo" ] = "disabled"
if version . CgoEnabled {
info [ "cgo" ] = "enabled"
2016-11-28 00:16:44 +00:00
}
2015-11-09 18:52:55 +00:00
2019-10-15 04:55:31 +00:00
infoKeys = append ( infoKeys , "recovery mode" )
info [ "recovery mode" ] = "false"
2015-04-04 19:06:41 +00:00
// Server configuration output
2016-03-30 16:31:47 +00:00
padding := 24
sort . Strings ( infoKeys )
2017-09-22 00:51:12 +00:00
c . UI . Output ( "==> Vault server configuration:\n" )
2015-04-04 19:06:41 +00:00
for _ , k := range infoKeys {
2017-09-22 00:51:12 +00:00
c . UI . Output ( fmt . Sprintf (
2015-04-04 19:06:41 +00:00
"%s%s: %s" ,
strings . Repeat ( " " , padding - len ( k ) ) ,
strings . Title ( k ) ,
info [ k ] ) )
}
2017-09-22 00:51:12 +00:00
c . UI . Output ( "" )
2015-04-04 19:06:41 +00:00
2017-09-22 00:51:12 +00:00
// Tests might not want to start a vault server and just want to verify
// the configuration.
if c . flagTestVerifyOnly {
2016-02-02 22:47:02 +00:00
return 0
}
2017-10-10 16:27:51 +00:00
// This needs to happen before we first unseal, so before we trigger dev
// mode if it's set
core . SetClusterListenerAddrs ( clusterAddrs )
2018-07-06 19:44:56 +00:00
core . SetClusterHandler ( vaulthttp . Handler ( & vault . HandlerProperties {
Core : core ,
} ) )
2017-10-10 16:27:51 +00:00
2018-10-23 06:34:02 +00:00
// Before unsealing with stored keys, setup seal migration if needed
2019-06-20 19:14:58 +00:00
if err := adjustCoreForSealMigration ( c . logger , core , barrierSeal , unwrapSeal ) ; err != nil {
2018-10-23 06:34:02 +00:00
c . UI . Error ( err . Error ( ) )
return 1
}
2019-01-23 21:34:34 +00:00
// Attempt unsealing in a background goroutine. This is needed for when a
// Vault cluster with multiple servers is configured with auto-unseal but is
// uninitialized. Once one server initializes the storage backend, this
// goroutine will pick up the unseal keys and unseal this instance.
2019-03-04 22:11:56 +00:00
if ! core . IsInSealMigration ( ) {
go func ( ) {
for {
err := core . UnsealWithStoredKeys ( context . Background ( ) )
if err == nil {
return
}
2019-01-23 21:34:34 +00:00
2019-03-04 22:11:56 +00:00
if vault . IsFatalError ( err ) {
c . logger . Error ( "error unsealing core" , "error" , err )
return
} else {
c . logger . Warn ( "failed to unseal core" , "error" , err )
}
2019-01-23 21:34:34 +00:00
2019-03-04 22:11:56 +00:00
select {
case <- c . ShutdownCh :
return
case <- time . After ( 5 * time . Second ) :
}
2019-01-23 21:34:34 +00:00
}
2019-03-04 22:11:56 +00:00
} ( )
}
2017-10-23 21:39:21 +00:00
2016-07-30 17:17:29 +00:00
// Perform service discovery registrations and initialization of
// HTTP server after the verifyOnly check.
// Instantiate the wait group
c . WaitGroup = & sync . WaitGroup { }
// If the backend supports service discovery, run service discovery
if coreConfig . HAPhysical != nil && coreConfig . HAPhysical . HAEnabled ( ) {
sd , ok := coreConfig . HAPhysical . ( physical . ServiceDiscovery )
if ok {
activeFunc := func ( ) bool {
2017-07-31 22:25:27 +00:00
if isLeader , _ , _ , err := core . Leader ( ) ; err == nil {
2016-07-30 17:17:29 +00:00
return isLeader
}
return false
}
2018-09-18 03:03:00 +00:00
if err := sd . RunServiceDiscovery ( c . WaitGroup , c . ShutdownCh , coreConfig . RedirectAddr , activeFunc , core . Sealed , core . PerfStandby ) ; err != nil {
2017-09-22 00:51:12 +00:00
c . UI . Error ( fmt . Sprintf ( "Error initializing service discovery: %v" , err ) )
2016-07-30 17:17:29 +00:00
return 1
}
}
}
2017-03-25 17:51:12 +00:00
// If we're in Dev mode, then initialize the core
2017-09-22 00:51:12 +00:00
if c . flagDev && ! c . flagDevSkipInit {
2017-07-31 15:28:06 +00:00
init , err := c . enableDev ( core , coreConfig )
2016-08-15 13:42:42 +00:00
if err != nil {
2017-09-22 00:51:12 +00:00
c . UI . Error ( fmt . Sprintf ( "Error initializing Dev mode: %s" , err ) )
2016-08-15 13:42:42 +00:00
return 1
}
2018-11-16 00:55:24 +00:00
var plugins , pluginsNotLoaded [ ] string
2018-03-28 21:36:55 +00:00
if c . flagDevPluginDir != "" && c . flagDevPluginInit {
2018-11-07 01:21:24 +00:00
2018-03-28 21:36:55 +00:00
f , err := os . Open ( c . flagDevPluginDir )
if err != nil {
c . UI . Error ( fmt . Sprintf ( "Error reading plugin dir: %s" , err ) )
return 1
}
list , err := f . Readdirnames ( 0 )
f . Close ( )
if err != nil {
c . UI . Error ( fmt . Sprintf ( "Error listing plugins: %s" , err ) )
return 1
}
for _ , name := range list {
path := filepath . Join ( f . Name ( ) , name )
if err := c . addPlugin ( path , init . RootToken , core ) ; err != nil {
2018-11-16 00:55:24 +00:00
if ! errwrap . Contains ( err , vault . ErrPluginBadType . Error ( ) ) {
c . UI . Error ( fmt . Sprintf ( "Error enabling plugin %s: %s" , name , err ) )
return 1
}
pluginsNotLoaded = append ( pluginsNotLoaded , name )
continue
2018-03-28 21:36:55 +00:00
}
plugins = append ( plugins , name )
}
sort . Strings ( plugins )
}
2017-09-22 00:51:12 +00:00
// Print the big dev mode warning!
c . UI . Warn ( wrapAtLength (
"WARNING! dev mode is enabled! In this mode, Vault runs entirely " +
"in-memory and starts unsealed with a single unseal key. The root " +
"token is already authenticated to the CLI, so you can immediately " +
"begin using Vault." ) )
c . UI . Warn ( "" )
c . UI . Warn ( "You may need to set the following environment variable:" )
c . UI . Warn ( "" )
2018-12-20 18:27:21 +00:00
2019-01-09 00:48:57 +00:00
endpointURL := "http://" + config . Listeners [ 0 ] . Config [ "address" ] . ( string )
2018-12-20 18:27:21 +00:00
if runtime . GOOS == "windows" {
c . UI . Warn ( "PowerShell:" )
c . UI . Warn ( fmt . Sprintf ( " $env:VAULT_ADDR=\"%s\"" , endpointURL ) )
c . UI . Warn ( "cmd.exe:" )
c . UI . Warn ( fmt . Sprintf ( " set VAULT_ADDR=%s" , endpointURL ) )
} else {
c . UI . Warn ( fmt . Sprintf ( " $ export VAULT_ADDR='%s'" , endpointURL ) )
}
2017-09-21 19:23:29 +00:00
// Unseal key is not returned if stored shares is supported
if len ( init . SecretShares ) > 0 {
2017-09-22 00:51:12 +00:00
c . UI . Warn ( "" )
c . UI . Warn ( wrapAtLength (
"The unseal key and root token are displayed below in case you want " +
"to seal/unseal the Vault or re-authenticate." ) )
c . UI . Warn ( "" )
c . UI . Warn ( fmt . Sprintf ( "Unseal Key: %s" , base64 . StdEncoding . EncodeToString ( init . SecretShares [ 0 ] ) ) )
2017-09-21 19:23:29 +00:00
}
if len ( init . RecoveryShares ) > 0 {
2017-09-22 00:51:12 +00:00
c . UI . Warn ( "" )
c . UI . Warn ( wrapAtLength (
"The recovery key and root token are displayed below in case you want " +
"to seal/unseal the Vault or re-authenticate." ) )
c . UI . Warn ( "" )
2018-10-29 13:30:24 +00:00
c . UI . Warn ( fmt . Sprintf ( "Recovery Key: %s" , base64 . StdEncoding . EncodeToString ( init . RecoveryShares [ 0 ] ) ) )
2017-09-21 19:23:29 +00:00
}
2017-09-22 00:51:12 +00:00
c . UI . Warn ( fmt . Sprintf ( "Root Token: %s" , init . RootToken ) )
2018-03-28 21:36:55 +00:00
if len ( plugins ) > 0 {
c . UI . Warn ( "" )
c . UI . Warn ( wrapAtLength (
"The following dev plugins are registered in the catalog:" ) )
for _ , p := range plugins {
c . UI . Warn ( fmt . Sprintf ( " - %s" , p ) )
}
}
2018-11-16 00:55:24 +00:00
if len ( pluginsNotLoaded ) > 0 {
c . UI . Warn ( "" )
c . UI . Warn ( wrapAtLength (
"The following dev plugins FAILED to be registered in the catalog due to unknown type:" ) )
for _ , p := range pluginsNotLoaded {
c . UI . Warn ( fmt . Sprintf ( " - %s" , p ) )
}
}
2017-09-22 00:51:12 +00:00
c . UI . Warn ( "" )
c . UI . Warn ( wrapAtLength (
"Development mode should NOT be used in production installations!" ) )
c . UI . Warn ( "" )
2016-08-15 13:42:42 +00:00
}
2017-11-02 14:30:04 +00:00
// Initialize the HTTP servers
2016-02-02 22:47:02 +00:00
for _ , ln := range lns {
2018-07-06 19:44:56 +00:00
handler := vaulthttp . Handler ( & vault . HandlerProperties {
2019-10-04 07:29:51 +00:00
Core : core ,
MaxRequestSize : ln . maxRequestSize ,
MaxRequestDuration : ln . maxRequestDuration ,
DisablePrintableCheck : config . DisablePrintableCheck ,
UnauthenticatedMetricsAccess : ln . unauthenticatedMetricsAccess ,
2019-10-15 04:55:31 +00:00
RecoveryMode : c . flagRecovery ,
2018-07-06 19:44:56 +00:00
} )
2018-04-17 22:52:09 +00:00
// We perform validation on the config earlier, we can just cast here
if _ , ok := ln . config [ "x_forwarded_for_authorized_addrs" ] ; ok {
hopSkips := ln . config [ "x_forwarded_for_hop_skips" ] . ( int )
authzdAddrs := ln . config [ "x_forwarded_for_authorized_addrs" ] . ( [ ] * sockaddr . SockAddrMarshaler )
rejectNotPresent := ln . config [ "x_forwarded_for_reject_not_present" ] . ( bool )
rejectNonAuthz := ln . config [ "x_forwarded_for_reject_not_authorized" ] . ( bool )
if len ( authzdAddrs ) > 0 {
handler = vaulthttp . WrapForwardedForHandler ( handler , authzdAddrs , rejectNotPresent , rejectNonAuthz , hopSkips )
}
}
2019-05-10 17:41:42 +00:00
// server defaults
2017-11-02 14:30:04 +00:00
server := & http . Server {
2018-06-16 22:21:33 +00:00
Handler : handler ,
ReadHeaderTimeout : 10 * time . Second ,
ReadTimeout : 30 * time . Second ,
IdleTimeout : 5 * time . Minute ,
2018-08-21 15:23:18 +00:00
ErrorLog : c . logger . StandardLogger ( nil ) ,
2017-11-02 14:30:04 +00:00
}
2019-05-10 17:41:42 +00:00
// override server defaults with config values for read/write/idle timeouts if configured
if readHeaderTimeoutInterface , ok := ln . config [ "http_read_header_timeout" ] ; ok {
readHeaderTimeout , err := parseutil . ParseDurationSecond ( readHeaderTimeoutInterface )
if err != nil {
c . UI . Error ( fmt . Sprintf ( "Could not parse a time value for http_read_header_timeout %v" , readHeaderTimeout ) )
return 1
}
server . ReadHeaderTimeout = readHeaderTimeout
}
if readTimeoutInterface , ok := ln . config [ "http_read_timeout" ] ; ok {
readTimeout , err := parseutil . ParseDurationSecond ( readTimeoutInterface )
if err != nil {
c . UI . Error ( fmt . Sprintf ( "Could not parse a time value for http_read_timeout %v" , readTimeout ) )
return 1
}
server . ReadTimeout = readTimeout
}
if writeTimeoutInterface , ok := ln . config [ "http_write_timeout" ] ; ok {
writeTimeout , err := parseutil . ParseDurationSecond ( writeTimeoutInterface )
if err != nil {
c . UI . Error ( fmt . Sprintf ( "Could not parse a time value for http_write_timeout %v" , writeTimeout ) )
return 1
}
server . WriteTimeout = writeTimeout
}
if idleTimeoutInterface , ok := ln . config [ "http_idle_timeout" ] ; ok {
idleTimeout , err := parseutil . ParseDurationSecond ( idleTimeoutInterface )
if err != nil {
c . UI . Error ( fmt . Sprintf ( "Could not parse a time value for http_idle_timeout %v" , idleTimeout ) )
return 1
}
server . IdleTimeout = idleTimeout
}
// server config tests can exit now
if c . flagTestServerConfig {
continue
}
2018-04-17 22:52:09 +00:00
go server . Serve ( ln . Listener )
2016-02-02 22:47:02 +00:00
}
2019-05-10 17:41:42 +00:00
if c . flagTestServerConfig {
return 0
}
2018-09-18 03:03:00 +00:00
if sealConfigError != nil {
init , err := core . Initialized ( context . Background ( ) )
if err != nil {
c . UI . Error ( fmt . Sprintf ( "Error checking if core is initialized: %v" , err ) )
return 1
}
if init {
c . UI . Error ( "Vault is initialized but no Seal key could be loaded" )
return 1
}
}
2016-04-04 14:44:22 +00:00
if newCoreError != nil {
2017-09-22 00:51:12 +00:00
c . UI . Warn ( wrapAtLength (
"WARNING! A non-fatal error occurred during initialization. Please " +
"check the logs for more information." ) )
c . UI . Warn ( "" )
2016-04-04 14:44:22 +00:00
}
2015-04-04 19:06:41 +00:00
// Output the header that the server has started
2018-06-15 18:47:37 +00:00
if ! c . flagCombineLogs {
c . UI . Output ( "==> Vault server started! Log data will stream in below:\n" )
}
2017-09-22 00:51:12 +00:00
// Inform any tests that the server is ready
select {
case c . startedCh <- struct { } { } :
default :
}
2015-04-04 19:06:41 +00:00
// Release the log gate.
2017-07-31 15:28:06 +00:00
c . logGate . Flush ( )
2015-04-04 19:06:41 +00:00
2017-09-16 21:09:37 +00:00
// Write out the PID to the file now that server has successfully started
if err := c . storePidFile ( config . PidFile ) ; err != nil {
2017-09-20 20:05:00 +00:00
c . UI . Error ( fmt . Sprintf ( "Error storing PID: %s" , err ) )
2017-09-16 21:09:37 +00:00
return 1
}
defer func ( ) {
if err := c . removePidFile ( config . PidFile ) ; err != nil {
2017-09-20 20:05:00 +00:00
c . UI . Error ( fmt . Sprintf ( "Error deleting the PID file: %s" , err ) )
2017-09-16 21:09:37 +00:00
}
} ( )
2016-08-01 15:58:45 +00:00
// Wait for shutdown
shutdownTriggered := false
2016-03-11 22:01:26 +00:00
for ! shutdownTriggered {
2016-03-11 21:46:56 +00:00
select {
case <- c . ShutdownCh :
2017-09-22 00:51:12 +00:00
c . UI . Output ( "==> Vault shutdown triggered" )
2016-10-10 17:18:19 +00:00
2018-03-20 18:54:10 +00:00
// Stop the listeners so that we don't process further client requests.
2016-10-10 17:18:19 +00:00
c . cleanupGuard . Do ( listenerCloseFunc )
// Shutdown will wait until after Vault is sealed, which means the
// request forwarding listeners will also be closed (and also
// waited for).
2016-03-11 21:46:56 +00:00
if err := core . Shutdown ( ) ; err != nil {
2017-09-22 00:51:12 +00:00
c . UI . Error ( fmt . Sprintf ( "Error with core shutdown: %s" , err ) )
2016-03-11 21:46:56 +00:00
}
2016-10-10 17:18:19 +00:00
2016-03-11 21:46:56 +00:00
shutdownTriggered = true
2016-10-10 17:18:19 +00:00
2016-03-11 21:46:56 +00:00
case <- c . SighupCh :
2017-09-22 00:51:12 +00:00
c . UI . Output ( "==> Vault reload triggered" )
2018-09-05 19:52:54 +00:00
// Check for new log level
var config * server . Config
var level log . Level
for _ , path := range c . flagConfigs {
2019-07-18 19:59:27 +00:00
current , err := server . LoadConfig ( path )
2018-09-05 19:52:54 +00:00
if err != nil {
c . logger . Error ( "could not reload config" , "path" , path , "error" , err )
goto RUNRELOADFUNCS
}
if config == nil {
config = current
} else {
config = config . Merge ( current )
}
}
// Ensure at least one config was found.
if config == nil {
c . logger . Error ( "no config found at reload time" )
goto RUNRELOADFUNCS
}
2019-10-08 17:57:15 +00:00
core . SetConfig ( config )
2018-09-05 19:52:54 +00:00
if config . LogLevel != "" {
configLogLevel := strings . ToLower ( strings . TrimSpace ( config . LogLevel ) )
switch configLogLevel {
case "trace" :
level = log . Trace
case "debug" :
level = log . Debug
case "notice" , "info" , "" :
level = log . Info
case "warn" , "warning" :
level = log . Warn
case "err" , "error" :
level = log . Error
default :
c . logger . Error ( "unknown log level found on reload" , "level" , config . LogLevel )
goto RUNRELOADFUNCS
}
core . SetLogLevel ( level )
}
RUNRELOADFUNCS :
2017-09-22 00:51:12 +00:00
if err := c . Reload ( c . reloadFuncsLock , c . reloadFuncs , c . flagConfigs ) ; err != nil {
c . UI . Error ( fmt . Sprintf ( "Error(s) were encountered during reload: %s" , err ) )
2016-03-11 21:46:56 +00:00
}
2019-03-15 13:27:53 +00:00
case <- c . SigUSR2Ch :
buf := make ( [ ] byte , 32 * 1024 * 1024 )
n := runtime . Stack ( buf [ : ] , true )
c . logger . Info ( "goroutine trace" , "stack" , string ( buf [ : n ] ) )
2016-03-11 21:46:56 +00:00
}
2015-06-18 01:24:56 +00:00
}
2016-04-14 01:12:58 +00:00
2016-08-01 15:15:25 +00:00
// Wait for dependent goroutines to complete
2016-07-30 17:17:29 +00:00
c . WaitGroup . Wait ( )
2015-03-12 22:21:11 +00:00
return 0
}
2017-07-31 15:28:06 +00:00
func ( c * ServerCommand ) enableDev ( core * vault . Core , coreConfig * vault . CoreConfig ) ( * vault . InitResult , error ) {
2018-09-18 03:03:00 +00:00
ctx := namespace . ContextWithNamespace ( context . Background ( ) , namespace . RootNamespace )
2017-09-21 19:23:29 +00:00
var recoveryConfig * vault . SealConfig
barrierConfig := & vault . SealConfig {
SecretShares : 1 ,
SecretThreshold : 1 ,
}
2018-01-19 08:44:06 +00:00
if core . SealAccess ( ) . RecoveryKeySupported ( ) {
2017-09-21 19:23:29 +00:00
recoveryConfig = & vault . SealConfig {
2016-09-13 22:42:24 +00:00
SecretShares : 1 ,
SecretThreshold : 1 ,
2017-09-21 19:23:29 +00:00
}
2015-03-31 23:44:47 +00:00
}
2019-10-18 18:46:00 +00:00
if core . SealAccess ( ) . StoredKeysSupported ( ) != vault . StoredKeysNotSupported {
2017-09-21 19:23:29 +00:00
barrierConfig . StoredShares = 1
}
2015-03-31 23:44:47 +00:00
2017-09-21 19:23:29 +00:00
// Initialize it with a basic single key
2018-01-19 06:44:44 +00:00
init , err := core . Initialize ( ctx , & vault . InitParams {
2017-09-21 19:23:29 +00:00
BarrierConfig : barrierConfig ,
RecoveryConfig : recoveryConfig ,
} )
2015-03-31 23:44:47 +00:00
if err != nil {
return nil , err
}
2017-09-21 19:23:29 +00:00
// Handle unseal with stored keys
2019-10-18 18:46:00 +00:00
if core . SealAccess ( ) . StoredKeysSupported ( ) == vault . StoredKeysSupportedGeneric {
2018-01-19 06:44:44 +00:00
err := core . UnsealWithStoredKeys ( ctx )
2017-09-21 19:23:29 +00:00
if err != nil {
return nil , err
}
} else {
// Copy the key so that it can be zeroed
key := make ( [ ] byte , len ( init . SecretShares [ 0 ] ) )
copy ( key , init . SecretShares [ 0 ] )
// Unseal the core
unsealed , err := core . Unseal ( key )
if err != nil {
return nil , err
}
if ! unsealed {
return nil , fmt . Errorf ( "failed to unseal Vault for dev mode" )
}
2015-03-31 23:44:47 +00:00
}
2017-07-31 22:25:27 +00:00
isLeader , _ , _ , err := core . Leader ( )
2016-08-15 13:42:42 +00:00
if err != nil && err != vault . ErrHANotEnabled {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( "failed to check active status: {{err}}" , err )
2016-08-15 13:42:42 +00:00
}
if err == nil {
leaderCount := 5
for ! isLeader {
if leaderCount == 0 {
buf := make ( [ ] byte , 1 << 16 )
runtime . Stack ( buf , true )
return nil , fmt . Errorf ( "failed to get active status after five seconds; call stack is\n%s\n" , buf )
}
time . Sleep ( 1 * time . Second )
2017-07-31 22:25:27 +00:00
isLeader , _ , _ , err = core . Leader ( )
2016-08-15 13:42:42 +00:00
if err != nil {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( "failed to check active status: {{err}}" , err )
2016-08-15 13:42:42 +00:00
}
leaderCount --
}
}
2017-09-21 19:23:29 +00:00
// Generate a dev root token if one is provided in the flag
2017-07-31 15:28:06 +00:00
if coreConfig . DevToken != "" {
2016-03-02 16:53:23 +00:00
req := & logical . Request {
2016-08-19 20:45:17 +00:00
ID : "dev-gen-root" ,
2016-03-02 16:53:23 +00:00
Operation : logical . UpdateOperation ,
ClientToken : init . RootToken ,
Path : "auth/token/create" ,
Data : map [ string ] interface { } {
2017-07-31 15:28:06 +00:00
"id" : coreConfig . DevToken ,
2016-03-02 16:53:23 +00:00
"policies" : [ ] string { "root" } ,
"no_parent" : true ,
"no_default_policy" : true ,
} ,
}
2018-09-18 03:03:00 +00:00
resp , err := core . HandleRequest ( ctx , req )
2016-03-02 16:53:23 +00:00
if err != nil {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( fmt . Sprintf ( "failed to create root token with ID %q: {{err}}" , coreConfig . DevToken ) , err )
2016-03-02 16:53:23 +00:00
}
if resp == nil {
2018-04-05 15:49:21 +00:00
return nil , fmt . Errorf ( "nil response when creating root token with ID %q" , coreConfig . DevToken )
2016-03-02 16:53:23 +00:00
}
if resp . Auth == nil {
2018-04-05 15:49:21 +00:00
return nil , fmt . Errorf ( "nil auth when creating root token with ID %q" , coreConfig . DevToken )
2016-03-02 16:53:23 +00:00
}
init . RootToken = resp . Auth . ClientToken
2016-08-19 20:45:17 +00:00
req . ID = "dev-revoke-init-root"
2016-03-02 16:53:23 +00:00
req . Path = "auth/token/revoke-self"
req . Data = nil
2018-09-18 03:03:00 +00:00
resp , err = core . HandleRequest ( ctx , req )
2016-03-02 16:53:23 +00:00
if err != nil {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( "failed to revoke initial root token: {{err}}" , err )
2016-03-02 16:53:23 +00:00
}
}
2015-03-31 23:44:47 +00:00
// Set the token
2019-07-24 16:41:07 +00:00
if ! c . flagDevNoStoreToken {
tokenHelper , err := c . TokenHelper ( )
if err != nil {
return nil , err
}
if err := tokenHelper . Store ( init . RootToken ) ; err != nil {
return nil , err
}
2015-03-31 23:44:47 +00:00
}
2019-02-14 19:55:32 +00:00
kvVer := "2"
2019-03-04 22:11:56 +00:00
if c . flagDevKVV1 || c . flagDevLeasedKV {
2019-02-14 19:55:32 +00:00
kvVer = "1"
}
req := & logical . Request {
Operation : logical . UpdateOperation ,
ClientToken : init . RootToken ,
Path : "sys/mounts/secret" ,
Data : map [ string ] interface { } {
"type" : "kv" ,
"path" : "secret/" ,
"description" : "key/value secret storage" ,
"options" : map [ string ] string {
"version" : kvVer ,
2018-04-09 19:35:49 +00:00
} ,
2019-02-14 19:55:32 +00:00
} ,
}
resp , err := core . HandleRequest ( ctx , req )
if err != nil {
return nil , errwrap . Wrapf ( "error creating default K/V store: {{err}}" , err )
}
if resp . IsError ( ) {
return nil , errwrap . Wrapf ( "failed to create default K/V store: {{err}}" , resp . Error ( ) )
2018-04-09 19:35:49 +00:00
}
2015-03-31 23:44:47 +00:00
return init , nil
}
2017-12-11 23:02:35 +00:00
func ( c * ServerCommand ) enableThreeNodeDevCluster ( base * vault . CoreConfig , info map [ string ] string , infoKeys [ ] string , devListenAddress , tempDir string ) int {
2017-08-01 18:07:08 +00:00
testCluster := vault . NewTestCluster ( & testing . RuntimeT { } , base , & vault . TestClusterOptions {
2017-07-31 15:28:06 +00:00
HandlerFunc : vaulthttp . Handler ,
2017-09-22 00:51:12 +00:00
BaseListenAddress : c . flagDevListenAddr ,
2018-04-03 00:46:59 +00:00
Logger : c . logger ,
2017-12-11 23:02:35 +00:00
TempDir : tempDir ,
2017-07-31 15:28:06 +00:00
} )
defer c . cleanupGuard . Do ( testCluster . Cleanup )
info [ "cluster parameters path" ] = testCluster . TempDir
2017-11-10 21:33:16 +00:00
infoKeys = append ( infoKeys , "cluster parameters path" )
2017-07-31 15:28:06 +00:00
for i , core := range testCluster . Cores {
2018-04-04 20:15:07 +00:00
info [ fmt . Sprintf ( "node %d api address" , i ) ] = fmt . Sprintf ( "https://%s" , core . Listeners [ 0 ] . Address . String ( ) )
infoKeys = append ( infoKeys , fmt . Sprintf ( "node %d api address" , i ) )
2017-07-31 15:28:06 +00:00
}
infoKeys = append ( infoKeys , "version" )
verInfo := version . GetVersion ( )
info [ "version" ] = verInfo . FullVersionNumber ( false )
if verInfo . Revision != "" {
info [ "version sha" ] = strings . Trim ( verInfo . Revision , "'" )
infoKeys = append ( infoKeys , "version sha" )
}
infoKeys = append ( infoKeys , "cgo" )
info [ "cgo" ] = "disabled"
if version . CgoEnabled {
info [ "cgo" ] = "enabled"
}
// Server configuration output
padding := 24
sort . Strings ( infoKeys )
2017-09-22 00:51:12 +00:00
c . UI . Output ( "==> Vault server configuration:\n" )
2017-07-31 15:28:06 +00:00
for _ , k := range infoKeys {
2017-09-22 00:51:12 +00:00
c . UI . Output ( fmt . Sprintf (
2017-07-31 15:28:06 +00:00
"%s%s: %s" ,
strings . Repeat ( " " , padding - len ( k ) ) ,
strings . Title ( k ) ,
info [ k ] ) )
}
2017-09-22 00:51:12 +00:00
c . UI . Output ( "" )
2017-07-31 15:28:06 +00:00
for _ , core := range testCluster . Cores {
2018-07-06 19:44:56 +00:00
core . Server . Handler = vaulthttp . Handler ( & vault . HandlerProperties {
Core : core . Core ,
} )
2017-07-31 15:28:06 +00:00
core . SetClusterHandler ( core . Server . Handler )
}
testCluster . Start ( )
2018-09-18 03:03:00 +00:00
ctx := namespace . ContextWithNamespace ( context . Background ( ) , namespace . RootNamespace )
2017-07-31 15:28:06 +00:00
if base . DevToken != "" {
req := & logical . Request {
ID : "dev-gen-root" ,
Operation : logical . UpdateOperation ,
ClientToken : testCluster . RootToken ,
Path : "auth/token/create" ,
Data : map [ string ] interface { } {
"id" : base . DevToken ,
"policies" : [ ] string { "root" } ,
"no_parent" : true ,
"no_default_policy" : true ,
} ,
}
2018-09-18 03:03:00 +00:00
resp , err := testCluster . Cores [ 0 ] . HandleRequest ( ctx , req )
2017-07-31 15:28:06 +00:00
if err != nil {
2017-09-22 00:51:12 +00:00
c . UI . Error ( fmt . Sprintf ( "failed to create root token with ID %s: %s" , base . DevToken , err ) )
2017-07-31 15:28:06 +00:00
return 1
}
if resp == nil {
2017-09-22 00:51:12 +00:00
c . UI . Error ( fmt . Sprintf ( "nil response when creating root token with ID %s" , base . DevToken ) )
2017-07-31 15:28:06 +00:00
return 1
}
if resp . Auth == nil {
2017-09-22 00:51:12 +00:00
c . UI . Error ( fmt . Sprintf ( "nil auth when creating root token with ID %s" , base . DevToken ) )
2017-07-31 15:28:06 +00:00
return 1
}
testCluster . RootToken = resp . Auth . ClientToken
req . ID = "dev-revoke-init-root"
req . Path = "auth/token/revoke-self"
req . Data = nil
2018-09-18 03:03:00 +00:00
resp , err = testCluster . Cores [ 0 ] . HandleRequest ( ctx , req )
2017-07-31 15:28:06 +00:00
if err != nil {
2017-09-22 00:51:12 +00:00
c . UI . Output ( fmt . Sprintf ( "failed to revoke initial root token: %s" , err ) )
2017-07-31 15:28:06 +00:00
return 1
}
}
// Set the token
tokenHelper , err := c . TokenHelper ( )
if err != nil {
2017-09-22 00:51:12 +00:00
c . UI . Error ( fmt . Sprintf ( "Error getting token helper: %s" , err ) )
2017-07-31 15:28:06 +00:00
return 1
}
if err := tokenHelper . Store ( testCluster . RootToken ) ; err != nil {
2017-09-22 00:51:12 +00:00
c . UI . Error ( fmt . Sprintf ( "Error storing in token helper: %s" , err ) )
2017-07-31 15:28:06 +00:00
return 1
}
if err := ioutil . WriteFile ( filepath . Join ( testCluster . TempDir , "root_token" ) , [ ] byte ( testCluster . RootToken ) , 0755 ) ; err != nil {
2017-09-22 00:51:12 +00:00
c . UI . Error ( fmt . Sprintf ( "Error writing token to tempfile: %s" , err ) )
2017-07-31 15:28:06 +00:00
return 1
}
2017-09-22 00:51:12 +00:00
c . UI . Output ( fmt . Sprintf (
2017-07-31 15:28:06 +00:00
"==> Three node dev mode is enabled\n\n" +
"The unseal key and root token are reproduced below in case you\n" +
"want to seal/unseal the Vault or play with authentication.\n" ,
) )
for i , key := range testCluster . BarrierKeys {
2017-09-22 00:51:12 +00:00
c . UI . Output ( fmt . Sprintf (
2017-07-31 15:28:06 +00:00
"Unseal Key %d: %s" ,
2017-08-01 15:12:45 +00:00
i + 1 , base64 . StdEncoding . EncodeToString ( key ) ,
2017-07-31 15:28:06 +00:00
) )
}
2017-09-22 00:51:12 +00:00
c . UI . Output ( fmt . Sprintf (
2017-07-31 15:28:06 +00:00
"\nRoot Token: %s\n" , testCluster . RootToken ,
) )
2017-09-22 00:51:12 +00:00
c . UI . Output ( fmt . Sprintf (
2017-08-01 15:50:41 +00:00
"\nUseful env vars:\n" +
"VAULT_TOKEN=%s\n" +
"VAULT_ADDR=%s\n" +
"VAULT_CACERT=%s/ca_cert.pem\n" ,
testCluster . RootToken ,
testCluster . Cores [ 0 ] . Client . Address ( ) ,
testCluster . TempDir ,
) )
2017-07-31 15:28:06 +00:00
// Output the header that the server has started
2017-09-22 00:51:12 +00:00
c . UI . Output ( "==> Vault server started! Log data will stream in below:\n" )
// Inform any tests that the server is ready
select {
case c . startedCh <- struct { } { } :
default :
}
2017-07-31 15:28:06 +00:00
// Release the log gate.
c . logGate . Flush ( )
// Wait for shutdown
shutdownTriggered := false
for ! shutdownTriggered {
select {
case <- c . ShutdownCh :
2017-09-22 00:51:12 +00:00
c . UI . Output ( "==> Vault shutdown triggered" )
2017-07-31 15:28:06 +00:00
2018-03-20 18:54:10 +00:00
// Stop the listeners so that we don't process further client requests.
2017-07-31 15:28:06 +00:00
c . cleanupGuard . Do ( testCluster . Cleanup )
// Shutdown will wait until after Vault is sealed, which means the
// request forwarding listeners will also be closed (and also
// waited for).
for _ , core := range testCluster . Cores {
if err := core . Shutdown ( ) ; err != nil {
2017-09-22 00:51:12 +00:00
c . UI . Error ( fmt . Sprintf ( "Error with core shutdown: %s" , err ) )
2017-07-31 15:28:06 +00:00
}
}
shutdownTriggered = true
case <- c . SighupCh :
2017-09-22 00:51:12 +00:00
c . UI . Output ( "==> Vault reload triggered" )
2017-07-31 15:28:06 +00:00
for _ , core := range testCluster . Cores {
if err := c . Reload ( core . ReloadFuncsLock , core . ReloadFuncs , nil ) ; err != nil {
2017-09-22 00:51:12 +00:00
c . UI . Error ( fmt . Sprintf ( "Error(s) were encountered during reload: %s" , err ) )
2017-07-31 15:28:06 +00:00
}
}
}
}
return 0
}
2018-03-28 21:36:55 +00:00
// addPlugin adds any plugins to the catalog
func ( c * ServerCommand ) addPlugin ( path , token string , core * vault . Core ) error {
// Get the sha256 of the file at the given path.
pluginSum := func ( p string ) ( string , error ) {
hasher := sha256 . New ( )
f , err := os . Open ( p )
if err != nil {
return "" , err
}
defer f . Close ( )
if _ , err := io . Copy ( hasher , f ) ; err != nil {
return "" , err
}
return hex . EncodeToString ( hasher . Sum ( nil ) ) , nil
}
// Mount any test plugins. We do this explicitly before we inform tests of
// a completely booted server intentionally.
sha256sum , err := pluginSum ( path )
if err != nil {
return err
}
// Default the name to the basename of the binary
name := filepath . Base ( path )
// File a request against core to enable the plugin
req := & logical . Request {
Operation : logical . UpdateOperation ,
ClientToken : token ,
2018-11-07 01:21:24 +00:00
Path : fmt . Sprintf ( "sys/plugins/catalog/%s" , name ) ,
2018-03-28 21:36:55 +00:00
Data : map [ string ] interface { } {
"sha256" : sha256sum ,
"command" : name ,
} ,
}
2018-09-18 03:03:00 +00:00
ctx := namespace . ContextWithNamespace ( context . Background ( ) , namespace . RootNamespace )
if _ , err := core . HandleRequest ( ctx , req ) ; err != nil {
2018-03-28 21:36:55 +00:00
return err
}
return nil
}
2016-08-15 13:42:42 +00:00
// detectRedirect is used to attempt redirect address detection
func ( c * ServerCommand ) detectRedirect ( detect physical . RedirectDetect ,
2015-05-02 22:57:40 +00:00
config * server . Config ) ( string , error ) {
// Get the hostname
host , err := detect . DetectHostAddr ( )
if err != nil {
return "" , err
}
2015-12-22 20:40:36 +00:00
// set [] for ipv6 addresses
if strings . Contains ( host , ":" ) && ! strings . Contains ( host , "]" ) {
host = "[" + host + "]"
}
2015-05-02 22:57:40 +00:00
// Default the port and scheme
scheme := "https"
port := 8200
// Attempt to detect overrides
for _ , list := range config . Listeners {
// Only attempt TCP
if list . Type != "tcp" {
continue
}
// Check if TLS is disabled
2015-05-15 20:41:30 +00:00
if val , ok := list . Config [ "tls_disable" ] ; ok {
2017-06-22 19:29:53 +00:00
disable , err := parseutil . ParseBool ( val )
2015-05-15 20:41:30 +00:00
if err != nil {
2018-04-05 15:49:21 +00:00
return "" , errwrap . Wrapf ( "tls_disable: {{err}}" , err )
2015-05-15 20:41:30 +00:00
}
if disable {
scheme = "http"
}
2015-05-02 22:57:40 +00:00
}
// Check for address override
2017-06-22 19:29:53 +00:00
var addr string
addrRaw , ok := list . Config [ "address" ]
2015-05-02 22:57:40 +00:00
if ! ok {
addr = "127.0.0.1:8200"
2017-06-22 19:29:53 +00:00
} else {
addr = addrRaw . ( string )
2015-05-02 22:57:40 +00:00
}
// Check for localhost
hostStr , portStr , err := net . SplitHostPort ( addr )
if err != nil {
continue
}
if hostStr == "127.0.0.1" {
host = hostStr
}
// Check for custom port
listPort , err := strconv . Atoi ( portStr )
if err != nil {
continue
}
port = listPort
}
// Build a URL
url := & url . URL {
Scheme : scheme ,
Host : fmt . Sprintf ( "%s:%d" , host , port ) ,
}
// Return the URL string
return url . String ( ) , nil
}
2019-02-14 20:46:59 +00:00
// setupTelemetry is used to setup the telemetry sub-systems and returns the in-memory sink to be used in http configuration
func ( c * ServerCommand ) setupTelemetry ( config * server . Config ) ( * metricsutil . MetricsHelper , error ) {
2015-04-15 01:44:09 +00:00
/ * Setup telemetry
Aggregate on 10 second intervals for 1 minute . Expose the
metrics over stderr when there is a SIGUSR1 received .
* /
inm := metrics . NewInmemSink ( 10 * time . Second , time . Minute )
metrics . DefaultInmemSignal ( inm )
2015-07-14 22:27:18 +00:00
var telConfig * server . Telemetry
2019-02-14 20:46:59 +00:00
if config . Telemetry != nil {
2015-07-14 22:27:18 +00:00
telConfig = config . Telemetry
2019-02-14 20:46:59 +00:00
} else {
telConfig = & server . Telemetry { }
2015-07-14 22:27:18 +00:00
}
2015-04-15 01:44:09 +00:00
metricsConf := metrics . DefaultConfig ( "vault" )
2015-07-14 22:27:18 +00:00
metricsConf . EnableHostname = ! telConfig . DisableHostname
2015-04-15 01:44:09 +00:00
// Configure the statsite sink
var fanout metrics . FanoutSink
2019-02-14 20:46:59 +00:00
var prometheusEnabled bool
// Configure the Prometheus sink
if telConfig . PrometheusRetentionTime != 0 {
prometheusEnabled = true
prometheusOpts := prometheus . PrometheusOpts {
Expiration : telConfig . PrometheusRetentionTime ,
}
sink , err := prometheus . NewPrometheusSinkFrom ( prometheusOpts )
if err != nil {
return nil , err
}
fanout = append ( fanout , sink )
}
metricHelper := metricsutil . NewMetricsHelper ( inm , prometheusEnabled )
2015-07-14 22:27:18 +00:00
if telConfig . StatsiteAddr != "" {
sink , err := metrics . NewStatsiteSink ( telConfig . StatsiteAddr )
2015-04-15 01:44:09 +00:00
if err != nil {
2019-02-14 20:46:59 +00:00
return nil , err
2015-04-15 01:44:09 +00:00
}
fanout = append ( fanout , sink )
}
// Configure the statsd sink
2015-07-14 22:27:18 +00:00
if telConfig . StatsdAddr != "" {
sink , err := metrics . NewStatsdSink ( telConfig . StatsdAddr )
2015-04-15 01:44:09 +00:00
if err != nil {
2019-02-14 20:46:59 +00:00
return nil , err
2015-04-15 01:44:09 +00:00
}
fanout = append ( fanout , sink )
}
2016-07-22 19:49:23 +00:00
// Configure the Circonus sink
if telConfig . CirconusAPIToken != "" || telConfig . CirconusCheckSubmissionURL != "" {
cfg := & circonus . Config { }
cfg . Interval = telConfig . CirconusSubmissionInterval
cfg . CheckManager . API . TokenKey = telConfig . CirconusAPIToken
cfg . CheckManager . API . TokenApp = telConfig . CirconusAPIApp
cfg . CheckManager . API . URL = telConfig . CirconusAPIURL
cfg . CheckManager . Check . SubmissionURL = telConfig . CirconusCheckSubmissionURL
cfg . CheckManager . Check . ID = telConfig . CirconusCheckID
cfg . CheckManager . Check . ForceMetricActivation = telConfig . CirconusCheckForceMetricActivation
cfg . CheckManager . Check . InstanceID = telConfig . CirconusCheckInstanceID
cfg . CheckManager . Check . SearchTag = telConfig . CirconusCheckSearchTag
2016-11-10 21:17:55 +00:00
cfg . CheckManager . Check . DisplayName = telConfig . CirconusCheckDisplayName
cfg . CheckManager . Check . Tags = telConfig . CirconusCheckTags
2016-07-22 19:49:23 +00:00
cfg . CheckManager . Broker . ID = telConfig . CirconusBrokerID
cfg . CheckManager . Broker . SelectTag = telConfig . CirconusBrokerSelectTag
if cfg . CheckManager . API . TokenApp == "" {
cfg . CheckManager . API . TokenApp = "vault"
}
2017-02-26 23:18:46 +00:00
if cfg . CheckManager . Check . DisplayName == "" {
cfg . CheckManager . Check . DisplayName = "Vault"
}
2016-07-22 19:49:23 +00:00
if cfg . CheckManager . Check . SearchTag == "" {
cfg . CheckManager . Check . SearchTag = "service:vault"
}
sink , err := circonus . NewCirconusSink ( cfg )
if err != nil {
2019-02-14 20:46:59 +00:00
return nil , err
2016-07-22 19:49:23 +00:00
}
sink . Start ( )
fanout = append ( fanout , sink )
}
2017-06-17 03:51:46 +00:00
if telConfig . DogStatsDAddr != "" {
var tags [ ] string
if telConfig . DogStatsDTags != nil {
tags = telConfig . DogStatsDTags
}
sink , err := datadog . NewDogStatsdSink ( telConfig . DogStatsDAddr , metricsConf . HostName )
if err != nil {
2019-02-14 20:46:59 +00:00
return nil , errwrap . Wrapf ( "failed to start DogStatsD sink: {{err}}" , err )
2017-06-17 03:51:46 +00:00
}
sink . SetTags ( tags )
fanout = append ( fanout , sink )
2019-08-20 21:47:08 +00:00
}
// Configure the stackdriver sink
if telConfig . StackdriverProjectID != "" {
client , err := monitoring . NewMetricClient ( context . Background ( ) , option . WithUserAgent ( useragent . String ( ) ) )
if err != nil {
return nil , fmt . Errorf ( "Failed to create stackdriver client: %v" , err )
}
sink := stackdriver . NewSink ( client , & stackdriver . Config {
ProjectID : telConfig . StackdriverProjectID ,
Location : telConfig . StackdriverLocation ,
Namespace : telConfig . StackdriverNamespace ,
} )
fanout = append ( fanout , sink )
2017-06-17 03:51:46 +00:00
}
2015-04-15 01:44:09 +00:00
// Initialize the global sink
2019-02-14 20:46:59 +00:00
if len ( fanout ) > 1 {
// Hostname enabled will create poor quality metrics name for prometheus
if ! telConfig . DisableHostname {
c . UI . Warn ( "telemetry.disable_hostname has been set to false. Recommended setting is true for Prometheus to avoid poorly named metrics." )
}
2015-04-15 01:44:09 +00:00
} else {
metricsConf . EnableHostname = false
}
2019-02-14 20:46:59 +00:00
fanout = append ( fanout , inm )
_ , err := metrics . NewGlobal ( metricsConf , fanout )
if err != nil {
return nil , err
}
return metricHelper , nil
2015-04-15 01:44:09 +00:00
}
2017-07-31 15:28:06 +00:00
func ( c * ServerCommand ) Reload ( lock * sync . RWMutex , reloadFuncs * map [ string ] [ ] reload . ReloadFunc , configPath [ ] string ) error {
lock . RLock ( )
defer lock . RUnlock ( )
2016-09-30 19:04:50 +00:00
var reloadErrors * multierror . Error
2017-07-31 15:28:06 +00:00
for k , relFuncs := range * reloadFuncs {
switch {
case strings . HasPrefix ( k , "listener|" ) :
for _ , relFunc := range relFuncs {
if relFunc != nil {
if err := relFunc ( nil ) ; err != nil {
2018-04-05 15:49:21 +00:00
reloadErrors = multierror . Append ( reloadErrors , errwrap . Wrapf ( "error encountered reloading listener: {{err}}" , err ) )
2017-07-31 15:28:06 +00:00
}
}
2016-09-30 19:04:50 +00:00
}
2017-07-31 15:28:06 +00:00
case strings . HasPrefix ( k , "audit_file|" ) :
for _ , relFunc := range relFuncs {
if relFunc != nil {
if err := relFunc ( nil ) ; err != nil {
2018-04-05 15:49:21 +00:00
reloadErrors = multierror . Append ( reloadErrors , errwrap . Wrapf ( fmt . Sprintf ( "error encountered reloading file audit device at path %q: {{err}}" , strings . TrimPrefix ( k , "audit_file|" ) ) , err ) )
2017-07-31 15:28:06 +00:00
}
2016-09-30 19:04:50 +00:00
}
2016-03-11 21:46:56 +00:00
}
}
}
2017-09-22 00:51:12 +00:00
// Send a message that we reloaded. This prevents "guessing" sleep times
// in tests.
select {
case c . reloadedCh <- struct { } { } :
default :
2017-08-24 22:23:40 +00:00
}
2017-09-20 20:05:00 +00:00
return reloadErrors . ErrorOrNil ( )
2017-08-24 22:23:40 +00:00
}
2017-09-16 21:09:37 +00:00
// storePidFile is used to write out our PID to a file if necessary
func ( c * ServerCommand ) storePidFile ( pidPath string ) error {
// Quit fast if no pidfile
if pidPath == "" {
return nil
}
// Open the PID file
pidFile , err := os . OpenFile ( pidPath , os . O_CREATE | os . O_WRONLY | os . O_TRUNC , 0644 )
if err != nil {
2018-04-05 15:49:21 +00:00
return errwrap . Wrapf ( "could not open pid file: {{err}}" , err )
2017-09-16 21:09:37 +00:00
}
defer pidFile . Close ( )
// Write out the PID
pid := os . Getpid ( )
_ , err = pidFile . WriteString ( fmt . Sprintf ( "%d" , pid ) )
if err != nil {
2018-04-05 15:49:21 +00:00
return errwrap . Wrapf ( "could not write to pid file: {{err}}" , err )
2017-09-16 21:09:37 +00:00
}
return nil
}
// removePidFile is used to cleanup the PID file if necessary
func ( c * ServerCommand ) removePidFile ( pidPath string ) error {
if pidPath == "" {
return nil
}
return os . Remove ( pidPath )
}
2018-10-23 06:34:02 +00:00
// storageMigrationActive checks and warns against in-progress storage migrations.
2018-10-01 21:35:35 +00:00
// This function will block until storage is available.
2018-10-23 06:34:02 +00:00
func ( c * ServerCommand ) storageMigrationActive ( backend physical . Backend ) bool {
2018-10-01 21:35:35 +00:00
first := true
for {
2018-10-23 06:34:02 +00:00
migrationStatus , err := CheckStorageMigration ( backend )
2018-10-01 21:35:35 +00:00
if err == nil {
if migrationStatus != nil {
startTime := migrationStatus . Start . Format ( time . RFC3339 )
c . UI . Error ( wrapAtLength ( fmt . Sprintf ( "ERROR! Storage migration in progress (started: %s). " +
"Server startup is prevented until the migration completes. Use 'vault operator migrate -reset' " +
"to force clear the migration lock." , startTime ) ) )
return true
}
return false
}
if first {
first = false
2018-10-23 06:34:02 +00:00
c . UI . Warn ( "\nWARNING! Unable to read storage migration status." )
2018-10-01 21:35:35 +00:00
// unexpected state, so stop buffering log messages
c . logGate . Flush ( )
}
2018-10-23 06:34:02 +00:00
c . logger . Warn ( "storage migration check error" , "error" , err . Error ( ) )
2018-10-01 21:35:35 +00:00
select {
case <- time . After ( 2 * time . Second ) :
case <- c . ShutdownCh :
return true
}
}
}
2018-10-23 06:34:02 +00:00
type StorageMigrationStatus struct {
2018-09-25 23:18:22 +00:00
Start time . Time ` json:"start" `
}
2018-10-23 06:34:02 +00:00
func CheckStorageMigration ( b physical . Backend ) ( * StorageMigrationStatus , error ) {
entry , err := b . Get ( context . Background ( ) , storageMigrationLock )
2018-09-25 23:18:22 +00:00
if err != nil {
return nil , err
}
if entry == nil {
return nil , nil
}
2018-10-23 06:34:02 +00:00
var status StorageMigrationStatus
2018-09-25 23:18:22 +00:00
if err := jsonutil . DecodeJSON ( entry . Value , & status ) ; err != nil {
return nil , err
}
return & status , nil
}
2018-10-23 06:34:02 +00:00
func SetStorageMigration ( b physical . Backend , active bool ) error {
2018-09-25 23:18:22 +00:00
if ! active {
2018-10-23 06:34:02 +00:00
return b . Delete ( context . Background ( ) , storageMigrationLock )
2018-09-25 23:18:22 +00:00
}
2018-10-23 06:34:02 +00:00
status := StorageMigrationStatus {
2018-09-25 23:18:22 +00:00
Start : time . Now ( ) ,
}
enc , err := jsonutil . EncodeJSON ( status )
if err != nil {
return err
}
entry := & physical . Entry {
2018-10-23 06:34:02 +00:00
Key : storageMigrationLock ,
2018-09-25 23:18:22 +00:00
Value : enc ,
}
return b . Put ( context . Background ( ) , entry )
}
2016-08-19 20:45:17 +00:00
type grpclogFaker struct {
logger log . Logger
2017-10-10 16:27:51 +00:00
log bool
2016-08-19 20:45:17 +00:00
}
func ( g * grpclogFaker ) Fatal ( args ... interface { } ) {
g . logger . Error ( fmt . Sprint ( args ... ) )
os . Exit ( 1 )
}
func ( g * grpclogFaker ) Fatalf ( format string , args ... interface { } ) {
g . logger . Error ( fmt . Sprintf ( format , args ... ) )
os . Exit ( 1 )
}
func ( g * grpclogFaker ) Fatalln ( args ... interface { } ) {
g . logger . Error ( fmt . Sprintln ( args ... ) )
os . Exit ( 1 )
}
func ( g * grpclogFaker ) Print ( args ... interface { } ) {
2018-04-03 00:46:59 +00:00
if g . log && g . logger . IsDebug ( ) {
g . logger . Debug ( fmt . Sprint ( args ... ) )
2017-10-10 16:27:51 +00:00
}
2016-08-19 20:45:17 +00:00
}
func ( g * grpclogFaker ) Printf ( format string , args ... interface { } ) {
2018-04-03 00:46:59 +00:00
if g . log && g . logger . IsDebug ( ) {
g . logger . Debug ( fmt . Sprintf ( format , args ... ) )
2017-10-10 16:27:51 +00:00
}
2016-08-19 20:45:17 +00:00
}
func ( g * grpclogFaker ) Println ( args ... interface { } ) {
2018-04-03 00:46:59 +00:00
if g . log && g . logger . IsDebug ( ) {
g . logger . Debug ( fmt . Sprintln ( args ... ) )
2017-10-10 16:27:51 +00:00
}
2016-08-19 20:45:17 +00:00
}