Skip to content

Commit

Permalink
deploy bpfman-restricted scc with operator
Browse files Browse the repository at this point in the history
As part of our default deployment in openshift we
need to deploy a custom SCC which can be used
by applications in order to receive access to their
eBPF maps without running as root.

Signed-off-by: Andrew Stoycos <astoycos@redhat.com>
  • Loading branch information
astoycos committed Jun 6, 2024
1 parent 93bfa93 commit bc7ea8e
Show file tree
Hide file tree
Showing 22 changed files with 7,369 additions and 22 deletions.
1 change: 1 addition & 0 deletions Containerfile.bpfman-operator
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ ARG TARGETARCH
WORKDIR /
COPY --from=bpfman-operator-build /usr/src/bpfman-operator/config/bpfman-deployment/daemonset.yaml ./config/bpfman-deployment/daemonset.yaml
COPY --from=bpfman-operator-build /usr/src/bpfman-operator/config/bpfman-deployment/csidriverinfo.yaml ./config/bpfman-deployment/csidriverinfo.yaml
COPY --from=bpfman-operator-build /usr/src/bpfman-operator/config/bpfman-deployment/csidriverinfo.yaml ./config/openshift/restricted-scc.yaml
COPY --from=bpfman-operator-build /usr/src/bpfman-operator/bpfman-operator .
USER 65532:65532

Expand Down
43 changes: 43 additions & 0 deletions cmd/bpfman-operator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ import (
"go.uber.org/zap/zapcore"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/discovery"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
_ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/client-go/rest"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
Expand All @@ -49,6 +51,31 @@ func init() {
//+kubebuilder:scaffold:scheme
}

func getPlatformInfo(client discovery.DiscoveryInterface, cfg *rest.Config) (bool, error) {
k8sVersion, err := client.ServerVersion()
if err != nil {
setupLog.Info("issue occurred while fetching ServerVersion")
return false, err

Check warning on line 58 in cmd/bpfman-operator/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/bpfman-operator/main.go#L54-L58

Added lines #L54 - L58 were not covered by tests
}

setupLog.Info("detected platform version", "PlatformVersion", k8sVersion)

Check warning on line 61 in cmd/bpfman-operator/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/bpfman-operator/main.go#L61

Added line #L61 was not covered by tests

apiList, err := client.ServerGroups()
if err != nil {
setupLog.Info("issue occurred while fetching ServerGroups")
return false, err

Check warning on line 66 in cmd/bpfman-operator/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/bpfman-operator/main.go#L63-L66

Added lines #L63 - L66 were not covered by tests
}

for _, v := range apiList.Groups {
if v.Name == "route.openshift.io" {

Check warning on line 70 in cmd/bpfman-operator/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/bpfman-operator/main.go#L69-L70

Added lines #L69 - L70 were not covered by tests

setupLog.Info("route.openshift.io found in apis, platform is OpenShift")
return true, nil

Check warning on line 73 in cmd/bpfman-operator/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/bpfman-operator/main.go#L72-L73

Added lines #L72 - L73 were not covered by tests
}
}
return false, nil

Check warning on line 76 in cmd/bpfman-operator/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/bpfman-operator/main.go#L76

Added line #L76 was not covered by tests
}

func main() {
var metricsAddr string
var enableLeaderElection bool
Expand Down Expand Up @@ -129,10 +156,26 @@ func main() {
Scheme: mgr.GetScheme(),
}

setupLog.Info("Discovering APIs")
dc, err := discovery.NewDiscoveryClientForConfig(mgr.GetConfig())
if err != nil {
setupLog.Error(err, "can't instantiate discovery client")
os.Exit(1)

Check warning on line 163 in cmd/bpfman-operator/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/bpfman-operator/main.go#L159-L163

Added lines #L159 - L163 were not covered by tests
}

isOpenshift, err := getPlatformInfo(dc, mgr.GetConfig())
if err != nil {
setupLog.Error(err, "unable to determine platform")
os.Exit(1)

Check warning on line 169 in cmd/bpfman-operator/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/bpfman-operator/main.go#L166-L169

Added lines #L166 - L169 were not covered by tests

}

if err = (&bpfmanoperator.BpfmanConfigReconciler{
ReconcilerCommon: common,
BpfmanStandardDeployment: internal.BpfmanDaemonManifestPath,
CsiDriverDeployment: internal.BpfmanCsiDriverPath,
RestrictedSCC: internal.BpfmanRestrictedSCCPath,
IsOpenshift: isOpenshift,

Check warning on line 178 in cmd/bpfman-operator/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/bpfman-operator/main.go#L177-L178

Added lines #L177 - L178 were not covered by tests
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create bpfmanCofig controller", "controller", "BpfProgram")
os.Exit(1)
Expand Down
14 changes: 14 additions & 0 deletions config/openshift/rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,17 @@ subjects:
- kind: ServiceAccount
name: bpfman-daemon
namespace: bpfman
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: user
rules:
- apiGroups:
- security.openshift.io
resourceNames:
- bpfman-restricted
resources:
- securitycontextconstraints
verbs:
- use
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
---
## This is part of the payload deployed by the bpfman-operator NOT kustomize.
apiVersion: security.openshift.io/v1
kind: SecurityContextConstraints
metadata:
name: restricted
name: bpfman-restricted
allowHostDirVolumePlugin: false
allowHostIPC: false
allowHostNetwork: false
Expand Down Expand Up @@ -35,18 +35,4 @@ volumes:
- persistentVolumeClaim
- projected
- secret
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: user
rules:
- apiGroups:
- security.openshift.io
resourceNames:
- bpfman-restricted
resources:
- securitycontextconstraints
verbs:
- use
---

10 changes: 10 additions & 0 deletions config/rbac/bpfman-operator/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,16 @@ rules:
- get
- list
- watch
- apiGroups:
- security.openshift.io
resources:
- securitycontextconstraints
verbs:
- create
- delete
- get
- list
- watch
- apiGroups:
- storage.k8s.io
resources:
Expand Down
50 changes: 45 additions & 5 deletions controllers/bpfman-operator/configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/predicate"

osv1 "github.com/openshift/api/security/v1"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/log"
Expand All @@ -43,12 +44,15 @@ import (
// +kubebuilder:rbac:groups=apps,resources=daemonsets,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=core,resources=configmaps,verbs=get;list;watch;create
// +kubebuilder:rbac:groups=storage.k8s.io,resources=csidrivers,verbs=get;list;watch;create;delete
// +kubebuilder:rbac:groups=security.openshift.io,resources=securitycontextconstraints,verbs=get;list;watch;create;delete
// +kubebuilder:rbac:groups=bpfman.io,resources=configmaps/finalizers,verbs=update

type BpfmanConfigReconciler struct {
ReconcilerCommon
BpfmanStandardDeployment string
CsiDriverDeployment string
RestrictedSCC string
IsOpenshift bool
}

// SetupWithManager sets up the controller with the Manager.
Expand Down Expand Up @@ -91,10 +95,6 @@ func (r *BpfmanConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request
}

func (r *BpfmanConfigReconciler) ReconcileBpfmanConfig(ctx context.Context, req ctrl.Request, bpfmanConfig *corev1.ConfigMap) (ctrl.Result, error) {
bpfmanDeployment := &appsv1.DaemonSet{}

staticBpfmanDeployment := LoadAndConfigureBpfmanDs(bpfmanConfig, r.BpfmanStandardDeployment)
r.Logger.V(1).Info("StaticBpfmanDeployment with CSI", "DS", staticBpfmanDeployment)
bpfmanCsiDriver := &storagev1.CSIDriver{}
// one-shot try to create bpfman's CSIDriver object if it doesn't exist, does not re-trigger reconcile.
if err := r.Get(ctx, types.NamespacedName{Namespace: corev1.NamespaceAll, Name: internal.BpfmanCsiDriverName}, bpfmanCsiDriver); err != nil {
Expand All @@ -109,6 +109,26 @@ func (r *BpfmanConfigReconciler) ReconcileBpfmanConfig(ctx context.Context, req
}
}

if r.IsOpenshift {
bpfmanRestrictedSCC := &osv1.SecurityContextConstraints{}

Check warning on line 113 in controllers/bpfman-operator/configmap.go

View check run for this annotation

Codecov / codecov/patch

controllers/bpfman-operator/configmap.go#L113

Added line #L113 was not covered by tests
// one-shot try to create the bpfman-restricted SCC if it doesn't exist, does not re-trigger reconcile.
if err := r.Get(ctx, types.NamespacedName{Namespace: corev1.NamespaceAll, Name: internal.BpfmanRestrictedSccName}, bpfmanRestrictedSCC); err != nil {
if errors.IsNotFound(err) {
bpfmanRestrictedSCC = LoadRestrictedSecurityContext(r.RestrictedSCC)

Check warning on line 117 in controllers/bpfman-operator/configmap.go

View check run for this annotation

Codecov / codecov/patch

controllers/bpfman-operator/configmap.go#L115-L117

Added lines #L115 - L117 were not covered by tests

r.Logger.Info("Creating Bpfman restricted scc object for unprivileged users to bind to")
if err := r.Create(ctx, bpfmanRestrictedSCC); err != nil {
r.Logger.Error(err, "Failed to create Bpfman restricted scc")
return ctrl.Result{Requeue: true, RequeueAfter: retryDurationOperator}, nil

Check warning on line 122 in controllers/bpfman-operator/configmap.go

View check run for this annotation

Codecov / codecov/patch

controllers/bpfman-operator/configmap.go#L119-L122

Added lines #L119 - L122 were not covered by tests
}
}
}
}

bpfmanDeployment := &appsv1.DaemonSet{}
staticBpfmanDeployment := LoadAndConfigureBpfmanDs(bpfmanConfig, r.BpfmanStandardDeployment)
r.Logger.V(1).Info("StaticBpfmanDeployment with CSI", "DS", staticBpfmanDeployment)
// one-shot try to create the bpfman-restricted SCC if it doesn't exist, does not re-trigger reconcile.
if err := r.Get(ctx, types.NamespacedName{Namespace: bpfmanConfig.Namespace, Name: internal.BpfmanDsName}, bpfmanDeployment); err != nil {
if errors.IsNotFound(err) {
r.Logger.Info("Creating Bpfman Daemon")
Expand Down Expand Up @@ -209,8 +229,28 @@ func bpfmanConfigPredicate() predicate.Funcs {
}
}

// LoadRestrictedSecurityContext loads the bpfman-restricted SCC from disk which
// users can bind to in order to utilize bpfman in an unprivileged way.
func LoadRestrictedSecurityContext(path string) *osv1.SecurityContextConstraints {

Check warning on line 234 in controllers/bpfman-operator/configmap.go

View check run for this annotation

Codecov / codecov/patch

controllers/bpfman-operator/configmap.go#L234

Added line #L234 was not covered by tests
// Load static SCC yaml from disk
file, err := os.Open(path)
if err != nil {
panic(err)

Check warning on line 238 in controllers/bpfman-operator/configmap.go

View check run for this annotation

Codecov / codecov/patch

controllers/bpfman-operator/configmap.go#L236-L238

Added lines #L236 - L238 were not covered by tests
}

b, err := io.ReadAll(file)
if err != nil {
panic(err)

Check warning on line 243 in controllers/bpfman-operator/configmap.go

View check run for this annotation

Codecov / codecov/patch

controllers/bpfman-operator/configmap.go#L241-L243

Added lines #L241 - L243 were not covered by tests
}

decode := scheme.Codecs.UniversalDeserializer().Decode
obj, _, _ := decode(b, nil, nil)

Check warning on line 247 in controllers/bpfman-operator/configmap.go

View check run for this annotation

Codecov / codecov/patch

controllers/bpfman-operator/configmap.go#L246-L247

Added lines #L246 - L247 were not covered by tests

return obj.(*osv1.SecurityContextConstraints)

Check warning on line 249 in controllers/bpfman-operator/configmap.go

View check run for this annotation

Codecov / codecov/patch

controllers/bpfman-operator/configmap.go#L249

Added line #L249 was not covered by tests
}

func LoadCsiDriver(path string) *storagev1.CSIDriver {
// Load static bpfman deployment from disk
// Load static CSIDriver yaml from disk
file, err := os.Open(path)
if err != nil {
panic(err)
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/go-logr/logr v1.4.2
github.com/google/go-cmp v0.6.0
github.com/kong/kubernetes-testing-framework v0.47.0
github.com/openshift/api v0.0.0-20240605201059-cefcda60d938
github.com/stretchr/testify v1.9.0
go.uber.org/zap v1.27.0
google.golang.org/grpc v1.64.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk=
github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/openshift/api v0.0.0-20240605201059-cefcda60d938 h1:3Y0E8q6pFb8PgzW0N52jVZBollMeW1kI13iU/vXPCnc=
github.com/openshift/api v0.0.0-20240605201059-cefcda60d938/go.mod h1:OOh6Qopf21pSzqNVCB5gomomBXb8o5sGKZxG2KNpaXM=
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
Expand Down
2 changes: 2 additions & 0 deletions internal/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@ const (
BpfmanDsName = "bpfman-daemon"
BpfmanConfigName = "bpfman-config"
BpfmanCsiDriverName = "csi.bpfman.io"
BpfmanRestrictedSccName = "bpfman-restricted"
BpfmanContainerName = "bpfman"
BpfmanAgentContainerName = "bpfman-agent"
BpfmanDaemonManifestPath = "./config/bpfman-deployment/daemonset.yaml"
BpfmanCsiDriverPath = "./config/bpfman-deployment/csidriverinfo.yaml"
BpfmanRestrictedSCCPath = "./config/bpfman-deployment/restricted-scc.yaml"
BpfmanMapFs = "/run/bpfman/fs/maps"
DefaultType = "tcp"
DefaultPath = "/run/bpfman-sock/bpfman.sock"
Expand Down
Loading

0 comments on commit bc7ea8e

Please sign in to comment.