Skip to content
Merged
4 changes: 4 additions & 0 deletions filebeat/beater/crawler.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ func (c *crawler) startInput(
inputRunner.Once = c.once
}

if err := checkFIPSCapability(runner); err != nil {
return err
}

c.inputs[id] = runner

c.log.Infof("Starting input (ID: %d)", id)
Expand Down
43 changes: 43 additions & 0 deletions filebeat/beater/crawler_fips.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

//go:build requirefips

package beater

import (
"fmt"

v2 "github.com/elastic/beats/v7/filebeat/input/v2"
"github.com/elastic/beats/v7/libbeat/cfgfile"
)

func checkFIPSCapability(runner cfgfile.Runner) error {
fipsAwareInput, ok := runner.(v2.FIPSAwareInput)
if !ok {
// Input is not FIPS-aware; assume it's FIPS capable and proceed
// without error
return nil
}

if fipsAwareInput.IsFIPSCapable() {
// Input is FIPS-capable, proceed without error
return nil
}

return fmt.Errorf("running a FIPS-capable distribution but input [%s] is not FIPS capable", runner.String())
}
74 changes: 74 additions & 0 deletions filebeat/beater/crawler_fips_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

//go:build requirefips

package beater

import (
"github.com/elastic/beats/v7/libbeat/cfgfile"
"github.com/stretchr/testify/require"
"testing"
)

type fipsUnawareInput struct{}

func newFIPSUnawareInput() *fipsUnawareInput { return &fipsUnawareInput{} }
func (f *fipsUnawareInput) String() string { return "fips_unaware_input" }
func (f *fipsUnawareInput) Start() {}
func (f *fipsUnawareInput) Stop() {}

type fipsAwareInput struct{ isFIPSCapable bool }

func newFIPSAwareInput(isFIPSCapable bool) *fipsAwareInput {
return &fipsAwareInput{isFIPSCapable: isFIPSCapable}
}
func (f *fipsAwareInput) String() string { return "fips_aware_input" }
func (f *fipsAwareInput) Start() {}
func (f *fipsAwareInput) Stop() {}
func (f *fipsAwareInput) IsFIPSCapable() bool { return f.isFIPSCapable }

func TestCheckFIPSCapability(t *testing.T) {
tests := map[string]struct {
runner cfgfile.Runner
expectedErr string
}{
"input_is_not_fips_aware": {
runner: newFIPSUnawareInput(),
expectedErr: "",
},
"input_is_fips_aware_but_not_fips_capable": {
runner: newFIPSAwareInput(false),
expectedErr: "running a FIPS-capable distribution but input [fips_aware_input] is not FIPS capable",
},
"input_is_fips_aware_and_fips_capable": {
runner: newFIPSAwareInput(true),
expectedErr: "",
},
}

for name, test := range tests {
t.Run(name, func(t *testing.T) {
err := checkFIPSCapability(test.runner)
if test.expectedErr == "" {
require.NoError(t, err)
} else {
require.EqualError(t, err, test.expectedErr)
}
})
}
}
28 changes: 28 additions & 0 deletions filebeat/beater/crawler_nofips.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

//go:build !requirefips

package beater

import "github.com/elastic/beats/v7/libbeat/cfgfile"

func checkFIPSCapability(_ cfgfile.Runner) error {
// In non-FIPS builds, we assume all inputs are FIPS capable
// and proceed without error
return nil
}
11 changes: 11 additions & 0 deletions filebeat/input/v2/compat/compat.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,3 +229,14 @@ func (f *factory) generateCheckConfig(config *conf.C) (*conf.C, error) {

return testCfg, nil
}

// IsFIPSCapable returns true if the input is capable of running with
// FIPS-compliant algorithms; false, otherwise.
func (r *runner) IsFIPSCapable() bool {
if fipsAwareInput, ok := r.input.(v2.FIPSAwareInput); ok {
return fipsAwareInput.IsFIPSCapable()
}

// Input does not implement FIPSAwareInput, assume it is FIPS-capable
return true
}
9 changes: 9 additions & 0 deletions filebeat/input/v2/input-cursor/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,15 @@
return nil
}

// IsFIPSCapable returns true if the input is capable of running with
// FIPS-compliant algorithms; false, otherwise.
func (inp *managedInput) IsFIPSCapable() bool {
if fipsAware, ok := inp.input.(input.FIPSAwareInput); ok {
return fipsAware.IsFIPSCapable()
}
return true
}

func (inp *managedInput) testSource(ctx input.TestContext, source Source) (err error) {
defer func() {
if v := recover(); v != nil {
Expand Down Expand Up @@ -224,6 +233,6 @@
if n == 0 {
return
}
private[last].(*updateOp).Execute(n)

Check failure on line 236 in filebeat/input/v2/input-cursor/input.go

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

Error return value is not checked (errcheck)

Check failure on line 236 in filebeat/input/v2/input-cursor/input.go

View workflow job for this annotation

GitHub Actions / lint (macos-latest)

Error return value is not checked (errcheck)
})
}
8 changes: 8 additions & 0 deletions filebeat/input/v2/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ type Input interface {
Run(Context, beat.PipelineConnector) error
}

// FIPSAwareInput is able to report if it is FIPS capable or not. If a type does
// not implement this interface, that type will be considered to be FIPS capable.
type FIPSAwareInput interface {
// IsFIPSCapable returns true if the input is capable of running with
// FIPS-compliant algorithms; false, otherwise.
IsFIPSCapable() bool
}

// Context provides the Input Run function with common environmental
// information and services.
type Context struct {
Expand Down
9 changes: 9 additions & 0 deletions x-pack/filebeat/input/o365audit/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,17 @@

func (inp *o365input) Name() string { return pluginName }

// IsFIPSCapable returns false because the o365 input indirectly does
// not use FIPS-compliant algorithms. Specifically, the input depends on
// the github.com/Azure/azure-sdk-for-go/sdk/azidentity package which, in
// turn, depends on the golang.org/x/crypto/pkcs12 package, which is not
// FIPS-compliant
func (inp *o365input) IsFIPSCapable() bool {
return false
}

func (inp *o365input) Test(src cursor.Source, ctx v2.TestContext) error {
tenantID := src.(*stream).tenantID

Check failure on line 106 in x-pack/filebeat/input/o365audit/input.go

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

Error return value is not checked (errcheck)

Check failure on line 106 in x-pack/filebeat/input/o365audit/input.go

View workflow job for this annotation

GitHub Actions / lint (macos-latest)

Error return value is not checked (errcheck)
auth, err := inp.config.NewTokenProvider(tenantID)
if err != nil {
return err
Expand Down
Loading