-
Notifications
You must be signed in to change notification settings - Fork 184
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
Add spec and parser for luksmeta command #3525
Merged
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
5a86b92
Add spec and parser for luksmeta command
danzatt b48dfe9
Add LuksDump parser to collect.py
danzatt a1218d4
Change luksmeta command documentation
danzatt 12076f9
Improve error handling in the luksmeta parser
danzatt fe88a56
Change LuksMeta parser to inherit from dict.
danzatt 5ae6c64
Extend test coverage
danzatt 921d179
Fix luksmeta parser documentation
danzatt a5a0618
Specs class cannot be decorated using datasource
danzatt 98543f7
Change luks1_block_devices to a combinder
danzatt 54f46dc
Add device UUID to LuksMeta parser output.
danzatt 2c3e7de
Convert LuksMeta to CommandParser
danzatt 71f0e50
Add LuksDevices combiner
danzatt 4b59bfc
Don't run luks1_block_devices during collection
danzatt b79d694
Fix cryptsetup LocalSpecs to use full path
danzatt 2b94177
Remove luks1_block_devices combiner
danzatt 166d689
Skip LuksDevices combiner if there are no results
danzatt File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.. automodule:: insights.combiners.cryptsetup | ||
:members: LuksDevices | ||
:show-inheritance: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.. automodule:: insights.parsers.luksmeta | ||
:members: | ||
:show-inheritance: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
""" | ||
Cryptsetup - combine metadata about LUKS devices | ||
================================================ | ||
|
||
Combine outputs of LuksDump and LuksMeta parsers (with the same UUID) into a | ||
single dictionary. | ||
""" | ||
|
||
import copy | ||
|
||
from insights import SkipComponent | ||
from insights.core.plugins import combiner | ||
from insights.parsers.cryptsetup_luksDump import LuksDump | ||
from insights.parsers.luksmeta import LuksMeta | ||
|
||
|
||
@combiner(LuksDump, optional=[LuksMeta]) | ||
class LuksDevices(list): | ||
""" | ||
Combiner for LUKS encrypted devices information. It uses the results of | ||
the ``LuksDump`` and ``LuksMeta`` parser (they are matched based UUID of | ||
the device they were collected from). | ||
|
||
|
||
Examples: | ||
>>> luks_devices[0]["header"]["Version"] | ||
'1' | ||
>>> "luksmeta" in luks_devices[0] | ||
True | ||
>>> "luksmeta" in luks_devices[1] | ||
False | ||
>>> luks_devices[0]["luksmeta"][0] | ||
Keyslot on index 0 is 'active' with no embedded metadata | ||
""" | ||
|
||
def __init__(self, luks_dumps, luks_metas): | ||
luksmeta_by_uuid = {} | ||
|
||
if luks_metas: | ||
for luks_meta in luks_metas: | ||
if "device_uuid" not in luks_meta: | ||
continue | ||
|
||
luksmeta_by_uuid[luks_meta["device_uuid"].lower()] = luks_meta | ||
|
||
for luks_dump in luks_dumps: | ||
uuid = luks_dump.dump["header"]["UUID"].lower() | ||
luks_dump_copy = copy.deepcopy(luks_dump.dump) | ||
|
||
if luks_metas and uuid in luksmeta_by_uuid: | ||
luks_dump_copy["luksmeta"] = luksmeta_by_uuid[uuid] | ||
|
||
self.append(luks_dump_copy) | ||
xiangce marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if not self: | ||
raise SkipComponent |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
""" | ||
luksmeta - command ``luksmeta show -d <device_name>`` | ||
===================================================== | ||
This class provides parsing for the output of luksmeta <device_name>. | ||
xiangce marked this conversation as resolved.
Show resolved
Hide resolved
|
||
""" | ||
|
||
from insights import parser, CommandParser | ||
from insights.specs import Specs | ||
|
||
|
||
class KeyslotSpecification: | ||
""" | ||
Class ``KeyslotSpecification`` describes information about a keyslot | ||
collected by the ``luksmeta show`` command. | ||
|
||
|
||
Attributes: | ||
index (int): the index of the described keyslot | ||
state (str): the state of the described keyslot | ||
metadata (str): the UUID of the application that stored metadata into | ||
the described keyslot | ||
""" | ||
|
||
def __init__(self, index, state, metadata): | ||
self.index = index | ||
self.state = state | ||
self.metadata = metadata | ||
|
||
def __repr__(self): | ||
ret = "Keyslot on index " + str(self.index) + " is '" + self.state + "' " | ||
if self.metadata: | ||
ret += "with metadata stored by application with UUID '" + self.metadata + "'" | ||
else: | ||
ret += "with no embedded metadata" | ||
|
||
return ret | ||
|
||
|
||
@parser(Specs.luksmeta) | ||
class LuksMeta(CommandParser, dict): | ||
""" | ||
Class ``LuksMeta`` parses the output of the ``luksmeta show -d <device>`` command. | ||
|
||
This command prints information if the device has custom user-defined | ||
metadata embedded in the keyslots (used e.g. by clevis). If the device was | ||
not initialized using ``luksmeta``, the parser raises SkipComponent. | ||
|
||
The parser can be indexed by the keyslot index (in the range 0-7). | ||
A KeyslotSpecification object is returned, which describes every LUKS | ||
keyslot. The KeyslotSpecification contains the ``index``, ``state`` and | ||
``metadata`` fileds. Metadata field stores the UUID of the application that | ||
has stored metadata in the keyslot. | ||
|
||
Sample input data is in the format:: | ||
|
||
0 active empty | ||
1 active cb6e8904-81ff-40da-a84a-07ab9ab5715e | ||
2 active empty | ||
3 active empty | ||
4 inactive empty | ||
5 active empty | ||
6 active cb6e8904-81ff-40da-a84a-07ab9ab5715e | ||
7 active cb6e8904-81ff-40da-a84a-07ab9ab5715e | ||
|
||
|
||
Examples: | ||
>>> type(parsed_result) | ||
<class 'insights.parsers.luksmeta.LuksMeta'> | ||
|
||
>>> parsed_result[0].index | ||
0 | ||
|
||
>>> parsed_result[0].state | ||
'active' | ||
|
||
>>> parsed_result[4].state | ||
'inactive' | ||
|
||
>>> parsed_result[0].metadata is None | ||
True | ||
|
||
>>> parsed_result[1].metadata | ||
'cb6e8904-81ff-40da-a84a-07ab9ab5715e' | ||
""" # noqa | ||
|
||
BAD_LINES = [ | ||
"device is not initialized", | ||
"luksmeta data appears corrupt", | ||
"unknown error", | ||
"invalid slot", | ||
"is not a luksv1 device", | ||
"invalid argument", | ||
"unable to read luksv1 header" | ||
] | ||
|
||
def __init__(self, context): | ||
super(LuksMeta, self).__init__(context, LuksMeta.BAD_LINES) | ||
|
||
def parse_content(self, content): | ||
filename_split = self.file_name.split(".") | ||
|
||
if len(filename_split) >= 4 and filename_split[-4] == "dev" and filename_split[-3] == "disk" and filename_split[-2] == "by-uuid": | ||
self["device_uuid"] = self.file_name.split(".")[-1] if self.file_name else None | ||
|
||
for line in content: | ||
index, state, metadata = line.split() | ||
index = int(index) | ||
metadata = None if metadata == "empty" else metadata | ||
self[index] = KeyslotSpecification(index, state, metadata) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
import doctest | ||
import pytest | ||
|
||
from insights import SkipComponent | ||
from insights.parsers.cryptsetup_luksDump import LuksDump | ||
from insights.parsers import luksmeta | ||
from insights.combiners.cryptsetup import LuksDevices | ||
import insights.combiners.cryptsetup | ||
from insights.tests import context_wrap | ||
|
||
LUKS1_DUMP = """LUKS header information for luks1 | ||
|
||
Version: 1 | ||
Cipher name: aes | ||
Cipher mode: xts-plain64 | ||
Hash spec: sha256 | ||
Payload offset: 4096 | ||
MK bits: 512 | ||
MK digest: ca fe ba be df 8c c4 b4 b8 0a cc dd 98 b5 d8 64 3a 95 3e 9e | ||
MK salt: ca fe ba be 04 3b 77 d8 ff 08 1e 0a 41 68 45 a5 | ||
ca fe ba be 7b 3f a9 69 9c 9b 51 24 58 47 8d a2 | ||
ca fe ba be 7b 3f a9 69 9c 9b 51 24 58 47 8d a2 | ||
ca fe ba be 7b 3f a9 69 9c 9b 51 24 58 47 8d a2 | ||
ca fe ba be 7b 3f a9 69 9c 9b 51 24 58 47 8d a2 | ||
ca fe ba be 7b 3f a9 69 9c de ad be ef | ||
MK iterations: 106562 | ||
UUID: 263902da-5f0c-43a9-82eb-cc6f14d90448 | ||
|
||
Key Slot 0: ENABLED | ||
Iterations: 2099250 | ||
Salt: de ad be ef | ||
Salt: ca fe ba be a1 f3 ae cb 4a 3f f0 2d de ad be ef | ||
de ad be ef | ||
Key material offset: 8 | ||
AF stripes: 4000 | ||
Key Slot 1: ENABLED | ||
Iterations: 1987820 | ||
Salt: ca fe ba be f2 b7 7d f3 29 c2 c8 80 de ad be ef | ||
ca fe ba be 9f a1 87 07 c6 4f aa cd de ad be ef | ||
ca fe ba be 9f a1 87 07 c6 4f aa de ad be ef | ||
Key material offset: 512 | ||
AF stripes: 4000 | ||
Key Slot 2: ENABLED | ||
Iterations: 2052006 | ||
Salt: ca fe ba be 47 94 e7 40 22 c1 bb 4a de ad be ef | ||
ca fe ba be 52 e8 8d 70 b2 1e 9d 47 de ad be ef | ||
Key material offset: 1016 | ||
AF stripes: 4000 | ||
Key Slot 3: DISABLED | ||
Key Slot 4: DISABLED | ||
Key Slot 5: DISABLED | ||
Key Slot 6: DISABLED | ||
Key Slot 7: DISABLED | ||
""" # noqa | ||
|
||
LUKS2_DUMP = """LUKS header information | ||
Version: 2 | ||
Epoch: 6 | ||
Metadata area: 16384 [bytes] | ||
Keyslots area: 16744448 [bytes] | ||
UUID: cfbcc942-e06b-4c4a-952f-e9c9b2011c27 | ||
Label: (no label) | ||
Subsystem: (no subsystem) | ||
Flags: (no flags) | ||
|
||
Data segments: | ||
0: crypt | ||
offset: 16777216 [bytes] | ||
length: (whole device) | ||
cipher: aes-xts-plain64 | ||
sector: 4096 [bytes] | ||
|
||
Keyslots: | ||
0: luks2 | ||
Key: 512 bits | ||
Priority: normal | ||
Cipher: aes-xts-plain64 | ||
Cipher key: 512 bits | ||
PBKDF: argon2id | ||
Time cost: 7 | ||
Memory: 1048576 | ||
Threads: 4 | ||
Salt: ca fe ba be fe 1c 90 d8 2a 35 b2 b2 de ad be ef | ||
ca fe ba be b2 dd 45 9e ed 9a 33 b2 de ad be ef | ||
de ad be ef | ||
AF stripes: 4000 | ||
AF hash: sha256 | ||
Area offset:32768 [bytes] | ||
Area length:258048 [bytes] | ||
Digest ID: 0 | ||
1: luks2 | ||
Key: 512 bits | ||
Priority: normal | ||
Cipher: aes-xts-plain64 | ||
Cipher key: 512 bits | ||
PBKDF: argon2id | ||
Time cost: 7 | ||
Memory: 1048576 | ||
Threads: 4 | ||
Salt: ca fe ba be c1 94 15 86 2a e9 26 f8 de ad be ef | ||
ca fe ba be 05 2d 80 c9 56 e8 4d 6f de ad be ef | ||
AF stripes: 4000 | ||
AF hash: sha256 | ||
Area offset:290816 [bytes] | ||
Area length:258048 [bytes] | ||
Digest ID: 0 | ||
2: luks2 | ||
Key: 512 bits | ||
Priority: normal | ||
Cipher: aes-xts-plain64 | ||
Cipher key: 512 bits | ||
PBKDF: pbkdf2 | ||
Hash: sha512 | ||
Iterations: 1000 | ||
Salt: ca fe ba be d7 8f a6 de a0 cb a4 d1 de ad be ef | ||
ca fe ba be fb 53 43 06 e8 83 90 93 de ad be ef | ||
AF stripes: 4000 | ||
AF hash: sha512 | ||
Area offset:548864 [bytes] | ||
Area length:258048 [bytes] | ||
Digest ID: 0 | ||
Tokens: | ||
0: systemd-tpm2 | ||
tpm2-pcrs: 7 | ||
tpm2-bank: sha256 | ||
tpm2-primary-alg: ecc | ||
tpm2-blob: 00 9e 00 20 bd 97 78 70 3f 3a 5b 93 d4 8f dc ed | ||
10 16 b2 ce f5 f7 a2 c8 63 f6 19 12 63 7a f2 94 | ||
26 f1 b6 1b 00 10 2e 36 26 c1 3b f7 1e 8d 86 55 | ||
tpm2-policy-hash: | ||
df 06 80 28 e7 67 b1 d0 34 f4 de 1b 8e ac 33 5a | ||
df 06 80 28 e7 67 b1 d0 34 f4 de 1b 8e ac 33 5a | ||
Keyslot: 2 | ||
Digests: | ||
0: pbkdf2 | ||
Hash: sha256 | ||
Iterations: 129774 | ||
Salt: ca fe ba be e0 65 83 82 35 03 29 56 de ad be ef | ||
ca fe ba be de 69 39 97 d5 b3 ac c4 de ad be ef | ||
de ad be ef | ||
Digest: ca fe ba be 9d 46 9b 0f 3a 0f 57 13 de ad be ef | ||
ca fe ba be ed 7d 09 2c 3d b6 fa f4 de ad be ef | ||
""" # noqa | ||
|
||
LUKSMETA_OUTPUT = """0 active empty | ||
1 active cb6e8904-81ff-40da-a84a-07ab9ab5715e | ||
2 active empty | ||
3 active empty | ||
4 inactive empty | ||
5 active empty | ||
6 active cb6e8904-81ff-40da-a84a-07ab9ab5715e | ||
7 active cb6e8904-81ff-40da-a84a-07ab9ab5715e | ||
""" # noqa | ||
|
||
luks1_device = LuksDump(context_wrap(LUKS1_DUMP)) | ||
luks2_device = LuksDump(context_wrap(LUKS2_DUMP)) | ||
uuid = luks1_device.dump["header"]["UUID"] | ||
luksmeta_parsed = luksmeta.LuksMeta(context_wrap(LUKSMETA_OUTPUT, path="/insights_commands/cryptsetup_luksDump_--disable-external-tokens_.dev.disk.by-uuid." + uuid)) | ||
luksmeta_parsed_no_uuid = luksmeta.LuksMeta(context_wrap(LUKSMETA_OUTPUT)) | ||
|
||
|
||
def test_luks_devices_combiner(): | ||
with pytest.raises(SkipComponent): | ||
luks_devices = LuksDevices([], None) | ||
|
||
luks_devices = LuksDevices([luks1_device, luks2_device], None) | ||
for device in luks_devices: | ||
assert "luksmeta" not in device | ||
|
||
luks_devices = LuksDevices([luks1_device, luks2_device], []) | ||
for device in luks_devices: | ||
assert "luksmeta" not in device | ||
|
||
luks_devices = LuksDevices([luks1_device, luks2_device], [luksmeta_parsed_no_uuid]) | ||
for device in luks_devices: | ||
assert "luksmeta" not in device | ||
|
||
luks_devices = LuksDevices([luks1_device, luks2_device], [luksmeta_parsed]) | ||
for device in luks_devices: | ||
if device["header"]["UUID"] == uuid: | ||
assert "luksmeta" in device | ||
else: | ||
assert "luksmeta" not in device | ||
|
||
|
||
def test_doc_examples(): | ||
env = { | ||
'luks_devices': LuksDevices([luks1_device, luks2_device], [luksmeta_parsed]) | ||
} | ||
failed, total = doctest.testmod(insights.combiners.cryptsetup, globs=env) | ||
assert failed == 0 |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that the
LuksMeta
should not be anoptional
for this combiner, since it's required for the check of L77.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My reasoning behind this is that every LUKS1/2 device has to have one
LuksDump
object, whereasLuksMeta
objects are created only for devices that are LUKS1 and are initialized usingluksmeta
. Therefore, if the device is not formatted usingluksmeta
, we just pass-throughLuksDump
dictionary, and if it is initialized usingluksmeta
we add a"luksmeta"
entry into theLuksDump
output. So theLuksDump
must always be present, and optionally forluksmeta
devices, we also add the information fromLuksMeta
parser.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just checked your latest update to the test of this combiner, it now looks good to me. Sorry for the late reply, I was just back from a long leave.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, thank you for the review.