Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

style(cli): boundary connect output returns pasteable X.509 certificates #3232

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

A-440Hz
Copy link
Contributor

@A-440Hz A-440Hz commented May 18, 2023

When a target accesses a session credential from a credential library with a vault path pointing to a .crt certificate, this credential is treated as an unspecified credential (which isn't username-password, ssh-private-key, or json type). Instead of being unmarshalled into a struct, the raw secret is decoded into a []byte by base64.StdEncoding.DecodeString, and then sent to a bytes.Buffer by json.Indent before being converted back into a string. This results in the certificate being returned in the CLI output as a json value containing \n characters like so (and in my environment there's some \rs as well):

image

I had thought that the newline characters were a valid format for a crt file , but I was told by the reporter that this format rendered the certificate useless for their kubernetes workflow. Furthermore, the newline between "BEGIN" and "CERTIFICATE" and the tabs before each "CERTIFICATE" makes the output bad to copy/paste.

I understand that setting -format=json fixes the latter issue.

This PR attempts to unmarshal and print all unspecified credential values without indentation when -format=table, so the certificates can be displayed like so in a nice-looking block.

image

https://hashicorp.atlassian.net/browse/ICU-7421

@github-actions github-actions bot added the core label May 18, 2023
@A-440Hz
Copy link
Contributor Author

A-440Hz commented May 18, 2023

For reference, here is the unchanged -format=json output of the same command

image

switch iface := iface.(type) {
case nil:
out = append(out, fmt.Sprintf("%s %s:", prefixStr, k))
case map[string]any:
Copy link
Contributor Author

@A-440Hz A-440Hz May 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The switch cases currently assume the PEM certificate will be located in the first json layer of a vault kv store i.e., data: <key_name>: <.crt here>. If it is possible for the certificate to be located in a different location i.e. data: <key_name>: <another_key_name>: <.crt here>, then the output will not display properly.

If it is possible for an 'unspecified' Boundary credential to come from a different vault path with a different expected format, then it might not be displayed properly either. Do you know what possible 'unspecified' Boundary credential formats I could expect to find, or who I can ask about this topic?

@A-440Hz A-440Hz marked this pull request as ready for review May 18, 2023 16:10
Copy link
Collaborator

@johanbrandhorst johanbrandhorst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be a great UX feature. I wonder, can we add an e2e test that ensures the behavior? Maybe a test that checks that we can successfully parse a certificate from the output?

internal/cmd/commands/connect/funcs.go Outdated Show resolved Hide resolved
out = append(out, fmt.Sprintf("%s %s:", prefixStr, k))
certs := make(map[string]any, len(iface))
for kk, vv := range iface {
if p, _ := pem.Decode([]byte(fmt.Sprintf("%v", vv))); p != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd sooner we have another type assertion than this string formatting, to make it a bit more predictable

switch iface := iface.(type) {
case []byte:
	if p, _ := pem.Decode(iface); p != nil {

etc. Maybe one for string too. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds like a better way to do it

Copy link
Contributor Author

@A-440Hz A-440Hz May 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@johanbrandhorst would you expect a case where the unmarshalled interface is anything other than a []byte or a string? What would you recommend I do in that scenario? Does it sound reasonable to return an error in that case?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might expect it to be a numeric type if it's not one of those, so I don't think we should panic, in those cases we could fall back to fmt.Sprintf maybe?

internal/cmd/commands/connect/funcs.go Outdated Show resolved Hide resolved
internal/cmd/commands/connect/funcs.go Outdated Show resolved Hide resolved
@A-440Hz A-440Hz added this to the 0.14.0 milestone May 30, 2023
@jefferai
Copy link
Member

Why 0.14 and not 0.13?

@A-440Hz
Copy link
Contributor Author

A-440Hz commented May 31, 2023

@jefferai I need to format the metadata correctly again after adding the second case statement, and I still need to implement e2e tests. It should probably still be 0.13, but I wanted to avoid confusion with the feature freeze going on

@psekar psekar removed this from the 0.14.0 milestone Sep 18, 2023
@jefferai jefferai added this to the 0.16.x milestone Mar 17, 2024
@ddebko ddebko modified the milestones: 0.16.x, 0.17.x Apr 19, 2024
@psekar psekar removed this from the 0.17.x milestone Jul 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants