我正在使用 Almalinux,以防这与此相关。
我们在本地磁盘上使用 LUKS2,并在其顶部使用 LVM - 因此 /dev/sda1 和 2 未加密,但 /dev/sda3 已加密并用于操作系统。
我们还使用 clevis/tang 进行自动解密(并且运行良好)。
当我们通过 kickstart 构建时,我们会在加密和构建时设置一个临时密码 - 然后当我们完成初始构建时,我们会使用 ansible 根据我们的保险库/安全实践设置高质量的密码。
因此这涉及一个执行下列操作的脚本:
cryptsetup luksOpen -S 0 --test-passphrase /dev/sda3 && cryptsetup luksChangeKey -S0 --force-password --batch-mode
(当然,我们会对‘默认’构建密码进行测试,并将其替换为我们密钥管理系统中的密码)。
最近它开始失败了,我有点困惑不知道可能出了什么问题。
它确实适用于我们最初的“构建”,它使用稍微过时的构建图像,但然后我们dnf update
到当前修订版,现在我们似乎无法再使用 luksChangeKey 或 luksAddkey。
# Adding new keyslot 2 by passphrase, volume key provided by passphrase (-1).
# Selected keyslot 2.
# Keyslot 0 priority 1 != 2 (required), skipped.
# Keyslot 1 priority 1 != 2 (required), skipped.
# Trying to open LUKS2 keyslot 0.
# Running keyslot key derivation.
# Reading keyslot area [0x8000].
# Acquiring read lock for device /dev/sda3.
# Opening lock resource file /run/cryptsetup/L_8:3
# Verifying lock handle for /dev/sda3.
# Device /dev/sda3 READ lock taken.
# Reusing open ro fd on device /dev/sda3
# Device /dev/sda3 READ lock released.
# Verifying key from keyslot 0, digest 0.
# Keyslot 2 assigned to digest 0.
# Trying to allocate LUKS2 keyslot 2.
# Found area 548864 -> 806912
# Running argon2id() benchmark.
# PBKDF benchmark: memory cost = 65536, iterations = 4, threads = 4 (took 72 ms)
# PBKDF benchmark: memory cost = 227555, iterations = 4, threads = 4 (took 264 ms)
# PBKDF benchmark: memory cost = 1048576, iterations = 6, threads = 4 (took 1982 ms)
# Benchmark returns argon2id() 6 iterations, 1048576 memory, 4 threads (for 512-bits key).
# JSON does not fit in the designated area.
# Not enough space in header json area for new keyslot.
# Rolling back in-memory LUKS2 json metadata.
# Releasing crypt device /dev/sda3 context.
# Releasing device-mapper backend.
# Closing read only fd for /dev/sda3.
Command failed with code -1 (wrong or missing parameters).
我想知道是否有人能够帮助我了解这里出了什么问题,以及我需要做什么来解决它。
是否有一个“初始标头大小”选项可以指定在我们的构建中?或者 cryptsetup 的参数?或者我“只是”发现了一个错误?(但我不相信像这种广泛使用的东西cryptsetup
会有“没有人可以更改密码”之类的错误)
这是 LUKs 标头在示例主机上的样子。
LUKS header information
Version: 2
Epoch: 5
Metadata area: 16384 [bytes]
Keyslots area: 16744448 [bytes]
UUID:
Label: (no label)
Subsystem: (no subsystem)
Flags: (no flags)
Data segments:
0: crypt
offset: 16777216 [bytes]
length: (whole device)
cipher: aes-xts-plain64
sector: 512 [bytes]
Keyslots:
0: luks2
Key: 512 bits
Priority: normal
Cipher: aes-xts-plain64
Cipher key: 512 bits
PBKDF: argon2id
Time cost: 9
Memory: 1048576
Threads: 4
Salt:
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: pbkdf2
Hash: sha256
Iterations: 1000
Salt:
AF stripes: 4000
AF hash: sha256
Area offset:290816 [bytes]
Area length:258048 [bytes]
Digest ID: 0
Tokens:
0: clevis
Keyslot: 1
Digests:
0: pbkdf2
Hash: sha256
Iterations: 105025
Salt:
Digest:
我是不是错过了什么深刻的东西?正如所说,如果我不将盒子“升级”到较新的内核,我确信这可以工作,所以我当前的解决方法是构建它,手动重新键入它,然后继续更新它,但这似乎……不是最理想的。
cryptsetup 版本 2.6.0 和 2.7.2
head -c 1M /dev/sda3 | strings -n 128
重新格式化:
{
"keyslots": {
"0": {
"type": "luks2",
"key_size": 64,
"af": {
"type": "luks1",
"stripes": 4000,
"hash": "sha256"
},
"area": {
"type": "raw",
"offset": "32768",
"size": "258048",
"encryption": "aes-xts-plain64",
"key_size": 64
},
"kdf": {
"type": "argon2id",
"time": 7,
"memory": 1048576,
"cpus": 4,
"salt": "(removed)"
}
},
"1": {
"type": "luks2",
"key_size": 64,
"af": {
"type": "luks1",
"stripes": 4000,
"hash": "sha256"
},
"area": {
"type": "raw",
"offset": "290816",
"size": "258048",
"encryption": "aes-xts-plain64",
"key_size": 64
},
"kdf": {
"type": "pbkdf2",
"hash": "sha256",
"iterations": 1000,
"salt": "(removed)"
}
}
},
"tokens": {
"0": {
"type": "clevis",
"keyslots": [
"1"
],
"jwe": {
"ciphertext": "(removed)",
"encrypted_key": "",
"iv": "(removed)",
"protected": "",
"tag": "(removed)"
}
}
},
"segments": {
"0": {
"type": "crypt",
"offset": "16777216",
"size": "dynamic",
"iv_tweak": "0",
"encryption": "aes-xts-plain64",
"sector_size": 512
}
},
"digests": {
"0": {
"type": "pbkdf2",
"keyslots": [
"0",
"1"
],
"segments": [
"0"
],
"hash": "sha256",
"iterations": 88086,
"salt": "(removed)",
"digest": "(removed)"
}
},
"config": {
"json_size": "12288",
"keyslots_size": "16744448"
}
}
编辑2:情节变得更加复杂:luksHeaderBackup 然后恢复失败。
但删除“插槽 0”并添加密钥仍然有效。(假设您可以提取“插槽 1”,但在我的案例中clevis-luks-pass
效果已经足够好了)
总结一下我针对 cryptsetup 的“问题”报告,可以在这里找到:https ://gitlab.com/cryptsetup/cryptsetup/-/issues/924
这个问题的根源与通过 Kickstart 创建时 LUKS 标头的默认大小以及 clevis/tang 占用的占用空间的大小有关。
具体来说,当我构建这些盒子时,我使用了 kickstart 指令:
这将应用 luksFormat 的默认值(在 almalinux 中,不确定是否始终是默认值),即 LUKS 标头为 16MB,但 JSON 元数据区域为 16k - 4k。
这通常没问题,因为 luks 密钥槽没有很多元数据,所以总体来说是一个合理的默认值。
然而,我们使用 U 形夹/柄脚进行解锁和设置 - 在启动过程中 -
clevis luks bind
出于弹性原因,我们使用 6 个 tang 服务器(每个站点 3 个)。
我们的 kickstart 安装后脚本包括:
但是,我们确实为解锁定义了 6 个 tang 服务器
sss
,这可能异常大。(但是为了双站点弹性 - 我们真的不想处于整个企业无法在没有多次故障的情况下启动的情况)uvis 元数据相当大,并且向元数据区域添加了大约 10k,因此如果我们检查占用情况:
其中大部分内容位于 tokens.0.jwe.protected 键中,大约有 10k。(在上面的文章中,为了简洁起见,将其截断)。
例如:
并将其与配置的元数据区域进行比较:
因此,我们只有“几个”空闲字节,这对于新密钥来说不够。
这曾经在我们的 9.1 部署中起作用,因为
cryptsetup
会进行就地替换,而这正是我感到困惑的根源——我仍然可以在启动后立即重现成功的 luksChangeKey,在 9.1 initrd 和 9.2 repo 上构建:我不清楚为什么这是不同的,因为这是具有相同加密库的 cryptsetup 2.6.0,但在我上面的例子中,ChangeKey 使用
我们没有空间容纳另一个键槽,而且我们从来没有这样做过,因为 clevis/tang 占据了更多的 JSON 标头,这就是它失败的原因。
因此,解决这个问题的方法是:
使用更大的 json 元数据区域重新格式化磁盘。
例如,默认值 16k 意味着 16k - 4k 可用,这就是我们所拥有的。
这将是一个破坏性的选择,需要备份/恢复或重建磁盘。
不方便的是,kickstart
part
指令不支持标志的任何必要选项--encryption
,因此您必须对分区创建逻辑做一些更复杂的事情,很可能通过%pre
脚本来选择驱动器、分区大小,并将所需的参数直接传递给 cryptsetup luksFormat。转储标题、调整其大小并恢复它。
没有详细的过程,但应该可以
cryptsetup luksDump --dump-volume-key
使用相同的设置创建适当大小的新标头:加密参数(密码、模式、扇区大小)、LUSK2 设备 uuid 和相同的数据偏移量 - 当然还有音量密钥 - 然后用新的替换旧的标头。cryptsetup-luksDump 和 cryptsetup-luksFormat 手册页将在这里作为参考。
尽管有一个巨大的警告,说这有点……危险,但以下方法似乎已经成功了:
祈祷并重新启动,因为如果您做错了,您的系统可能就无法恢复了。(我的意思是,也许您将 volkey/header 备份到了另一台设备,但请记住,这存在安全风险,因此请谨慎使用)。
通过在“新”标题上设置的临时密码上使用 luksChangeKey 来验证是否成功,将其更改为您通常使用的更合适的密码。(如果它启动了,您就知道 clevis/tang 起作用了)。
只需使用两个键槽,并在需要时使用 U 形夹解密选项来更改“其他”键。
将提取 clevis 生成并使用的密码,以便您可以使用它来
luksKillSlot
执行luksAddKey
。这可能并不总是适用,但在上述情况下(我们的插槽 0 luks 密码是当 U 形夹/柄脚机制失效时的后备情况),它将是可行的。不过,您仍然无法添加任何密钥。