Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Service] Delegate TPM-based encryption to YaST #826

Merged
merged 2 commits into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions products.d/ALP-Dolomite.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,12 @@ software:
- alp_hardware
optional_patterns: null # no optional pattern shared
mandatory_packages:
- package: device-mapper # Apparently needed if devices at /dev/mapper are used at boot (eg. FDE)
- package: fde-tools # Needed for FDE with TPM, hardcoded here temporarily
archs: aarch64, x86_64
- package: libtss2-tcti-device0
- package: ppc64-diag # Needed for hardware-based installations
archs: ppc64
optional_packages: null
base_product: ALP-Dolomite

security:
tpm_luks_open: true
lsm: selinux
available_lsms:
# apparmor:
Expand All @@ -48,6 +43,7 @@ storage:
encryption:
method: luks2
pbkd_function: pbkdf2
tpm_luks_open: true
volumes:
- "/"
volume_templates:
Expand Down
8 changes: 2 additions & 6 deletions products.d/leap16.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,11 @@ software:
- alp-container_runtime
- alp_defaults
optional_patterns: null # no optional pattern shared
mandatory_packages:
- package: device-mapper # Apparently needed if devices at /dev/mapper are used at boot (eg. FDE)
- package: fde-tools # Needed for FDE with TPM, hardcoded here temporarily
archs: aarch64, x86_64
- package: libtss2-tcti-device0
mandatory_packages: null
optional_packages: null
base_product: Leap16

security:
tpm_luks_open: true
lsm: selinux
available_lsms:
# apparmor:
Expand All @@ -42,6 +37,7 @@ storage:
encryption:
method: luks2
pbkd_function: pbkdf2
tpm_luks_open: true
volumes:
- "/"
volume_templates:
Expand Down
7 changes: 7 additions & 0 deletions service/lib/agama/dbus/y2dir/manager/modules/Package.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ def Available(_package_name)
true
end

# Determines whether the package is available
#
# @todo Perform a real D-Bus call.
def AvailableAll(_package_names)
true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we always assume true?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. We can't. It's the same TODO we have for Available in the line above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But not that you mention it, I will search for the corresponding Trello card/Github issue/Whatever and will reference it here.

Copy link
Contributor Author

@ancorgs ancorgs Nov 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything originated here (it says "We need to add support for Package#Available and Package#Installed to D-Bus):

#202

But I don't see any follow-up card or issue to track it. So I will create one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

end

# Determines whether the package is available
#
# @see https://github.com/yast/yast-yast2/blob/b8cd178b7f341f6e3438782cb703f4a3ab0529ed/library/packages/src/modules/Package.rb#L121
Expand Down
106 changes: 24 additions & 82 deletions service/lib/agama/storage/finisher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ def possible_steps
[
SecurityStep.new(logger, security),
CopyFilesStep.new(logger),
StorageStep.new(logger),
BootloaderStep.new(logger),
TpmStep.new(logger, config),
IguanaStep.new(logger),
SnapshotsStep.new(logger),
CopyLogsStep.new(logger),
Expand Down Expand Up @@ -113,18 +113,6 @@ def run?
def wfm_write(function)
Yast::WFM.CallFunction(function, ["Write"])
end

# Representation on the staging devicegraph of the root mount point
#
# @return [Y2Storage::MountPoint]
def root_mount_point
staging_graph.mount_points.find(&:root?)
end

# @return [Y2Storage::Devicegraph]
def staging_graph
Y2Storage::StorageManager.instance.staging
end
end

# Step to copy files from the inst-sys to the target system
Expand Down Expand Up @@ -196,6 +184,17 @@ def cio_ignore_finish
end
end

# Step to finish the Y2Storage configuration
class StorageStep < Step
def label
"Adjusting storage configuration"
end

def run
wfm_write("storage_finish")
end
end

# Step to configure the file-system snapshots
class SnapshotsStep < Step
def label
Expand Down Expand Up @@ -229,75 +228,6 @@ def run
end
end

# Step to configure LUKS unlocking via TPMv2, if possible
class TpmStep < Step
# Constructor
def initialize(logger, config)
super(logger)
@config = config
end

def label
"Preparing the system to unlock the encryption using the TPM"
end

def run?
tpm_product? && tpm_proposal? && tpm_system?
end

def run
keyfile_path = File.join("root", ".root.keyfile")
Yast::Execute.on_target!(
"fdectl", "add-secondary-key", "--keyfile", keyfile_path,
stdin: "#{luks.password}\n",
recorder: Yast::ReducedRecorder.new(skip: :stdin)
)

service = Yast2::Systemd::Service.find("fde-tpm-enroll.service")
logger.info "FDE: TPM enroll service: #{service}"
service&.enable
rescue Cheetah::ExecutionFailed
false
end

private

def tpm_proposal?
!!luks
end

# LUKS device from the devicegraph
#
# @return [Y2Storage::Luks, nil] nil if the root mount point is not encrypted
def luks
root_mount_point.ancestors.find do |dev|
dev.is?(:luks)
end
end

def tpm_system?
Y2Storage::Arch.new.efiboot? && tpm_present?
end

def tpm_present?
return @tpm_present unless @tpm_present.nil?

@tpm_present =
begin
Yast::Execute.on_target!("fdectl", "tpm-present")
logger.info "FDE: TPMv2 detected"
true
rescue Cheetah::ExecutionFailed
logger.info "FDE: TPMv2 not detected"
false
end
end

def tpm_product?
@config.data.fetch("security", {}).fetch("tpm_luks_open", false)
end
end

# Step to write the mountlist file for Iguana, if needed
class IguanaStep < Step
IGUANA_PATH = "/iguana"
Expand Down Expand Up @@ -336,6 +266,18 @@ def root_mount_options

options.empty? ? "defaults" : options.join(",")
end

# Representation on the staging devicegraph of the root mount point
#
# @return [Y2Storage::MountPoint]
def root_mount_point
staging_graph.mount_points.find(&:root?)
end

# @return [Y2Storage::Devicegraph]
def staging_graph
Y2Storage::StorageManager.instance.staging
end
end
end
end
Expand Down
15 changes: 14 additions & 1 deletion service/lib/agama/storage/proposal_settings_reader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,26 @@ def lvm_reader(settings, value)
# @param settings [Agama::Storage::ProposalSettings]
# @param encryption [Hash]
def encryption_reader(settings, encryption)
method = Y2Storage::EncryptionMethod.find(encryption.fetch("method", ""))
method =
if try_tpm_fde?(encryption)
Y2Storage::EncryptionMethod::TPM_FDE
else
Y2Storage::EncryptionMethod.find(encryption.fetch("method", ""))
end
pbkd_function = Y2Storage::PbkdFunction.find(encryption.fetch("pbkd_function", ""))

settings.encryption.method = method if method
settings.encryption.pbkd_function = pbkd_function if pbkd_function
end

# @param encryption [Hash]
# @return [Boolean]
def try_tpm_fde?(encryption)
return false unless encryption["tpm_luks_open"] == true

Y2Storage::EncryptionMethod::TPM_FDE.possible?
end

# @param settings [Agama::Storage::ProposalSettings]
# @param value [String]
def space_policy_reader(settings, value)
Expand Down
1 change: 1 addition & 0 deletions service/test/agama/storage/manager_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@
expect(security).to receive(:write)
expect(copy_files).to receive(:run)
expect(bootloader_finish).to receive(:write)
expect(Yast::WFM).to receive(:CallFunction).with("storage_finish", ["Write"])
expect(Yast::WFM).to receive(:CallFunction).with("snapshots_finish", ["Write"])
expect(Yast::WFM).to receive(:CallFunction).with("copy_logs_finish", ["Write"])
expect(Yast::WFM).to receive(:CallFunction).with("umount_finish", ["Write"])
Expand Down
Loading