Skip to content

Commit 1fcbfaa

Browse files
committed
Add FIPS disabled components flag
Signed-off-by: Pavol Loffay <[email protected]>
1 parent e82f595 commit 1fcbfaa

File tree

11 files changed

+219
-7
lines changed

11 files changed

+219
-7
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ kubectl apply -f - <<EOF
3333
apiVersion: opentelemetry.io/v1beta1
3434
kind: OpenTelemetryCollector
3535
metadata:
36-
name: simplest
36+
name: simplest222
3737
spec:
3838
config:
3939
receivers:

apis/v1beta1/collector_webhook.go

+11-2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
2828

2929
"github.com/open-telemetry/opentelemetry-operator/internal/config"
30+
"github.com/open-telemetry/opentelemetry-operator/internal/fips"
3031
ta "github.com/open-telemetry/opentelemetry-operator/internal/manifests/targetallocator/adapters"
3132
"github.com/open-telemetry/opentelemetry-operator/internal/rbac"
3233
)
@@ -48,6 +49,7 @@ type CollectorWebhook struct {
4849
reviewer *rbac.Reviewer
4950
metrics *Metrics
5051
bv BuildValidator
52+
fips fips.FipsCheck
5153
}
5254

5355
func (c CollectorWebhook) Default(_ context.Context, obj runtime.Object) error {
@@ -290,6 +292,11 @@ func (c CollectorWebhook) Validate(ctx context.Context, r *OpenTelemetryCollecto
290292
return warnings, fmt.Errorf("the OpenTelemetry Collector mode is set to %s, which does not support the attribute 'deploymentUpdateStrategy'", r.Spec.Mode)
291293
}
292294

295+
components := r.Spec.Config.GetEnabledComponents()
296+
if notAllowedComponents := c.fips.Check(components[KindReceiver], components[KindExporter], components[KindProcessor], components[KindExtension]); notAllowedComponents != nil {
297+
return nil, fmt.Errorf("the collector configuration contains not FIPS compliant components: %s. Please remove it from the config", notAllowedComponents)
298+
}
299+
293300
return warnings, nil
294301
}
295302

@@ -423,6 +430,7 @@ func NewCollectorWebhook(
423430
reviewer *rbac.Reviewer,
424431
metrics *Metrics,
425432
bv BuildValidator,
433+
fips fips.FipsCheck,
426434
) *CollectorWebhook {
427435
return &CollectorWebhook{
428436
logger: logger,
@@ -431,11 +439,12 @@ func NewCollectorWebhook(
431439
reviewer: reviewer,
432440
metrics: metrics,
433441
bv: bv,
442+
fips: fips,
434443
}
435444
}
436445

437-
func SetupCollectorWebhook(mgr ctrl.Manager, cfg config.Config, reviewer *rbac.Reviewer, metrics *Metrics, bv BuildValidator) error {
438-
cvw := NewCollectorWebhook(mgr.GetLogger().WithValues("handler", "CollectorWebhook", "version", "v1beta1"), mgr.GetScheme(), cfg, reviewer, metrics, bv)
446+
func SetupCollectorWebhook(mgr ctrl.Manager, cfg config.Config, reviewer *rbac.Reviewer, metrics *Metrics, bv BuildValidator, fipsCheck fips.FipsCheck) error {
447+
cvw := NewCollectorWebhook(mgr.GetLogger().WithValues("handler", "CollectorWebhook", "version", "v1beta1"), mgr.GetScheme(), cfg, reviewer, metrics, bv, fipsCheck)
439448
return ctrl.NewWebhookManagedBy(mgr).
440449
For(&OpenTelemetryCollector{}).
441450
WithValidator(cvw).

apis/v1beta1/collector_webhook_test.go

+5
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import (
3939

4040
"github.com/open-telemetry/opentelemetry-operator/apis/v1beta1"
4141
"github.com/open-telemetry/opentelemetry-operator/internal/config"
42+
"github.com/open-telemetry/opentelemetry-operator/internal/fips"
4243
"github.com/open-telemetry/opentelemetry-operator/internal/manifests"
4344
collectorManifests "github.com/open-telemetry/opentelemetry-operator/internal/manifests/collector"
4445
"github.com/open-telemetry/opentelemetry-operator/internal/rbac"
@@ -113,6 +114,7 @@ func TestValidate(t *testing.T) {
113114
getReviewer(test.shouldFailSar),
114115
nil,
115116
bv,
117+
fips.NewFipsCheck(nil, nil, nil, nil),
116118
)
117119
t.Run(tt.name, func(t *testing.T) {
118120
tt := tt
@@ -494,6 +496,7 @@ func TestCollectorDefaultingWebhook(t *testing.T) {
494496
getReviewer(test.shouldFailSar),
495497
nil,
496498
bv,
499+
fips.NewFipsCheck(nil, nil, nil, nil),
497500
)
498501
ctx := context.Background()
499502
err := cvw.Default(ctx, &test.otelcol)
@@ -1285,6 +1288,7 @@ func TestOTELColValidatingWebhook(t *testing.T) {
12851288
getReviewer(test.shouldFailSar),
12861289
nil,
12871290
bv,
1291+
fips.NewFipsCheck(nil, nil, nil, nil),
12881292
)
12891293
ctx := context.Background()
12901294
warnings, err := cvw.ValidateCreate(ctx, &test.otelcol)
@@ -1352,6 +1356,7 @@ func TestOTELColValidateUpdateWebhook(t *testing.T) {
13521356
getReviewer(test.shouldFailSar),
13531357
nil,
13541358
bv,
1359+
fips.NewFipsCheck(nil, nil, nil, nil),
13551360
)
13561361
ctx := context.Background()
13571362
warnings, err := cvw.ValidateUpdate(ctx, &test.otelcolOld, &test.otelcolNew)

apis/v1beta1/config.go

+8
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ const (
4141
KindReceiver ComponentKind = iota
4242
KindExporter
4343
KindProcessor
44+
KindExtension
4445
)
4546

4647
func (c ComponentKind) String() string {
@@ -108,7 +109,14 @@ func (c *Config) GetEnabledComponents() map[ComponentKind]map[string]interface{}
108109
KindReceiver: {},
109110
KindProcessor: {},
110111
KindExporter: {},
112+
KindExtension: {},
111113
}
114+
if c.Service.Extensions != nil {
115+
for _, extension := range *c.Service.Extensions {
116+
toReturn[KindExtension][extension] = struct{}{}
117+
}
118+
}
119+
112120
for _, pipeline := range c.Service.Pipelines {
113121
if pipeline == nil {
114122
continue

apis/v1beta1/config_test.go

+12
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ func TestConfig_GetEnabledComponents(t *testing.T) {
304304
"bar": struct{}{},
305305
"count": struct{}{},
306306
},
307+
KindExtension: {},
307308
},
308309
},
309310
{
@@ -321,6 +322,7 @@ func TestConfig_GetEnabledComponents(t *testing.T) {
321322
KindExporter: {
322323
"prometheus": struct{}{},
323324
},
325+
KindExtension: {},
324326
},
325327
},
326328
{
@@ -339,6 +341,11 @@ func TestConfig_GetEnabledComponents(t *testing.T) {
339341
"otlp": struct{}{},
340342
"prometheus": struct{}{},
341343
},
344+
KindExtension: {
345+
"pprof": struct{}{},
346+
"zpages": struct{}{},
347+
"health_check": struct{}{},
348+
},
342349
},
343350
},
344351
{
@@ -352,6 +359,9 @@ func TestConfig_GetEnabledComponents(t *testing.T) {
352359
KindExporter: {
353360
"otlp/auth": struct{}{},
354361
},
362+
KindExtension: {
363+
"oauth2client": struct{}{},
364+
},
355365
},
356366
},
357367
{
@@ -365,6 +375,7 @@ func TestConfig_GetEnabledComponents(t *testing.T) {
365375
KindExporter: {
366376
"debug": struct{}{},
367377
},
378+
KindExtension: {},
368379
},
369380
},
370381
{
@@ -374,6 +385,7 @@ func TestConfig_GetEnabledComponents(t *testing.T) {
374385
KindReceiver: {},
375386
KindProcessor: {},
376387
KindExporter: {},
388+
KindExtension: {},
377389
},
378390
},
379391
}

controllers/suite_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ import (
5959
"github.com/open-telemetry/opentelemetry-operator/internal/autodetect/prometheus"
6060
autoRBAC "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/rbac"
6161
"github.com/open-telemetry/opentelemetry-operator/internal/config"
62+
"github.com/open-telemetry/opentelemetry-operator/internal/fips"
6263
"github.com/open-telemetry/opentelemetry-operator/internal/manifests"
6364
"github.com/open-telemetry/opentelemetry-operator/internal/manifests/collector/testdata"
6465
"github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils"
@@ -178,7 +179,7 @@ func TestMain(m *testing.M) {
178179
}
179180
reviewer := rbac.NewReviewer(clientset)
180181

181-
if err = v1beta1.SetupCollectorWebhook(mgr, config.New(), reviewer, nil, nil); err != nil {
182+
if err = v1beta1.SetupCollectorWebhook(mgr, config.New(), reviewer, nil, nil, fips.NewFipsCheck(nil, nil, nil, nil)); err != nil {
182183
fmt.Printf("failed to SetupWebhookWithManager: %v", err)
183184
os.Exit(1)
184185
}

internal/fips/check.go

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// Copyright The OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package fips
16+
17+
import (
18+
"errors"
19+
"fmt"
20+
"os"
21+
"strings"
22+
)
23+
24+
const fipsFile = "/proc/sys/crypto/fips_enabled"
25+
26+
// FipsCheck holds configuration for FIPS black list.
27+
type FipsCheck struct {
28+
isFIPSEnabled bool
29+
30+
receivers map[string]bool
31+
exporters map[string]bool
32+
processors map[string]bool
33+
extensions map[string]bool
34+
}
35+
36+
// NewFipsCheck creates new FipsCheck.
37+
// It checks if FIPS is enabled on the platform in /proc/sys/crypto/fips_enabled
38+
func NewFipsCheck(receivers, exporters, processors, extensions []string) FipsCheck {
39+
return FipsCheck{
40+
isFIPSEnabled: isFipsEnabled(),
41+
receivers: listToMap(receivers),
42+
exporters: listToMap(exporters),
43+
processors: listToMap(processors),
44+
extensions: listToMap(extensions),
45+
}
46+
}
47+
48+
func listToMap(list []string) map[string]bool {
49+
m := map[string]bool{}
50+
for _, v := range list {
51+
m[v] = true
52+
}
53+
return m
54+
}
55+
56+
// Check checks if a submitted components are back lister or not.
57+
func (fips FipsCheck) Check(receivers map[string]interface{}, exporters map[string]interface{}, processors map[string]interface{}, extensions map[string]interface{}) []string {
58+
if !fips.isFIPSEnabled {
59+
return nil
60+
}
61+
var disabled []string
62+
if comp := isBlackListed(fips.receivers, receivers); comp != "" {
63+
disabled = append(disabled, comp)
64+
}
65+
if comp := isBlackListed(fips.exporters, exporters); comp != "" {
66+
disabled = append(disabled, comp)
67+
}
68+
if comp := isBlackListed(fips.processors, processors); comp != "" {
69+
disabled = append(disabled, comp)
70+
}
71+
if comp := isBlackListed(fips.extensions, extensions); comp != "" {
72+
disabled = append(disabled, comp)
73+
}
74+
return disabled
75+
}
76+
77+
func isBlackListed(blackListed map[string]bool, cfg map[string]interface{}) string {
78+
for id, _ := range cfg {
79+
component := strings.Split(id, "/")[0]
80+
if blackListed[component] {
81+
return component
82+
}
83+
}
84+
return ""
85+
}
86+
87+
func isFipsEnabled() bool {
88+
// check if file exists
89+
if _, err := os.Stat(fipsFile); errors.Is(err, os.ErrNotExist) {
90+
fmt.Println("fips file doesn't exist")
91+
return false
92+
}
93+
content, err := os.ReadFile(fipsFile)
94+
if err != nil {
95+
// file cannot be read, enable FIPS to avoid any violations
96+
fmt.Println("cannot read fips file")
97+
return true
98+
}
99+
contentStr := string(content)
100+
contentStr = strings.TrimSpace(contentStr)
101+
return contentStr == "1"
102+
}

internal/fips/check_test.go

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright The OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package fips
16+
17+
import (
18+
"testing"
19+
20+
"github.com/stretchr/testify/assert"
21+
)
22+
23+
func TestFipsCheck(t *testing.T) {
24+
fipsCheck := NewFipsCheck([]string{"rec1", "rec2"}, []string{"exp1"}, []string{"processor"}, []string{"ext1"})
25+
assert.Equal(t, map[string]bool{"rec1": true, "rec2": true}, fipsCheck.receivers)
26+
assert.Equal(t, map[string]bool{"exp1": true}, fipsCheck.exporters)
27+
assert.Equal(t, map[string]bool{"processor": true}, fipsCheck.processors)
28+
assert.Equal(t, map[string]bool{"ext1": true}, fipsCheck.extensions)
29+
30+
// test machine probably does not have this enabled
31+
fipsCheck.isFIPSEnabled = true
32+
blocked := fipsCheck.Check(
33+
map[string]interface{}{"otlp": true, "rec1/my": true},
34+
map[string]interface{}{"exp1": true},
35+
map[string]interface{}{"processor": true},
36+
map[string]interface{}{"ext1": true})
37+
38+
assert.Equal(t, []string{"rec1", "exp1", "processor", "ext1"}, blocked)
39+
}

internal/webhook/podmutation/webhookhandler_suite_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"context"
1919
"crypto/tls"
2020
"fmt"
21+
"github.com/open-telemetry/opentelemetry-operator/internal/fips"
2122
"net"
2223
"os"
2324
"path/filepath"
@@ -105,7 +106,7 @@ func TestMain(m *testing.M) {
105106
}
106107
reviewer := rbac.NewReviewer(clientset)
107108

108-
if err = v1beta1.SetupCollectorWebhook(mgr, config.New(), reviewer, nil, nil); err != nil {
109+
if err = v1beta1.SetupCollectorWebhook(mgr, config.New(), reviewer, nil, nil, fips.NewFipsCheck(nil, nil, nil, nil)); err != nil {
109110
fmt.Printf("failed to SetupWebhookWithManager: %v", err)
110111
os.Exit(1)
111112
}

0 commit comments

Comments
 (0)