Skip to content

Commit 6851f3c

Browse files
Merge branch 'main' into dependabot/go_modules/otel-dependencies-40b20a2a27
2 parents 51090f2 + cb7e377 commit 6851f3c

21 files changed

+697
-30
lines changed

.github/dependabot.yml

+13-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ updates:
88
labels:
99
- automation
1010
- skip-changelog
11-
- Team:Elastic-Agent
11+
- Team:Elastic-Agent-Control-Plane
1212
groups:
1313
otel-dependencies:
1414
exclude-patterns:
@@ -24,3 +24,15 @@ updates:
2424
reviewers:
2525
- "elastic/elastic-agent-control-plane"
2626
open-pull-requests-limit: 10
27+
28+
- package-ecosystem: "github-actions"
29+
directory: "/"
30+
schedule:
31+
interval: "daily"
32+
labels:
33+
- automation
34+
- skip-changelog
35+
- Team:Elastic-Agent-Control-Plane
36+
reviewers:
37+
- "elastic/elastic-agent-control-plane"
38+
open-pull-requests-limit: 10

.github/workflows/bump-agent-versions.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
fetch-depth: 0
2323

2424
- name: Set up Go
25-
uses: actions/setup-go@v4
25+
uses: actions/setup-go@v5
2626
with:
2727
go-version: 1.21
2828

.github/workflows/bump-golang.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
- uses: actions/checkout@v4
2323

2424
- name: Install Updatecli in the runner
25-
uses: updatecli/updatecli-action@9a37c7e35598d7b37d8e7568b40ed9538112be01 # v0.76.1
25+
uses: updatecli/updatecli-action@fa41baa922561b436c449de1a0bd1f5bd768248c # v0.76.1
2626

2727
- name: Run Updatecli in Apply mode
2828
run: updatecli apply --config .github/updatecli-bump-golang.yml

.github/workflows/fragment-in-pr.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
runs-on: ubuntu-latest
1010
steps:
1111
- uses: actions/checkout@v3
12-
- uses: actions/setup-go@v3
12+
- uses: actions/setup-go@v5
1313
with:
1414
go-version-file: .go-version
1515
- name: check pr-has-fragment

.github/workflows/golangci-lint.yml

+2-5
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ jobs:
2020
steps:
2121
- uses: actions/checkout@v3
2222

23-
- uses: actions/setup-go@v3
23+
- uses: actions/setup-go@v5
2424
with:
2525
go-version-file: .go-version
2626

2727
- name: golangci-lint
28-
uses: golangci/golangci-lint-action@v3
28+
uses: golangci/golangci-lint-action@v6
2929
with:
3030
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
3131
version: v1.55.2
@@ -39,8 +39,5 @@ jobs:
3939
# into fixing all linting issues in the whole file instead.
4040
args: --timeout=30m --whole-files
4141

42-
# Optional: if set to true then the action will use pre-installed Go.
43-
skip-go-installation: true
44-
4542
# Optional: show only new issues if it's a pull request. The default value is `false`.
4643
only-new-issues: true

.github/workflows/post-dependabot.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
steps:
1919
- uses: actions/checkout@v3
2020

21-
- uses: actions/setup-go@v4
21+
- uses: actions/setup-go@v5
2222
with:
2323
go-version-file: .go-version
2424

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Kind can be one of:
2+
# - breaking-change: a change to previously-documented behavior
3+
# - deprecation: functionality that is being removed in a later release
4+
# - bug-fix: fixes a problem in a previous version
5+
# - enhancement: extends functionality but does not break or fix existing behavior
6+
# - feature: new functionality
7+
# - known-issue: problems that we are aware of in a given version
8+
# - security: impacts on the security of a product or a user’s deployment.
9+
# - upgrade: important information for someone upgrading from a prior version
10+
# - other: does not fit into any of the other categories
11+
kind: enhancement
12+
13+
# Change summary; a 80ish characters long description of the change.
14+
summary: Fleet Server component now uses policy output configuration to communicate with Elasticsearch
15+
16+
# Long description; in case the summary is not enough to describe the change
17+
# this field accommodate a description without length limits.
18+
# NOTE: This field will be rendered only for breaking-change and known-issue kinds at the moment.
19+
description: |
20+
Alter how elatic-agent passes the fleet-server output component so that the policy's output is used.
21+
In cases where fleet-server encounters an error when trying to use the policy's output it will use
22+
the configuration specified during enrollment as a fallback. In cases where it uses the fallback
23+
the policy's output is periodically retested and used if it's successful.
24+
25+
# Affected component; a word indicating the component this changeset affects.
26+
component:
27+
28+
# PR URL; optional; the PR number that added the changeset.
29+
# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added.
30+
# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number.
31+
# Please provide it if you are adding a fragment for a different PR.
32+
pr: https://github.com/elastic/elastic-agent/pull/4643
33+
34+
# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of).
35+
# If not present is automatically filled by the tooling with the issue linked to the PR number.
36+
issue: https://github.com/elastic/elastic-agent/issue/2784

docs/fleet-server-bootstrap.asciidoc

+58
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,61 @@ its API key to use for communication. The new `fleet.yml` still includes the `fl
8888
but this time the `fleet.server.bootstrap: false` is set.
8989
. `enroll` command then either restarts the running Elatic Agent daemon if one was running
9090
from Step 2, or it stops the spawned `run` subprocess and returns.
91+
92+
=== Elasticsearch output
93+
94+
The options passed that are used to specify fleet-server initially connects to elasticsearch are:
95+
96+
- `--fleet-server-es`
97+
- `--fleet-server-es-ca`
98+
- `--fleet-server-es-ca-trusted-fingerprint`
99+
- `--fleet-server-es-insecure`
100+
- `--fleet-server-es-cert`
101+
- `--fleet-server-es-cert-key`
102+
- `--fleet-server-es-service-token`
103+
- `--fleet-server-es-service-token-path`
104+
- `--proxy-url`
105+
- `--proxy-disabled`
106+
- `--proxy-header`
107+
108+
These options are always passed under a `bootstrap` attribute in the output when elastic-agent is passing config to fleet-server.
109+
When the fleet-server recieves an output block, it will inject any keys that are missing from the top level output but are specified in the `bootstrap` block
110+
After injecting the keys from bootstrap, fleet-server will test connecting the Elasticsearch with the output.
111+
If the test fails, the values under the `bootstrap` attribute are used as the output and fleet-server will periodically retest the output in case the error was caused by a temporary network issue.
112+
Note that if `--fleet-server-es-insecure` is specified, and the output in the policy contains one or more CA, or a CA fingerprint, the `--fleet-server-es-insecure` flag is ignored.
113+
114+
An example of this sequence is sequence is:
115+
116+
1) elastic-agent starts fleet-server and sends an output block that looks similar to:
117+
```yaml
118+
output:
119+
bootstrap:
120+
service_token: VALUE
121+
hosts: ["HOST"]
122+
```
123+
124+
2) fleet-server injects attributes into the top level from bootstrap if they are missing, resulting in
125+
```yaml
126+
output:
127+
service_token: VALUE
128+
hosts: ["HOST"]
129+
```
130+
131+
3) fleet-server connects to Elasticsearch with the output block
132+
4) elastic-agent enrolls and recieves its policy
133+
5) elastic-agent sends configuration generated from the policy to fleet-server, this may result in the output as follows:
134+
```yaml
135+
output:
136+
hosts: ["HOST", "HOST2"]
137+
bootstrap:
138+
service_token: VALUE
139+
hosts: ["HOST"]
140+
```
141+
142+
6) fleet-server will inject missing values resulting in:
143+
```yaml
144+
output:
145+
service_token: VALUE
146+
hosts: ["HOST", "HOST2"]
147+
```
148+
7) fleet-server tests and uses the resulting output block.

internal/pkg/agent/application/fleet_server_bootstrap.go

+17-1
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,13 @@ func FleetServerComponentModifier(serverCfg *configuration.FleetServerConfig) co
6565
} else {
6666
for j, unit := range comp.Units {
6767
if unit.Type == client.UnitTypeOutput && unit.Config.Type == elasticsearch {
68-
unitCfgMap, err := toMapStr(unit.Config.Source.AsMap(), &serverCfg.Output.Elasticsearch)
68+
unitCfgMap, err := toMapStr(unit.Config.Source.AsMap())
6969
if err != nil {
7070
return nil, err
7171
}
72+
if err := addBootstrapCfg(unitCfgMap, &serverCfg.Output.Elasticsearch); err != nil {
73+
return nil, err
74+
}
7275
fixOutputMap(unitCfgMap)
7376
unitCfg, err := component.ExpectedConfig(unitCfgMap)
7477
if err != nil {
@@ -100,6 +103,19 @@ func FleetServerComponentModifier(serverCfg *configuration.FleetServerConfig) co
100103
}
101104
}
102105

106+
// addBootrapCfg will transform the passed configuration.Elasticsearch to a map and add it to dst under the bootstrap key.
107+
func addBootstrapCfg(dst map[string]interface{}, es *configuration.Elasticsearch) error {
108+
if es == nil {
109+
return fmt.Errorf("fleet-server bootstrap output config is undefined")
110+
}
111+
mp, err := toMapStr(es)
112+
if err != nil {
113+
return err
114+
}
115+
dst["bootstrap"] = mp
116+
return nil
117+
}
118+
103119
// InjectFleetConfigComponentModifier The modifier that injects the fleet configuration for the components
104120
// that need to be able to connect to fleet server.
105121
func InjectFleetConfigComponentModifier(fleetCfg *configuration.FleetAgentConfig, agentInfo info.Agent) coordinator.ComponentsModifier {

internal/pkg/agent/application/fleet_server_bootstrap_test.go

+81
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,87 @@ func TestFleetServerComponentModifier_NoServerConfig(t *testing.T) {
7474
}
7575
}
7676

77+
func TestFleetServerComponentModifier(t *testing.T) {
78+
tests := []struct {
79+
name string
80+
source map[string]interface{}
81+
expect map[string]interface{}
82+
}{{
83+
name: "empty output component",
84+
source: map[string]interface{}{},
85+
expect: map[string]interface{}{
86+
"bootstrap": map[string]interface{}{
87+
"protocol": "https",
88+
"hosts": []interface{}{"elasticsearch:9200"},
89+
"service_token": "example-token",
90+
},
91+
},
92+
}, {
93+
name: "output component provided",
94+
source: map[string]interface{}{
95+
"protocol": "http",
96+
"hosts": []interface{}{"elasticsearch:9200", "host:9200"},
97+
},
98+
expect: map[string]interface{}{
99+
"protocol": "http",
100+
"hosts": []interface{}{"elasticsearch:9200", "host:9200"},
101+
"bootstrap": map[string]interface{}{
102+
"protocol": "https",
103+
"hosts": []interface{}{"elasticsearch:9200"},
104+
"service_token": "example-token",
105+
},
106+
},
107+
}}
108+
cfg := &configuration.FleetServerConfig{
109+
Output: configuration.FleetServerOutputConfig{
110+
Elasticsearch: configuration.Elasticsearch{
111+
Protocol: "https",
112+
Hosts: []string{"elasticsearch:9200"},
113+
ServiceToken: "example-token",
114+
},
115+
},
116+
}
117+
modifier := FleetServerComponentModifier(cfg)
118+
119+
for _, tc := range tests {
120+
t.Run(tc.name, func(t *testing.T) {
121+
src, err := structpb.NewStruct(tc.source)
122+
require.NoError(t, err)
123+
comps, err := modifier([]component.Component{{
124+
InputSpec: &component.InputRuntimeSpec{
125+
InputType: "fleet-server",
126+
},
127+
Units: []component.Unit{{
128+
Type: client.UnitTypeOutput,
129+
Config: &proto.UnitExpectedConfig{
130+
Type: "elasticsearch",
131+
Source: src,
132+
},
133+
}},
134+
}}, nil)
135+
require.NoError(t, err)
136+
137+
require.Len(t, comps, 1)
138+
require.Len(t, comps[0].Units, 1)
139+
res := comps[0].Units[0].Config.Source.AsMap()
140+
for k, v := range tc.expect {
141+
val, ok := res[k]
142+
require.Truef(t, ok, "expected %q to be in output unit config", k)
143+
if mp, ok := v.(map[string]interface{}); ok {
144+
rMap, ok := val.(map[string]interface{})
145+
require.Truef(t, ok, "expected %q to be map[string]interface{} was %T", k, val)
146+
for kk, vv := range mp {
147+
assert.Contains(t, rMap, kk)
148+
assert.Equal(t, rMap[kk], vv)
149+
}
150+
} else {
151+
assert.Equal(t, v, val)
152+
}
153+
}
154+
})
155+
}
156+
}
157+
77158
func TestInjectFleetConfigComponentModifier(t *testing.T) {
78159
fleetConfig := &configuration.FleetAgentConfig{
79160
Enabled: true,

internal/pkg/agent/configuration/fleet_server.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,14 @@ type FleetServerOutputConfig struct {
3232
Elasticsearch Elasticsearch `config:"elasticsearch" yaml:"elasticsearch"`
3333
}
3434

35-
// Elasticsearch is the configuration for elasticsearch.
35+
// Elasticsearch is the configuration for fleet-server's connection to elasticsearch.
36+
// Note that these keys may be injected into policy output by fleet-server.
37+
// The following TLS options may be set in bootstrap:
38+
// - VerificationMode
39+
// - CAs
40+
// - CATrustedFingerprint
41+
// - CertificateConfig.Certificate AND CertificateConfig.Key
42+
// If an attribute is added to this struct, or another TLS attribute is passed ensure that it is handled as part of the bootstrap config handler in fleet-server/internal/pkg/server/agent.go
3643
type Elasticsearch struct {
3744
Protocol string `config:"protocol" yaml:"protocol"`
3845
Hosts []string `config:"hosts" yaml:"hosts"`

internal/pkg/otel/run.go

+10-17
Original file line numberDiff line numberDiff line change
@@ -53,18 +53,19 @@ func newSettings(version string, configPaths []string) (*otelcol.CollectorSettin
5353
Description: buildDescription,
5454
Version: version,
5555
}
56-
converterSet := confmap.ConverterSettings{}
5756
configProviderSettings := otelcol.ConfigProviderSettings{
5857
ResolverSettings: confmap.ResolverSettings{
5958
URIs: configPaths,
60-
Providers: makeMapProvidersMap(
61-
fileprovider.NewWithSettings(confmap.ProviderSettings{}),
62-
envprovider.NewWithSettings(confmap.ProviderSettings{}),
63-
yamlprovider.NewWithSettings(confmap.ProviderSettings{}),
64-
httpprovider.NewWithSettings(confmap.ProviderSettings{}),
65-
httpsprovider.NewWithSettings(confmap.ProviderSettings{}),
66-
),
67-
Converters: []confmap.Converter{expandconverter.New(converterSet)},
59+
ProviderFactories: []confmap.ProviderFactory{
60+
fileprovider.NewFactory(),
61+
envprovider.NewFactory(),
62+
yamlprovider.NewFactory(),
63+
httpprovider.NewFactory(),
64+
httpsprovider.NewFactory(),
65+
},
66+
ConverterFactories: []confmap.ConverterFactory{
67+
expandconverter.NewFactory(),
68+
},
6869
},
6970
}
7071
provider, err := otelcol.NewConfigProvider(configProviderSettings)
@@ -81,11 +82,3 @@ func newSettings(version string, configPaths []string) (*otelcol.CollectorSettin
8182
DisableGracefulShutdown: true,
8283
}, nil
8384
}
84-
85-
func makeMapProvidersMap(providers ...confmap.Provider) map[string]confmap.Provider {
86-
ret := make(map[string]confmap.Provider, len(providers))
87-
for _, provider := range providers {
88-
ret[provider.Scheme()] = provider
89-
}
90-
return ret
91-
}

0 commit comments

Comments
 (0)