image: system layer

This commit is contained in:
Malte Poll 2023-09-11 15:54:08 +02:00 committed by Malte Poll
parent 4ef3d10be3
commit c6ea596eb9
7 changed files with 398 additions and 0 deletions

81
image/system/BUILD.bazel Normal file
View File

@ -0,0 +1,81 @@
load("//bazel/mkosi:mkosi_image.bzl", "mkosi_image")
load(":variants.bzl", "CSPS", "STREAMS", "VARIANTS", "autologin", "constellation_packages", "images_for_csp", "images_for_csp_and_stream", "images_for_stream", "kernel_command_line", "kernel_command_line_dict")
[
mkosi_image(
name = variant["csp"] + "_" + variant["attestation_variant"] + "_" + stream,
srcs = [
"mkosi.postinst",
] + glob([
"mkosi.repart/**",
]),
autologin = autologin(
variant["csp"],
variant["attestation_variant"],
stream,
),
base_trees = [
"//image/base",
],
extra_trees = constellation_packages(stream),
initrds = [
"//image/initrd",
],
kernel_command_line = kernel_command_line(
variant["csp"],
variant["attestation_variant"],
stream,
),
kernel_command_line_dict = kernel_command_line_dict(
variant["csp"],
variant["attestation_variant"],
stream,
),
mkosi_conf = "mkosi.conf",
out_dir = variant["csp"] + "_" + variant["attestation_variant"] + "_" + stream,
tags = [
"manual",
"no-cache",
],
version_file = "//bazel/settings:tag",
)
for variant in VARIANTS
for stream in STREAMS
]
[
filegroup(
name = stream,
srcs = images_for_stream(stream),
tags = [
"manual",
"no-cache",
],
)
for stream in STREAMS
]
[
filegroup(
name = csp,
srcs = images_for_csp(csp),
tags = [
"manual",
"no-cache",
],
)
for csp in CSPS
]
[
filegroup(
name = csp + "_" + stream,
srcs = images_for_csp_and_stream(csp, stream),
tags = [
"manual",
"no-cache",
],
)
for csp in CSPS
for stream in STREAMS
]

24
image/system/mkosi.conf Normal file
View File

@ -0,0 +1,24 @@
[Distribution]
Distribution=fedora
Release=38
[Output]
Format=disk
ManifestFormat=json
Output=constellation
ImageId=constellation
Seed=0e9a6fe0-68f6-408c-bbeb-136054d20445
SourceDateEpoch=0
[Content]
Bootable=yes
Bootloader=uki
KernelCommandLine=preempt=full rd.shell=0 rd.emergency=reboot loglevel=8 console=ttyS0
RemoveFiles=/var/log
RemoveFiles=/var/cache
RemoveFiles=/etc/pki/ca-trust/extracted/java/cacerts
/usr/lib/sysimage/libdnf5/transaction_history.sqlite*
/var/cache/ldconfig/aux-cache
# https://github.com/authselect/authselect/pull/348
# RemoveFiles=/etc/authselect/*
CleanPackageMetadata=true

35
image/system/mkosi.postinst Executable file
View File

@ -0,0 +1,35 @@
#!/usr/bin/env bash
set -euxo pipefail
# add motd for constellation console access
if [[ ${CONSOLE_MOTD:-false} == "true" ]]; then
cat << EOF > "${BUILDROOT}/usr/lib/motd.d/10-constellation-console-access.motd"
~ Welcome to Constellation! ~
Usually, on release versions of Constellation running in the cloud, you are not able to login through the serial console.
This shell access is specifically granted for debug images and MiniConstellation to allow users to research the environment Constellation runs in.
Have fun! Feel free to report any issues to GitHub or security@edgeless.systems (for security vulnerabilities only).
EOF
fi
# update /etc/os-release
echo "IMAGE_ID=\"${IMAGE_ID}\"" >> "${BUILDROOT}/etc/os-release"
# TODO(malt3): ensure IMAGE_VERSION is actually set (shell wrapper)
export IMAGE_VERSION=${IMAGE_VERSION-v0.0.0}
echo "IMAGE_VERSION=\"${IMAGE_VERSION}\"" >> "${BUILDROOT}/etc/os-release"
# enable debugd
ln -s /usr/lib/systemd/system/debugd.service "${BUILDROOT}/etc/systemd/system/multi-user.target.wants/debugd.service"
# ensure google_nvme_id is executable
chmod o+x "${BUILDROOT}/usr/lib/udev/google_nvme_id"
chmod g+x "${BUILDROOT}/usr/lib/udev/google_nvme_id"
chmod u+x "${BUILDROOT}/usr/lib/udev/google_nvme_id"
# mask unwanted services
ln -s /dev/null "${BUILDROOT}/etc/systemd/system/systemd-pcrmachine.service"
ln -s /dev/null "${BUILDROOT}/etc/systemd/system/systemd-pcrfs-root.service"
ln -s /dev/null "${BUILDROOT}/etc/systemd/system/systemd-pcrfs@.service"
ln -s /dev/null "${BUILDROOT}/etc/systemd/system/systemd-pcrphase@.service"
ln -s /dev/null "${BUILDROOT}/etc/systemd/system/systemd-pcrphase-initrd.service"
ln -s /dev/null "${BUILDROOT}/etc/systemd/system/systemd-pcrphase-sysinit.service"
ln -s /dev/null "${BUILDROOT}/etc/systemd/system/systemd-pcrphase.service"

View File

@ -0,0 +1,6 @@
[Partition]
Type=esp
Format=vfat
CopyFiles=/efi:/
SizeMinBytes=256M
SizeMaxBytes=512M

View File

@ -0,0 +1,7 @@
[Partition]
Type=root
Format=squashfs
Verity=data
VerityMatchKey=root
CopyFiles=/
Minimize=guess

View File

@ -0,0 +1,6 @@
[Partition]
Type=root-verity
Verity=hash
VerityMatchKey=root
SizeMinBytes=64M
SizeMaxBytes=64M

239
image/system/variants.bzl Normal file
View File

@ -0,0 +1,239 @@
""" Constellation OS image configuration / variants """
VARIANTS = [
{
"attestation_variant": "aws-sev-snp",
"csp": "aws",
},
{
"attestation_variant": "aws-nitro-tpm",
"csp": "aws",
},
{
"attestation_variant": "azure-sev-snp",
"csp": "azure",
},
{
"attestation_variant": "gcp-sev-es",
"csp": "gcp",
},
{
"attestation_variant": "gcp-sev-snp",
"csp": "gcp",
},
{
"attestation_variant": "qemu-vtpm",
"csp": "openstack",
},
{
"attestation_variant": "qemu-vtpm",
"csp": "qemu",
},
]
STREAMS = [
"stable",
"nightly",
"console",
"debug",
]
CSPS = [
"aws",
"azure",
"gcp",
"openstack",
"qemu",
]
base_cmdline = "selinux=1 enforcing=0 audit=0"
csp_settings = {
"aws": {
"kernel_command_line_dict": {
"constel.csp": "aws",
"idle": "poll",
"mitigations": "auto",
},
},
"azure": {
"kernel_command_line_dict": {
"constel.csp": "azure",
"mitigations": "auto,nosmt",
},
},
"gcp": {
"kernel_command_line_dict": {
"constel.csp": "gcp",
"mitigations": "auto,nosmt",
},
},
"openstack": {
"autologin": True,
"kernel_command_line": "console=tty0 console=ttyS0",
"kernel_command_line_dict": {
"console": "tty0",
"constel.csp": "openstack",
"kvm_amd.sev": "1",
"mem_encrypt": "on",
"mitigations": "auto,nosmt",
"module_blacklist": "qemu_fw_cfg",
},
},
"qemu": {
"autologin": True,
"kernel_command_line_dict": {
"constel.csp": "qemu",
"mitigations": "auto,nosmt",
},
},
}
attestation_variant_settings = {
"aws-nitro-tpm": {
"kernel_command_line_dict": {
"constel.attestation-variant": "aws-nitro-tpm",
},
},
"aws-sev-snp": {
"kernel_command_line_dict": {
"constel.attestation-variant": "aws-sev-snp",
},
},
"azure-sev-snp": {
"kernel_command_line_dict": {
"constel.attestation-variant": "azure-sev-snp",
},
},
"gcp-sev-es": {
"kernel_command_line_dict": {
"constel.attestation-variant": "gcp-sev-es",
},
},
"gcp-sev-snp": {
"kernel_command_line_dict": {
"constel.attestation-variant": "gcp-sev-snp",
},
},
"qemu-vtpm": {
"kernel_command_line_dict": {
"constel.attestation-variant": "qemu-vtpm",
},
},
}
stream_settings = {
"console": {
"autologin": True,
},
"debug": {
"autologin": True,
"kernel_command_line": "constellation.debug",
},
"nightly": {},
"stable": {},
}
def from_settings(csp, attestation_variant, stream, strict = True, default = None):
"""Generates a list of settings dictionaries for the given csp, attestation_variant and stream.
Args:
csp: The cloud service provider to use.
attestation_variant: The attestation variant to use.
stream: The stream to use.
strict: If True, fail if any of the given csp, attestation_variant or stream is unknown.
default: The default value to use if any of the given csp, attestation_variant or stream is unknown.
Returns:
A list of settings dictionaries.
"""
if strict:
if not csp in csp_settings:
fail("Unknown csp: " + csp)
if not attestation_variant in attestation_variant_settings:
fail("Unknown attestation_variant: " + attestation_variant)
if not stream in stream_settings:
fail("Unknown stream: " + stream)
return [
csp_settings.get(csp, default),
attestation_variant_settings.get(attestation_variant, default),
stream_settings.get(stream, default),
]
def constellation_packages(stream):
base_packages = ["//measurement-reader/cmd:measurement-reader-package"]
if stream == "debug":
return ["//debugd/cmd/debugd:debugd-package"] + base_packages
return [
"//upgrade-agent/cmd:upgrade-agent-package",
"//bootstrapper/cmd/bootstrapper:bootstrapper-package",
] + base_packages
def autologin(csp, attestation_variant, stream):
"""Generates a boolean indicating whether autologin should be enabled for the given csp, attestation_variant and stream.
Args:
csp: The cloud service provider to use.
attestation_variant: The attestation variant to use.
stream: The stream to use.
Returns:
A boolean indicating whether autologin should be enabled.
"""
out = None
for settings in from_settings(csp, attestation_variant, stream):
if not "autologin" in settings:
continue
if out != None and out != settings["autologin"]:
fail("Inconsistent autologin settings")
out = settings["autologin"]
return out
def kernel_command_line(csp, attestation_variant, stream):
cmdline = base_cmdline
for settings in from_settings(csp, attestation_variant, stream, default = {}):
cmdline = append_cmdline(cmdline, settings.get("kernel_command_line", ""))
return cmdline
def kernel_command_line_dict(csp, attestation_variant, stream):
commandline_dict = {}
for settings in from_settings(csp, attestation_variant, stream, default = {}):
commandline_dict = commandline_dict | settings.get("kernel_command_line_dict", {})
return commandline_dict
def append_cmdline(current, append):
"""Append a string to an existing commandline, separating them with a space.
Args:
current: The existing commandline. May be empty.
append: The string to append. May be empty.
Returns:
The combined commandline.
"""
if len(current) == 0:
return append
if len(append) == 0:
return current
return current + " " + append
def images_for_stream(stream):
return [
variant["csp"] + "_" + variant["attestation_variant"] + "_" + stream
for variant in VARIANTS
]
def images_for_csp(csp):
return [
csp + "_" + variant["attestation_variant"] + "_" + stream
for variant in VARIANTS
if variant["csp"] == csp
for stream in STREAMS
]
def images_for_csp_and_stream(csp, stream):
return [
csp + "_" + variant["attestation_variant"] + "_" + stream
for variant in VARIANTS
if variant["csp"] == csp
]