-
Notifications
You must be signed in to change notification settings - Fork 5.7k
feat(inputs.x509_cert): Add support for JKS and PKCS#12 keystores #16508
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
Conversation
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
@paulojmdias please check the linter issues. You can reproduce them locally using |
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Fixed 🙌 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your contribution @paulojmdias! This is very much appreciated! I do have some comments in the code...
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@paulojmdias some more comments...
err = jks.Store(output, []byte("test-password")) | ||
require.NoError(t, err) | ||
|
||
return "jks://" + jksPath |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't work on Windows, you should do
return "jks://" + jksPath | |
jksPath = filepath.ToSlash(jksPath) | |
if !strings.HasPrefix(jksPath, "/") { | |
jksPath = "/" + jksPath | |
} | |
return "jks://" + jksPath |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed also pkcs12Path
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
…keystore_cert Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @paulojmdias, this looks really nice already. Some more comments regarding the test code but we are almost there.
if runtime.GOOS == "windows" { | ||
jksPath = strings.TrimPrefix(jksPath, "/") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you need this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm what if in Windows I use a path like \TEMP\foo
which is an absolute path, won't this be converted to TEMP/foo
instead of /TEMP/foo
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I see the issue now. The problem is that you do solve something in the test which must be solved in the actual code. Imagine the user wants to specify a JKS path of C:\MyCerts\foo.jks
, then he has to set
[[inputs.x509_cert]]
sources = ["jks:///C:/MyCerts/foo.jks"]
and then you need to remove the leading slash in your regular code if (and only if) you get a drive letter. Please see line 282 and following for how to do this!
if runtime.GOOS == "windows" { | ||
pkcs12Path = strings.TrimPrefix(pkcs12Path, "/") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you need this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Answered above
func TestGatherKeystores(t *testing.T) { | ||
pkcs12Path, jksPath := generateTestKeystores(t) | ||
|
||
tests := []struct { | ||
name string | ||
mode os.FileMode | ||
content string | ||
password string | ||
error bool | ||
}{ | ||
{name: "valid PKCS12 keystore", mode: 0640, content: pkcs12Path, password: "test-password"}, | ||
{name: "valid JKS keystore", mode: 0640, content: jksPath, password: "test-password"}, | ||
{name: "missing password PKCS12", mode: 0640, content: pkcs12Path, error: true}, | ||
{name: "missing password JKS", mode: 0640, content: jksPath, error: true}, | ||
{name: "wrong password PKCS12", mode: 0640, content: pkcs12Path, password: "wrong-password", error: true}, | ||
{name: "wrong password JKS", mode: 0640, content: jksPath, password: "wrong-password", error: true}, | ||
} | ||
|
||
for _, test := range tests { | ||
t.Run(test.name, func(t *testing.T) { | ||
if runtime.GOOS != "windows" { | ||
// To be Reviewed | ||
path := strings.TrimPrefix(test.content, "pkcs12://") | ||
path = strings.TrimPrefix(path, "jks://") | ||
require.NoError(t, os.Chmod(path, test.mode)) | ||
} | ||
|
||
sc := X509Cert{ | ||
Sources: []string{test.content}, | ||
Log: testutil.Logger{}, | ||
} | ||
|
||
// Set password if provided | ||
if test.password != "" { | ||
sc.Password = config.NewSecret([]byte(test.password)) | ||
} else { | ||
sc.Password = config.NewSecret(nil) | ||
} | ||
|
||
require.NoError(t, sc.Init()) | ||
|
||
acc := testutil.Accumulator{} | ||
err := sc.Gather(&acc) | ||
|
||
if (len(acc.Errors) > 0) != test.error { | ||
t.Errorf("%s", err) | ||
} | ||
}) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about splitting this function into one testing for failures (those with error: true
) and another one where we don't expect errors. This has the advantage of simplifying the code and it is easier to follow as the function will set the context.
Please also test for the error message with require.ErrorContains(t, err, "essential part of the expected error message")
!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @paulojmdias! You need to fix the path handling on Windows. Currently your tests will pass but any real Windows path will fail as you need to remove the leading slash for the path contains a drive-letter.
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
…keystore_cert Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Download PR build artifacts for linux_amd64.tar.gz, darwin_arm64.tar.gz, and windows_amd64.zip. 📦 Click here to get additional PR build artifactsArtifact URLs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome! Thanks a lot for your contribution and patience @paulojmdias!
…fluxdata#16508) Signed-off-by: Paulo Dias <paulodias.gm@gmail.com>
Summary
I initially thought about creating a separate input plugin for JKS & PKCS12 key stores but decided to integrate it into x509_cert since the changes were minimal. This update allows x509_cert to automatically detect and parse JKS & PKCS12 files while maintaining the existing certificate validation and metric collection logic. I also added tests to ensure everything works smoothly without overcomplicating the code.
Please evaluate if make sense and let me know what changes you feel are needed to accommodate this feature.
Checklist
Related issues
resolves #7013