Skip to content

Commit 5468832

Browse files
authored
fix for setting GODEBUG environment variable to fips140=on in a FIPS cluster (#1822)
* Added FIPS checker which sets the GODEBUG flag with appropriate fips140 value Signed-off-by: Anand Francis Joseph <[email protected]> * Fixed golint errors and warnings Signed-off-by: Anand Francis Joseph <[email protected]> * Fixed go lint errors in cmd/main.go Signed-off-by: Anand Francis Joseph <[email protected]> --------- Signed-off-by: Anand Francis Joseph <[email protected]>
1 parent f8fa0de commit 5468832

File tree

6 files changed

+354
-6
lines changed

6 files changed

+354
-6
lines changed

cmd/main.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import (
3838
"github.com/argoproj-labs/argocd-operator/common"
3939
"github.com/argoproj-labs/argocd-operator/controllers/argocd"
4040
"github.com/argoproj-labs/argocd-operator/controllers/argocdexport"
41+
"github.com/argoproj-labs/argocd-operator/controllers/argoutil"
4142

4243
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
4344

@@ -243,9 +244,10 @@ func main() {
243244
}
244245

245246
if err = (&argocd.ReconcileArgoCD{
246-
Client: mgr.GetClient(),
247-
Scheme: mgr.GetScheme(),
248-
LabelSelector: labelSelectorFlag,
247+
Client: mgr.GetClient(),
248+
Scheme: mgr.GetScheme(),
249+
LabelSelector: labelSelectorFlag,
250+
FipsConfigChecker: argoutil.NewLinuxFipsConfigChecker(),
249251
}).SetupWithManager(mgr); err != nil {
250252
setupLog.Error(err, "unable to create controller", "controller", "ArgoCD")
251253
os.Exit(1)

controllers/argocd/argocd_controller.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/prometheus/client_golang/prometheus"
2525

2626
argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1"
27+
"github.com/argoproj-labs/argocd-operator/controllers/argoutil"
2728

2829
corev1 "k8s.io/api/core/v1"
2930
"k8s.io/apimachinery/pkg/api/errors"
@@ -51,6 +52,8 @@ type ReconcileArgoCD struct {
5152
ManagedApplicationSetSourceNamespaces map[string]string
5253
// Stores label selector used to reconcile a subset of ArgoCD
5354
LabelSelector string
55+
// FipsConfigChecker checks if the deployment needs FIPS specific environment variables set.
56+
FipsConfigChecker argoutil.FipsConfigChecker
5457
}
5558

5659
var log = logr.Log.WithName("controller_argocd")
@@ -99,9 +102,9 @@ func (r *ReconcileArgoCD) Reconcile(ctx context.Context, request ctrl.Request) (
99102
message = err.Error()
100103
}
101104

102-
if error := updateStatusConditionOfArgoCD(ctx, createCondition(message), argocd, r.Client, log); error != nil {
103-
log.Error(error, "unable to update status of ArgoCD")
104-
return reconcile.Result{}, error
105+
if err := updateStatusConditionOfArgoCD(ctx, createCondition(message), argocd, r.Client, log); err != nil {
106+
log.Error(err, "unable to update status of ArgoCD")
107+
return reconcile.Result{}, err
105108
}
106109

107110
return result, err

controllers/argocd/deployment.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,21 @@ func (r *ReconcileArgoCD) reconcileRepoDeployment(cr *argoproj.ArgoCD, useTLSFor
982982
repoEnv = argoutil.EnvMerge(repoEnv, []corev1.EnvVar{{Name: "ARGOCD_EXEC_TIMEOUT", Value: fmt.Sprintf("%ds", *cr.Spec.Repo.ExecTimeout)}}, true)
983983
}
984984

985+
// if running in a FIPS enabled host, set the GODEBUG env wit appropriate value
986+
fipsConfigChecker := r.FipsConfigChecker
987+
if fipsConfigChecker != nil {
988+
fipsEnabled, err := fipsConfigChecker.IsFipsEnabled()
989+
if err != nil {
990+
return err
991+
}
992+
if fipsEnabled {
993+
repoEnv = append(repoEnv, corev1.EnvVar{
994+
Name: "GODEBUG",
995+
Value: "fips140=on",
996+
})
997+
}
998+
}
999+
9851000
AddSeccompProfileForOpenShift(r.Client, &deploy.Spec.Template.Spec)
9861001

9871002
deploy.Spec.Template.Spec.InitContainers = []corev1.Container{{

controllers/argocd/deployment_test.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,18 @@ var (
4141
"argocd-server"}
4242
)
4343

44+
type MockTrueFipsChecker struct{}
45+
46+
func (a *MockTrueFipsChecker) IsFipsEnabled() (bool, error) {
47+
return true, nil
48+
}
49+
50+
type MockFalseFipsChecker struct{}
51+
52+
func (a *MockFalseFipsChecker) IsFipsEnabled() (bool, error) {
53+
return false, nil
54+
}
55+
4456
func TestReconcileArgoCD_reconcileRepoDeployment_replicas(t *testing.T) {
4557
logf.SetLogger(ZapLogger(true))
4658

@@ -2875,3 +2887,72 @@ func TestSetReplicasAndEnvVar_WhenServerReplicasIsDefined(t *testing.T) {
28752887
})
28762888

28772889
}
2890+
2891+
func TestReconcileArgoCD_reconcileRepoServerWithFipsEnabled(t *testing.T) {
2892+
cr := makeTestArgoCD()
2893+
2894+
resObjs := []client.Object{cr}
2895+
subresObjs := []client.Object{cr}
2896+
runtimeObjs := []runtime.Object{}
2897+
sch := makeTestReconcilerScheme(argoproj.AddToScheme)
2898+
cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
2899+
r := makeTestReconciler(cl, sch)
2900+
r.FipsConfigChecker = &MockTrueFipsChecker{}
2901+
repoServerRemote := "https://remote.repo-server.instance"
2902+
2903+
cr.Spec.Repo.Remote = &repoServerRemote
2904+
assert.NoError(t, r.reconcileRepoDeployment(cr, false))
2905+
2906+
d := &appsv1.Deployment{}
2907+
2908+
assert.ErrorContains(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: cr.Name + "-repo-server", Namespace: cr.Namespace}, d),
2909+
"deployments.apps \""+cr.Name+"-repo-server\" not found")
2910+
2911+
// once remote is set to nil, reconciliation should trigger deployment resource creation
2912+
cr.Spec.Repo.Remote = nil
2913+
2914+
assert.NoError(t, r.reconcileRepoDeployment(cr, false))
2915+
assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: cr.Name + "-repo-server", Namespace: cr.Namespace}, d))
2916+
foundEnv := false
2917+
for _, env := range d.Spec.Template.Spec.Containers[0].Env {
2918+
if env.Name == "GODEBUG" {
2919+
foundEnv = true
2920+
assert.Equal(t, env.Value, "fips140=on", "GODEBUG environment must be set to fips140=on when fips is enabled")
2921+
}
2922+
}
2923+
assert.True(t, foundEnv, "environment GODEBUG must be set when FIPS is enabled")
2924+
}
2925+
2926+
func TestReconcileArgoCD_reconcileRepoServerWithFipsDisabled(t *testing.T) {
2927+
cr := makeTestArgoCD()
2928+
2929+
resObjs := []client.Object{cr}
2930+
subresObjs := []client.Object{cr}
2931+
runtimeObjs := []runtime.Object{}
2932+
sch := makeTestReconcilerScheme(argoproj.AddToScheme)
2933+
cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
2934+
r := makeTestReconciler(cl, sch)
2935+
r.FipsConfigChecker = &MockFalseFipsChecker{}
2936+
repoServerRemote := "https://remote.repo-server.instance"
2937+
2938+
cr.Spec.Repo.Remote = &repoServerRemote
2939+
assert.NoError(t, r.reconcileRepoDeployment(cr, false))
2940+
2941+
d := &appsv1.Deployment{}
2942+
2943+
assert.ErrorContains(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: cr.Name + "-repo-server", Namespace: cr.Namespace}, d),
2944+
"deployments.apps \""+cr.Name+"-repo-server\" not found")
2945+
2946+
// once remote is set to nil, reconciliation should trigger deployment resource creation
2947+
cr.Spec.Repo.Remote = nil
2948+
2949+
assert.NoError(t, r.reconcileRepoDeployment(cr, false))
2950+
assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: cr.Name + "-repo-server", Namespace: cr.Namespace}, d))
2951+
foundEnv := false
2952+
for _, env := range d.Spec.Template.Spec.Containers[0].Env {
2953+
if env.Name == "GODEBUG" {
2954+
foundEnv = true
2955+
}
2956+
}
2957+
assert.False(t, foundEnv, "environment GODEBUG must NOT be set when FIPS is disabled")
2958+
}

controllers/argoutil/fips.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package argoutil
2+
3+
import (
4+
"os"
5+
)
6+
7+
// FipsConfigChecker defines the behavior for reading the FIPS config.
8+
type FipsConfigChecker interface {
9+
IsFipsEnabled() (bool, error)
10+
}
11+
12+
// LinuxFipsConfigChecker implements the config reader for checking if the Linux based host is running in FIPS enabled mode.
13+
type LinuxFipsConfigChecker struct {
14+
ConfigFilePath string
15+
}
16+
17+
// NewLinuxFipsConfigChecker returns a Linux based config checker
18+
func NewLinuxFipsConfigChecker() *LinuxFipsConfigChecker {
19+
return &LinuxFipsConfigChecker{
20+
ConfigFilePath: "/proc/sys/crypto/fips_enabled",
21+
}
22+
}
23+
24+
// IsFipsEnabled reads the specified FIPS config file in a Linux based host and returns true FIPS is enabled, false otherwise.
25+
func (l *LinuxFipsConfigChecker) IsFipsEnabled() (bool, error) {
26+
found, err := fileExists(l.ConfigFilePath)
27+
if err != nil {
28+
return false, err
29+
}
30+
if !found {
31+
return false, nil
32+
}
33+
b, err := os.ReadFile(l.ConfigFilePath)
34+
if err != nil {
35+
return false, err
36+
}
37+
return b[0] == '1', err
38+
}
39+
40+
// fileExists checks if a file with the given path exists
41+
func fileExists(path string) (bool, error) {
42+
info, err := os.Stat(path)
43+
if err != nil {
44+
if os.IsNotExist(err) {
45+
return false, nil
46+
}
47+
return false, err
48+
}
49+
return !info.IsDir(), nil
50+
}

0 commit comments

Comments
 (0)