func atlasListenerFactory(config map[string]string, logger io.Writer) (net.Listener, map[string]string, ReloadFunc, error) { scadaConfig := &scada.Config{ Service: "vault", Version: version.GetVersion().String(), ResourceType: "vault-cluster", Meta: map[string]string{ "node_id": config["node_id"], }, Atlas: scada.AtlasConfig{ Endpoint: config["endpoint"], Infrastructure: config["infrastructure"], Token: config["token"], }, } provider, list, err := scada.NewHTTPProvider(scadaConfig, logger) if err != nil { return nil, nil, nil, err } ln := &SCADAListener{ ln: list, scadaProvider: provider, } props := map[string]string{ "addr": "Atlas/SCADA", "infrastructure": scadaConfig.Atlas.Infrastructure, } return listenerWrapTLS(ln, props, config) }
func handleSysSealStatusRaw(core *vault.Core, w http.ResponseWriter, r *http.Request) { sealed, err := core.Sealed() if err != nil { respondError(w, http.StatusInternalServerError, err) return } sealConfig, err := core.SealAccess().BarrierConfig() if err != nil { respondError(w, http.StatusInternalServerError, err) return } if sealConfig == nil { respondError(w, http.StatusBadRequest, fmt.Errorf( "server is not yet initialized")) return } // Fetch the local cluster name and identifier var clusterName, clusterID string if !sealed { cluster, err := core.Cluster() if err != nil { respondError(w, http.StatusInternalServerError, err) return } if cluster == nil { respondError(w, http.StatusInternalServerError, fmt.Errorf("failed to fetch cluster details")) return } clusterName = cluster.Name clusterID = cluster.ID } respondOk(w, &SealStatusResponse{ Sealed: sealed, T: sealConfig.SecretThreshold, N: sealConfig.SecretShares, Progress: core.SecretProgress(), Version: version.GetVersion().VersionNumber(), ClusterName: clusterName, ClusterID: clusterID, }) }
func atlasListenerFactory(config map[string]string, logger io.Writer) (net.Listener, map[string]string, vault.ReloadFunc, error) { scadaConfig := &scada.Config{ Service: "vault", Version: version.GetVersion().VersionNumber(), ResourceType: "vault-cluster", Meta: map[string]string{ "node_id": config["node_id"], "cluster_name": config["cluster_name"], }, Atlas: scada.AtlasConfig{ Endpoint: config["endpoint"], Infrastructure: config["infrastructure"], Token: config["token"], }, } provider, list, err := scada.NewHTTPProvider(scadaConfig, logger) if err != nil { return nil, nil, nil, err } ln := &SCADAListener{ ln: list, scadaProvider: provider, } props := map[string]string{ "addr": "Atlas/SCADA", "infrastructure": scadaConfig.Atlas.Infrastructure, } // The outer connection is already TLS-enabled; this is just the listener // that reaches back inside that connection config["tls_disable"] = "1" return listenerWrapTLS(ln, props, config) }
// Commands returns the mapping of CLI commands for Vault. The meta // parameter lets you set meta options for all commands. func Commands(metaPtr *command.Meta) map[string]cli.CommandFactory { if metaPtr == nil { metaPtr = new(command.Meta) } meta := *metaPtr if meta.Ui == nil { meta.Ui = &cli.BasicUi{ Writer: os.Stdout, ErrorWriter: os.Stderr, } } return map[string]cli.CommandFactory{ "init": func() (cli.Command, error) { return &command.InitCommand{ Meta: meta, }, nil }, "server": func() (cli.Command, error) { return &command.ServerCommand{ Meta: meta, AuditBackends: map[string]audit.Factory{ "file": auditFile.Factory, "syslog": auditSyslog.Factory, }, CredentialBackends: map[string]logical.Factory{ "cert": credCert.Factory, "app-id": credAppId.Factory, "github": credGitHub.Factory, "userpass": credUserpass.Factory, "ldap": credLdap.Factory, }, LogicalBackends: map[string]logical.Factory{ "aws": aws.Factory, "consul": consul.Factory, "postgresql": postgresql.Factory, "cassandra": cassandra.Factory, "pki": pki.Factory, "transit": transit.Factory, "mysql": mysql.Factory, "oracle": oracle.Factory, "ssh": ssh.Factory, }, ShutdownCh: makeShutdownCh(), }, nil }, "ssh": func() (cli.Command, error) { return &command.SSHCommand{ Meta: meta, }, nil }, "path-help": func() (cli.Command, error) { return &command.PathHelpCommand{ Meta: meta, }, nil }, "auth": func() (cli.Command, error) { return &command.AuthCommand{ Meta: meta, Handlers: map[string]command.AuthHandler{ "github": &credGitHub.CLIHandler{}, "userpass": &credUserpass.CLIHandler{}, "ldap": &credLdap.CLIHandler{}, "cert": &credCert.CLIHandler{}, }, }, nil }, "auth-enable": func() (cli.Command, error) { return &command.AuthEnableCommand{ Meta: meta, }, nil }, "auth-disable": func() (cli.Command, error) { return &command.AuthDisableCommand{ Meta: meta, }, nil }, "audit-list": func() (cli.Command, error) { return &command.AuditListCommand{ Meta: meta, }, nil }, "audit-disable": func() (cli.Command, error) { return &command.AuditDisableCommand{ Meta: meta, }, nil }, "audit-enable": func() (cli.Command, error) { return &command.AuditEnableCommand{ Meta: meta, }, nil }, "key-status": func() (cli.Command, error) { return &command.KeyStatusCommand{ Meta: meta, }, nil }, "policies": func() (cli.Command, error) { return &command.PolicyListCommand{ Meta: meta, }, nil }, "policy-delete": func() (cli.Command, error) { return &command.PolicyDeleteCommand{ Meta: meta, }, nil }, "policy-write": func() (cli.Command, error) { return &command.PolicyWriteCommand{ Meta: meta, }, nil }, "read": func() (cli.Command, error) { return &command.ReadCommand{ Meta: meta, }, nil }, "list": func() (cli.Command, error) { return &command.ListCommand{ Meta: meta, }, nil }, "write": func() (cli.Command, error) { return &command.WriteCommand{ Meta: meta, }, nil }, "delete": func() (cli.Command, error) { return &command.DeleteCommand{ Meta: meta, }, nil }, "rekey": func() (cli.Command, error) { return &command.RekeyCommand{ Meta: meta, }, nil }, "generate-root": func() (cli.Command, error) { return &command.GenerateRootCommand{ Meta: meta, }, nil }, "renew": func() (cli.Command, error) { return &command.RenewCommand{ Meta: meta, }, nil }, "revoke": func() (cli.Command, error) { return &command.RevokeCommand{ Meta: meta, }, nil }, "seal": func() (cli.Command, error) { return &command.SealCommand{ Meta: meta, }, nil }, "status": func() (cli.Command, error) { return &command.StatusCommand{ Meta: meta, }, nil }, "unseal": func() (cli.Command, error) { return &command.UnsealCommand{ Meta: meta, }, nil }, "mount": func() (cli.Command, error) { return &command.MountCommand{ Meta: meta, }, nil }, "mounts": func() (cli.Command, error) { return &command.MountsCommand{ Meta: meta, }, nil }, "mount-tune": func() (cli.Command, error) { return &command.MountTuneCommand{ Meta: meta, }, nil }, "remount": func() (cli.Command, error) { return &command.RemountCommand{ Meta: meta, }, nil }, "rotate": func() (cli.Command, error) { return &command.RotateCommand{ Meta: meta, }, nil }, "unmount": func() (cli.Command, error) { return &command.UnmountCommand{ Meta: meta, }, nil }, "token-create": func() (cli.Command, error) { return &command.TokenCreateCommand{ Meta: meta, }, nil }, "token-lookup": func() (cli.Command, error) { return &command.TokenLookupCommand{ Meta: meta, }, nil }, "token-renew": func() (cli.Command, error) { return &command.TokenRenewCommand{ Meta: meta, }, nil }, "token-revoke": func() (cli.Command, error) { return &command.TokenRevokeCommand{ Meta: meta, }, nil }, "version": func() (cli.Command, error) { versionInfo := version.GetVersion() return &command.VersionCommand{ VersionInfo: versionInfo, Ui: meta.Ui, }, nil }, } }
func (c *ServerCommand) Run(args []string) int { var dev, verifyOnly bool var configPath []string var logLevel string flags := c.Meta.FlagSet("server", FlagSetDefault) flags.BoolVar(&dev, "dev", false, "") flags.StringVar(&logLevel, "log-level", "info", "") flags.BoolVar(&verifyOnly, "verify-only", false, "") flags.Usage = func() { c.Ui.Error(c.Help()) } flags.Var((*sliceflag.StringFlag)(&configPath), "config", "config") if err := flags.Parse(args); err != nil { return 1 } // Validation if !dev && len(configPath) == 0 { c.Ui.Error("At least one config path must be specified with -config") flags.Usage() return 1 } // Load the configuration var config *server.Config if dev { config = server.DevConfig() } for _, path := range configPath { current, err := server.LoadConfig(path) if err != nil { c.Ui.Error(fmt.Sprintf( "Error loading configuration from %s: %s", path, err)) return 1 } if config == nil { config = current } else { config = config.Merge(current) } } // Ensure that a backend is provided if config.Backend == nil { c.Ui.Error("A physical backend must be specified") return 1 } // If mlock isn't supported, show a warning. We disable this in // dev because it is quite scary to see when first using Vault. if !dev && !mlock.Supported() { c.Ui.Output("==> WARNING: mlock not supported on this system!\n") c.Ui.Output(" The `mlock` syscall to prevent memory from being swapped to") c.Ui.Output(" disk is not supported on this system. Enabling mlock or") c.Ui.Output(" running Vault on a system with mlock is much more secure.\n") } // Create a logger. We wrap it in a gated writer so that it doesn't // start logging too early. logGate := &gatedwriter.Writer{Writer: os.Stderr} logger := log.New(&logutils.LevelFilter{ Levels: []logutils.LogLevel{ "TRACE", "DEBUG", "INFO", "WARN", "ERR"}, MinLevel: logutils.LogLevel(strings.ToUpper(logLevel)), Writer: logGate, }, "", log.LstdFlags) if err := c.setupTelementry(config); err != nil { c.Ui.Error(fmt.Sprintf("Error initializing telemetry: %s", err)) return 1 } // Initialize the backend backend, err := physical.NewBackend( config.Backend.Type, config.Backend.Config) if err != nil { c.Ui.Error(fmt.Sprintf( "Error initializing backend of type %s: %s", config.Backend.Type, err)) return 1 } coreConfig := &vault.CoreConfig{ Physical: backend, AdvertiseAddr: config.Backend.AdvertiseAddr, HAPhysical: nil, AuditBackends: c.AuditBackends, CredentialBackends: c.CredentialBackends, LogicalBackends: c.LogicalBackends, Logger: logger, DisableCache: config.DisableCache, DisableMlock: config.DisableMlock, MaxLeaseTTL: config.MaxLeaseTTL, DefaultLeaseTTL: config.DefaultLeaseTTL, } // Initialize the separate HA physical backend, if it exists if config.HABackend != nil { habackend, err := physical.NewBackend( config.HABackend.Type, config.HABackend.Config) if err != nil { c.Ui.Error(fmt.Sprintf( "Error initializing backend of type %s: %s", config.HABackend.Type, err)) return 1 } var ok bool if coreConfig.HAPhysical, ok = habackend.(physical.HABackend); !ok { c.Ui.Error("Specified HA backend does not support HA") return 1 } coreConfig.AdvertiseAddr = config.HABackend.AdvertiseAddr } if envAA := os.Getenv("VAULT_ADVERTISE_ADDR"); envAA != "" { coreConfig.AdvertiseAddr = envAA } // Attempt to detect the advertise address possible var detect physical.AdvertiseDetect var ok bool if coreConfig.HAPhysical != nil { detect, ok = coreConfig.HAPhysical.(physical.AdvertiseDetect) } else { detect, ok = coreConfig.Physical.(physical.AdvertiseDetect) } if ok && coreConfig.AdvertiseAddr == "" { advertise, err := c.detectAdvertise(detect, config) if err != nil { c.Ui.Error(fmt.Sprintf("Error detecting advertise address: %s", err)) } else if advertise == "" { c.Ui.Error("Failed to detect advertise address.") } else { coreConfig.AdvertiseAddr = advertise } } // Initialize the core core, err := vault.NewCore(coreConfig) if err != nil { c.Ui.Error(fmt.Sprintf("Error initializing core: %s", err)) return 1 } // If we're in dev mode, then initialize the core if dev { init, err := c.enableDev(core) if err != nil { c.Ui.Error(fmt.Sprintf( "Error initializing dev mode: %s", err)) return 1 } export := "export" quote := "'" if runtime.GOOS == "windows" { export = "set" quote = "" } c.Ui.Output(fmt.Sprintf( "==> WARNING: Dev mode is enabled!\n\n"+ "In this mode, Vault is completely in-memory and unsealed.\n"+ "Vault is configured to only have a single unseal key. The root\n"+ "token has already been authenticated with the CLI, so you can\n"+ "immediately begin using the Vault CLI.\n\n"+ "The only step you need to take is to set the following\n"+ "environment variables:\n\n"+ " "+export+" VAULT_ADDR="+quote+"http://127.0.0.1:8200"+quote+"\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\n"+ "Unseal Key: %s\nRoot Token: %s\n", hex.EncodeToString(init.SecretShares[0]), init.RootToken, )) } // Compile server information for output later infoKeys := make([]string, 0, 10) info := make(map[string]string) info["backend"] = config.Backend.Type info["log level"] = logLevel info["mlock"] = fmt.Sprintf( "supported: %v, enabled: %v", mlock.Supported(), !config.DisableMlock) infoKeys = append(infoKeys, "log level", "mlock", "backend") if config.HABackend != nil { info["HA backend"] = config.HABackend.Type info["advertise address"] = coreConfig.AdvertiseAddr infoKeys = append(infoKeys, "HA backend", "advertise address") } else { // If the backend supports HA, then note it if coreConfig.HAPhysical != nil { info["backend"] += " (HA available)" info["advertise address"] = coreConfig.AdvertiseAddr infoKeys = append(infoKeys, "advertise address") } } // Initialize the listeners lns := make([]net.Listener, 0, len(config.Listeners)) for i, lnConfig := range config.Listeners { ln, props, err := server.NewListener(lnConfig.Type, lnConfig.Config) if err != nil { c.Ui.Error(fmt.Sprintf( "Error initializing listener of type %s: %s", lnConfig.Type, err)) return 1 } // 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, ", ")) lns = append(lns, ln) } if verifyOnly { return 0 } // Initialize the HTTP server server := &http.Server{} server.Handler = vaulthttp.Handler(core) for _, ln := range lns { go server.Serve(ln) } infoKeys = append(infoKeys, "version") info["version"] = version.GetVersion().String() // Server configuration output padding := 18 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("") // Output the header that the server has started c.Ui.Output("==> Vault server started! Log data will stream in below:\n") // Release the log gate. logGate.Flush() // Wait for shutdown select { case <-c.ShutdownCh: c.Ui.Output("==> Vault shutdown triggered") if err := core.Shutdown(); err != nil { c.Ui.Error(fmt.Sprintf("Error with core shutdown: %s", err)) } } return 0 }
func (c *ServerCommand) Run(args []string) int { var dev, verifyOnly, devHA bool var configPath []string var logLevel, devRootTokenID, devListenAddress string flags := c.Meta.FlagSet("server", meta.FlagSetDefault) flags.BoolVar(&dev, "dev", false, "") flags.StringVar(&devRootTokenID, "dev-root-token-id", "", "") flags.StringVar(&devListenAddress, "dev-listen-address", "", "") flags.StringVar(&logLevel, "log-level", "info", "") flags.BoolVar(&verifyOnly, "verify-only", false, "") flags.BoolVar(&devHA, "dev-ha", false, "") flags.Usage = func() { c.Ui.Output(c.Help()) } flags.Var((*sliceflag.StringFlag)(&configPath), "config", "config") if err := flags.Parse(args); err != nil { return 1 } // Create a logger. We wrap it in a gated writer so that it doesn't // start logging too early. logGate := &gatedwriter.Writer{Writer: colorable.NewColorable(os.Stderr)} var level int switch logLevel { case "trace": level = log.LevelTrace case "debug": level = log.LevelDebug case "info": level = log.LevelInfo case "notice": level = log.LevelNotice case "warn": level = log.LevelWarn case "err": level = log.LevelError default: c.Ui.Output(fmt.Sprintf("Unknown log level %s", logLevel)) return 1 } logFormat := os.Getenv("VAULT_LOG_FORMAT") if logFormat == "" { logFormat = os.Getenv("LOGXI_FORMAT") } switch strings.ToLower(logFormat) { case "vault", "vault_json", "vault-json", "vaultjson", "json", "": c.logger = logformat.NewVaultLoggerWithWriter(logGate, level) default: c.logger = log.NewLogger(logGate, "vault") c.logger.SetLevel(level) } grpclog.SetLogger(&grpclogFaker{ logger: c.logger, }) if os.Getenv("VAULT_DEV_ROOT_TOKEN_ID") != "" && devRootTokenID == "" { devRootTokenID = os.Getenv("VAULT_DEV_ROOT_TOKEN_ID") } if os.Getenv("VAULT_DEV_LISTEN_ADDRESS") != "" && devListenAddress == "" { devListenAddress = os.Getenv("VAULT_DEV_LISTEN_ADDRESS") } if devHA { dev = true } // Validation if !dev { switch { case len(configPath) == 0: c.Ui.Output("At least one config path must be specified with -config") flags.Usage() return 1 case devRootTokenID != "": c.Ui.Output("Root token ID can only be specified with -dev") flags.Usage() return 1 } } // Load the configuration var config *server.Config if dev { config = server.DevConfig(devHA) if devListenAddress != "" { config.Listeners[0].Config["address"] = devListenAddress } } for _, path := range configPath { current, err := server.LoadConfig(path, c.logger) if err != nil { c.Ui.Output(fmt.Sprintf( "Error loading configuration from %s: %s", path, err)) return 1 } if config == nil { config = current } else { config = config.Merge(current) } } // Ensure at least one config was found. if config == nil { c.Ui.Output("No configuration files found.") return 1 } // Ensure that a backend is provided if config.Backend == nil { c.Ui.Output("A physical backend must be specified") return 1 } // 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. if !dev && !mlock.Supported() { c.Ui.Output("==> WARNING: mlock not supported on this system!\n") c.Ui.Output(" An `mlockall(2)`-like syscall to prevent memory from being") c.Ui.Output(" swapped to disk is not supported on this system. Running") c.Ui.Output(" Vault on an mlockall(2) enabled system is much more secure.\n") } if err := c.setupTelemetry(config); err != nil { c.Ui.Output(fmt.Sprintf("Error initializing telemetry: %s", err)) return 1 } // Initialize the backend backend, err := physical.NewBackend( config.Backend.Type, c.logger, config.Backend.Config) if err != nil { c.Ui.Output(fmt.Sprintf( "Error initializing backend of type %s: %s", config.Backend.Type, err)) return 1 } infoKeys := make([]string, 0, 10) info := make(map[string]string) var seal vault.Seal = &vault.DefaultSeal{} // Ensure that the seal finalizer is called, even if using verify-only defer func() { if seal != nil { err = seal.Finalize() if err != nil { c.Ui.Error(fmt.Sprintf("Error finalizing seals: %v", err)) } } }() if seal == nil { c.Ui.Error(fmt.Sprintf("Could not create seal")) return 1 } coreConfig := &vault.CoreConfig{ Physical: backend, RedirectAddr: config.Backend.RedirectAddr, HAPhysical: nil, Seal: seal, 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, } var disableClustering bool // Initialize the separate HA physical backend, if it exists var ok bool if config.HABackend != nil { habackend, err := physical.NewBackend( config.HABackend.Type, c.logger, config.HABackend.Config) if err != nil { c.Ui.Output(fmt.Sprintf( "Error initializing backend of type %s: %s", config.HABackend.Type, err)) return 1 } if coreConfig.HAPhysical, ok = habackend.(physical.HABackend); !ok { c.Ui.Output("Specified HA backend does not support HA") return 1 } if !coreConfig.HAPhysical.HAEnabled() { c.Ui.Output("Specified HA backend has HA support disabled; please consult documentation") return 1 } coreConfig.RedirectAddr = config.HABackend.RedirectAddr disableClustering = config.HABackend.DisableClustering if !disableClustering { coreConfig.ClusterAddr = config.HABackend.ClusterAddr } } else { if coreConfig.HAPhysical, ok = backend.(physical.HABackend); ok { coreConfig.RedirectAddr = config.Backend.RedirectAddr disableClustering = config.Backend.DisableClustering if !disableClustering { coreConfig.ClusterAddr = config.Backend.ClusterAddr } } } if envRA := os.Getenv("VAULT_REDIRECT_ADDR"); envRA != "" { coreConfig.RedirectAddr = envRA } else if envAA := os.Getenv("VAULT_ADVERTISE_ADDR"); envAA != "" { coreConfig.RedirectAddr = envAA } // Attempt to detect the redirect address, if possible var detect physical.RedirectDetect if coreConfig.HAPhysical != nil && coreConfig.HAPhysical.HAEnabled() { detect, ok = coreConfig.HAPhysical.(physical.RedirectDetect) } else { detect, ok = coreConfig.Physical.(physical.RedirectDetect) } if ok && coreConfig.RedirectAddr == "" { redirect, err := c.detectRedirect(detect, config) if err != nil { c.Ui.Output(fmt.Sprintf("Error detecting redirect address: %s", err)) } else if redirect == "" { c.Ui.Output("Failed to detect redirect address.") } else { coreConfig.RedirectAddr = redirect } } // 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 } else if coreConfig.ClusterAddr == "" && coreConfig.RedirectAddr != "" { u, err := url.ParseRequestURI(coreConfig.RedirectAddr) if err != nil { c.Ui.Output(fmt.Sprintf("Error parsing redirect address %s: %v", coreConfig.RedirectAddr, err)) return 1 } host, port, err := net.SplitHostPort(u.Host) nPort, nPortErr := strconv.Atoi(port) if err != nil { // assume it's due to there not being a port specified, in which case // use 443 host = u.Host nPort = 443 } if nPortErr != nil { c.Ui.Output(fmt.Sprintf("Cannot parse %s as a numeric port: %v", port, nPortErr)) return 1 } u.Host = net.JoinHostPort(host, strconv.Itoa(nPort+1)) // Will always be TLS-secured u.Scheme = "https" coreConfig.ClusterAddr = u.String() } if coreConfig.ClusterAddr != "" { // Force https as we'll always be TLS-secured u, err := url.ParseRequestURI(coreConfig.ClusterAddr) if err != nil { c.Ui.Output(fmt.Sprintf("Error parsing cluster address %s: %v", coreConfig.RedirectAddr, err)) return 1 } u.Scheme = "https" coreConfig.ClusterAddr = u.String() } // Initialize the core core, newCoreError := vault.NewCore(coreConfig) if newCoreError != nil { if !errwrap.ContainsType(newCoreError, new(vault.NonFatalError)) { c.Ui.Output(fmt.Sprintf("Error initializing core: %s", newCoreError)) return 1 } } // Copy the reload funcs pointers back c.reloadFuncs = coreConfig.ReloadFuncs c.reloadFuncsLock = coreConfig.ReloadFuncsLock // Compile server information for output later info["backend"] = config.Backend.Type info["log level"] = logLevel info["mlock"] = fmt.Sprintf( "supported: %v, enabled: %v", mlock.Supported(), !config.DisableMlock && mlock.Supported()) infoKeys = append(infoKeys, "log level", "mlock", "backend") if config.HABackend != nil { info["HA backend"] = config.HABackend.Type info["redirect address"] = coreConfig.RedirectAddr infoKeys = append(infoKeys, "HA backend", "redirect address") if coreConfig.ClusterAddr != "" { info["cluster address"] = coreConfig.ClusterAddr infoKeys = append(infoKeys, "cluster address") } } else { // If the backend supports HA, then note it if coreConfig.HAPhysical != nil { if coreConfig.HAPhysical.HAEnabled() { info["backend"] += " (HA available)" info["redirect address"] = coreConfig.RedirectAddr infoKeys = append(infoKeys, "redirect address") if coreConfig.ClusterAddr != "" { info["cluster address"] = coreConfig.ClusterAddr infoKeys = append(infoKeys, "cluster address") } } else { info["backend"] += " (HA disabled)" } } } clusterAddrs := []*net.TCPAddr{} // Initialize the listeners c.reloadFuncsLock.Lock() lns := make([]net.Listener, 0, len(config.Listeners)) for i, lnConfig := range config.Listeners { if lnConfig.Type == "atlas" { if config.ClusterName == "" { c.Ui.Output("cluster_name is not set in the config and is a required value") return 1 } lnConfig.Config["cluster_name"] = config.ClusterName } ln, props, reloadFunc, err := server.NewListener(lnConfig.Type, lnConfig.Config, logGate) if err != nil { c.Ui.Output(fmt.Sprintf( "Error initializing listener of type %s: %s", lnConfig.Type, err)) return 1 } lns = append(lns, ln) if reloadFunc != nil { relSlice := (*c.reloadFuncs)["listener|"+lnConfig.Type] relSlice = append(relSlice, reloadFunc) (*c.reloadFuncs)["listener|"+lnConfig.Type] = relSlice } if !disableClustering && lnConfig.Type == "tcp" { var addr string var ok bool if addr, ok = lnConfig.Config["cluster_address"]; ok { tcpAddr, err := net.ResolveTCPAddr("tcp", addr) if err != nil { c.Ui.Output(fmt.Sprintf( "Error resolving cluster_address: %s", err)) return 1 } clusterAddrs = append(clusterAddrs, tcpAddr) } else { tcpAddr, ok := ln.Addr().(*net.TCPAddr) if !ok { c.Ui.Output("Failed to parse tcp listener") return 1 } clusterAddrs = append(clusterAddrs, &net.TCPAddr{ IP: tcpAddr.IP, Port: tcpAddr.Port + 1, }) } props["cluster address"] = addr } // 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, ", ")) } c.reloadFuncsLock.Unlock() if !disableClustering { if c.logger.IsTrace() { c.logger.Trace("cluster listener addresses synthesized", "cluster_addresses", clusterAddrs) } } // Make sure we close all listeners from this point on listenerCloseFunc := func() { for _, ln := range lns { ln.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, "cgo") info["cgo"] = "disabled" if version.CgoEnabled { info["cgo"] = "enabled" } // 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("") if verifyOnly { return 0 } // 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 { if isLeader, _, err := core.Leader(); err == nil { return isLeader } return false } sealedFunc := func() bool { if sealed, err := core.Sealed(); err == nil { return sealed } return true } if err := sd.RunServiceDiscovery(c.WaitGroup, c.ShutdownCh, coreConfig.RedirectAddr, activeFunc, sealedFunc); err != nil { c.Ui.Output(fmt.Sprintf("Error initializing service discovery: %v", err)) return 1 } } } handler := vaulthttp.Handler(core) // This needs to happen before we first unseal, so before we trigger dev // mode if it's set core.SetClusterListenerAddrs(clusterAddrs) core.SetClusterSetupFuncs(vault.WrapHandlerForClustering(handler, c.logger)) // If we're in dev mode, then initialize the core if dev { init, err := c.enableDev(core, devRootTokenID) if err != nil { c.Ui.Output(fmt.Sprintf( "Error initializing dev mode: %s", err)) return 1 } export := "export" quote := "'" if runtime.GOOS == "windows" { export = "set" quote = "" } c.Ui.Output(fmt.Sprintf( "==> WARNING: Dev mode is enabled!\n\n"+ "In this mode, Vault is completely in-memory and unsealed.\n"+ "Vault is configured to only have a single unseal key. The root\n"+ "token has already been authenticated with the CLI, so you can\n"+ "immediately begin using the Vault CLI.\n\n"+ "The only step you need to take is to set the following\n"+ "environment variables:\n\n"+ " "+export+" VAULT_ADDR="+quote+"http://"+config.Listeners[0].Config["address"]+quote+"\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\n"+ "Unseal Key: %s\nRoot Token: %s\n", base64.StdEncoding.EncodeToString(init.SecretShares[0]), init.RootToken, )) } // Initialize the HTTP server server := &http.Server{} server.Handler = handler for _, ln := range lns { go server.Serve(ln) } if newCoreError != nil { c.Ui.Output("==> Warning:\n\nNon-fatal error during initialization; check the logs for more information.") c.Ui.Output("") } // Output the header that the server has started c.Ui.Output("==> Vault server started! Log data will stream in below:\n") // Release the log gate. logGate.Flush() // Wait for shutdown shutdownTriggered := false for !shutdownTriggered { select { case <-c.ShutdownCh: c.Ui.Output("==> Vault shutdown triggered") // Stop the listners so that we don't process further client requests. 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). if err := core.Shutdown(); err != nil { c.Ui.Output(fmt.Sprintf("Error with core shutdown: %s", err)) } shutdownTriggered = true case <-c.SighupCh: c.Ui.Output("==> Vault reload triggered") if err := c.Reload(configPath); err != nil { c.Ui.Output(fmt.Sprintf("Error(s) were encountered during reload: %s", err)) } } } // Wait for dependent goroutines to complete c.WaitGroup.Wait() return 0 }
func getSysHealth(core *vault.Core, r *http.Request) (int, *HealthResponse, error) { // Check if being a standby is allowed for the purpose of a 200 OK _, standbyOK := r.URL.Query()["standbyok"] uninitCode := http.StatusNotImplemented if code, found, ok := fetchStatusCode(r, "uninitcode"); !ok { return http.StatusBadRequest, nil, nil } else if found { uninitCode = code } sealedCode := http.StatusServiceUnavailable if code, found, ok := fetchStatusCode(r, "sealedcode"); !ok { return http.StatusBadRequest, nil, nil } else if found { sealedCode = code } standbyCode := http.StatusTooManyRequests // Consul warning code if code, found, ok := fetchStatusCode(r, "standbycode"); !ok { return http.StatusBadRequest, nil, nil } else if found { standbyCode = code } activeCode := http.StatusOK if code, found, ok := fetchStatusCode(r, "activecode"); !ok { return http.StatusBadRequest, nil, nil } else if found { activeCode = code } // Check system status sealed, _ := core.Sealed() standby, _ := core.Standby() init, err := core.Initialized() if err != nil { return http.StatusInternalServerError, nil, err } // Determine the status code code := activeCode switch { case !init: code = uninitCode case sealed: code = sealedCode case !standbyOK && standby: code = standbyCode } // Fetch the local cluster name and identifier var clusterName, clusterID string if !sealed { cluster, err := core.Cluster() if err != nil { return http.StatusInternalServerError, nil, err } if cluster == nil { return http.StatusInternalServerError, nil, fmt.Errorf("failed to fetch cluster details") } clusterName = cluster.Name clusterID = cluster.ID } // Format the body body := &HealthResponse{ Initialized: init, Sealed: sealed, Standby: standby, ServerTimeUTC: time.Now().UTC().Unix(), Version: version.GetVersion().VersionNumber(), ClusterName: clusterName, ClusterID: clusterID, } return code, body, nil }
func (c *ServerCommand) Run(args []string) int { var dev, verifyOnly bool var configPath []string var logLevel, devRootTokenID, devListenAddress string flags := c.Meta.FlagSet("server", meta.FlagSetDefault) flags.BoolVar(&dev, "dev", false, "") flags.StringVar(&devRootTokenID, "dev-root-token-id", "", "") flags.StringVar(&devListenAddress, "dev-listen-address", "", "") flags.StringVar(&logLevel, "log-level", "info", "") flags.BoolVar(&verifyOnly, "verify-only", false, "") flags.Usage = func() { c.Ui.Error(c.Help()) } flags.Var((*sliceflag.StringFlag)(&configPath), "config", "config") if err := flags.Parse(args); err != nil { return 1 } if os.Getenv("VAULT_DEV_ROOT_TOKEN_ID") != "" && devRootTokenID == "" { devRootTokenID = os.Getenv("VAULT_DEV_ROOT_TOKEN_ID") } if os.Getenv("VAULT_DEV_LISTEN_ADDRESS") != "" && devListenAddress == "" { devListenAddress = os.Getenv("VAULT_DEV_LISTEN_ADDRESS") } // Validation if !dev { switch { case len(configPath) == 0: c.Ui.Error("At least one config path must be specified with -config") flags.Usage() return 1 case devRootTokenID != "": c.Ui.Error("Root token ID can only be specified with -dev") flags.Usage() return 1 case devListenAddress != "": c.Ui.Error("Development address can only be specified with -dev") flags.Usage() return 1 } } // Load the configuration var config *server.Config if dev { config = server.DevConfig() if devListenAddress != "" { config.Listeners[0].Config["address"] = devListenAddress } } for _, path := range configPath { current, err := server.LoadConfig(path) if err != nil { c.Ui.Error(fmt.Sprintf( "Error loading configuration from %s: %s", path, err)) return 1 } if config == nil { config = current } else { config = config.Merge(current) } } // Ensure at least one config was found. if config == nil { c.Ui.Error("No configuration files found.") return 1 } // Ensure that a backend is provided if config.Backend == nil { c.Ui.Error("A physical backend must be specified") return 1 } // 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. if !dev && !mlock.Supported() { c.Ui.Output("==> WARNING: mlock not supported on this system!\n") c.Ui.Output(" An `mlockall(2)`-like syscall to prevent memory from being") c.Ui.Output(" swapped to disk is not supported on this system. Running") c.Ui.Output(" Vault on an mlockall(2) enabled system is much more secure.\n") } // Create a logger. We wrap it in a gated writer so that it doesn't // start logging too early. logGate := &gatedwriter.Writer{Writer: os.Stderr} c.logger = log.New(&logutils.LevelFilter{ Levels: []logutils.LogLevel{ "TRACE", "DEBUG", "INFO", "WARN", "ERR"}, MinLevel: logutils.LogLevel(strings.ToUpper(logLevel)), Writer: logGate, }, "", log.LstdFlags) if err := c.setupTelemetry(config); err != nil { c.Ui.Error(fmt.Sprintf("Error initializing telemetry: %s", err)) return 1 } // Initialize the backend backend, err := physical.NewBackend( config.Backend.Type, c.logger, config.Backend.Config) if err != nil { c.Ui.Error(fmt.Sprintf( "Error initializing backend of type %s: %s", config.Backend.Type, err)) return 1 } infoKeys := make([]string, 0, 10) info := make(map[string]string) var seal vault.Seal = &vault.DefaultSeal{} // Ensure that the seal finalizer is called, even if using verify-only defer func() { err = seal.Finalize() if err != nil { c.Ui.Error(fmt.Sprintf("Error finalizing seals: %v", err)) } }() coreConfig := &vault.CoreConfig{ Physical: backend, AdvertiseAddr: config.Backend.AdvertiseAddr, HAPhysical: nil, Seal: seal, AuditBackends: c.AuditBackends, CredentialBackends: c.CredentialBackends, LogicalBackends: c.LogicalBackends, Logger: c.logger, DisableCache: config.DisableCache, DisableMlock: config.DisableMlock, MaxLeaseTTL: config.MaxLeaseTTL, DefaultLeaseTTL: config.DefaultLeaseTTL, } // Initialize the separate HA physical backend, if it exists var ok bool if config.HABackend != nil { habackend, err := physical.NewBackend( config.HABackend.Type, c.logger, config.HABackend.Config) if err != nil { c.Ui.Error(fmt.Sprintf( "Error initializing backend of type %s: %s", config.HABackend.Type, err)) return 1 } if coreConfig.HAPhysical, ok = habackend.(physical.HABackend); !ok { c.Ui.Error("Specified HA backend does not support HA") return 1 } coreConfig.AdvertiseAddr = config.HABackend.AdvertiseAddr } else { if coreConfig.HAPhysical, ok = backend.(physical.HABackend); ok { coreConfig.AdvertiseAddr = config.Backend.AdvertiseAddr } } if envAA := os.Getenv("VAULT_ADVERTISE_ADDR"); envAA != "" { coreConfig.AdvertiseAddr = envAA } // Attempt to detect the advertise address, if possible var detect physical.AdvertiseDetect if coreConfig.HAPhysical != nil { detect, ok = coreConfig.HAPhysical.(physical.AdvertiseDetect) } else { detect, ok = coreConfig.Physical.(physical.AdvertiseDetect) } if ok && coreConfig.AdvertiseAddr == "" { advertise, err := c.detectAdvertise(detect, config) if err != nil { c.Ui.Error(fmt.Sprintf("Error detecting advertise address: %s", err)) } else if advertise == "" { c.Ui.Error("Failed to detect advertise address.") } else { coreConfig.AdvertiseAddr = advertise } } // Initialize the core core, newCoreError := vault.NewCore(coreConfig) if newCoreError != nil { if !errwrap.ContainsType(newCoreError, new(vault.NonFatalError)) { c.Ui.Error(fmt.Sprintf("Error initializing core: %s", newCoreError)) return 1 } } // If we're in dev mode, then initialize the core if dev { init, err := c.enableDev(core, devRootTokenID) if err != nil { c.Ui.Error(fmt.Sprintf( "Error initializing dev mode: %s", err)) return 1 } export := "export" quote := "'" if runtime.GOOS == "windows" { export = "set" quote = "" } c.Ui.Output(fmt.Sprintf( "==> WARNING: Dev mode is enabled!\n\n"+ "In this mode, Vault is completely in-memory and unsealed.\n"+ "Vault is configured to only have a single unseal key. The root\n"+ "token has already been authenticated with the CLI, so you can\n"+ "immediately begin using the Vault CLI.\n\n"+ "The only step you need to take is to set the following\n"+ "environment variables:\n\n"+ " "+export+" VAULT_ADDR="+quote+"http://"+config.Listeners[0].Config["address"]+quote+"\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\n"+ "Unseal Key: %s\nRoot Token: %s\n", hex.EncodeToString(init.SecretShares[0]), init.RootToken, )) } // Compile server information for output later info["backend"] = config.Backend.Type info["log level"] = logLevel info["mlock"] = fmt.Sprintf( "supported: %v, enabled: %v", mlock.Supported(), !config.DisableMlock) infoKeys = append(infoKeys, "log level", "mlock", "backend") if config.HABackend != nil { info["HA backend"] = config.HABackend.Type info["advertise address"] = coreConfig.AdvertiseAddr infoKeys = append(infoKeys, "HA backend", "advertise address") } else { // If the backend supports HA, then note it if coreConfig.HAPhysical != nil { info["backend"] += " (HA available)" info["advertise address"] = coreConfig.AdvertiseAddr infoKeys = append(infoKeys, "advertise address") } } // If the backend supports service discovery, run service discovery if coreConfig.HAPhysical != nil { sd, ok := coreConfig.HAPhysical.(physical.ServiceDiscovery) if ok { activeFunc := func() bool { if isLeader, _, err := core.Leader(); err == nil { return isLeader } return false } sealedFunc := func() bool { if sealed, err := core.Sealed(); err == nil { return sealed } return true } if err := sd.RunServiceDiscovery(c.ShutdownCh, coreConfig.AdvertiseAddr, activeFunc, sealedFunc); err != nil { c.Ui.Error(fmt.Sprintf("Error initializing service discovery: %v", err)) return 1 } } } // Initialize the listeners lns := make([]net.Listener, 0, len(config.Listeners)) for i, lnConfig := range config.Listeners { ln, props, reloadFunc, err := server.NewListener(lnConfig.Type, lnConfig.Config, logGate) if err != nil { c.Ui.Error(fmt.Sprintf( "Error initializing listener of type %s: %s", lnConfig.Type, err)) return 1 } // 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, ", ")) lns = append(lns, ln) if reloadFunc != nil { relSlice := c.ReloadFuncs["listener|"+lnConfig.Type] relSlice = append(relSlice, reloadFunc) c.ReloadFuncs["listener|"+lnConfig.Type] = relSlice } } // Make sure we close all listeners from this point on defer func() { for _, ln := range lns { ln.Close() } }() infoKeys = append(infoKeys, "version") info["version"] = version.GetVersion().String() // 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("") if verifyOnly { return 0 } // Initialize the HTTP server server := &http.Server{} server.Handler = vaulthttp.Handler(core) for _, ln := range lns { go server.Serve(ln) } if newCoreError != nil { c.Ui.Output("==> Warning:\n\nNon-fatal error during initialization; check the logs for more information.") c.Ui.Output("") } // Output the header that the server has started c.Ui.Output("==> Vault server started! Log data will stream in below:\n") // Release the log gate. logGate.Flush() // Wait for shutdown shutdownTriggered := false for !shutdownTriggered { select { case <-c.ShutdownCh: c.Ui.Output("==> Vault shutdown triggered") if err := core.Shutdown(); err != nil { c.Ui.Error(fmt.Sprintf("Error with core shutdown: %s", err)) } shutdownTriggered = true case <-c.SighupCh: c.Ui.Output("==> Vault reload triggered") if err := c.Reload(configPath); err != nil { c.Ui.Error(fmt.Sprintf("Error(s) were encountered during reload: %s", err)) } } } return 0 }