diff --git a/tools/osbuilder/image-builder/image_builder.sh b/tools/osbuilder/image-builder/image_builder.sh index 8b65ab4e8..75b23b176 100755 --- a/tools/osbuilder/image-builder/image_builder.sh +++ b/tools/osbuilder/image-builder/image_builder.sh @@ -64,6 +64,8 @@ readonly -a systemd_files=( # Set a default value AGENT_INIT=${AGENT_INIT:-no} +SELINUX=${SELINUX:-no} +SELINUXFS="/sys/fs/selinux" # Align image to 128M readonly mem_boundary_mb=128 @@ -93,6 +95,10 @@ Extra environment variables: DEFAULT: not set USE_PODMAN: If set and USE_DOCKER not set, will build image in a Podman Container (requries podman) DEFAULT: not set + SELINUX: If set to "yes", the rootfs is labeled for SELinux. + Make sure that selinuxfs is mounted to /sys/fs/selinux on the host + and the rootfs is built with SELINUX=yes. + DEFAULT value: "no" Following diagram shows how the resulting image will look like @@ -134,6 +140,7 @@ build_with_container() { local nsdax_bin="$9" local container_image_name="image-builder-osbuilder" local shared_files="" + local selinuxfs="" image_dir=$(readlink -f "$(dirname "${image}")") image_name=$(basename "${image}") @@ -157,6 +164,14 @@ build_with_container() { shared_files+="-v ${mke2fs_conf}:${mke2fs_conf}:ro " fi + if [ "${SELINUX}" == "yes" ]; then + if mountpoint $SELINUXFS > /dev/null; then + selinuxfs="-v ${SELINUXFS}:${SELINUXFS}" + else + die "Make sure that SELinux is enabled on the host" + fi + fi + #Make sure we use a compatible runtime to build rootfs # In case Clear Containers Runtime is installed we dont want to hit issue: #https://github.com/clearcontainers/runtime/issues/828 @@ -170,12 +185,14 @@ build_with_container() { --env BLOCK_SIZE="${block_size}" \ --env ROOT_FREE_SPACE="${root_free_space}" \ --env NSDAX_BIN="${nsdax_bin}" \ + --env SELINUX="${SELINUX}" \ --env DEBUG="${DEBUG}" \ -v /dev:/dev \ -v "${script_dir}":"/osbuilder" \ -v "${script_dir}/../scripts":"/scripts" \ -v "${rootfs}":"/rootfs" \ -v "${image_dir}":"/image" \ + ${selinuxfs} \ ${shared_files} \ ${container_image_name} \ bash "/osbuilder/${script_name}" -o "/image/${image_name}" /rootfs @@ -384,6 +401,7 @@ create_rootfs_image() { local img_size="$3" local fs_type="$4" local block_size="$5" + local agent_bin="$6" create_disk "${image}" "${img_size}" "${fs_type}" "${rootfs_start}" @@ -402,6 +420,31 @@ create_rootfs_image() { info "Copying content from rootfs to root partition" cp -a "${rootfs}"/* "${mount_dir}" + + if [ "${SELINUX}" == "yes" ]; then + if [ "${AGENT_INIT}" == "yes" ]; then + die "Guest SELinux with the agent init is not supported yet" + fi + + info "Labeling rootfs for SELinux" + selinuxfs_path="${mount_dir}${SELINUXFS}" + mkdir -p $selinuxfs_path + if mountpoint $SELINUXFS > /dev/null && \ + chroot "${mount_dir}" command -v restorecon > /dev/null; then + mount -t selinuxfs selinuxfs $selinuxfs_path + chroot "${mount_dir}" restorecon -RF -e ${SELINUXFS} / + # TODO: This operation will be removed after the updated container-selinux that + # includes the following commit is released. + # https://github.com/containers/container-selinux/commit/39f83cc74d50bd10ab6be4d0bdd98bc04857469f + # We use chcon as an interim solution until then. + chroot "${mount_dir}" chcon -t container_runtime_exec_t "/usr/bin/${agent_bin}" + umount $selinuxfs_path + else + die "Could not label the rootfs. Make sure that SELinux is enabled on the host \ +and the rootfs is built with SELINUX=yes" + fi + fi + sync OK "rootfs copied" @@ -529,7 +572,7 @@ main() { # consider in calculate_img_size rootfs_img_size=$((img_size - dax_header_sz)) create_rootfs_image "${rootfs}" "${image}" "${rootfs_img_size}" \ - "${fs_type}" "${block_size}" + "${fs_type}" "${block_size}" "${agent_bin}" # insert at the beginning of the image the MBR + DAX header set_dax_header "${image}" "${img_size}" "${fs_type}" "${nsdax_bin}" diff --git a/tools/osbuilder/rootfs-builder/centos/config.sh b/tools/osbuilder/rootfs-builder/centos/config.sh index 7226da047..2123903a0 100644 --- a/tools/osbuilder/rootfs-builder/centos/config.sh +++ b/tools/osbuilder/rootfs-builder/centos/config.sh @@ -8,10 +8,15 @@ OS_VERSION=${OS_VERSION:-stream9} PACKAGES="chrony iptables" [ "$AGENT_INIT" = no ] && PACKAGES+=" systemd" [ "$SECCOMP" = yes ] && PACKAGES+=" libseccomp" +[ "$SELINUX" = yes ] && PACKAGES+=" container-selinux" # Container registry tag is different from metalink repo, e.g. "stream9" => "9-stream" os_repo_version="$(sed -E "s/(stream)(.+)/\2-\1/" <<< "$OS_VERSION")" METALINK="https://mirrors.centos.org/metalink?repo=centos-baseos-$os_repo_version&arch=\$basearch" +if [ "$SELINUX" == yes ]; then + # AppStream repository is required for the container-selinux package + METALINK_APPSTREAM="https://mirrors.centos.org/metalink?repo=centos-appstream-$os_repo_version&arch=\$basearch" +fi GPG_KEY_FILE=RPM-GPG-KEY-CentOS-Official GPG_KEY_URL="https://centos.org/keys/$GPG_KEY_FILE" diff --git a/tools/osbuilder/rootfs-builder/rootfs.sh b/tools/osbuilder/rootfs-builder/rootfs.sh index c69f8dfef..43c79fd7d 100755 --- a/tools/osbuilder/rootfs-builder/rootfs.sh +++ b/tools/osbuilder/rootfs-builder/rootfs.sh @@ -25,6 +25,7 @@ LIBC=${LIBC:-musl} # The kata agent enables seccomp feature. # However, it is not enforced by default: you need to enable that in the main configuration file. SECCOMP=${SECCOMP:-"yes"} +SELINUX=${SELINUX:-"no"} lib_file="${script_dir}/../scripts/lib.sh" source "$lib_file" @@ -142,6 +143,11 @@ ROOTFS_DIR Path to the directory that is populated with the rootfs. SECCOMP When set to "no", the kata-agent is built without seccomp capability. Default value: "yes" +SELINUX When set to "yes", build the rootfs with the required packages to + enable SELinux in the VM. + Make sure the guest kernel is compiled with SELinux enabled. + Default value: "no" + USE_DOCKER If set, build the rootfs inside a container (requires Docker). Default value: @@ -346,6 +352,15 @@ build_rootfs_distro() echo "Required rust version: $RUST_VERSION" + if [ "${SELINUX}" == "yes" ]; then + if [ "${AGENT_INIT}" == "yes" ]; then + die "Guest SELinux with the agent init is not supported yet" + fi + if [ "${distro}" != "centos" ]; then + die "The guest rootfs must be CentOS to enable guest SELinux" + fi + fi + if [ -z "${USE_DOCKER}" ] && [ -z "${USE_PODMAN}" ]; then info "build directly" build_rootfs ${ROOTFS_DIR} @@ -426,6 +441,7 @@ build_rootfs_distro() --env OS_VERSION="${OS_VERSION}" \ --env INSIDE_CONTAINER=1 \ --env SECCOMP="${SECCOMP}" \ + --env SELINUX="${SELINUX}" \ --env DEBUG="${DEBUG}" \ --env HOME="/root" \ -v "${repo_dir}":"/kata-containers" \ diff --git a/tools/osbuilder/scripts/lib.sh b/tools/osbuilder/scripts/lib.sh index 5ed017677..615ff10a9 100644 --- a/tools/osbuilder/scripts/lib.sh +++ b/tools/osbuilder/scripts/lib.sh @@ -79,7 +79,23 @@ gpgcheck=1 gpgkey=file://${CONFIG_DIR}/${GPG_KEY_FILE} EOF fi - + if [ "$SELINUX" == "yes" ]; then + cat > "${DNF_CONF}" << EOF +[appstream] +name=${OS_NAME}-${OS_VERSION} upstream +releasever=${OS_VERSION} +EOF + echo "metalink=$METALINK_APPSTREAM" >> "$DNF_CONF" + if [ -n "$GPG_KEY_URL" ]; then + if [ ! -f "${CONFIG_DIR}/${GPG_KEY_FILE}" ]; then + curl -L "${GPG_KEY_URL}" -o "${CONFIG_DIR}/${GPG_KEY_FILE}" + fi + cat >> "${DNF_CONF}" << EOF +gpgcheck=1 +gpgkey=file://${CONFIG_DIR}/${GPG_KEY_FILE} +EOF + fi + fi } build_rootfs()