stages: add org.osbuild.ostree.selinux
Fix SELinux labels for an OSTree deployment.
This commit is contained in:
parent
467f313cee
commit
3d197247b2
1 changed files with 95 additions and 0 deletions
95
stages/org.osbuild.ostree.selinux
Executable file
95
stages/org.osbuild.ostree.selinux
Executable file
|
|
@ -0,0 +1,95 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Fix SELinux labels for an OSTree deployment[1].
|
||||
|
||||
[1] https://ostree.readthedocs.io/en/latest/manual/deployment/
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
from osbuild.util import ostree
|
||||
from osbuild.util import selinux
|
||||
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": false,
|
||||
"required": ["deployment"],
|
||||
"properties": {
|
||||
"deployment": {
|
||||
"additionalProperties": false,
|
||||
"required": ["osname", "ref"],
|
||||
"properties": {
|
||||
"osname": {
|
||||
"description": "Name of the stateroot to be used in the deployment",
|
||||
"type": "string"
|
||||
},
|
||||
"ref": {
|
||||
"description": "OStree ref to create and use for deployment",
|
||||
"type": "string"
|
||||
},
|
||||
"serial": {
|
||||
"description": "The deployment serial (usually '0')",
|
||||
"type": "number",
|
||||
"default": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main(tree, options):
|
||||
dep = options["deployment"]
|
||||
osname = dep["osname"]
|
||||
ref = dep["ref"]
|
||||
serial = dep.get("serial", 0)
|
||||
|
||||
# this created a state root at `osname`
|
||||
stateroot = f"{tree}/ostree/deploy/{osname}"
|
||||
|
||||
root = ostree.deployment_path(tree, osname, ref, serial)
|
||||
|
||||
# deploying a tree creates new files that need to be properly
|
||||
# labeled for SELinux. In theory, ostree will take care of
|
||||
# this by loading the SELinux config from the deployment and
|
||||
# then applying the labels; but it does so conditionally on
|
||||
# is_selinux_enabled(2), which in our container is FALSE
|
||||
# Therefore we have to do the same dance as ostree does, at
|
||||
# least for now, and manually re-label the affected paths
|
||||
se_policy = None
|
||||
|
||||
for p in ["etc/selinux", "usr/etc/selinux"]:
|
||||
se_home = os.path.join(root, p)
|
||||
cfgfile = os.path.join(se_home, "config")
|
||||
if not os.path.isfile(cfgfile):
|
||||
continue
|
||||
|
||||
with open(cfgfile, 'r') as f:
|
||||
cfg = selinux.parse_config(f)
|
||||
se_policy = selinux.config_get_policy(cfg)
|
||||
|
||||
if se_policy:
|
||||
break
|
||||
|
||||
if not se_policy:
|
||||
raise ValueError("Could not find SELinux policy")
|
||||
|
||||
spec = f"{se_home}/{se_policy}/contexts/files/file_contexts"
|
||||
# kernel, initramfs & BLS config snippets were
|
||||
# written to {tree}/boot
|
||||
selinux.setfiles(spec, tree, "/boot")
|
||||
# various config files will be created as a result
|
||||
# of the 3-way configuration merge, see ostree(3)
|
||||
selinux.setfiles(spec, root, "/etc")
|
||||
# if we populated /var, we need to fix its labels
|
||||
selinux.setfiles(spec, stateroot, "/var")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
stage_args = osbuild.api.arguments()
|
||||
r = main(stage_args["tree"],
|
||||
stage_args["options"])
|
||||
sys.exit(r)
|
||||
Loading…
Add table
Add a link
Reference in a new issue