Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions cmd/export/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,12 +218,18 @@ func (c *ClusterScopedRbacHandler) acceptSecurityContextConstraints(clusterResou

if crb.RoleRef.Kind == "SecurityContextConstraints" && crb.RoleRef.Name == scc.Name {
c.log.Infof("Accepted %s of kind %s", clusterResource.GetName(), clusterResource.GetKind())
c.log.Warnf("WARNING: SecurityContextConstraints '%s' requires elevated privileges on the destination cluster. "+
"Ensure you have access to appropriate SCCs when applying to the target environment, especially when migrating to OpenShift.",
clusterResource.GetName())
return true
} else {
sccSystemName := fmt.Sprintf("system:openshift:scc:%s", clusterResource.GetName())
if crb.RoleRef.Kind == "ClusterRole" && crb.RoleRef.Name == sccSystemName {
c.log.Infof("Accepted %s of kind %s (match via ClusterRoleBinding %s)",
clusterResource.GetName(), clusterResource.GetKind(), crb.Name)
c.log.Warnf("WARNING: SecurityContextConstraints '%s' requires elevated privileges on the destination cluster. "+
"Ensure you have access to appropriate SCCs when applying to the target environment, especially when migrating to OpenShift.",
clusterResource.GetName())
return true
}
}
Expand All @@ -237,6 +243,9 @@ func (c *ClusterScopedRbacHandler) acceptSecurityContextConstraints(clusterResou
if c.anyServiceAccountInNamespace(namespaceName, serviceAccountName) {
c.log.Infof("Accepted %s of kind %s (match wia user %s)",
clusterResource.GetName(), clusterResource.GetKind(), u)
c.log.Warnf("WARNING: SecurityContextConstraints '%s' requires elevated privileges on the destination cluster. "+
"Ensure you have access to appropriate SCCs when applying to the target environment, especially when migrating to OpenShift.",
clusterResource.GetName())
return true
}
}
Expand Down
138 changes: 138 additions & 0 deletions cmd/export/cluster_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package export

import (
"bytes"
"strings"
"testing"

securityv1 "github.com/openshift/api/security/v1"
"github.com/sirupsen/logrus"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
)

func TestSecurityContextConstraintsWarning(t *testing.T) {
// Create a test logger that captures output
var logOutput bytes.Buffer
logger := logrus.New()
logger.SetOutput(&logOutput)
logger.SetLevel(logrus.InfoLevel) // Set to Info to capture both info and warning messages

// Create a test SecurityContextConstraints
scc := &securityv1.SecurityContextConstraints{
TypeMeta: metav1.TypeMeta{
APIVersion: "security.openshift.io/v1",
Kind: "SecurityContextConstraints",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test-scc",
},
Users: []string{"system:serviceaccount:test-namespace:test-sa"},
}

// Convert to unstructured
sccObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(scc)
if err != nil {
t.Fatalf("Failed to convert SCC to unstructured: %v", err)
}

sccUnstructured := &unstructured.Unstructured{Object: sccObj}
sccUnstructured.SetGroupVersionKind(securityv1.GroupVersion.WithKind("SecurityContextConstraints"))

// Create a test service account
saObj := &unstructured.Unstructured{}
saObj.SetAPIVersion("v1")
saObj.SetKind("ServiceAccount")
saObj.SetName("test-sa")
saObj.SetNamespace("test-namespace")

// Create handler with test logger
handler := NewClusterScopedRbacHandler(logger)
handler.serviceAccounts = []unstructured.Unstructured{*saObj}
handler.filteredClusterRoleBindings = &groupResource{
objects: &unstructured.UnstructuredList{Items: []unstructured.Unstructured{}},
}

// Test the acceptance function
result := handler.acceptSecurityContextConstraints(*sccUnstructured)

// Check that the function returns true (SCC is accepted)
if !result {
t.Errorf("Expected acceptSecurityContextConstraints to return true, got false")
}

// Check that warning message is logged
logContents := logOutput.String()
t.Logf("Log output: %s", logContents) // Show the actual log output for verification

if !strings.Contains(logContents, "WARNING: SecurityContextConstraints 'test-scc' requires elevated privileges") {
t.Errorf("Expected warning message about SecurityContextConstraints privileges, got: %s", logContents)
}

// Check that the warning mentions destination cluster and OpenShift
if !strings.Contains(logContents, "destination cluster") {
t.Errorf("Expected warning to mention 'destination cluster', got: %s", logContents)
}

if !strings.Contains(logContents, "OpenShift") {
t.Errorf("Expected warning to mention 'OpenShift', got: %s", logContents)
}
}

func TestSecurityContextConstraintsNoWarningWhenNotAccepted(t *testing.T) {
// Create a test logger that captures output
var logOutput bytes.Buffer
logger := logrus.New()
logger.SetOutput(&logOutput)
logger.SetLevel(logrus.WarnLevel)

// Create a test SecurityContextConstraints that won't be accepted
scc := &securityv1.SecurityContextConstraints{
TypeMeta: metav1.TypeMeta{
APIVersion: "security.openshift.io/v1",
Kind: "SecurityContextConstraints",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test-scc",
},
Users: []string{"system:serviceaccount:other-namespace:other-sa"},
}

// Convert to unstructured
sccObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(scc)
if err != nil {
t.Fatalf("Failed to convert SCC to unstructured: %v", err)
}

sccUnstructured := &unstructured.Unstructured{Object: sccObj}
sccUnstructured.SetGroupVersionKind(securityv1.GroupVersion.WithKind("SecurityContextConstraints"))

// Create a test service account with different name/namespace
saObj := &unstructured.Unstructured{}
saObj.SetAPIVersion("v1")
saObj.SetKind("ServiceAccount")
saObj.SetName("test-sa")
saObj.SetNamespace("test-namespace")

// Create handler with test logger
handler := NewClusterScopedRbacHandler(logger)
handler.serviceAccounts = []unstructured.Unstructured{*saObj}
handler.filteredClusterRoleBindings = &groupResource{
objects: &unstructured.UnstructuredList{Items: []unstructured.Unstructured{}},
}

// Test the acceptance function
result := handler.acceptSecurityContextConstraints(*sccUnstructured)

// Check that the function returns false (SCC is not accepted)
if result {
t.Errorf("Expected acceptSecurityContextConstraints to return false, got true")
}

// Check that no warning message is logged since SCC was not accepted
logContents := logOutput.String()
if strings.Contains(logContents, "WARNING: SecurityContextConstraints") {
t.Errorf("Expected no warning message when SCC is not accepted, but got: %s", logContents)
}
}