Skip to content

Commit

Permalink
Auto-select selinuxd image based on nodeInfo.OSImage
Browse files Browse the repository at this point in the history
Cluster nodes might be upgraded between major OS releases where the
libselinux major version is incompatible. This means that the selinuxd
image must be based on images matching the OS release and the libselinux
major version.

But SPO must also be able to select the images based on what OS are the
cluster nodes running.

To implement that, this patch adds a new key to the
security-profiles-operator-profile configmap that maps regexes matching
nodeInfo.OSImage to selinuxd images. The operator then selects the right
selinuxd image, falling back to using the RELATED_IMAGE environment
variable.
  • Loading branch information
jhrozek committed Apr 4, 2023
1 parent 7175fb7 commit 0990e44
Show file tree
Hide file tree
Showing 16 changed files with 304 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,17 @@ data:
}
]
}
selinuxd-image-mapping.json: |
[
{
"regex":"(.*)(CoreOS).*([\\d+])\\.8[\\d+]\\.(.*)",
"image":"quay.io/security-profiles-operator/selinuxd-el8:latest"
},
{
"regex":"(.*)(CoreOS).*([\\d+])\\.9[\\d+]\\.(.*)",
"image":"quay.io/security-profiles-operator/selinuxd-el9:latest"
}
]
selinuxd.cil: |
(block selinuxd
(blockinherit container)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,14 @@ spec:
spec:
clusterPermissions:
- rules:
- apiGroups:
- ""
resourceNames:
- security-profiles-operator-profile
resources:
- configmaps
verbs:
- get
- apiGroups:
- ""
resources:
Expand Down
1 change: 1 addition & 0 deletions deploy/base/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ configMapGenerator:
- profiles/security-profiles-operator.json
- profiles/selinuxd.cil
- profiles/selinuxrecording.cil
- profiles/selinuxd-image-mapping.json
name: security-profiles-operator-profile

generatorOptions:
Expand Down
10 changes: 10 additions & 0 deletions deploy/base/profiles/selinuxd-image-mapping.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[
{
"regex":"(.*)(CoreOS).*([\\d+])\\.8[\\d+]\\.(.*)",
"image":"quay.io/security-profiles-operator/selinuxd-el8:latest"
},
{
"regex":"(.*)(CoreOS).*([\\d+])\\.9[\\d+]\\.(.*)",
"image":"quay.io/security-profiles-operator/selinuxd-el9:latest"
}
]
8 changes: 8 additions & 0 deletions deploy/base/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ metadata:
creationTimestamp: null
name: security-profiles-operator
rules:
- apiGroups:
- ""
resourceNames:
- security-profiles-operator-profile
resources:
- configmaps
verbs:
- get
- apiGroups:
- ""
resources:
Expand Down
19 changes: 19 additions & 0 deletions deploy/helm/templates/static-resources.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ metadata:
helm.sh/chart: security-profiles-operator
name: security-profiles-operator
rules:
- apiGroups:
- ""
resourceNames:
- security-profiles-operator-profile
resources:
- configmaps
verbs:
- get
- apiGroups:
- ""
resources:
Expand Down Expand Up @@ -966,6 +974,17 @@ data:
}
]
}
selinuxd-image-mapping.json: |
[
{
"regex":"(.*)(CoreOS).*([\\d+])\\.8[\\d+]\\.(.*)",
"image":"quay.io/security-profiles-operator/selinuxd-el8:latest"
},
{
"regex":"(.*)(CoreOS).*([\\d+])\\.9[\\d+]\\.(.*)",
"image":"quay.io/security-profiles-operator/selinuxd-el9:latest"
}
]
selinuxd.cil: |
(block selinuxd
(blockinherit container)
Expand Down
19 changes: 19 additions & 0 deletions deploy/namespace-operator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2082,6 +2082,14 @@ metadata:
app: security-profiles-operator
name: security-profiles-operator
rules:
- apiGroups:
- ""
resourceNames:
- security-profiles-operator-profile
resources:
- configmaps
verbs:
- get
- apiGroups:
- ""
resources:
Expand Down Expand Up @@ -2922,6 +2930,17 @@ data:
}
]
}
selinuxd-image-mapping.json: |
[
{
"regex":"(.*)(CoreOS).*([\\d+])\\.8[\\d+]\\.(.*)",
"image":"quay.io/security-profiles-operator/selinuxd-el8:latest"
},
{
"regex":"(.*)(CoreOS).*([\\d+])\\.9[\\d+]\\.(.*)",
"image":"quay.io/security-profiles-operator/selinuxd-el9:latest"
}
]
selinuxd.cil: |
(block selinuxd
(blockinherit container)
Expand Down
19 changes: 19 additions & 0 deletions deploy/openshift-dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2154,6 +2154,14 @@ metadata:
app: security-profiles-operator
name: security-profiles-operator
rules:
- apiGroups:
- ""
resourceNames:
- security-profiles-operator-profile
resources:
- configmaps
verbs:
- get
- apiGroups:
- ""
resources:
Expand Down Expand Up @@ -2904,6 +2912,17 @@ data:
}
]
}
selinuxd-image-mapping.json: |
[
{
"regex":"(.*)(CoreOS).*([\\d+])\\.8[\\d+]\\.(.*)",
"image":"quay.io/security-profiles-operator/selinuxd-el8:latest"
},
{
"regex":"(.*)(CoreOS).*([\\d+])\\.9[\\d+]\\.(.*)",
"image":"quay.io/security-profiles-operator/selinuxd-el9:latest"
}
]
selinuxd.cil: |
(block selinuxd
(blockinherit container)
Expand Down
19 changes: 19 additions & 0 deletions deploy/openshift-downstream.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2082,6 +2082,14 @@ metadata:
app: security-profiles-operator
name: security-profiles-operator
rules:
- apiGroups:
- ""
resourceNames:
- security-profiles-operator-profile
resources:
- configmaps
verbs:
- get
- apiGroups:
- ""
resources:
Expand Down Expand Up @@ -2935,6 +2943,17 @@ data:
}
]
}
selinuxd-image-mapping.json: |
[
{
"regex":"(.*)(CoreOS).*([\\d+])\\.8[\\d+]\\.(.*)",
"image":"quay.io/security-profiles-operator/selinuxd-el8:latest"
},
{
"regex":"(.*)(CoreOS).*([\\d+])\\.9[\\d+]\\.(.*)",
"image":"quay.io/security-profiles-operator/selinuxd-el9:latest"
}
]
selinuxd.cil: |
(block selinuxd
(blockinherit container)
Expand Down
19 changes: 19 additions & 0 deletions deploy/operator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2082,6 +2082,14 @@ metadata:
app: security-profiles-operator
name: security-profiles-operator
rules:
- apiGroups:
- ""
resourceNames:
- security-profiles-operator-profile
resources:
- configmaps
verbs:
- get
- apiGroups:
- ""
resources:
Expand Down Expand Up @@ -2922,6 +2930,17 @@ data:
}
]
}
selinuxd-image-mapping.json: |
[
{
"regex":"(.*)(CoreOS).*([\\d+])\\.8[\\d+]\\.(.*)",
"image":"quay.io/security-profiles-operator/selinuxd-el8:latest"
},
{
"regex":"(.*)(CoreOS).*([\\d+])\\.9[\\d+]\\.(.*)",
"image":"quay.io/security-profiles-operator/selinuxd-el9:latest"
}
]
selinuxd.cil: |
(block selinuxd
(blockinherit container)
Expand Down
19 changes: 19 additions & 0 deletions deploy/webhook-operator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2154,6 +2154,14 @@ metadata:
app: security-profiles-operator
name: security-profiles-operator
rules:
- apiGroups:
- ""
resourceNames:
- security-profiles-operator-profile
resources:
- configmaps
verbs:
- get
- apiGroups:
- ""
resources:
Expand Down Expand Up @@ -2893,6 +2901,17 @@ data:
}
]
}
selinuxd-image-mapping.json: |
[
{
"regex":"(.*)(CoreOS).*([\\d+])\\.8[\\d+]\\.(.*)",
"image":"quay.io/security-profiles-operator/selinuxd-el8:latest"
},
{
"regex":"(.*)(CoreOS).*([\\d+])\\.9[\\d+]\\.(.*)",
"image":"quay.io/security-profiles-operator/selinuxd-el9:latest"
}
]
selinuxd.cil: |
(block selinuxd
(blockinherit container)
Expand Down
44 changes: 38 additions & 6 deletions internal/pkg/manager/spod/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
corev1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/event"
Expand Down Expand Up @@ -120,15 +121,11 @@ func isStaticWebhook(ctx context.Context) bool {
}

func (r *ReconcileSPOd) getTunables(ctx context.Context) (*daemonTunables, error) {
var err error

dt := &daemonTunables{}
dt.watchNamespace = os.Getenv(config.RestrictNamespaceEnvKey)

selinuxdImage := os.Getenv(selinuxdImageKey)
if selinuxdImage == "" {
return dt, errors.New("invalid selinuxd image")
}
dt.selinuxdImage = selinuxdImage

rbacProxyImage := os.Getenv(rbacProxyImageKey)
if rbacProxyImage == "" {
return dt, errors.New("invalid rbac proxy image")
Expand All @@ -146,10 +143,45 @@ func (r *ReconcileSPOd) getTunables(ctx context.Context) (*daemonTunables, error
}
dt.seccompLocalhostProfile = util.GetSeccompLocalhostProfilePath(node)
dt.containerRuntime = util.GetContainerRuntime(node)
dt.selinuxdImage, err = r.getSelinuxdImage(ctx, node)
if err != nil {
return dt, fmt.Errorf("could not determine selinuxd image: %w", err)
}

return dt, nil
}

func (r *ReconcileSPOd) getSelinuxdImage(ctx context.Context, node *corev1.Node) (string, error) {
var operatorCm corev1.ConfigMap
operatorCmName := types.NamespacedName{
Namespace: config.GetOperatorNamespace(),
Name: util.OperatorConfigMap,
}

if err := r.clientReader.Get(ctx, operatorCmName, &operatorCm); err != nil {
return "", err
}
selinuxdImageMapping := operatorCm.Data[util.SelinuxdImageMappingKey]

selinuxdImage, err := util.MatchSelinuxdImageJSONMapping(node, []byte(selinuxdImageMapping))
if err != nil {
return "", fmt.Errorf("matching selinuxd image: %w", err)
}

if selinuxdImage != "" {
r.log.Info("matched selinuxd image against nodeInfo", "image", selinuxdImage)
return selinuxdImage, nil
}

selinuxdImage = os.Getenv(selinuxdImageKey)
if selinuxdImage != "" {
r.log.Info("using selinuxd image from envVar", "image", selinuxdImage)
return selinuxdImage, nil
}

return "", errors.New("invalid selinuxd image")
}

func getEffectiveSPOd(dt *daemonTunables) *appsv1.DaemonSet {
refSPOd := bindata.Manifest.DeepCopy()
refSPOd.SetNamespace(config.GetOperatorNamespace())
Expand Down
3 changes: 3 additions & 0 deletions internal/pkg/manager/spod/spod_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ func (r *ReconcileSPOd) Healthz(*http.Request) error {
//
// Needed to detect which runtime is active
// +kubebuilder:rbac:groups="",resources=nodes,verbs=get;list;get
//
// Needed to detect the proper selinux image
// +kubebuilder:rbac:groups="",resources=configmaps,resourceNames=security-profiles-operator-profile,verbs=get

// Reconcile reads that state of the cluster for a SPOD object and makes changes based on the state read
// and what is in the `ConfigMap.Spec`.
Expand Down
8 changes: 8 additions & 0 deletions internal/pkg/util/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,11 @@ const (
EventTypeNormal string = "Normal"
EventTypeWarning string = "Warning"
)

const (
// OperatorConfigMap corresponds to the configMap created from deploy/base/profiles.
OperatorConfigMap = "security-profiles-operator-profile"
// SelinuxdImageMappingKey is the key in the configMap that contains the mapping
// between the selinuxd image and the OS version.
SelinuxdImageMappingKey = "selinuxd-image-mapping.json"
)
Loading

0 comments on commit 0990e44

Please sign in to comment.