From 5ece71109a80bc508f077573fb12ed796dff29c3 Mon Sep 17 00:00:00 2001 From: Kit Haines Date: Fri, 27 Jan 2023 16:41:16 -0500 Subject: [PATCH] Vault 11798 vault cli issue intermediate (#18467) * The verify-sign command in it's cleanest existing form. * Working state * Updates to proper verification syntax Co-authored-by: 'Alex Scheel' * make fmt * Git CI caught some stuff. * Base functionality. * make fmt; changelog * pki issue command. * Make fmt. Changelog. * Error Handling Is Almost A Tutorial * What I thought empty issuers response fix would be. * Some tests * PR-review updates. * make fmt. * Fix null response data for listing empty issuers causing a crash. * Update command/pki_list_children_command.go Fix double specifier Co-authored-by: Steven Clark * Add test for pki_list_children. * Fix tests. * Update descriptions for correctness based on PR reviews. * make fmt. * Updates based on PR feedback. * Allow multiple arguements (space separated) * Remove bad merge-thing. * White-space hell fix change. * Tests, and return information for issue ca * Fix make fmt error introduced here: https://github.com/hashicorp/vault/pull/18876 * Update command/pki_issue_intermediate.go Puncutation. Co-authored-by: Alexander Scheel * Remove smart quotes for standard quotes. * More information as part of the help text. * Better help text. * Add missing "/" into error message. --------- Co-authored-by: 'Alex Scheel' Co-authored-by: Steven Clark --- changelog/18467.txt | 3 + command/commands.go | 5 + command/pki_issue_intermediate.go | 355 +++++++++++++++++++++++++ command/pki_issue_intermediate_test.go | 205 ++++++++++++++ command/pki_list_intermediate_test.go | 6 + command/pki_verify_sign_test.go | 9 +- vault/cluster/inmem_layer.go | 10 +- 7 files changed, 585 insertions(+), 8 deletions(-) create mode 100644 changelog/18467.txt create mode 100644 command/pki_issue_intermediate.go create mode 100644 command/pki_issue_intermediate_test.go diff --git a/changelog/18467.txt b/changelog/18467.txt new file mode 100644 index 000000000..55a85a648 --- /dev/null +++ b/changelog/18467.txt @@ -0,0 +1,3 @@ +```release-note:improvement +cli/pki: Add pki issue command, which creates a CSR, has a vault mount sign it, then reimports it. +``` \ No newline at end of file diff --git a/command/commands.go b/command/commands.go index 6953440dd..c03d8bf8c 100644 --- a/command/commands.go +++ b/command/commands.go @@ -543,6 +543,11 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) { BaseCommand: getBaseCommand(), }, nil }, + "pki issue": func() (cli.Command, error) { + return &PKIIssueCACommand{ + BaseCommand: getBaseCommand(), + }, nil + }, "pki list-intermediates": func() (cli.Command, error) { return &PKIListIntermediateCommand{ BaseCommand: getBaseCommand(), diff --git a/command/pki_issue_intermediate.go b/command/pki_issue_intermediate.go new file mode 100644 index 000000000..fd0da19ae --- /dev/null +++ b/command/pki_issue_intermediate.go @@ -0,0 +1,355 @@ +package command + +import ( + "context" + "fmt" + "io" + "os" + paths "path" + "strings" + + "github.com/hashicorp/vault/api" + "github.com/posener/complete" +) + +type PKIIssueCACommand struct { + *BaseCommand + + flagConfig string + flagReturnIndicator string + flagDefaultDisabled bool + flagList bool + + flagKeyStorageSource string + flagNewIssuerName string +} + +func (c *PKIIssueCACommand) Synopsis() string { + return "Given a Parent Certificate, and a List of Generation Parameters, Creates an Issue on a Specified Mount" +} + +func (c *PKIIssueCACommand) Help() string { + helpText := ` +Usage: vault pki issue PARENT CHILD_MOUNT options + +PARENT is the fully qualified path of the Certificate Authority in vault which will issue the new intermediate certificate. + +CHILD_MOUNT is the path of the mount in vault where the new issuer is saved. + +options are the superset of the options passed to generate/intermediate and sign-intermediate commands. At least one option must be set. + +This command creates a intermediate certificate authority certificate signed by the parent in the CHILD_MOUNT. + +` + c.Flags().Help() + return strings.TrimSpace(helpText) +} + +func (c *PKIIssueCACommand) Flags() *FlagSets { + set := c.flagSet(FlagSetHTTP | FlagSetOutputFormat) + f := set.NewFlagSet("Command Options") + + f.StringVar(&StringVar{ + Name: "type", + Target: &c.flagKeyStorageSource, + Default: "internal", + EnvVar: "", + Usage: `Options are "existing" - to use an existing key inside vault, "internal" - to generate a new key inside vault, or "kms" - to link to an external key. Exported keys are not available through this API.`, + Completion: complete.PredictSet("internal", "existing", "kms"), + }) + + f.StringVar(&StringVar{ + Name: "issuer_name", + Target: &c.flagNewIssuerName, + Default: "", + EnvVar: "", + Usage: `If present, the newly created issuer will be given this name.`, + }) + + return set +} + +func (c *PKIIssueCACommand) Run(args []string) int { + // Parse Args + f := c.Flags() + if err := f.Parse(args); err != nil { + c.UI.Error(err.Error()) + return 1 + } + args = f.Args() + + if len(args) < 3 { + c.UI.Error("Not enough arguments expected parent issuer and child-mount location and some key_value argument") + return 1 + } + + stdin := (io.Reader)(os.Stdin) + data, err := parseArgsData(stdin, args[2:]) + if err != nil { + c.UI.Error(fmt.Sprintf("Failed to parse K=V data: %s", err)) + return 1 + } + + // Check We Have a Client + client, err := c.Client() + if err != nil { + c.UI.Error(fmt.Sprintf("Failed to obtain client: %v", err)) + return 1 + } + + // Sanity Check the Parent Issuer + parentMountIssuer := sanitizePath(args[0]) // /pki/issuer/default + _, parentIssuerName := paths.Split(parentMountIssuer) + if !strings.Contains(parentMountIssuer, "/issuer/") { + c.UI.Error(fmt.Sprintf("Parent Issuer %v is Not a PKI Issuer Path of the format /mount/issuer/issuer-ref", parentMountIssuer)) + } + _, err = client.Logical().Read(parentMountIssuer + "/json") + if err != nil { + c.UI.Error(fmt.Sprintf("Unable to access parent issuer %v: %v", parentMountIssuer, err)) + } + + // Set-up Failure State (Immediately Before First Write Call) + intermediateMount := sanitizePath(args[1]) + failureState := inCaseOfFailure{ + intermediateMount: intermediateMount, + parentMount: strings.Split(parentMountIssuer, "/issuer/")[0], + parentIssuer: parentMountIssuer, + newName: c.flagNewIssuerName, + } + + // Generate Certificate Signing Request + csrResp, err := client.Logical().Write(intermediateMount+"/intermediate/generate/"+c.flagKeyStorageSource, data) + if err != nil { + if strings.Contains(err.Error(), "no handler for route") { // Mount Given Does Not Exist + c.UI.Error(fmt.Sprintf("Given Intermediate Mount %v Does Not Exist: %v", intermediateMount, err)) + } else if strings.Contains(err.Error(), "unsupported path") { // Expected if Not a PKI Mount + c.UI.Error(fmt.Sprintf("Given Intermeidate Mount %v Is Not a PKI Mount: %v", intermediateMount, err)) + } else { + c.UI.Error(fmt.Sprintf("Failled to Generate Intermediate CSR on %v: %v", intermediateMount, err)) + } + return 1 + } + // Parse CSR Response, Also Verifies that this is a PKI Mount + // (eg. calling the above call on cubbyhole/ won't return an error response) + csrPemRaw, present := csrResp.Data["csr"] + if !present { + c.UI.Error(fmt.Sprintf("Failed to Generate Intermediate CSR on %v, got response: %v", intermediateMount, csrResp)) + return 1 + } + keyIdRaw, present := csrResp.Data["key_id"] + if !present && c.flagKeyStorageSource == "internal" { + c.UI.Error(fmt.Sprintf("Failed to Generate Key on %v, got response: %v", intermediateMount, csrResp)) + return 1 + } + + // If that all Parses, then we've successfully generated a CSR! Save It (and the Key-ID) + failureState.csrGenerated = true + if c.flagKeyStorageSource == "internal" { + failureState.createdKeyId = keyIdRaw.(string) + } + csr := csrPemRaw.(string) + failureState.csr = csr + data["csr"] = csr + + // Next, Sign the CSR + rootResp, err := client.Logical().Write(parentMountIssuer+"/sign-intermediate", data) + if err != nil { + c.UI.Error(failureState.generateFailureMessage()) + c.UI.Error(fmt.Sprintf("Error Signing Intermiate On %v", err)) + return 1 + } + // Success! Save Our Progress (and Parse the Response) + failureState.csrSigned = true + serialNumber := rootResp.Data["serial_number"].(string) + failureState.certSerialNumber = serialNumber + + caChain := rootResp.Data["ca_chain"].([]interface{}) + caChainPemBundle := "" + for _, cert := range caChain { + caChainPemBundle += cert.(string) + "\n" + } + failureState.caChain = caChainPemBundle + + // Next Import Certificate + certificate := rootResp.Data["certificate"].(string) + issuerId, err := importIssuerWithName(client, intermediateMount, certificate, c.flagNewIssuerName) + failureState.certIssuerId = issuerId + if err != nil { + if strings.Contains(err.Error(), "error naming issuer") { + failureState.certImported = true + c.UI.Error(failureState.generateFailureMessage()) + c.UI.Error(fmt.Sprintf("Error Naming Newly Imported Issuer: %v", err)) + return 1 + } else { + c.UI.Error(failureState.generateFailureMessage()) + c.UI.Error(fmt.Sprintf("Error Importing Into %v Newly Created Issuer %v: %v", intermediateMount, certificate, err)) + return 1 + } + } + failureState.certImported = true + + // Then Import Issuing Certificate + issuingCa := rootResp.Data["issuing_ca"].(string) + _, err = importIssuerWithName(client, intermediateMount, issuingCa, parentIssuerName) + if err != nil { + if strings.Contains(err.Error(), "error naming issuer") { + c.UI.Warn(fmt.Sprintf("Unable to Set Name on Parent Cert from %v Imported Into %v with serial %v, err: %v", parentIssuerName, intermediateMount, serialNumber, err)) + } else { + c.UI.Error(failureState.generateFailureMessage()) + c.UI.Error(fmt.Sprintf("Error Importing Into %v Newly Created Issuer %v: %v", intermediateMount, certificate, err)) + return 1 + } + } + + // Finally Import CA_Chain (just in case there's more information) + if len(caChain) > 2 { // We've already imported parent cert and newly issued cert above + importData := map[string]interface{}{ + "pem_bundle": caChainPemBundle, + } + _, err := client.Logical().Write(intermediateMount+"/issuers/import/cert", importData) + if err != nil { + c.UI.Error(failureState.generateFailureMessage()) + c.UI.Error(fmt.Sprintf("Error Importing CaChain into %v: %v", intermediateMount, err)) + return 1 + } + } + failureState.caChainImported = true + + // Finally we read our newly issued certificate in order to tell our caller about it + c.readAndOutputNewCertificate(client, intermediateMount, issuerId) + + return 0 +} + +func (c *PKIIssueCACommand) readAndOutputNewCertificate(client *api.Client, intermediateMount string, issuerId string) { + resp, err := client.Logical().Read(sanitizePath(intermediateMount + "/issuer/" + issuerId)) + if err != nil || resp == nil { + c.UI.Error(fmt.Sprintf("Error Reading Fully Imported Certificate from %v : %v", + intermediateMount+"/issuer/"+issuerId, err)) + } + + OutputSecret(c.UI, resp) +} + +func importIssuerWithName(client *api.Client, mount string, bundle string, name string) (issuerUUID string, err error) { + importData := map[string]interface{}{ + "pem_bundle": bundle, + } + writeResp, err := client.Logical().Write(mount+"/issuers/import/cert", importData) + if err != nil { + return "", err + } + mapping := writeResp.Data["mapping"].(map[string]interface{}) + if len(mapping) > 1 { + return "", fmt.Errorf("multiple issuers returned, while expected one, got %v", writeResp) + } + for issuerId := range mapping { + issuerUUID = issuerId + } + if name != "" && name != "default" { + nameReq := map[string]interface{}{ + "issuer_name": name, + } + ctx := context.Background() + _, err = client.Logical().JSONMergePatch(ctx, mount+"/issuer/"+issuerUUID, nameReq) + if err != nil { + return issuerUUID, fmt.Errorf("error naming issuer %v to %v: %v", issuerUUID, name, err) + } + } + return issuerUUID, nil +} + +type inCaseOfFailure struct { + csrGenerated bool + csrSigned bool + certImported bool + certNamed bool + caChainImported bool + + intermediateMount string + createdKeyId string + csr string + caChain string + parentMount string + parentIssuer string + certSerialNumber string + certIssuerId string + newName string +} + +func (state inCaseOfFailure) generateFailureMessage() string { + message := "A failure has occurred" + + if state.csrGenerated { + message += fmt.Sprintf(" after \n a Certificate Signing Request was successfully generated on mount %v", state.intermediateMount) + } + if state.csrSigned { + message += fmt.Sprintf(" and after \n that Certificate Signing Request was successfully signed by mount %v", state.parentMount) + } + if state.certImported { + message += fmt.Sprintf(" and after \n the signed certificate was reimported into mount %v , with issuerID %v", state.intermediateMount, state.certIssuerId) + } + + if state.csrGenerated { + message += "\n\nTO CONTINUE: \n" + state.toContinue() + } + if state.csrGenerated && !state.certImported { + message += "\n\nTO ABORT: \n" + state.toAbort() + } + + message += "\n" + + return message +} + +func (state inCaseOfFailure) toContinue() string { + message := "" + if !state.csrSigned { + message += fmt.Sprintf("You can continue to work with this Certificate Signing Request CSR PEM, by saving"+ + " it as `pki_int.csr`: %v \n Then call `vault write %v/sign-intermediate csr=@pki_int.csr ...` adding the "+ + "same key-value arguements as to `pki issue` (except key_type and issuer_name) to generate the certificate "+ + "and ca_chain", state.csr, state.parentIssuer) + } + if !state.certImported { + if state.caChain != "" { + message += fmt.Sprintf("The certificate chain, signed by %v, for this new certificate is: %v", state.parentIssuer, state.caChain) + } + message += fmt.Sprintf("You can continue to work with this Certificate (and chain) by saving it as "+ + "chain.pem and importing it as `vault write %v/issuers/import/cert pem_bundle=@chain.pem`", + state.intermediateMount) + } + if !state.certNamed { + issuerId := state.certIssuerId + if issuerId == "" { + message += fmt.Sprintf("The issuer_id is returned as the key in a key_value map from importing the " + + "certificate chain.") + issuerId = "" + } + message += fmt.Sprintf("You can name the newly imported issuer by calling `vault patch %v/issuer/%v "+ + "issuer_name=%v`", state.intermediateMount, issuerId, state.newName) + } + return message +} + +func (state inCaseOfFailure) toAbort() string { + if !state.csrGenerated || (!state.csrSigned && state.createdKeyId == "") { + return "No state was created by running this command. Try rerunning this command after resolving the error." + } + message := "" + if state.csrGenerated && state.createdKeyId != "" { + message += fmt.Sprintf(" A key, with key ID %v was created on mount %v as part of this command."+ + " If you do not with to use this key and corresponding CSR/cert, you can delete that information by calling"+ + " `vault delete %v/key/%v`", state.createdKeyId, state.intermediateMount, state.intermediateMount, state.createdKeyId) + } + if state.csrSigned { + message += fmt.Sprintf("A certificate with serial number %v was signed by mount %v as part of this command."+ + " If you do not want to use this certificate, consider revoking it by calling `vault write %v/revoke/%v`", + state.certSerialNumber, state.parentMount, state.parentMount, state.certSerialNumber) + } + //if state.certImported { + // message += fmt.Sprintf("An issuer with UUID %v was created on mount %v as part of this command. " + + // "If you do not wish to use this issuer, consider deleting it by calling `vault delete %v/issuer/%v`", + // state.certIssuerId, state.intermediateMount, state.intermediateMount, state.certIssuerId) + //} + + return message +} diff --git a/command/pki_issue_intermediate_test.go b/command/pki_issue_intermediate_test.go new file mode 100644 index 000000000..dfe2671d6 --- /dev/null +++ b/command/pki_issue_intermediate_test.go @@ -0,0 +1,205 @@ +package command + +import ( + "bytes" + "encoding/json" + "testing" + + "github.com/hashicorp/vault/api" +) + +func TestPKIIssueIntermediate(t *testing.T) { + t.Parallel() + + client, closer := testVaultServer(t) + defer closer() + + // Relationship Map to Create + // pki-root | pki-newroot | pki-empty + // RootX1 RootX2 RootX4 RootX3 + // | | + // ---------------------------------------------- + // v v + // IntX1 IntX2 pki-int + // | | + // v v + // IntX3 (-----------------------) IntX3 + // + // Here X1,X2 have the same name (same mount) + // RootX4 uses the same key as RootX1 (but a different common_name/subject) + // RootX3 has the same name, and is on a different mount + // RootX1 has issued IntX1; RootX3 has issued IntX2 + createComplicatedIssuerSetUpWithIssueIntermediate(t, client) + + runPkiVerifySignTests(t, client) + + runPkiListIntermediateTests(t, client) +} + +func createComplicatedIssuerSetUpWithIssueIntermediate(t *testing.T, client *api.Client) { + // Relationship Map to Create + // pki-root | pki-newroot | pki-empty + // RootX1 RootX2 RootX4 RootX3 + // | | + // ---------------------------------------------- + // v v + // IntX1 IntX2 pki-int + // | | + // v v + // IntX3 (-----------------------) IntX3 + // + // Here X1,X2 have the same name (same mount) + // RootX4 uses the same key as RootX1 (but a different common_name/subject) + // RootX3 has the same name, and is on a different mount + // RootX1 has issued IntX1; RootX3 has issued IntX2 + + if err := client.Sys().Mount("pki-root", &api.MountInput{ + Type: "pki", + Config: api.MountConfigInput{ + MaxLeaseTTL: "36500d", + }, + }); err != nil { + t.Fatalf("pki mount error: %#v", err) + } + + if err := client.Sys().Mount("pki-newroot", &api.MountInput{ + Type: "pki", + Config: api.MountConfigInput{ + MaxLeaseTTL: "36500d", + }, + }); err != nil { + t.Fatalf("pki mount error: %#v", err) + } + + if err := client.Sys().Mount("pki-int", &api.MountInput{ + Type: "pki", + Config: api.MountConfigInput{ + MaxLeaseTTL: "36500d", + }, + }); err != nil { + t.Fatalf("pki mount error: %#v", err) + } + + // Used to check handling empty list responses: Not Used for Any Issuers / Certificates + if err := client.Sys().Mount("pki-empty", &api.MountInput{ + Type: "pki", + Config: api.MountConfigInput{}, + }); err != nil { + t.Fatalf("pki mount error: %#v", err) + } + + resp, err := client.Logical().Write("pki-root/root/generate/internal", map[string]interface{}{ + "key_type": "ec", + "common_name": "Root X", + "ttl": "3650d", + "issuer_name": "rootX1", + "key_name": "rootX1", + }) + if err != nil || resp == nil { + t.Fatalf("failed to prime CA: %v", err) + } + + resp, err = client.Logical().Write("pki-root/root/generate/internal", map[string]interface{}{ + "key_type": "ec", + "common_name": "Root X", + "ttl": "3650d", + "issuer_name": "rootX2", + }) + if err != nil || resp == nil { + t.Fatalf("failed to prime CA: %v", err) + } + + if resp, err := client.Logical().Write("pki-newroot/root/generate/internal", map[string]interface{}{ + "key_type": "ec", + "common_name": "Root X", + "ttl": "3650d", + "issuer_name": "rootX3", + }); err != nil || resp == nil { + t.Fatalf("failed to prime CA: %v", err) + } + + if resp, err := client.Logical().Write("pki-root/root/generate/existing", map[string]interface{}{ + "common_name": "Root X4", + "ttl": "3650d", + "issuer_name": "rootX4", + "key_ref": "rootX1", + }); err != nil || resp == nil { + t.Fatalf("failed to prime CA: %v", err) + } + + // Next we create the Intermediates Using the Issue Intermediate Command + stdout := bytes.NewBuffer(nil) + stderr := bytes.NewBuffer(nil) + runOpts := &RunOptions{ + Stdout: stdout, + Stderr: stderr, + Client: client, + } + + // Intermediate X1 + intX1CallArgs := []string{ + "pki", "issue", "-format=json", "-issuer_name=intX1", + "pki-root/issuer/rootX1", + "pki-int/", + "key_type=rsa", + "common_name=Int X1", + "ttl=3650d", + } + codeOut := RunCustom(intX1CallArgs, runOpts) + if codeOut != 0 { + t.Fatalf("error issuing intermediate X1, code: %d \n stdout: %v \n stderr: %v", codeOut, stdout, stderr) + } + + // Intermediate X2 + intX2CallArgs := []string{ + "pki", "issue", "-format=json", "-issuer_name=intX2", + "pki-newroot/issuer/rootX3", + "pki-int/", + "key_type=ed25519", + "common_name=Int X2", + "ttl=3650d", + } + codeOut = RunCustom(intX2CallArgs, runOpts) + if codeOut != 0 { + t.Fatalf("error issuing intermediate X2, code: %d \n stdout: %v \n stderr: %v", codeOut, stdout, stderr) + } + + // Intermediate X3 + // Clear Buffers so that we can unmarshall json of just this call + stdout = bytes.NewBuffer(nil) + stderr = bytes.NewBuffer(nil) + runOpts = &RunOptions{ + Stdout: stdout, + Stderr: stderr, + Client: client, + } + intX3OriginalCallArgs := []string{ + "pki", "issue", "-format=json", "-issuer_name=intX3", + "pki-int/issuer/intX1", + "pki-int/", + "key_type=rsa", + "common_name=Int X3", + "ttl=3650d", + } + codeOut = RunCustom(intX3OriginalCallArgs, runOpts) + if codeOut != 0 { + t.Fatalf("error issuing intermediate X3, code: %d \n stdout: %v \n stderr: %v", codeOut, stdout, stderr) + } + var intX3Resp map[string]interface{} + json.Unmarshal(stdout.Bytes(), &intX3Resp) + intX3Data := intX3Resp["data"].(map[string]interface{}) + keyId := intX3Data["key_id"].(string) + + intX3AdaptedCallArgs := []string{ + "pki", "issue", "-format=json", "-issuer_name=intX3also", "-type=existing", + "pki-int/issuer/intX2", + "pki-int/", + "key_ref=" + keyId, + "common_name=Int X3", + "ttl=3650d", + } + codeOut = RunCustom(intX3AdaptedCallArgs, runOpts) + if codeOut != 0 { + t.Fatalf("error issuing intermediate X3also, code: %d \n stdout: %v \n stderr: %v", codeOut, stdout, stderr) + } +} diff --git a/command/pki_list_intermediate_test.go b/command/pki_list_intermediate_test.go index 84739ad8d..87b38ec59 100644 --- a/command/pki_list_intermediate_test.go +++ b/command/pki_list_intermediate_test.go @@ -3,6 +3,8 @@ package command import ( "strings" "testing" + + "github.com/hashicorp/vault/api" ) func TestPKIListIntermediate(t *testing.T) { @@ -28,6 +30,10 @@ func TestPKIListIntermediate(t *testing.T) { // RootX1 has issued IntX1; RootX3 has issued IntX2 createComplicatedIssuerSetUp(t, client) + runPkiListIntermediateTests(t, client) +} + +func runPkiListIntermediateTests(t *testing.T, client *api.Client) { cases := []struct { name string args []string diff --git a/command/pki_verify_sign_test.go b/command/pki_verify_sign_test.go index 12e5698fa..3d141a138 100644 --- a/command/pki_verify_sign_test.go +++ b/command/pki_verify_sign_test.go @@ -18,7 +18,7 @@ func TestPKIVerifySign(t *testing.T) { defer closer() // Relationship Map to Create - // pki-root | pki-newroot + // pki-root | pki-newroot | pki-empty // RootX1 RootX2 RootX4 RootX3 // | | // ---------------------------------------------- @@ -34,6 +34,10 @@ func TestPKIVerifySign(t *testing.T) { // RootX1 has issued IntX1; RootX3 has issued IntX2 createComplicatedIssuerSetUp(t, client) + runPkiVerifySignTests(t, client) +} + +func runPkiVerifySignTests(t *testing.T, client *api.Client) { cases := []struct { name string args []string @@ -217,7 +221,6 @@ func createComplicatedIssuerSetUp(t *testing.T, client *api.Client) { "issuer_name": "rootX1", "key_name": "rootX1", }) - if err != nil || resp == nil { t.Fatalf("failed to prime CA: %v", err) } @@ -228,7 +231,6 @@ func createComplicatedIssuerSetUp(t *testing.T, client *api.Client) { "ttl": "3650d", "issuer_name": "rootX2", }) - if err != nil || resp == nil { t.Fatalf("failed to prime CA: %v", err) } @@ -414,6 +416,7 @@ func createComplicatedIssuerSetUp(t *testing.T, client *api.Client) { break } } + // sign by intX2 and import int3CertResp2, err := client.Logical().Write("pki-int/issuer/intX2/sign-intermediate", map[string]interface{}{ "csr": int3Csr, diff --git a/vault/cluster/inmem_layer.go b/vault/cluster/inmem_layer.go index 77c48e668..538dc374a 100644 --- a/vault/cluster/inmem_layer.go +++ b/vault/cluster/inmem_layer.go @@ -122,14 +122,14 @@ func (l *InmemLayer) Dial(addr string, timeout time.Duration, tlsConfig *tls.Con panic(fmt.Sprintf("%q attempted to dial itself", l.addr)) } - // This simulates an i/o timeout by sleeping for 20 seconds and returning - // an error when the forceTimeout name is the same as the host we are - // currently connecting to. Useful for checking how gRPC connections react + // This simulates an i/o timeout by sleeping for 20 seconds and returning + // an error when the forceTimeout name is the same as the host we are + // currently connecting to. Useful for checking how gRPC connections react // with timeouts. if l.forceTimeout == addr { l.logger.Debug("forcing timeout", "addr", addr, "me", l.addr) - - // gRPC sets a deadline of 20 seconds on the dail attempt, so + + // gRPC sets a deadline of 20 seconds on the dail attempt, so // matching that here. time.Sleep(time.Second * 20) return nil, deadlineError("i/o timeout")