Skip to content

Commit

Permalink
Set Istiod env COMPLIANCE_POLICY when running on a FIPS enabled OpenS…
Browse files Browse the repository at this point in the history
…hift cluster (#619)

* Set Istiod env when running on FIPS enabled OpenShift cluster

Signed-off-by: Yuanlin Xu <[email protected]>

* review updates

Signed-off-by: Yuanlin Xu <[email protected]>

* review update test

Signed-off-by: Yuanlin Xu <[email protected]>

* fix filename typo

Signed-off-by: Yuanlin Xu <[email protected]>

* remove fmt line

Signed-off-by: Yuanlin Xu <[email protected]>

* optimization: detect FIPS at the start time

Signed-off-by: Yuanlin Xu <[email protected]>

* review update: refactor

Signed-off-by: Yuanlin Xu <[email protected]>

* review update: refactor

Signed-off-by: Yuanlin Xu <[email protected]>

* remove log line

Signed-off-by: Yuanlin Xu <[email protected]>

* fix lint error

Signed-off-by: Yuanlin Xu <[email protected]>

---------

Signed-off-by: Yuanlin Xu <[email protected]>
  • Loading branch information
yxun authored Feb 12, 2025
1 parent 72c1264 commit b88e3a8
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 0 deletions.
55 changes: 55 additions & 0 deletions pkg/istiovalues/fips.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright Istio Authors
//
// Licensed 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.

package istiovalues

import (
"fmt"
"os"
"strings"

"github.com/istio-ecosystem/sail-operator/pkg/helm"
)

var (
FipsEnabled bool
FipsEnableFilePath = "/proc/sys/crypto/fips_enabled"
)

// detectFipsMode checks if FIPS mode is enabled in the system.
func init() {
detectFipsMode(FipsEnableFilePath)
}

func detectFipsMode(filepath string) {
contents, err := os.ReadFile(filepath)
if err != nil {
FipsEnabled = false
} else {
fipsEnabled := strings.TrimSuffix(string(contents), "\n")
if fipsEnabled == "1" {
FipsEnabled = true
}
}
}

// ApplyFipsValues sets value pilot.env.COMPLIANCE_POLICY if FIPS mode is enabled in the system.
func ApplyFipsValues(values helm.Values) (helm.Values, error) {
if FipsEnabled {
if err := values.SetIfAbsent("pilot.env.COMPLIANCE_POLICY", "fips-140-2"); err != nil {
return nil, fmt.Errorf("failed to set pilot.env.COMPLIANCE_POLICY: %w", err)
}
}
return values, nil
}
103 changes: 103 additions & 0 deletions pkg/istiovalues/fips_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright Istio Authors
//
// Licensed 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.

package istiovalues

import (
"os"
"path"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/istio-ecosystem/sail-operator/pkg/helm"
)

func TestDetectFipsMode(t *testing.T) {
resourceDir := t.TempDir()
os.WriteFile(path.Join(resourceDir, "fips_enabled"), []byte(("1\n")), 0o644)
os.WriteFile(path.Join(resourceDir, "fips_not_enabled"), []byte(("0\n")), 0o644)
tests := []struct {
name string
filepath string
expectValue bool
}{
{
name: "FIPS not enabled",
filepath: path.Join(resourceDir, "fips_not_enabled"),
expectValue: false,
},
{
name: "FIPS enabled",
filepath: path.Join(resourceDir, "fips_enabled"),
expectValue: true,
},
{
name: "file not found",
filepath: path.Join(resourceDir, "fips_not_found"),
expectValue: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
detectFipsMode(tt.filepath)
actual := FipsEnabled

if diff := cmp.Diff(tt.expectValue, actual); diff != "" {
t.Errorf("FipsEnabled variable wasn't applied properly; diff (-expected, +actual):\n%v", diff)
}
})
}
}

func TestApplyFipsValues(t *testing.T) {
tests := []struct {
name string
fipsEnabled bool
expectValues helm.Values
expectErr bool
}{
{
name: "FIPS not enabled",
fipsEnabled: false,
expectValues: helm.Values{},
},
{
name: "FIPS enabled",
fipsEnabled: true,
expectValues: helm.Values{
"pilot": map[string]any{
"env": map[string]any{"COMPLIANCE_POLICY": string("fips-140-2")},
},
},
},
}

values := helm.Values{}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
FipsEnabled = tt.fipsEnabled
actual, err := ApplyFipsValues(values)
if (err != nil) != tt.expectErr {
t.Errorf("applyFipsValues() error = %v, expectErr %v", err, tt.expectErr)
}

if err == nil {
if diff := cmp.Diff(tt.expectValues, actual); diff != "" {
t.Errorf("COMPLIANCE_POLICY env wasn't applied properly; diff (-expected, +actual):\n%v", diff)
}
}
})
}
}
6 changes: 6 additions & 0 deletions pkg/revision/values.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ func ComputeValues(
return nil, fmt.Errorf("failed to apply profile: %w", err)
}

// apply FipsValues on top of mergedHelmValues from profile
mergedHelmValues, err = istiovalues.ApplyFipsValues(mergedHelmValues)
if err != nil {
return nil, fmt.Errorf("failed to apply FIPS values: %w", err)
}

values, err := helm.ToValues(mergedHelmValues, &v1.Values{})
if err != nil {
return nil, fmt.Errorf("conversion to Helm values failed: %w", err)
Expand Down
41 changes: 41 additions & 0 deletions pkg/revision/values_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (

v1 "github.com/istio-ecosystem/sail-operator/api/v1"
"github.com/istio-ecosystem/sail-operator/pkg/config"
"github.com/istio-ecosystem/sail-operator/pkg/istiovalues"

"istio.io/istio/pkg/ptr"
)
Expand Down Expand Up @@ -90,6 +91,46 @@ spec:
}
}

// TestFipsComputeValues tests that the pilot.env.COMPLIANCE_POLICY is set in values
func TestFipsComputeValues(t *testing.T) {
const (
namespace = "istio-system"
version = "my-version"
revisionName = "my-revision"
)
resourceDir := t.TempDir()
profilesDir := path.Join(resourceDir, version, "profiles")
Must(t, os.MkdirAll(profilesDir, 0o755))

Must(t, os.WriteFile(path.Join(profilesDir, "default.yaml"), []byte((`
apiVersion: sailoperator.io/v1
kind: IstioRevision
spec:`)), 0o644))

istiovalues.FipsEnabled = true
values := &v1.Values{}
result, err := ComputeValues(values, namespace, version, config.PlatformOpenShift, "default", "",
resourceDir, revisionName)
if err != nil {
t.Errorf("Expected no error, but got an error: %v", err)
}

expected := &v1.Values{
Pilot: &v1.PilotConfig{
Env: map[string]string{"COMPLIANCE_POLICY": "fips-140-2"},
},
Global: &v1.GlobalConfig{
Platform: ptr.Of("openshift"),
IstioNamespace: ptr.Of(namespace), // this value is always added/overridden based on IstioRevision.spec.namespace
},
Revision: ptr.Of(revisionName),
}

if !reflect.DeepEqual(result, expected) {
t.Errorf("Result does not match the expected Values.\nExpected: %v\nActual: %v", expected, result)
}
} // when checking a temp test file content.

func Must(t *testing.T, err error) {
t.Helper()
if err != nil {
Expand Down

0 comments on commit b88e3a8

Please sign in to comment.