mirror of
https://github.com/hashicorp/vault.git
synced 2025-08-07 07:07:05 +02:00
* Adding explicit MPL license for sub-package. This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository. * Adding explicit MPL license for sub-package. This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository. * Updating the license from MPL to Business Source License. Going forward, this project will be licensed under the Business Source License v1.1. Please see our blog post for more details at https://hashi.co/bsl-blog, FAQ at www.hashicorp.com/licensing-faq, and details of the license at www.hashicorp.com/bsl. * add missing license headers * Update copyright file headers to BUS-1.1 * Fix test that expected exact offset on hcl file --------- Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com> Co-authored-by: Sarah Thompson <sthompson@hashicorp.com> Co-authored-by: Brian Kassouf <bkassouf@hashicorp.com>
561 lines
13 KiB
Go
561 lines
13 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
//go:build !race
|
|
|
|
package command
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/vault/vault/diagnose"
|
|
"github.com/mitchellh/cli"
|
|
)
|
|
|
|
func testOperatorDiagnoseCommand(tb testing.TB) *OperatorDiagnoseCommand {
|
|
tb.Helper()
|
|
|
|
ui := cli.NewMockUi()
|
|
return &OperatorDiagnoseCommand{
|
|
diagnose: diagnose.New(ioutil.Discard),
|
|
BaseCommand: &BaseCommand{
|
|
UI: ui,
|
|
},
|
|
skipEndEnd: true,
|
|
}
|
|
}
|
|
|
|
func TestOperatorDiagnoseCommand_Run(t *testing.T) {
|
|
t.Parallel()
|
|
cases := []struct {
|
|
name string
|
|
args []string
|
|
expected []*diagnose.Result
|
|
}{
|
|
{
|
|
"diagnose_ok",
|
|
[]string{
|
|
"-config", "./server/test-fixtures/config_diagnose_ok.hcl",
|
|
},
|
|
[]*diagnose.Result{
|
|
{
|
|
Name: "Parse Configuration",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
{
|
|
Name: "Start Listeners",
|
|
Status: diagnose.WarningStatus,
|
|
Children: []*diagnose.Result{
|
|
{
|
|
Name: "Create Listeners",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
{
|
|
Name: "Check Listener TLS",
|
|
Status: diagnose.WarningStatus,
|
|
Warnings: []string{
|
|
"TLS is disabled in a listener config stanza.",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "Check Storage",
|
|
Status: diagnose.OkStatus,
|
|
Children: []*diagnose.Result{
|
|
{
|
|
Name: "Create Storage Backend",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
{
|
|
Name: "Check Consul TLS",
|
|
Status: diagnose.SkippedStatus,
|
|
},
|
|
{
|
|
Name: "Check Consul Direct Storage Access",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "Check Service Discovery",
|
|
Status: diagnose.OkStatus,
|
|
Children: []*diagnose.Result{
|
|
{
|
|
Name: "Check Consul Service Discovery TLS",
|
|
Status: diagnose.SkippedStatus,
|
|
},
|
|
{
|
|
Name: "Check Consul Direct Service Discovery",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "Create Vault Server Configuration Seals",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
{
|
|
Name: "Create Core Configuration",
|
|
Status: diagnose.OkStatus,
|
|
Children: []*diagnose.Result{
|
|
{
|
|
Name: "Initialize Randomness for Core",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "HA Storage",
|
|
Status: diagnose.OkStatus,
|
|
Children: []*diagnose.Result{
|
|
{
|
|
Name: "Create HA Storage Backend",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
{
|
|
Name: "Check HA Consul Direct Storage Access",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
{
|
|
Name: "Check Consul TLS",
|
|
Status: diagnose.SkippedStatus,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "Determine Redirect Address",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
{
|
|
Name: "Check Cluster Address",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
{
|
|
Name: "Check Core Creation",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
{
|
|
Name: "Start Listeners",
|
|
Status: diagnose.WarningStatus,
|
|
Children: []*diagnose.Result{
|
|
{
|
|
Name: "Create Listeners",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
{
|
|
Name: "Check Listener TLS",
|
|
Status: diagnose.WarningStatus,
|
|
Warnings: []string{
|
|
"TLS is disabled in a listener config stanza.",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "Check Autounseal Encryption",
|
|
Status: diagnose.SkippedStatus,
|
|
Message: "Skipping barrier encryption",
|
|
},
|
|
{
|
|
Name: "Check Server Before Runtime",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
{
|
|
Name: "Finalize Shamir Seal",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"diagnose_raft_problems",
|
|
[]string{
|
|
"-config", "./server/test-fixtures/config_raft.hcl",
|
|
},
|
|
[]*diagnose.Result{
|
|
{
|
|
Name: "Check Storage",
|
|
Status: diagnose.WarningStatus,
|
|
Children: []*diagnose.Result{
|
|
{
|
|
Name: "Create Storage Backend",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
{
|
|
Name: "Check Raft Folder Permissions",
|
|
Status: diagnose.WarningStatus,
|
|
Message: "too many permissions",
|
|
},
|
|
{
|
|
Name: "Check For Raft Quorum",
|
|
Status: diagnose.WarningStatus,
|
|
Message: "0 voters found",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"diagnose_invalid_storage",
|
|
[]string{
|
|
"-config", "./server/test-fixtures/nostore_config.hcl",
|
|
},
|
|
[]*diagnose.Result{
|
|
{
|
|
Name: "Check Storage",
|
|
Status: diagnose.ErrorStatus,
|
|
Message: "No storage stanza in Vault server configuration.",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"diagnose_listener_config_ok",
|
|
[]string{
|
|
"-config", "./server/test-fixtures/tls_config_ok.hcl",
|
|
},
|
|
[]*diagnose.Result{
|
|
{
|
|
Name: "Start Listeners",
|
|
Status: diagnose.OkStatus,
|
|
Children: []*diagnose.Result{
|
|
{
|
|
Name: "Create Listeners",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
{
|
|
Name: "Check Listener TLS",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"diagnose_invalid_https_storage",
|
|
[]string{
|
|
"-config", "./server/test-fixtures/config_bad_https_storage.hcl",
|
|
},
|
|
[]*diagnose.Result{
|
|
{
|
|
Name: "Check Storage",
|
|
Status: diagnose.ErrorStatus,
|
|
Children: []*diagnose.Result{
|
|
{
|
|
Name: "Create Storage Backend",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
{
|
|
Name: "Check Consul TLS",
|
|
Status: diagnose.ErrorStatus,
|
|
Message: "certificate has expired or is not yet valid",
|
|
Warnings: []string{
|
|
"expired or near expiry",
|
|
},
|
|
},
|
|
{
|
|
Name: "Check Consul Direct Storage Access",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"diagnose_invalid_https_hastorage",
|
|
[]string{
|
|
"-config", "./server/test-fixtures/config_diagnose_hastorage_bad_https.hcl",
|
|
},
|
|
[]*diagnose.Result{
|
|
{
|
|
Name: "Check Storage",
|
|
Status: diagnose.WarningStatus,
|
|
Children: []*diagnose.Result{
|
|
{
|
|
Name: "Create Storage Backend",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
{
|
|
Name: "Check Consul TLS",
|
|
Status: diagnose.SkippedStatus,
|
|
},
|
|
{
|
|
Name: "Check Consul Direct Storage Access",
|
|
Status: diagnose.WarningStatus,
|
|
Advice: "We recommend connecting to a local agent.",
|
|
Warnings: []string{
|
|
"Vault storage is directly connected to a Consul server.",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "HA Storage",
|
|
Status: diagnose.ErrorStatus,
|
|
Children: []*diagnose.Result{
|
|
{
|
|
Name: "Create HA Storage Backend",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
{
|
|
Name: "Check HA Consul Direct Storage Access",
|
|
Status: diagnose.WarningStatus,
|
|
Advice: "We recommend connecting to a local agent.",
|
|
Warnings: []string{
|
|
"Vault storage is directly connected to a Consul server.",
|
|
},
|
|
},
|
|
{
|
|
Name: "Check Consul TLS",
|
|
Status: diagnose.ErrorStatus,
|
|
Message: "certificate has expired or is not yet valid",
|
|
Warnings: []string{
|
|
"expired or near expiry",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "Check Cluster Address",
|
|
Status: diagnose.ErrorStatus,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"diagnose_seal_transit_tls_check_fail",
|
|
[]string{
|
|
"-config", "./server/test-fixtures/diagnose_seal_transit_tls_check.hcl",
|
|
},
|
|
[]*diagnose.Result{
|
|
{
|
|
Name: "Check Transit Seal TLS",
|
|
Status: diagnose.WarningStatus,
|
|
Warnings: []string{
|
|
"Found at least one intermediate certificate in the CA certificate file.",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"diagnose_invalid_https_sr",
|
|
[]string{
|
|
"-config", "./server/test-fixtures/diagnose_bad_https_consul_sr.hcl",
|
|
},
|
|
[]*diagnose.Result{
|
|
{
|
|
Name: "Check Service Discovery",
|
|
Status: diagnose.ErrorStatus,
|
|
Children: []*diagnose.Result{
|
|
{
|
|
Name: "Check Consul Service Discovery TLS",
|
|
Status: diagnose.ErrorStatus,
|
|
Message: "certificate has expired or is not yet valid",
|
|
Warnings: []string{
|
|
"expired or near expiry",
|
|
},
|
|
},
|
|
{
|
|
Name: "Check Consul Direct Service Discovery",
|
|
Status: diagnose.WarningStatus,
|
|
Warnings: []string{
|
|
diagnose.DirAccessErr,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"diagnose_direct_storage_access",
|
|
[]string{
|
|
"-config", "./server/test-fixtures/diagnose_ok_storage_direct_access.hcl",
|
|
},
|
|
[]*diagnose.Result{
|
|
{
|
|
Name: "Check Storage",
|
|
Status: diagnose.WarningStatus,
|
|
Children: []*diagnose.Result{
|
|
{
|
|
Name: "Create Storage Backend",
|
|
Status: diagnose.OkStatus,
|
|
},
|
|
{
|
|
Name: "Check Consul TLS",
|
|
Status: diagnose.SkippedStatus,
|
|
},
|
|
{
|
|
Name: "Check Consul Direct Storage Access",
|
|
Status: diagnose.WarningStatus,
|
|
Warnings: []string{
|
|
diagnose.DirAccessErr,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"diagnose_raft_no_folder_backend",
|
|
[]string{
|
|
"-config", "./server/test-fixtures/diagnose_raft_no_bolt_folder.hcl",
|
|
},
|
|
[]*diagnose.Result{
|
|
{
|
|
Name: "Check Storage",
|
|
Status: diagnose.ErrorStatus,
|
|
Message: "Diagnose could not initialize storage backend.",
|
|
Children: []*diagnose.Result{
|
|
{
|
|
Name: "Create Storage Backend",
|
|
Status: diagnose.ErrorStatus,
|
|
Message: "no such file or directory",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"diagnose_telemetry_partial_circonus",
|
|
[]string{
|
|
"-config", "./server/test-fixtures/diagnose_bad_telemetry1.hcl",
|
|
},
|
|
[]*diagnose.Result{
|
|
{
|
|
Name: "Check Telemetry",
|
|
Status: diagnose.ErrorStatus,
|
|
Message: "incomplete Circonus telemetry configuration, missing circonus_api_url",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"diagnose_telemetry_partial_dogstats",
|
|
[]string{
|
|
"-config", "./server/test-fixtures/diagnose_bad_telemetry2.hcl",
|
|
},
|
|
[]*diagnose.Result{
|
|
{
|
|
Name: "Check Telemetry",
|
|
Status: diagnose.ErrorStatus,
|
|
Message: "incomplete DogStatsD telemetry configuration, missing dogstatsd_addr, while dogstatsd_tags specified",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"diagnose_telemetry_partial_stackdriver",
|
|
[]string{
|
|
"-config", "./server/test-fixtures/diagnose_bad_telemetry3.hcl",
|
|
},
|
|
[]*diagnose.Result{
|
|
{
|
|
Name: "Check Telemetry",
|
|
Status: diagnose.ErrorStatus,
|
|
Message: "incomplete Stackdriver telemetry configuration, missing stackdriver_project_id",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"diagnose_telemetry_default",
|
|
[]string{
|
|
"-config", "./server/test-fixtures/config4.hcl",
|
|
},
|
|
[]*diagnose.Result{
|
|
{
|
|
Name: "Check Telemetry",
|
|
Status: diagnose.WarningStatus,
|
|
Warnings: []string{"Telemetry is using default configuration"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
t.Run("validations", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
for _, tc := range cases {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
client, closer := testVaultServer(t)
|
|
defer closer()
|
|
cmd := testOperatorDiagnoseCommand(t)
|
|
cmd.client = client
|
|
|
|
cmd.Run(tc.args)
|
|
result := cmd.diagnose.Finalize(context.Background())
|
|
|
|
if err := compareResults(tc.expected, result.Children); err != nil {
|
|
t.Fatalf("Did not find expected test results: %v", err)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
func compareResults(expected []*diagnose.Result, actual []*diagnose.Result) error {
|
|
for _, exp := range expected {
|
|
found := false
|
|
// Check them all so we don't have to be order specific
|
|
for _, act := range actual {
|
|
fmt.Printf("%+v", act)
|
|
if exp.Name == act.Name {
|
|
found = true
|
|
if err := compareResult(exp, act); err != nil {
|
|
return err
|
|
}
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
return fmt.Errorf("could not find expected test result: %s", exp.Name)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func compareResult(exp *diagnose.Result, act *diagnose.Result) error {
|
|
if exp.Name != act.Name {
|
|
return fmt.Errorf("names mismatch: %s vs %s", exp.Name, act.Name)
|
|
}
|
|
if exp.Status != act.Status {
|
|
if act.Status != diagnose.OkStatus {
|
|
return fmt.Errorf("section %s, status mismatch: %s vs %s, got error %s", exp.Name, exp.Status, act.Status, act.Message)
|
|
}
|
|
return fmt.Errorf("section %s, status mismatch: %s vs %s", exp.Name, exp.Status, act.Status)
|
|
}
|
|
if exp.Message != "" && exp.Message != act.Message && !strings.Contains(act.Message, exp.Message) {
|
|
return fmt.Errorf("section %s, message not found: %s in %s", exp.Name, exp.Message, act.Message)
|
|
}
|
|
if exp.Advice != "" && exp.Advice != act.Advice && !strings.Contains(act.Advice, exp.Advice) {
|
|
return fmt.Errorf("section %s, advice not found: %s in %s", exp.Name, exp.Advice, act.Advice)
|
|
}
|
|
if len(exp.Warnings) != len(act.Warnings) {
|
|
return fmt.Errorf("section %s, warning count mismatch: %d vs %d", exp.Name, len(exp.Warnings), len(act.Warnings))
|
|
}
|
|
for j := range exp.Warnings {
|
|
if !strings.Contains(act.Warnings[j], exp.Warnings[j]) {
|
|
return fmt.Errorf("section %s, warning message not found: %s in %s", exp.Name, exp.Warnings[j], act.Warnings[j])
|
|
}
|
|
}
|
|
if len(exp.Children) > len(act.Children) {
|
|
errStrings := []string{}
|
|
for _, c := range act.Children {
|
|
errStrings = append(errStrings, fmt.Sprintf("%+v", c))
|
|
}
|
|
return fmt.Errorf(strings.Join(errStrings, ","))
|
|
}
|
|
|
|
if len(exp.Children) > 0 {
|
|
return compareResults(exp.Children, act.Children)
|
|
}
|
|
|
|
// Remove raft file if it exists
|
|
os.Remove("./server/test-fixtures/vault.db")
|
|
os.RemoveAll("./server/test-fixtures/raft")
|
|
|
|
return nil
|
|
}
|