From bfca99b2107ed7ef31f37057eda9c3b74844ba61 Mon Sep 17 00:00:00 2001 From: Andrew Wilkins Date: Thu, 27 Oct 2022 09:56:30 +0800 Subject: [PATCH] Deprecate `apm-server apikey` Emit a deprecation notice to stderr for every `apm-server apikey` command. JSON errors are now sent to stdout, so they can be parsed independently of the notice. --- changelogs/head.asciidoc | 1 + .../docs/command-reference.asciidoc | 2 ++ .../secure-communication-agents.asciidoc | 2 ++ internal/beatcmd/apikey.go | 21 ++++++++++----- systemtest/apikeycmd_test.go | 26 +++++++++---------- 5 files changed, 33 insertions(+), 19 deletions(-) diff --git a/changelogs/head.asciidoc b/changelogs/head.asciidoc index bfac9862bc7..d77a403c709 100644 --- a/changelogs/head.asciidoc +++ b/changelogs/head.asciidoc @@ -11,6 +11,7 @@ https://github.com/elastic/apm-server/compare/8.5\...main[View commits] [float] ==== Deprecations +- `apm-server apikey` commands have been deprecated. API Keys should be managed through Kibana or the Elasticsearch REST API {pull}9446[9446] [float] ==== Bug fixes diff --git a/docs/legacy/copied-from-beats/docs/command-reference.asciidoc b/docs/legacy/copied-from-beats/docs/command-reference.asciidoc index ae30db07277..00740535cd8 100644 --- a/docs/legacy/copied-from-beats/docs/command-reference.asciidoc +++ b/docs/legacy/copied-from-beats/docs/command-reference.asciidoc @@ -139,6 +139,8 @@ ifdef::apm-server[] experimental::[] +deprecated::[8.6.0, Users should create API Keys through {kib} or the {es} REST API. See <>.] + Communication between APM agents and APM Server now supports sending an <>. APM Server provides an `apikey` command that can create, verify, invalidate, diff --git a/docs/legacy/secure-communication-agents.asciidoc b/docs/legacy/secure-communication-agents.asciidoc index 40a5ad6ebc9..a84fbaf7e5e 100644 --- a/docs/legacy/secure-communication-agents.asciidoc +++ b/docs/legacy/secure-communication-agents.asciidoc @@ -181,6 +181,8 @@ API keys can also be created and validated outside of {kib}: [float] ==== APM Server API key workflow +deprecated::[8.6.0, Users should create API Keys through {kib} or the {es} REST API] + APM Server provides a command line interface for creating, retrieving, invalidating, and verifying API keys. Keys created using this method can only be used for communication with APM Server. diff --git a/internal/beatcmd/apikey.go b/internal/beatcmd/apikey.go index b1de1eda1ec..9291ca210ba 100644 --- a/internal/beatcmd/apikey.go +++ b/internal/beatcmd/apikey.go @@ -40,9 +40,12 @@ import ( es "github.com/elastic/apm-server/internal/elasticsearch" ) +const apikeyDeprecationNotice = `NOTE: "apm-server apikey" is deprecated, and will be removed in a future release. +See https://www.elastic.co/guide/en/apm/guide/current/api-key.html for managing API Keys.` + func genApikeyCmd() *cobra.Command { - short := "Manage API Keys for communication between APM agents and server" + short := "Manage API Keys for communication between APM agents and server (deprecated)" apikeyCmd := cobra.Command{ Use: "apikey", Short: short, @@ -50,7 +53,9 @@ func genApikeyCmd() *cobra.Command { Most operations require the "manage_api_key" cluster privilege. Ensure to configure "apm-server.api_key.*" or "output.elasticsearch.*" appropriately. APM Server will create security privileges for the "apm" application; you can freely query them. If you modify or delete apm privileges, APM Server might reject all requests. -Check the Elastic Security API documentation for details.`, +Check the Elastic Security API documentation for details. + +` + apikeyDeprecationNotice, } apikeyCmd.AddCommand( @@ -195,13 +200,17 @@ type cobraRunFunc func(cmd *cobra.Command, args []string) func makeAPIKeyRun(json *bool, f apikeyRunFunc) cobraRunFunc { return func(cmd *cobra.Command, args []string) { + var failed bool client, config, err := bootstrap() if err != nil { + failed = true printErr(err, *json) - os.Exit(1) - } - if err := f(client, config, args); err != nil { + } else if err := f(client, config, args); err != nil { + failed = true printErr(err, *json) + } + fmt.Fprintf(os.Stderr, "\n%s\n", apikeyDeprecationNotice) + if failed { os.Exit(1) } } @@ -492,7 +501,7 @@ func printErr(err error, asJSON bool) { Error: err.Error(), }, "", "\t") } - fmt.Fprintln(os.Stderr, string(data)) + fmt.Fprintln(os.Stdout, string(data)) } else { fmt.Fprintln(os.Stderr, err.Error()) } diff --git a/systemtest/apikeycmd_test.go b/systemtest/apikeycmd_test.go index de6843cbac1..680157aaa11 100644 --- a/systemtest/apikeycmd_test.go +++ b/systemtest/apikeycmd_test.go @@ -66,7 +66,7 @@ func TestAPIKeyCreate(t *testing.T) { defer systemtest.InvalidateAPIKeys(t) cmd := apiKeyCommand("create", "--name", t.Name(), "--json") - out, err := cmd.CombinedOutput() + out, err := cmd.Output() require.NoError(t, err) attrs := decodeJSONMap(t, bytes.NewReader(out)) @@ -99,7 +99,7 @@ func TestAPIKeyCreateExpiration(t *testing.T) { defer systemtest.InvalidateAPIKeys(t) cmd := apiKeyCommand("create", "--name", t.Name(), "--json", "--expiration=1d") - out, err := cmd.CombinedOutput() + out, err := cmd.Output() require.NoError(t, err) attrs := decodeJSONMap(t, bytes.NewReader(out)) @@ -115,7 +115,7 @@ func TestAPIKeyCreateInvalidUser(t *testing.T) { cfg.Output.Elasticsearch.Password = "changeme" cmd := apiKeyCommandConfig(cfg, "create", "--name", t.Name(), "--json") - out, err := cmd.CombinedOutput() + out, err := cmd.Output() require.Error(t, err) attrs := decodeJSONMap(t, bytes.NewReader(out)) assert.Regexp(t, username+` is missing the following requested privilege\(s\): .*`, attrs["error"]) @@ -129,7 +129,7 @@ func TestAPIKeyInvalidateName(t *testing.T) { var clients []*estest.Client for i := 0; i < 2; i++ { cmd := apiKeyCommand("create", "--name", t.Name(), "--json") - out, err := cmd.CombinedOutput() + out, err := cmd.Output() require.NoError(t, err) attrs := decodeJSONMap(t, bytes.NewReader(out)) @@ -139,7 +139,7 @@ func TestAPIKeyInvalidateName(t *testing.T) { } cmd := apiKeyCommand("invalidate", "--name", t.Name(), "--json") - out, err := cmd.CombinedOutput() + out, err := cmd.Output() require.NoError(t, err) result := decodeJSONMap(t, bytes.NewReader(out)) @@ -156,7 +156,7 @@ func TestAPIKeyInvalidateID(t *testing.T) { defer systemtest.InvalidateAPIKeys(t) cmd := apiKeyCommand("create", "--json") - out, err := cmd.CombinedOutput() + out, err := cmd.Output() require.NoError(t, err) attrs := decodeJSONMap(t, bytes.NewReader(out)) @@ -166,7 +166,7 @@ func TestAPIKeyInvalidateID(t *testing.T) { // NOTE(axw) it is important to use "--id=" rather than "--id" , // as API keys may begin with a hyphen and be interpreted as flags. cmd = apiKeyCommand("invalidate", "--json", "--id="+attrs["id"].(string)) - out, err = cmd.CombinedOutput() + out, err = cmd.Output() require.NoError(t, err) result := decodeJSONMap(t, bytes.NewReader(out)) @@ -180,13 +180,13 @@ func TestAPIKeyVerify(t *testing.T) { defer systemtest.InvalidateAPIKeys(t) cmd := apiKeyCommand("create", "--name", t.Name(), "--json", "--ingest", "--agent-config") - out, err := cmd.CombinedOutput() + out, err := cmd.Output() require.NoError(t, err) attrs := decodeJSONMap(t, bytes.NewReader(out)) credentials := attrs["credentials"].(string) cmd = apiKeyCommand("verify", "--json", "--credentials="+credentials) - out, err = cmd.CombinedOutput() + out, err = cmd.Output() require.NoError(t, err) attrs = decodeJSONMap(t, bytes.NewReader(out)) assert.Equal(t, map[string]interface{}{ @@ -196,7 +196,7 @@ func TestAPIKeyVerify(t *testing.T) { }, attrs) cmd = apiKeyCommand("verify", "--json", "--credentials="+credentials, "--ingest") - out, err = cmd.CombinedOutput() + out, err = cmd.Output() require.NoError(t, err) attrs = decodeJSONMap(t, bytes.NewReader(out)) assert.Equal(t, map[string]interface{}{"event:write": true}, attrs) @@ -209,7 +209,7 @@ func TestAPIKeyInfo(t *testing.T) { var ids []string for i := 0; i < 2; i++ { cmd := apiKeyCommand("create", "--name", t.Name(), "--json", "--ingest", "--agent-config") - out, err := cmd.CombinedOutput() + out, err := cmd.Output() require.NoError(t, err) attrs := decodeJSONMap(t, bytes.NewReader(out)) ids = append(ids, attrs["id"].(string)) @@ -224,7 +224,7 @@ func TestAPIKeyInfo(t *testing.T) { } cmd := apiKeyCommand("info", "--json", "--id="+ids[0]) - out, err := cmd.CombinedOutput() + out, err := cmd.Output() require.NoError(t, err) err = json.Unmarshal(out, &result) require.NoError(t, err) @@ -235,7 +235,7 @@ func TestAPIKeyInfo(t *testing.T) { result.APIKeys = nil cmd = apiKeyCommand("info", "--json", "--name="+t.Name()) - out, err = cmd.CombinedOutput() + out, err = cmd.Output() require.NoError(t, err) err = json.Unmarshal(out, &result) require.NoError(t, err)