AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 787635
Accepted
Sobrique
Sobrique
Asked: 2024-12-04 20:37:19 +0800 CST2024-12-04 20:37:19 +0800 CST 2024-12-04 20:37:19 +0800 CST

Cryptsetup 报告“标头 json 区域中没有足够的空间容纳新的密钥槽”

  • 772

我正在使用 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效果已经足够好了)

luks
  • 1 1 个回答
  • 51 Views

1 个回答

  • Voted
  1. Best Answer
    Sobrique
    2024-12-12T22:08:30+08:002024-12-12T22:08:30+08:00

    总结一下我针对 cryptsetup 的“问题”报告,可以在这里找到:https ://gitlab.com/cryptsetup/cryptsetup/-/issues/924

    这个问题的根源与通过 Kickstart 创建时 LUKS 标头的默认大小以及 clevis/tang 占用的占用空间的大小有关。

    具体来说,当我构建这些盒子时,我使用了 kickstart 指令:

    part pv.0 --fstype=lvmpv --size=1000 --grow --encrypted --passphrase=DEFAULT_PASSWORD
    

    这将应用 luksFormat 的默认值(在 almalinux 中,不确定是否始终是默认值),即 LUKS 标头为 16MB,但 JSON 元数据区域为 16k - 4k。

    这通常没问题,因为 luks 密钥槽没有很多元数据,所以总体来说是一个合理的默认值。

    然而,我们使用 U 形夹/柄脚进行解锁和设置 - 在启动过程中 -clevis luks bind

    出于弹性原因,我们使用 6 个 tang 服务器(每个站点 3 个)。

    我们的 kickstart 安装后脚本包括:

    ## Below has been manually wrapped for ease of reading
    
    CLEVIS_CFG='{"t":2,"pins":{"tang":[{"url":"http://tang-10.sitea.domain"},
    {"url":"http://tang-11.siteb.domain"},
    {"url":"http://tang-12.sitea.domain"},
    {"url":"http://tang-13.siteb.domain"},
    {"url":"http://tang-14.sitea.domain"},
    {"url":"http://tang-15.siteb.domain"}]}}'
    
    for device in /dev/sd*[0-9] /dev/nvm*[0-9]
    do
       echo checking $device for being LUKS
       cryptsetup isLuks $device
       if [ $? -eq 0 ] 
       then
          echo "$device is LUKS doing clevis sss config"
          clevis luks list -d $device
          echo $DEFAULT_PASSWORD | clevis luks bind -k - -d $device -y -f sss $CLEVIS_CFG
          echo "Final state post clevis:"
          cryptsetup luksDump $device
       fi
    done
    

    但是,我们确实为解锁定义了 6 个 tang 服务器sss,这可能异常大。(但是为了双站点弹性 - 我们真的不想处于整个企业无法在没有多次故障的情况下启动的情况)

    uvis 元数据相当大,并且向元数据区域添加了大约 10k,因此如果我们检查占用情况:

    [root@desktop~]# cryptsetup luksDump --dump-json-metadata /dev/sda3 | jq -c | wc -c
    12111
    

    其中大部分内容位于 tokens.0.jwe.protected 键中,大约有 10k。(在上面的文章中,为了简洁起见,将其截断)。

    例如:

    [root@desktop ~]# cryptsetup luksDump /dev/sda3 --dump-json-metadata | jq '.tokens."0".jwe.protected' | wc -c
    10849
    

    并将其与配置的元数据区域进行比较:

    "config":{
        "json_size":"12288",
        "keyslots_size":"16744448"
      }
    

    因此,我们只有“几个”空闲字节,这对于新密钥来说不够。

    这曾经在我们的 9.1 部署中起作用,因为cryptsetup会进行就地替换,而这正是我感到困惑的根源——我仍然可以在启动后立即重现成功的 luksChangeKey,在 9.1 initrd 和 9.2 repo 上构建:

    # Key change, old slot 0, new slot 0.
    # Key slot 0 is going to be overwritten.
    # Wiping keyslot 0 area only.
    

    我不清楚为什么这是不同的,因为这是具有相同加密库的 cryptsetup 2.6.0,但在我上面的例子中,ChangeKey 使用

    # Verifying key from keyslot 0, digest 0.
    # Keyslot 2 assigned to digest 0.
    # Trying to allocate LUKS2 keyslot 2.
    

    我们没有空间容纳另一个键槽,而且我们从来没有这样做过,因为 clevis/tang 占据了更多的 JSON 标头,这就是它失败的原因。

    因此,解决这个问题的方法是:

    使用更大的 json 元数据区域重新格式化磁盘。

      --luks2-metadata-size <size>
           This option can be used to enlarge the LUKS2 metadata (JSON)
           area. The size includes 4096 bytes for binary metadata
           (usable JSON area is smaller of the binary area). According
           to LUKS2 specification, only these values are valid: 16, 32,
           64, 128, 256, 512, 1024, 2048 and 4096 kB The <size> can be
           specified with unit suffix (for example 128k).
    

    例如,默认值 16k 意味着 16k - 4k 可用,这就是我们所拥有的。

    这将是一个破坏性的选择,需要备份/恢复或重建磁盘。

    不方便的是,kickstartpart指令不支持标志的任何必要选项--encryption,因此您必须对分区创建逻辑做一些更复杂的事情,很可能通过%pre脚本来选择驱动器、分区大小,并将所需的参数直接传递给 cryptsetup luksFormat。

    转储标题、调整其大小并恢复它。

    没有详细的过程,但应该可以cryptsetup luksDump --dump-volume-key使用相同的设置创建适当大小的新标头:加密参数(密码、模式、扇区大小)、LUSK2 设备 uuid 和相同的数据偏移量 - 当然还有音量密钥 - 然后用新的替换旧的标头。

    cryptsetup-luksDump 和 cryptsetup-luksFormat 手册页将在这里作为参考。

    尽管有一个巨大的警告,说这有点……危险,但以下方法似乎已经成功了:

    cryptsetup luksDump --dump-volume-key --volume-key-file=volkey /dev/sda3 
    cryptsetup luksHeaderBackup /dev/sda3 --header-backup-file=headerbackup.img
    
    ## Copy these files to somewhere in case the rest goes wrong. Just bear in mind that someone can use those files to "recover" your system too, so ensure they're handled securely
    
    clevis luks unbind -d /dev/sda3 -s 1 ## may not be necessary
    dd if=/dev/zero of=/tmp/luks_test.img bs=1M count=32
    losetup -f --show /tmp/luks_test.img 
    ## This created /dev/loop0, so use that in the next line. 
    ## note: This NEEDS to have the same block sizes and encryption of sda3
    ## This works because they used the same defaults each time. 
    ##NB If you set a different passphrase, it's a bit easier to confirm that you're using the 'new' one not the 'old' one. 
    cryptsetup luksFormat --volume-key=volkey --uuid=<UUID OF sda3> --luks-metadata-size=32k --force-password /dev/loop0
    cryptsetup luksHeaderBackup /dev/loop0 --header-backup-file=new_luks_header.img
    cryptsetup luksHeaderRestore /dev/sda3 --header-backup-file=new_luks_header.img
    ## rerun the clevis luks bind script referenced in my OP to re-apply the clevis-tang config. 
    

    祈祷并重新启动,因为如果您做错了,您的系统可能就无法恢复了。(我的意思是,也许您将 volkey/header 备份到了另一台设备,但请记住,这存在安全风险,因此请谨慎使用)。

    通过在“新”标题上设置的临时密码上使用 luksChangeKey 来验证是否成功,将其更改为您通常使用的更合适的密码。(如果它启动了,您就知道 clevis/tang 起作用了)。

    只需使用两个键槽,并在需要时使用 U 形夹解密选项来更改“其他”键。

    clevis-luks-pass -d <devicename> -s 1 
    

    将提取 clevis 生成并使用的密码,以便您可以使用它来luksKillSlot执行luksAddKey。

    这可能并不总是适用,但在上述情况下(我们的插槽 0 luks 密码是当 U 形夹/柄脚机制失效时的后备情况),它将是可行的。不过,您仍然无法添加任何密钥。

    • 2

相关问题

  • 在分区上计算零字节的最快方法

  • 向 udisk 提供密码以解锁 LUKS 加密的设备

  • 如何仔细检查 LUKS 密码

  • 如何增加位于加密分区之前的分区大小?

  • 更改加密的lvm根的指定名称?在crypttab中从sdo到sdn?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve