Repository navigation
Conversation
This commit will allow the user to pass in a directory to the `apm-server keystore add` command to store files as values with their filenames as keys. The command will simply scan the directory and not walk it recursively. Additionally, it will skip hidden files.
🤖 GitHub commentsJust comment with:
|
|
This pull request does not have a backport label. Could you fix it @aelnahas? 🙏
|
There was a problem hiding this comment.
🟡 Changes recommended
The keystore system tests run against the FIPS binary, which omits the keystore command, causing both tests to fail.
3 open issues
What changed in this PR
Adds directory-based secret imports to apm-server keystore add, supporting bulk setup in shell-less containers such as those used by ECK.
Changes:
- Adds
--from-dirto import filenames as keys and file contents as values, skipping hidden entries and subdirectories. - Refactors input handling and supports noninteractive keystore creation for directory and stdin imports.
- Adds unit and system tests for imports, validation, and overwrite behavior.
| File | Description |
|---|---|
systemtest/keystore_test.go |
Adds end-to-end directory and stdin import tests. |
internal/beatcmd/keystore_nofips.go |
Implements directory imports and shared secret-input handling. |
internal/beatcmd/keystore_nofips_test.go |
Tests directory filtering, validation, persistence, and conflicts. |
Review effort: Balanced
There was a problem hiding this comment.
🟡 Changes recommended
Removing whitespace normalization breaks existing positional-key removal: a key added as ' token ' is stored as 'token' but can no longer be removed using the original argument.
1 open issue
3 resolved since last review
Review effort: Balanced
carsonip
left a comment
There was a problem hiding this comment.
i think we can drop 9.4 backport because there is no scheduled release. And for 9.6 please observe FF.
| c.keys = make([]string, len(args)) | ||
| for i, arg := range args { | ||
| c.keys[i] = strings.TrimSpace(arg) | ||
| } |
There was a problem hiding this comment.
nit: there's no need to go through this if loading from directory
There was a problem hiding this comment.
That's true, I can guard this with the flag check.
| if err != nil { | ||
| return fmt.Errorf("could not read value from the input, error: %w", err) | ||
|
|
||
| if err = writableKeystore.Store(key, keyValue); err != nil { |
There was a problem hiding this comment.
| if err = writableKeystore.Store(key, keyValue); err != nil { | |
| if err := writableKeystore.Store(key, keyValue); err != nil { |
| return fmt.Errorf("could not add the key in the keystore, error: %w", err) | ||
| } | ||
|
|
||
| if err = writableKeystore.Save(); err != nil { |
There was a problem hiding this comment.
| if err = writableKeystore.Save(); err != nil { | |
| if err := writableKeystore.Save(); err != nil { |
There was a problem hiding this comment.
suggestion: will it be helpful for --from-dir to print the number of keys added / updated?
|
|
||
| if !store.IsPersisted() { | ||
| if !force { | ||
| if !force && interactive { |
There was a problem hiding this comment.
q: why change the condition? --from-dir and --stdin can be in an interactive environment as well
There was a problem hiding this comment.
More of an opinion than strong reason. When I was working on this, I took a look at some other cli commands such as kubectl unzip mv cp and the like. some ignore the interactive option while others would have additional options such as All/None or -n do not overwrite.
It is a bit split. I ended up following kubectl approach with kubectl create secret --from-file since that felt the closest to what we are doing and I assumed this is utility is mostly used in automated script.
I can changes this bit if it is undesired.
| for _, key := range keys { | ||
| if _, err := store.Retrieve(key); err == nil { | ||
| if !force { | ||
| if !interactive { |
There was a problem hiding this comment.
ditto. I'm not sure deriving interactive from from-dir vs stdin vs input is correct.
| if len(c.keys) == 0 { | ||
| return fmt.Errorf("directory %q is empty", c.fromDir) |
There was a problem hiding this comment.
i think this is likely correct, but i wonder if there is any case if an empty directory is not an error case and should be no-op and exit cleanly.
- empty directory is demoted to a warn message - added updated/added count - allow both --from-dir and --stdin to be used interactively - add tests
There was a problem hiding this comment.
🟡 Changes recommended
Creation tests omit required keystore confirmation, an overwrite test expects the wrong error, and empty-directory imports bypass mutually exclusive option validation.
4 open issues
1 resolved since last review
Review effort: Balanced
| files: map[string]string{"a": "1", "b": "new"}, | ||
| wantErr: "the settings b already exist", |
| seedKeystore(t, ksPath, tt.seed) | ||
| } | ||
|
|
||
| c := &addKeystoreCmd{force: tt.force} |
| require.NoError(tb, os.WriteFile(filepath.Join(homedir, "apm-server.yml"), nil, 0644)) | ||
| return homedir |
| if c.fromDir != "" { | ||
| keys, err := getKeysFromDir(c.fromDir) |
💚 Build Succeeded
History
|


Motivation/summary
This commit will allow the user to pass in a directory to the
apm-server keystore addcommand to store files as values with their filenames as keys by passing a--from-dirflag. The command will simply scan the directory and not walk it recursively. Additionally, it will skip hidden files.e.g
Checklist
For functional changes, consider:
How to test these changes
I found it tricky to try and pull the secret content to verify it if is written correctly. So one workaround is to setup the secrets so that they are used for request and then attempt to use a correct and incorrect secret token to authenticate the request.
Steps:
apm-server.ymlas following:Add the
SECRET_TOKENfile something like`echo "some-token" >> /tmp/test/secrets/SECRET_TOKEN
add the token via --from-dir
apm keystore add --from-dir /tmp/test/secrets4 start the apm server
send a request to intake with the correct token
Related issues
Fixes: #21863