BLFS Security

p11-kit

备注

make-ca 依赖 p11-kit ,而 p11-kit 依赖 libtasn1

安装p11-kit
cd /sources

p11_kit_VERSION=0.25.5
tar xf p11-kit-${p11_kit_VERSION}.tar.xz
cd p11-kit-${p11_kit_VERSION}

# 准备发行版特定anchor hook
sed '20,$ d' -i trust/trust-extract-compat &&

cat >> trust/trust-extract-compat << "EOF"
# Copy existing anchor modifications to /etc/ssl/local
/usr/libexec/make-ca/copy-trust-modifications

# Update trust stores
/usr/sbin/make-ca -r
EOF

# 安装
mkdir p11-build &&
cd    p11-build &&

meson setup ..            \
      --prefix=/usr       \
      --buildtype=release \
      -D trust_paths=/etc/pki/anchors &&
ninja

ninja install &&
ln -sfv /usr/libexec/p11-kit/trust-extract-compat \
        /usr/bin/update-ca-certificates

make-ca

备注

cURL依赖 make-ca 提供的证书来验证HTTPS网站CA,所以这个库必须安装

最好在之前先安装好 Fcron ,这样就可以设置定时任务进行证书更新

公钥基础设施 (PKI) 是一种在不受信任的网络上验证未知实体真实性的方法。

PKI 的工作原理是建立信任链,而不是明确信任每个单独的主机或实体。为了使远程实体提供的证书受到信任,该证书必须提供完整的证书链,可以使用本地计算机信任的证书颁发机构 (CA) 的根证书进行验证。

BLFS使用的证书存储取自 Mozilla 基金会,他们制定了此处描述的非常严格的包含政策。

安装make-ca
cd /sources

make_ca_VERSION=1.14
tar xf make-ca-${make_ca_VERSION}.tar.gz
cd make-ca-${make_ca_VERSION}

# make-ca脚本会瞎子啊和处理包含在 certdata.txt 文件中的证书作为p11-kit信任模块的信任发布者
make install &&
install -vdm755 /etc/ssl/local

# 注意: 这步一定要确保成功,因为需要下载存放一个 /etc/ssl/certdata.txt
# 这个 certdata.txt 将用于后续 Adding Additional CA Certificates
# 注意: 这个命令执行失败是应为GFW屏蔽了Mozilla的证书下载服务器 https://hg.mozilla.org/ ,需要设置代理
# 注意: 只有这个命令执行成功才能确保本地根证书正确,才能使用 curl 下载 HTTPS 文件
/usr/sbin/make-ca -g

# 需要周期性执行以下命令,所以需要先安装一个fcron以便能够定时执行
# 然后执行以下命令创建定时任务
mkdir /etc/cron.weekly
cat > /etc/cron.weekly/update-pki.sh << "EOF" &&
#!/bin/bash
/usr/sbin/make-ca -g
EOF
chmod 754 /etc/cron.weekly/update-pki.sh

# 添加CA证书 Adding Additional CA Certificates
# 也就是更新之前 ``install -vdm755 /etc/ssl/local`` 在 ``/etc/ssl/local`` 目录下生成的
# CAcert_Class_1_root.pem 和 CAcert_Class_3_root.pem
# 初次安装这个步骤不需要,不过后续更新了 /etc/ssl/certdata.txt 则需要执行
wget http://www.cacert.org/certs/root.crt &&
wget http://www.cacert.org/certs/class3.crt &&
openssl x509 -in root.crt -text -fingerprint -setalias "CAcert Class 1 root" \
        -addtrust serverAuth -addtrust emailProtection -addtrust codeSigning \
        > /etc/ssl/local/CAcert_Class_1_root.pem &&
openssl x509 -in class3.crt -text -fingerprint -setalias "CAcert Class 3 root" \
        -addtrust serverAuth -addtrust emailProtection -addtrust codeSigning \
        > /etc/ssl/local/CAcert_Class_3_root.pem &&
/usr/sbin/make-ca -r

# 设置Python3使用系统证书,则添加以下变量
mkdir -pv /etc/profile.d &&
cat > /etc/profile.d/pythoncerts.sh << "EOF"
# Begin /etc/profile.d/pythoncerts.sh

export _PIP_STANDALONE_CERT=/etc/pki/tls/certs/ca-bundle.crt

# End /etc/profile.d/pythoncerts.sh
EOF

make-ca 通常不需要配置,而且,默认的 certdata.txt 由mozilla发布所提供后由 make-ca 创建。不过,这个文件对于一些发行版或Mozilla,使用 nss 版本。(这部分我没有实践)

  • 我在执行 make-ca -g 时遇到报错 Unable to get revision from server! Exiting. ,也就是没有能够获得 /etc/ssl/certdata.txt 。而这个 /etc/ssl/certdata.txt 是用于后续 Adding Additional CA Certificates ,所以非常关键。

  • 仔细阅读BLFS,这个 certdata.txt 是从 https://hg.mozilla.org 获得的,如果拿不到服务器上这个文件,说明需要从 make-ca release page 下载最新的版本才能解决。但是,比较奇怪,我发现当前 make-ca release page 就是我使用的 make-ca-1.14 。所以我暂时不知道怎么解决这个问题

我的 make-ca 安装部署存在问题,导致 curl 下载 HTTPS 文件(包括 git clone https )都会提示报错:

提示SSL证书错误
Cloning into 'libffi'...
fatal: unable to access 'https://gitlab.freedesktop.org/gstreamer/meson-ports/libffi.git/': SSL certificate problem: unable to get local issuer certificate

../meson.build:2218:13: ERROR: Git command failed: ['/usr/bin/git', '-c', 'advice.detachedHead=false', 'clone', '--depth', '1', '--branch', 'meson', 'https://gitlab.freedesktop.org/gstreamer/meson-ports/libffi.git', 'libffi']

对比了 Debian 安装的虚拟机,我发现我的LFS系统 /etc/ssl/certs 是空目录,正常情况下,这个目录下是CA根证书

根据BLFS make-ca 文档,执行 make-ca -g 会下载证书源,但看起来我这个步骤失败

原因是 https://hg.mozilla.org/ 被GFW屏蔽了

执行 -x 运行 /usr/bin/make-ca -g 可以看到需要下载的是 https://hg.mozilla.org/projects/nss/log/tip/lib/ckfw/builtins/certdata.txt ,下载命令实际上是通过 openssl 来完成的:

获取 certdata.txt 的脚本命令
+ echo GET https://hg.mozilla.org/projects/nss/log/tip/lib/ckfw/builtins/certdata.txt
+ /usr/bin/openssl s_client -ign_eof -connect hg.mozilla.org:443 -verifyCAfile /etc/make-ca/mozilla-ca-root.pem -verifyCApath /etc/ssl/certs -verify_return_error

参考 Using OpenSSL Behind a (Corporate) Proxy , openssl 有一个 -proxy 参数,类似可以传递 -proxy 127.0.0.1:3128 。由于 /usr/bin/make-ca 是一个脚本,检查可以看到该脚本检查环境变量 PROXY 来对应设置 openssl -proxy ,所以通过以下方法成功完成:

设置 openssl 代理
export PROXY="117.0.0.1:3128"
/usr/sbin/make-ca -g

成功执行 /usr/sbin/make-ca -g 之后,就能够正常执行 git clone https://...

OpenSSH

  • openssh:

安装openssh
cd /sources

openssh_VERSION=9.8p1
tar xf openssh-${openssh_VERSION}.tar.gz
cd openssh-${openssh_VERSION}

# 准备环境
install -v -g sys -m700 -d /var/lib/sshd &&

groupadd -g 50 sshd        &&
useradd  -c 'sshd PrivSep' \
         -d /var/lib/sshd  \
         -g sshd           \
         -s /bin/false     \
         -u 50 sshd

# 安装
./configure --prefix=/usr                            \
            --sysconfdir=/etc/ssh                    \
            --with-privsep-path=/var/lib/sshd        \
            --with-default-path=/usr/bin             \
            --with-superuser-path=/usr/sbin:/usr/bin \
            --with-pid-dir=/run                      &&
make

make install &&
install -v -m755    contrib/ssh-copy-id /usr/bin     &&

install -v -m644    contrib/ssh-copy-id.1 \
                    /usr/share/man/man1              &&
install -v -m755 -d /usr/share/doc/openssh-${openssh_VERSION}     &&
install -v -m644    INSTALL LICENCE OVERVIEW README* \
                    /usr/share/doc/openssh-${openssh_VERSION}
  • 设置

配置openssh
echo "PermitRootLogin no" >> /etc/ssh/sshd_config
echo "PasswordAuthentication no" >> /etc/ssh/sshd_config &&
echo "KbdInteractiveAuthentication no" >> /etc/ssh/sshd_config

# 如果添加了Linux-PAM支持,就可以通过密码认证登陆
sed 's@d/login@d/sshd@g' /etc/pam.d/login > /etc/pam.d/sshd &&
chmod 644 /etc/pam.d/sshd &&
echo "UsePAM yes" >> /etc/ssh/sshd_config

备注

ssh 使用 Linux-PAM 支持来做密码认证,如果不需要密码认证,就不需要Linux-PAM

我采用密钥认证登陆

启动配置

启动配置是通过 BLFS Boot Scripts

通过BLFS Boot Scripts启动ssh
cd /sources

blfs_bootscripts_VERSION=20240416
tar xf blfs-bootscripts-${blfs_bootscripts_VERSION}.tar.xz
cd blfs-bootscripts-${blfs_bootscripts_VERSION}

make install-sshd

异常排查

遇到一个非常奇怪的问题,完全一样的 authorized_keys ,分别存放在 root 用户和 admin 用户的 ~/.ssh/ 目录下 , root 用户无密码登陆完全正常,但是 admin 用户登陆直接拒绝:

公钥登陆被拒绝
admin@192.168.7.200: Permission denied (publickey).

已经核对:

  • ~/.ssh/ 目录 700 , ~/.ssh/authorized_keys 文件 644 或者 600

  • ~/.ssh/authorized_keys 文件内容和md5都对比一致

我以前遇到类似密钥无法登陆,基本上就是认证密钥文件属性设置不正确,但这次不是。

我在检查 /etc/shadow 文件时意外发现 admin 账号没有设置过密码。我原本以为我强制通过密钥认证可以不用设置这个普 通用户密码,但是实践发现, 用户账号必须设置密码,即使SSH是通过密钥认证登陆

也就是说,在 /etc/ssh/sshd_config 中设置了(默认)如下:

默认设置sshd不可以空白密码
# To disable tunneled clear text passwords, change to no here!
#PasswordAuthentication yes
#PermitEmptyPasswords no

这个不允许用户空密码原来不是指ssh客户端连接以后,用户输入的空密码,而是服务器端用户账号本身就不允许空密码。只要服务器上 的用户密码没有设置,ssh就禁止该账号登陆,哪怕SSH客户端密钥认证是正确的也不行。 空密码校验逻辑在前

sudo

sudo
cd /sources

sudo_VERSION=1.9.15p5
tar xf sudo-${sudo_VERSION}.tar.gz
cd sudo-${sudo_VERSION}

./configure --prefix=/usr              \
            --libexecdir=/usr/lib      \
            --with-secure-path         \
            --with-env-editor          \
            --docdir=/usr/share/doc/sudo-${sudo_VERSION} \
            --with-passprompt="[sudo] password for %p: " &&
make

env LC_ALL=C make check |& tee make-check.log
grep failed make-check.log

make install

配置

/etc/sudoers
%wheel ALL=(ALL:ALL) NOPASSWD: ALL

admin 用户加入 wheel 组,这样可以无密码切换到 root