call into snapd to set up encryption when required
This commit is contained in:
parent
cabb8dda8e
commit
5dafdb916d
|
@ -0,0 +1 @@
|
|||
{"type":"sync","status-code":200,"status":"OK","result":{"id":"6","kind":"install-step-setup-storage-encryption","summary":"Setup storage encryption for installing system \"classic\"","status":"Doing","tasks":[{"id":"45","kind":"install-setup-storage-encryption","summary":"Setup storage encryption for installing system \"classic\"","status":"Doing","progress":{"label":"","done":1,"total":1},"spawn-time":"2022-10-28T10:04:23.859233629Z"}],"ready":false,"spawn-time":"2022-10-28T10:04:23.859232232Z"}}
|
|
@ -0,0 +1 @@
|
|||
{"type":"sync","status-code":200,"status":"OK","result":{"id":"6","kind":"install-step-setup-storage-encryption","summary":"Setup storage encryption for installing system \"classic\"","status":"Doing","tasks":[{"id":"45","kind":"install-setup-storage-encryption","summary":"Setup storage encryption for installing system \"classic\"","status":"Doing","progress":{"label":"","done":1,"total":1},"spawn-time":"2022-10-28T10:04:23.859233629Z"}],"ready":false,"spawn-time":"2022-10-28T10:04:23.859232232Z"}}
|
|
@ -0,0 +1 @@
|
|||
{"type":"sync","status-code":200,"status":"OK","result":{"id":"6","kind":"install-step-setup-storage-encryption","summary":"Setup storage encryption for installing system \"classic\"","status":"Doing","tasks":[{"id":"45","kind":"install-setup-storage-encryption","summary":"Setup storage encryption for installing system \"classic\"","status":"Doing","progress":{"label":"","done":1,"total":1},"spawn-time":"2022-10-28T10:04:23.859233629Z"}],"ready":false,"spawn-time":"2022-10-28T10:04:23.859232232Z"}}
|
|
@ -0,0 +1 @@
|
|||
{"type":"sync","status-code":200,"status":"OK","result":{"id":"6","kind":"install-step-setup-storage-encryption","summary":"Setup storage encryption for installing system \"classic\"","status":"Doing","tasks":[{"id":"45","kind":"install-setup-storage-encryption","summary":"Setup storage encryption for installing system \"classic\"","status":"Doing","progress":{"label":"","done":1,"total":1},"spawn-time":"2022-10-28T10:04:23.859233629Z"}],"ready":false,"spawn-time":"2022-10-28T10:04:23.859232232Z"}}
|
|
@ -0,0 +1 @@
|
|||
{"type":"sync","status-code":200,"status":"OK","result":{"id":"6","kind":"install-step-setup-storage-encryption","summary":"Setup storage encryption for installing system \"classic\"","status":"Doing","tasks":[{"id":"45","kind":"install-setup-storage-encryption","summary":"Setup storage encryption for installing system \"classic\"","status":"Doing","progress":{"label":"","done":1,"total":1},"spawn-time":"2022-10-28T10:04:23.859233629Z"}],"ready":false,"spawn-time":"2022-10-28T10:04:23.859232232Z"}}
|
|
@ -0,0 +1 @@
|
|||
{"type":"sync","status-code":200,"status":"OK","result":{"id":"6","kind":"install-step-setup-storage-encryption","summary":"Setup storage encryption for installing system \"classic\"","status":"Done","tasks":[{"id":"45","kind":"install-setup-storage-encryption","summary":"Setup storage encryption for installing system \"classic\"","status":"Done","progress":{"label":"","done":1,"total":1},"spawn-time":"2022-10-28T10:04:23.859233629Z","ready-time":"2022-10-28T10:04:29.092142293Z"}],"ready":true,"spawn-time":"2022-10-28T10:04:23.859232232Z","ready-time":"2022-10-28T10:04:29.092145478Z","data":{"encrypted-devices":{"system-data":"/dev/mapper/ubuntu-data","system-save":"/dev/mapper/ubuntu-save"}}}}
|
|
@ -25,7 +25,14 @@ validate () {
|
|||
fi
|
||||
|
||||
if [ "${mode}" = "install" ]; then
|
||||
python3 scripts/validate-yaml.py "$tmpdir"/var/log/installer/curtin-install/subiquity-partitioning.conf
|
||||
cfgs=
|
||||
for stage in partitioning formatting; do
|
||||
cfg="$tmpdir"/var/log/installer/curtin-install/subiquity-$stage.conf
|
||||
if [ -e $cfg ]; then
|
||||
cfgs="$cfgs $cfg"
|
||||
fi
|
||||
done
|
||||
python3 scripts/validate-yaml.py $cfgs
|
||||
if [ ! -e $tmpdir/subiquity-client-debug.log ] || [ ! -e $tmpdir/subiquity-server-debug.log ]; then
|
||||
echo "log file not created"
|
||||
exit 1
|
||||
|
|
|
@ -75,13 +75,17 @@ class StorageChecker:
|
|||
assert '/' in self.path_to_mount
|
||||
|
||||
|
||||
config = yaml.safe_load(open(sys.argv[1]))
|
||||
|
||||
|
||||
def main():
|
||||
storage_checker = StorageChecker()
|
||||
|
||||
for action in config['storage']['config']:
|
||||
actions = []
|
||||
for path in sys.argv[1:]:
|
||||
config = yaml.safe_load(open(path))
|
||||
actions.extend(config['storage']['config'])
|
||||
|
||||
for action in actions:
|
||||
try:
|
||||
storage_checker.check(action)
|
||||
except Exception:
|
||||
|
|
|
@ -959,6 +959,19 @@ class DM_Crypt:
|
|||
return self.volume.size - LUKS_OVERHEAD
|
||||
|
||||
|
||||
@fsobj("device")
|
||||
class ArbitraryDevice(_Device):
|
||||
ptable = attr.ib(default=None)
|
||||
path = attr.ib(default=None)
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
return 0
|
||||
|
||||
ok_for_raid = False
|
||||
ok_for_lvm_vg = False
|
||||
|
||||
|
||||
@fsobj("format")
|
||||
class Filesystem:
|
||||
fstype = attr.ib()
|
||||
|
|
|
@ -74,6 +74,7 @@ from subiquity.common.types import (
|
|||
)
|
||||
from subiquity.models.filesystem import (
|
||||
ActionRenderMode,
|
||||
ArbitraryDevice,
|
||||
align_up,
|
||||
align_down,
|
||||
_Device,
|
||||
|
@ -142,6 +143,7 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
|
|||
self._core_boot_classic_error: str = ''
|
||||
self._system_mounter: Optional[Mounter] = None
|
||||
self._role_to_device: Dict[snapdapi.Role: _Device] = {}
|
||||
self.use_tpm: bool = False
|
||||
|
||||
def load_autoinstall_data(self, data):
|
||||
log.debug("load_autoinstall_data %s", data)
|
||||
|
@ -496,6 +498,27 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
|
|||
on_volume_structure.device = self._role_to_device[role].path
|
||||
return {key: on_volume}
|
||||
|
||||
@with_context(description="configuring TPM-backed full disk encryption")
|
||||
async def setup_encryption(self, context):
|
||||
label = self.app.base_model.source.current.snapd_system_label
|
||||
result = await snapdapi.post_and_wait(
|
||||
self.app.snapdapi,
|
||||
self.app.snapdapi.v2.systems[label].POST,
|
||||
snapdapi.SystemActionRequest(
|
||||
action=snapdapi.SystemAction.INSTALL,
|
||||
step=snapdapi.SystemActionStep.SETUP_STORAGE_ENCRYPTION,
|
||||
on_volumes=self._on_volumes()))
|
||||
role_to_encrypted_device = result['encrypted-devices']
|
||||
for role, enc_path in role_to_encrypted_device.items():
|
||||
role = snapdapi.Role(role)
|
||||
arb_device = ArbitraryDevice(m=self.model, path=enc_path)
|
||||
self.model._actions.append(arb_device)
|
||||
part = self._role_to_device[role]
|
||||
for fs in self.model._all(type='format'):
|
||||
if fs.volume == part:
|
||||
fs.volume = arb_device
|
||||
self._role_to_device[role] = arb_device
|
||||
|
||||
@with_context(description="making system bootable")
|
||||
async def finish_install(self, context):
|
||||
label = self.app.base_model.source.current.snapd_system_label
|
||||
|
@ -510,6 +533,7 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
|
|||
async def guided_POST(self, data: GuidedChoice) -> StorageResponse:
|
||||
log.debug(data)
|
||||
if self._system is not None:
|
||||
self.use_tpm = data.use_tpm
|
||||
self.apply_system(data.disk_id)
|
||||
await self.configured()
|
||||
else:
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import asyncio
|
||||
import functools
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
|
@ -39,6 +40,7 @@ from subiquity.common.types import (
|
|||
from subiquity.journald import (
|
||||
journald_listen,
|
||||
)
|
||||
from subiquity.models.filesystem import ActionRenderMode
|
||||
from subiquity.server.controller import (
|
||||
SubiquityController,
|
||||
)
|
||||
|
@ -187,10 +189,12 @@ class InstallController(SubiquityController):
|
|||
}
|
||||
}
|
||||
|
||||
def acquire_filesystem_config(self, step: CurtinPartitioningStep,
|
||||
def acquire_filesystem_config(
|
||||
self, step: CurtinPartitioningStep,
|
||||
mode: ActionRenderMode = ActionRenderMode.DEFAULT
|
||||
) -> Dict[str, Any]:
|
||||
cfg = self.acquire_initial_config(step)
|
||||
cfg.update(self.model.filesystem.render())
|
||||
cfg.update(self.model.filesystem.render(mode=mode))
|
||||
cfg['storage']['device_map_path'] = str(step.device_map_path)
|
||||
return cfg
|
||||
|
||||
|
@ -255,10 +259,24 @@ class InstallController(SubiquityController):
|
|||
]
|
||||
if self.model.source.current.snapd_system_label:
|
||||
fs_controller = self.app.controllers.Filesystem
|
||||
steps.extend([
|
||||
steps.append(
|
||||
make_curtin_step(
|
||||
name="partitioning", stages=["partitioning"],
|
||||
acquire_config=self.acquire_filesystem_config,
|
||||
acquire_config=functools.partial(
|
||||
self.acquire_filesystem_config,
|
||||
mode=ActionRenderMode.DEVICES),
|
||||
cls=CurtinPartitioningStep,
|
||||
device_map_path=logs_dir / "device-map.json",
|
||||
).run,
|
||||
)
|
||||
if fs_controller.use_tpm:
|
||||
steps.append(fs_controller.setup_encryption)
|
||||
steps.extend([
|
||||
make_curtin_step(
|
||||
name="formatting", stages=["partitioning"],
|
||||
acquire_config=functools.partial(
|
||||
self.acquire_filesystem_config,
|
||||
mode=ActionRenderMode.FORMAT_MOUNT),
|
||||
cls=CurtinPartitioningStep,
|
||||
device_map_path=logs_dir / "device-map.json",
|
||||
).run,
|
||||
|
|
|
@ -538,6 +538,22 @@ class TestCoreBootInstallMethods(IsolatedAsyncioTestCase):
|
|||
self.assertEqual(set(mounts.keys()), {'/', '/boot', '/boot/efi'})
|
||||
device_map = {p.id: random_string() for p in disk.partitions()}
|
||||
self.fsc.update_devices(device_map)
|
||||
|
||||
with mock.patch.object(snapdapi, "post_and_wait",
|
||||
new_callable=mock.AsyncMock) as mocked:
|
||||
mocked.return_value = {
|
||||
'encrypted-devices': {
|
||||
snapdapi.Role.SYSTEM_DATA: 'enc-system-data',
|
||||
},
|
||||
}
|
||||
await self.fsc.setup_encryption(context=self.fsc.context)
|
||||
|
||||
# setup_encryption mutates the filesystem model objects to
|
||||
# reference the newly created encrypted objects so re-read the
|
||||
# mount to device mapping.
|
||||
mounts = {m.path: m.device.volume for m in model._all(type='mount')}
|
||||
self.assertEqual(mounts['/'].path, 'enc-system-data')
|
||||
|
||||
with mock.patch.object(snapdapi, "post_and_wait",
|
||||
new_callable=mock.AsyncMock) as mocked:
|
||||
await self.fsc.finish_install(context=self.fsc.context)
|
||||
|
|
|
@ -152,6 +152,8 @@ class FakeSnapdConnection:
|
|||
change = "15"
|
||||
else:
|
||||
change = "5"
|
||||
elif step == 'setup-storage-encryption':
|
||||
change = "6"
|
||||
if change is not None:
|
||||
return _FakeMemoryResponse({
|
||||
"type": "async",
|
||||
|
|
Loading…
Reference in New Issue