Skip to content

Commit d714fde

Browse files
mstuparurdner
andauthored
[Filebeat] Fix Kubernetes secret resolution in Filebeat hints builder (#48787)
Pass options (including Kubernetes keystore resolver) into ApplyConfigTemplate in the log hints builder so that variables like ${kubernetes.namespace.secret.key} are resolved when using autodiscover hints (e.g. co.elastic.logs/raw). This aligns Filebeat with Metricbeat, which already passes options to ApplyConfigTemplate in its hints builder. --------- Co-authored-by: Denis <denis.rechkunov@elastic.co>
1 parent 6bfbe86 commit d714fde

File tree

3 files changed

+52
-2
lines changed

3 files changed

+52
-2
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
kind: bugfix
2+
summary: Fix Kubernetes secret variable resolution in Filebeat autodiscover hints
3+
component: filebeat

filebeat/autodiscover/builder/hints/logs.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ func (l *logHints) CreateConfig(event bus.Event, options ...ucfg.Option) []*conf
102102
}
103103
l.log.Debugf("Generated %d input configs from hint.", len(configs))
104104
// Apply information in event to the template to generate the final config
105-
return template.ApplyConfigTemplate(event, configs, l.log)
105+
return template.ApplyConfigTemplate(event, configs, l.log, options...)
106106
}
107107

108108
var configs []*conf.C //nolint:prealloc //breaks tests
@@ -199,7 +199,7 @@ func (l *logHints) CreateConfig(event bus.Event, options ...ucfg.Option) []*conf
199199
configs = append(configs, config)
200200
}
201201
// Apply information in event to the template to generate the final config
202-
return template.ApplyConfigTemplate(event, configs, l.log)
202+
return template.ApplyConfigTemplate(event, configs, l.log, options...)
203203
}
204204

205205
func (l *logHints) getMultiline(hints mapstr.M) mapstr.M {

filebeat/autodiscover/builder/hints/logs_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@ import (
2525
"github.com/stretchr/testify/assert"
2626
"github.com/stretchr/testify/require"
2727

28+
"github.com/elastic/beats/v7/testing/testutils"
2829
"github.com/elastic/elastic-agent-autodiscover/bus"
2930
conf "github.com/elastic/elastic-agent-libs/config"
31+
"github.com/elastic/elastic-agent-libs/keystore"
3032
"github.com/elastic/elastic-agent-libs/logp/logptest"
3133
"github.com/elastic/elastic-agent-libs/mapstr"
3234
"github.com/elastic/elastic-agent-libs/paths"
35+
"github.com/elastic/go-ucfg"
3336
)
3437

3538
func TestMain(m *testing.M) {
@@ -1460,3 +1463,47 @@ func TestGenerateHintsWithPaths(t *testing.T) {
14601463

14611464
}
14621465
}
1466+
1467+
// TestCreateConfigResolvesVariablesFromOptions checks that variables in raw hint
1468+
// configs are resolved using the options passed to CreateConfig (e.g. keystore resolver
1469+
// from the Kubernetes autodiscover provider so ${kubernetes.namespace.secret.key} works).
1470+
func TestCreateConfigResolvesVariablesFromOptions(t *testing.T) {
1471+
testutils.SkipIfFIPSOnly(t, "keystore implementation does not use NewGCMWithRandomNonce.")
1472+
1473+
path := filepath.Join(t.TempDir(), "keystore")
1474+
opts := []ucfg.Option{ucfg.Resolve(keystore.ResolverWrap(logsTestKeystore(t, path, "secret")))}
1475+
1476+
cfg := conf.MustNewConfigFrom(map[string]any{
1477+
"default_config": map[string]any{
1478+
"type": "docker",
1479+
"containers": map[string]any{"ids": []string{"${data.container.id}"}},
1480+
"close_timeout": "true",
1481+
},
1482+
})
1483+
event := bus.Event{
1484+
"host": "1.2.3.4",
1485+
"kubernetes": mapstr.M{"container": mapstr.M{"name": "foobar", "id": "abc"}},
1486+
"container": mapstr.M{"name": "foobar", "id": "abc"},
1487+
"hints": mapstr.M{"logs": mapstr.M{"raw": `[{"type":"docker","containers":{"ids":["${data.container.id}"]},"password":"${PASSWORD}"}]`}},
1488+
}
1489+
1490+
l, err := NewLogHints(cfg, logptest.NewTestingLogger(t, ""))
1491+
require.NoError(t, err)
1492+
cfgs := l.CreateConfig(event, opts...)
1493+
require.Len(t, cfgs, 1)
1494+
1495+
var out mapstr.M
1496+
require.NoError(t, cfgs[0].Unpack(&out))
1497+
assert.Equal(t, "secret", out["password"])
1498+
}
1499+
1500+
func logsTestKeystore(t *testing.T, path, secret string) keystore.Keystore {
1501+
t.Helper()
1502+
ks, err := keystore.NewFileKeystore(path)
1503+
require.NoError(t, err)
1504+
w, err := keystore.AsWritableKeystore(ks)
1505+
require.NoError(t, err)
1506+
require.NoError(t, w.Store("PASSWORD", []byte(secret)))
1507+
require.NoError(t, w.Save())
1508+
return ks
1509+
}

0 commit comments

Comments
 (0)