1package command
2
3import (
4	"context"
5	"encoding/json"
6	"fmt"
7	"io"
8	"os"
9	"strings"
10	"sync"
11	"time"
12
13	"golang.org/x/term"
14
15	wrapping "github.com/hashicorp/go-kms-wrapping"
16	"github.com/hashicorp/vault/helper/constants"
17
18	"github.com/docker/docker/pkg/ioutils"
19	"github.com/hashicorp/consul/api"
20	log "github.com/hashicorp/go-hclog"
21	uuid "github.com/hashicorp/go-uuid"
22	cserver "github.com/hashicorp/vault/command/server"
23	"github.com/hashicorp/vault/helper/metricsutil"
24	"github.com/hashicorp/vault/internalshared/configutil"
25	"github.com/hashicorp/vault/internalshared/listenerutil"
26	"github.com/hashicorp/vault/internalshared/reloadutil"
27	physconsul "github.com/hashicorp/vault/physical/consul"
28	"github.com/hashicorp/vault/physical/raft"
29	"github.com/hashicorp/vault/sdk/physical"
30	"github.com/hashicorp/vault/sdk/version"
31	sr "github.com/hashicorp/vault/serviceregistration"
32	srconsul "github.com/hashicorp/vault/serviceregistration/consul"
33	"github.com/hashicorp/vault/vault"
34	"github.com/hashicorp/vault/vault/diagnose"
35	"github.com/mitchellh/cli"
36	"github.com/posener/complete"
37)
38
39const OperatorDiagnoseEnableEnv = "VAULT_DIAGNOSE"
40
41const CoreConfigUninitializedErr = "Diagnose cannot attempt this step because core config could not be set."
42
43var (
44	_ cli.Command             = (*OperatorDiagnoseCommand)(nil)
45	_ cli.CommandAutocomplete = (*OperatorDiagnoseCommand)(nil)
46)
47
48type OperatorDiagnoseCommand struct {
49	*BaseCommand
50	diagnose *diagnose.Session
51
52	flagDebug    bool
53	flagSkips    []string
54	flagConfigs  []string
55	cleanupGuard sync.Once
56
57	reloadFuncsLock      *sync.RWMutex
58	reloadFuncs          *map[string][]reloadutil.ReloadFunc
59	ServiceRegistrations map[string]sr.Factory
60	startedCh            chan struct{} // for tests
61	reloadedCh           chan struct{} // for tests
62	skipEndEnd           bool          // for tests
63}
64
65func (c *OperatorDiagnoseCommand) Synopsis() string {
66	return "Troubleshoot problems starting Vault"
67}
68
69func (c *OperatorDiagnoseCommand) Help() string {
70	helpText := `
71Usage: vault operator diagnose
72
73  This command troubleshoots Vault startup issues, such as TLS configuration or
74  auto-unseal. It should be run using the same environment variables and configuration
75  files as the "vault server" command, so that startup problems can be accurately
76  reproduced.
77
78  Start diagnose with a configuration file:
79
80     $ vault operator diagnose -config=/etc/vault/config.hcl
81
82  Perform a diagnostic check while Vault is still running:
83
84     $ vault operator diagnose -config=/etc/vault/config.hcl -skip=listener
85
86` + c.Flags().Help()
87	return strings.TrimSpace(helpText)
88}
89
90func (c *OperatorDiagnoseCommand) Flags() *FlagSets {
91	set := NewFlagSets(c.UI)
92	f := set.NewFlagSet("Command Options")
93
94	f.StringSliceVar(&StringSliceVar{
95		Name:   "config",
96		Target: &c.flagConfigs,
97		Completion: complete.PredictOr(
98			complete.PredictFiles("*.hcl"),
99			complete.PredictFiles("*.json"),
100			complete.PredictDirs("*"),
101		),
102		Usage: "Path to a Vault configuration file or directory of configuration " +
103			"files. This flag can be specified multiple times to load multiple " +
104			"configurations. If the path is a directory, all files which end in " +
105			".hcl or .json are loaded.",
106	})
107
108	f.StringSliceVar(&StringSliceVar{
109		Name:   "skip",
110		Target: &c.flagSkips,
111		Usage:  "Skip the health checks named as arguments. May be 'listener', 'storage', or 'autounseal'.",
112	})
113
114	f.BoolVar(&BoolVar{
115		Name:    "debug",
116		Target:  &c.flagDebug,
117		Default: false,
118		Usage:   "Dump all information collected by Diagnose.",
119	})
120
121	f.StringVar(&StringVar{
122		Name:   "format",
123		Target: &c.flagFormat,
124		Usage:  "The output format",
125	})
126	return set
127}
128
129func (c *OperatorDiagnoseCommand) AutocompleteArgs() complete.Predictor {
130	return complete.PredictNothing
131}
132
133func (c *OperatorDiagnoseCommand) AutocompleteFlags() complete.Flags {
134	return c.Flags().Completions()
135}
136
137const (
138	status_unknown = "[      ] "
139	status_ok      = "\u001b[32m[  ok  ]\u001b[0m "
140	status_failed  = "\u001b[31m[failed]\u001b[0m "
141	status_warn    = "\u001b[33m[ warn ]\u001b[0m "
142	same_line      = "\u001b[F"
143)
144
145func (c *OperatorDiagnoseCommand) Run(args []string) int {
146	f := c.Flags()
147	if err := f.Parse(args); err != nil {
148		c.UI.Error(err.Error())
149		return 3
150	}
151	return c.RunWithParsedFlags()
152}
153
154func (c *OperatorDiagnoseCommand) RunWithParsedFlags() int {
155
156	if len(c.flagConfigs) == 0 {
157		c.UI.Error("Must specify a configuration file using -config.")
158		return 3
159	}
160
161	if c.diagnose == nil {
162		if c.flagFormat == "json" {
163			c.diagnose = diagnose.New(&ioutils.NopWriter{})
164		} else {
165			c.UI.Output(version.GetVersion().FullVersionNumber(true))
166			c.diagnose = diagnose.New(os.Stdout)
167		}
168	}
169	ctx := diagnose.Context(context.Background(), c.diagnose)
170	c.diagnose.SkipFilters = c.flagSkips
171	err := c.offlineDiagnostics(ctx)
172
173	results := c.diagnose.Finalize(ctx)
174	if c.flagFormat == "json" {
175		resultsJS, err := json.MarshalIndent(results, "", "  ")
176		if err != nil {
177			fmt.Fprintf(os.Stderr, "Error marshalling results: %v.", err)
178			return 4
179		}
180		c.UI.Output(string(resultsJS))
181	} else {
182		c.UI.Output("\nResults:")
183		w, _, err := term.GetSize(0)
184		if err == nil {
185			results.Write(os.Stdout, w)
186		} else {
187			results.Write(os.Stdout, 0)
188		}
189	}
190
191	if err != nil {
192		return 4
193	}
194	// Use a different return code
195	switch results.Status {
196	case diagnose.WarningStatus:
197		return 2
198	case diagnose.ErrorStatus:
199		return 1
200	}
201	return 0
202}
203
204func (c *OperatorDiagnoseCommand) offlineDiagnostics(ctx context.Context) error {
205	rloadFuncs := make(map[string][]reloadutil.ReloadFunc)
206	server := &ServerCommand{
207		// TODO: set up a different one?
208		// In particular, a UI instance that won't output?
209		BaseCommand: c.BaseCommand,
210
211		// TODO: refactor to a common place?
212		AuditBackends:        auditBackends,
213		CredentialBackends:   credentialBackends,
214		LogicalBackends:      logicalBackends,
215		PhysicalBackends:     physicalBackends,
216		ServiceRegistrations: serviceRegistrations,
217
218		// TODO: other ServerCommand options?
219
220		logger: log.NewInterceptLogger(&log.LoggerOptions{
221			Level: log.Off,
222		}),
223		allLoggers:      []log.Logger{},
224		reloadFuncs:     &rloadFuncs,
225		reloadFuncsLock: new(sync.RWMutex),
226	}
227
228	ctx, span := diagnose.StartSpan(ctx, "Vault Diagnose")
229	defer span.End()
230
231	// OS Specific checks
232	diagnose.OSChecks(ctx)
233
234	var config *cserver.Config
235
236	diagnose.Test(ctx, "Parse Configuration", func(ctx context.Context) (err error) {
237		server.flagConfigs = c.flagConfigs
238		var configErrors []configutil.ConfigError
239		config, configErrors, err = server.parseConfig()
240		if err != nil {
241			return fmt.Errorf("Could not parse configuration: %w.", err)
242		}
243		for _, ce := range configErrors {
244			diagnose.Warn(ctx, diagnose.CapitalizeFirstLetter(ce.String())+".")
245		}
246		diagnose.Success(ctx, "Vault configuration syntax is ok.")
247		return nil
248	})
249	if config == nil {
250		return fmt.Errorf("No vault server configuration found.")
251	}
252
253	var metricSink *metricsutil.ClusterMetricSink
254	var metricsHelper *metricsutil.MetricsHelper
255
256	var backend *physical.Backend
257	diagnose.Test(ctx, "Check Storage", func(ctx context.Context) error {
258
259		// Ensure that there is a storage stanza
260		if config.Storage == nil {
261			diagnose.Advise(ctx, "To learn how to specify a storage backend, see the Vault server configuration documentation.")
262			return fmt.Errorf("No storage stanza in Vault server configuration.")
263		}
264
265		diagnose.Test(ctx, "Create Storage Backend", func(ctx context.Context) error {
266			b, err := server.setupStorage(config)
267			if err != nil {
268				return err
269			}
270			if b == nil {
271				diagnose.Advise(ctx, "To learn how to specify a storage backend, see the Vault server configuration documentation.")
272				return fmt.Errorf("Storage backend could not be initialized.")
273			}
274			backend = &b
275			return nil
276		})
277
278		if backend == nil {
279			diagnose.Fail(ctx, "Diagnose could not initialize storage backend.")
280			span.End()
281			return fmt.Errorf("Diagnose could not initialize storage backend.")
282		}
283
284		// Check for raft quorum status
285		if config.Storage.Type == storageTypeRaft {
286			path := os.Getenv(raft.EnvVaultRaftPath)
287			if path == "" {
288				path, ok := config.Storage.Config["path"]
289				if !ok {
290					diagnose.SpotError(ctx, "Check Raft Folder Permissions", fmt.Errorf("Storage folder path is required."))
291				}
292				diagnose.RaftFileChecks(ctx, path)
293			}
294			diagnose.RaftStorageQuorum(ctx, (*backend).(*raft.RaftBackend))
295		}
296
297		// Consul storage checks
298		if config.Storage != nil && config.Storage.Type == storageTypeConsul {
299			diagnose.Test(ctx, "Check Consul TLS", func(ctx context.Context) error {
300				err := physconsul.SetupSecureTLS(ctx, api.DefaultConfig(), config.Storage.Config, server.logger, true)
301				if err != nil {
302					return err
303				}
304				return nil
305			})
306
307			diagnose.Test(ctx, "Check Consul Direct Storage Access", func(ctx context.Context) error {
308				dirAccess := diagnose.ConsulDirectAccess(config.Storage.Config)
309				if dirAccess != "" {
310					diagnose.Warn(ctx, dirAccess)
311				}
312				if dirAccess == diagnose.DirAccessErr {
313					diagnose.Advise(ctx, diagnose.DirAccessAdvice)
314				}
315				return nil
316			})
317		}
318
319		// Attempt to use storage backend
320		if !c.skipEndEnd && config.Storage.Type != storageTypeRaft {
321			diagnose.Test(ctx, "Check Storage Access", diagnose.WithTimeout(30*time.Second, func(ctx context.Context) error {
322				maxDurationCrudOperation := "write"
323				maxDuration := time.Duration(0)
324				uuidSuffix, err := uuid.GenerateUUID()
325				if err != nil {
326					return err
327				}
328				uuid := "diagnose/latency/" + uuidSuffix
329				dur, err := diagnose.EndToEndLatencyCheckWrite(ctx, uuid, *backend)
330				if err != nil {
331					return err
332				}
333				maxDuration = dur
334				dur, err = diagnose.EndToEndLatencyCheckRead(ctx, uuid, *backend)
335				if err != nil {
336					return err
337				}
338				if dur > maxDuration {
339					maxDuration = dur
340					maxDurationCrudOperation = "read"
341				}
342				dur, err = diagnose.EndToEndLatencyCheckDelete(ctx, uuid, *backend)
343				if err != nil {
344					return err
345				}
346				if dur > maxDuration {
347					maxDuration = dur
348					maxDurationCrudOperation = "delete"
349				}
350
351				if maxDuration > time.Duration(0) {
352					diagnose.Warn(ctx, diagnose.LatencyWarning+fmt.Sprintf("duration: %s, operation: %s", maxDuration, maxDurationCrudOperation))
353				}
354				return nil
355			}))
356		}
357		return nil
358	})
359
360	// Return from top-level span when backend is nil
361	if backend == nil {
362		return fmt.Errorf("Diagnose could not initialize storage backend.")
363	}
364
365	var configSR sr.ServiceRegistration
366	diagnose.Test(ctx, "Check Service Discovery", func(ctx context.Context) error {
367		if config.ServiceRegistration == nil || config.ServiceRegistration.Config == nil {
368			diagnose.Skipped(ctx, "No service registration configured.")
369			return nil
370		}
371		srConfig := config.ServiceRegistration.Config
372
373		diagnose.Test(ctx, "Check Consul Service Discovery TLS", func(ctx context.Context) error {
374			// SetupSecureTLS for service discovery uses the same cert and key to set up physical
375			// storage. See the consul package in physical for details.
376			err := srconsul.SetupSecureTLS(ctx, api.DefaultConfig(), srConfig, server.logger, true)
377			if err != nil {
378				return err
379			}
380			return nil
381		})
382
383		if config.ServiceRegistration != nil && config.ServiceRegistration.Type == "consul" {
384			diagnose.Test(ctx, "Check Consul Direct Service Discovery", func(ctx context.Context) error {
385				dirAccess := diagnose.ConsulDirectAccess(config.ServiceRegistration.Config)
386				if dirAccess != "" {
387					diagnose.Warn(ctx, dirAccess)
388				}
389				if dirAccess == diagnose.DirAccessErr {
390					diagnose.Advise(ctx, diagnose.DirAccessAdvice)
391				}
392				return nil
393			})
394		}
395		return nil
396	})
397
398	sealcontext, sealspan := diagnose.StartSpan(ctx, "Create Vault Server Configuration Seals")
399	var seals []vault.Seal
400	var sealConfigError error
401
402	barrierSeal, barrierWrapper, unwrapSeal, seals, sealConfigError, err := setSeal(server, config, make([]string, 0), make(map[string]string))
403
404	// Check error here
405	if err != nil {
406		diagnose.Advise(ctx, "For assistance with the seal stanza, see the Vault configuration documentation.")
407		diagnose.Fail(sealcontext, fmt.Sprintf("Seal creation resulted in the following error: %s.", err.Error()))
408		goto SEALFAIL
409	}
410	if sealConfigError != nil {
411		diagnose.Fail(sealcontext, "Seal could not be configured: seals may already be initialized.")
412		goto SEALFAIL
413	}
414
415	if seals != nil {
416		for _, seal := range seals {
417			// There is always one nil seal. We need to skip it so we don't start an empty Finalize-Seal-Shamir
418			// section.
419			if seal == nil {
420				continue
421			}
422			// Ensure that the seal finalizer is called, even if using verify-only
423			defer func(seal *vault.Seal) {
424				sealType := diagnose.CapitalizeFirstLetter((*seal).BarrierType())
425				finalizeSealContext, finalizeSealSpan := diagnose.StartSpan(ctx, "Finalize "+sealType+" Seal")
426				err = (*seal).Finalize(finalizeSealContext)
427				if err != nil {
428					diagnose.Fail(finalizeSealContext, "Error finalizing seal.")
429					diagnose.Advise(finalizeSealContext, "This likely means that the barrier is still in use; therefore, finalizing the seal timed out.")
430					finalizeSealSpan.End()
431				}
432				finalizeSealSpan.End()
433			}(&seal)
434		}
435	}
436
437	if barrierSeal == nil {
438		diagnose.Fail(sealcontext, "Could not create barrier seal. No error was generated, but it is likely that the seal stanza is misconfigured. For guidance, see Vault's configuration documentation on the seal stanza.")
439	}
440
441SEALFAIL:
442	sealspan.End()
443
444	diagnose.Test(ctx, "Check Transit Seal TLS", func(ctx context.Context) error {
445		var checkSealTransit bool
446		for _, seal := range config.Seals {
447			if seal.Type == "transit" {
448				checkSealTransit = true
449
450				tlsSkipVerify, _ := seal.Config["tls_skip_verify"]
451				if tlsSkipVerify == "true" {
452					diagnose.Warn(ctx, "TLS verification is skipped. This is highly discouraged and decreases the security of data transmissions to and from the Vault server.")
453					return nil
454				}
455
456				// Checking tls_client_cert and tls_client_key
457				tlsClientCert, ok := seal.Config["tls_client_cert"]
458				if !ok {
459					diagnose.Warn(ctx, "Missing tls_client_cert in the seal configuration.")
460					return nil
461				}
462				tlsClientKey, ok := seal.Config["tls_client_key"]
463				if !ok {
464					diagnose.Warn(ctx, "Missing tls_client_key in the seal configuration.")
465					return nil
466				}
467				_, err := diagnose.TLSFileChecks(tlsClientCert, tlsClientKey)
468				if err != nil {
469					return fmt.Errorf("The TLS certificate and key configured through the tls_client_cert and tls_client_key fields of the transit seal configuration are invalid: %w.", err)
470				}
471
472				// checking tls_ca_cert
473				tlsCACert, ok := seal.Config["tls_ca_cert"]
474				if !ok {
475					diagnose.Warn(ctx, "Missing tls_ca_cert in the seal configuration.")
476					return nil
477				}
478				warnings, err := diagnose.TLSCAFileCheck(tlsCACert)
479				if len(warnings) != 0 {
480					for _, warning := range warnings {
481						diagnose.Warn(ctx, warning)
482					}
483				}
484				if err != nil {
485					return fmt.Errorf("The TLS CA certificate configured through the tls_ca_cert field of the transit seal configuration is invalid: %w.", err)
486				}
487			}
488		}
489		if !checkSealTransit {
490			diagnose.Skipped(ctx, "No transit seal found in seal configuration.")
491		}
492		return nil
493	})
494
495	var coreConfig vault.CoreConfig
496	diagnose.Test(ctx, "Create Core Configuration", func(ctx context.Context) error {
497		var secureRandomReader io.Reader
498		// prepare a secure random reader for core
499		randReaderTestName := "Initialize Randomness for Core"
500		secureRandomReader, err = configutil.CreateSecureRandomReaderFunc(config.SharedConfig, barrierWrapper)
501		if err != nil {
502			return diagnose.SpotError(ctx, randReaderTestName, fmt.Errorf("Could not initialize randomness for core: %w.", err))
503		}
504		diagnose.SpotOk(ctx, randReaderTestName, "")
505		coreConfig = createCoreConfig(server, config, *backend, configSR, barrierSeal, unwrapSeal, metricsHelper, metricSink, secureRandomReader)
506		return nil
507	})
508
509	var disableClustering bool
510	diagnose.Test(ctx, "HA Storage", func(ctx context.Context) error {
511		diagnose.Test(ctx, "Create HA Storage Backend", func(ctx context.Context) error {
512			// Initialize the separate HA storage backend, if it exists
513			disableClustering, err = initHaBackend(server, config, &coreConfig, *backend)
514			if err != nil {
515				return err
516			}
517			return nil
518		})
519
520		diagnose.Test(ctx, "Check HA Consul Direct Storage Access", func(ctx context.Context) error {
521			if config.HAStorage == nil {
522				diagnose.Skipped(ctx, "No HA storage stanza is configured.")
523			} else {
524				dirAccess := diagnose.ConsulDirectAccess(config.HAStorage.Config)
525				if dirAccess != "" {
526					diagnose.Warn(ctx, dirAccess)
527				}
528				if dirAccess == diagnose.DirAccessErr {
529					diagnose.Advise(ctx, diagnose.DirAccessAdvice)
530				}
531			}
532			return nil
533		})
534		if config.HAStorage != nil && config.HAStorage.Type == storageTypeConsul {
535			diagnose.Test(ctx, "Check Consul TLS", func(ctx context.Context) error {
536				err = physconsul.SetupSecureTLS(ctx, api.DefaultConfig(), config.HAStorage.Config, server.logger, true)
537				if err != nil {
538					return err
539				}
540				return nil
541			})
542		}
543		return nil
544	})
545
546	// Determine the redirect address from environment variables
547	err = determineRedirectAddr(server, &coreConfig, config)
548	if err != nil {
549		return diagnose.SpotError(ctx, "Determine Redirect Address", fmt.Errorf("Redirect Address could not be determined: %w.", err))
550	}
551	diagnose.SpotOk(ctx, "Determine Redirect Address", "")
552
553	err = findClusterAddress(server, &coreConfig, config, disableClustering)
554	if err != nil {
555		return diagnose.SpotError(ctx, "Check Cluster Address", fmt.Errorf("Cluster Address could not be determined or was invalid: %w.", err),
556			diagnose.Advice("Please check that the API and Cluster addresses are different, and that the API, Cluster and Redirect addresses have both a host and port."))
557	}
558	diagnose.SpotOk(ctx, "Check Cluster Address", "Cluster address is logically valid and can be found.")
559
560	var vaultCore *vault.Core
561
562	// Run all the checks that are utilized when initializing a core object
563	// without actually calling core.Init. These are in the init-core section
564	// as they are runtime checks.
565	diagnose.Test(ctx, "Check Core Creation", func(ctx context.Context) error {
566		var newCoreError error
567		if coreConfig.RawConfig == nil {
568			return fmt.Errorf(CoreConfigUninitializedErr)
569		}
570		core, newCoreError := vault.CreateCore(&coreConfig)
571		if newCoreError != nil {
572			if vault.IsFatalError(newCoreError) {
573				return fmt.Errorf("Error initializing core: %s.", newCoreError)
574			}
575			diagnose.Warn(ctx, wrapAtLength(
576				"A non-fatal error occurred during initialization. Please check the logs for more information."))
577		} else {
578			vaultCore = core
579		}
580		return nil
581	})
582
583	if vaultCore == nil {
584		return fmt.Errorf("Diagnose could not initialize the Vault core from the Vault server configuration.")
585	}
586
587	licenseCtx, licenseSpan := diagnose.StartSpan(ctx, "Check For Autoloaded License")
588	// If we are not in enterprise, return from the check
589	if !constants.IsEnterprise {
590		diagnose.Skipped(licenseCtx, "License check will not run on OSS Vault.")
591	} else {
592		// Load License from environment variables. These take precedence over the
593		// configured license.
594		if envLicensePath := os.Getenv(EnvVaultLicensePath); envLicensePath != "" {
595			coreConfig.LicensePath = envLicensePath
596		}
597		if envLicense := os.Getenv(EnvVaultLicense); envLicense != "" {
598			coreConfig.License = envLicense
599		}
600		vault.DiagnoseCheckLicense(licenseCtx, vaultCore, coreConfig, false)
601	}
602	licenseSpan.End()
603
604	var lns []listenerutil.Listener
605	diagnose.Test(ctx, "Start Listeners", func(ctx context.Context) error {
606		disableClustering := config.HAStorage != nil && config.HAStorage.DisableClustering
607		infoKeys := make([]string, 0, 10)
608		info := make(map[string]string)
609		var listeners []listenerutil.Listener
610		var status int
611
612		diagnose.ListenerChecks(ctx, config.Listeners)
613
614		diagnose.Test(ctx, "Create Listeners", func(ctx context.Context) error {
615			status, listeners, _, err = server.InitListeners(config, disableClustering, &infoKeys, &info)
616			if status != 0 {
617				return err
618			}
619			return nil
620		})
621
622		lns = listeners
623
624		// Make sure we close all listeners from this point on
625		listenerCloseFunc := func() {
626			for _, ln := range lns {
627				ln.Listener.Close()
628			}
629		}
630
631		c.cleanupGuard.Do(listenerCloseFunc)
632
633		return nil
634	})
635
636	// TODO: Diagnose logging configuration
637
638	// The unseal diagnose check will simply attempt to use the barrier to encrypt and
639	// decrypt a mock value. It will not call runUnseal.
640	diagnose.Test(ctx, "Check Autounseal Encryption", diagnose.WithTimeout(30*time.Second, func(ctx context.Context) error {
641		if barrierSeal == nil {
642			return fmt.Errorf("Diagnose could not create a barrier seal object.")
643		}
644		if barrierSeal.BarrierType() == wrapping.Shamir {
645			diagnose.Skipped(ctx, "Skipping barrier encryption test. Only supported for auto-unseal.")
646			return nil
647		}
648		barrierUUID, err := uuid.GenerateUUID()
649		if err != nil {
650			return fmt.Errorf("Diagnose could not create unique UUID for unsealing.")
651		}
652		barrierEncValue := "diagnose-" + barrierUUID
653		ciphertext, err := barrierWrapper.Encrypt(ctx, []byte(barrierEncValue), nil)
654		if err != nil {
655			return fmt.Errorf("Error encrypting with seal barrier: %w.", err)
656		}
657		plaintext, err := barrierWrapper.Decrypt(ctx, ciphertext, nil)
658		if err != nil {
659			return fmt.Errorf("Error decrypting with seal barrier: %w", err)
660
661		}
662		if string(plaintext) != barrierEncValue {
663			return fmt.Errorf("Barrier returned incorrect decrypted value for mock data.")
664		}
665		return nil
666	}))
667
668	// The following block contains static checks that are run during the
669	// startHttpServers portion of server run. In other words, they are static
670	// checks during resource creation. Currently there is nothing important in this
671	// diagnose check. For now it is a placeholder for any checks that will be done
672	// before server run.
673	diagnose.Test(ctx, "Check Server Before Runtime", func(ctx context.Context) error {
674		for _, ln := range lns {
675			if ln.Config == nil {
676				return fmt.Errorf("Found no listener config after parsing the Vault configuration.")
677			}
678		}
679		return nil
680	})
681	return nil
682}
683