fengbeihong


  • Home

  • Archives

Bash Shell Tips

Posted on 2018-01-07

对企业级产品里的脚本中常用shell做个记录,平时不写shell很少注意到。

set

控制环境变量

1
set -o errexit -o nounset -o pipefail

shift

用来修改参数数组$@
假设执行shell命令bash test.sh 1 2 3 4 5

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash

echo $@ # 1 2 3 4 5

shift
# 等同于shift 1
echo $@ # 2 3 4 5

shift
echo $@ # 3 4 5

shift 2
echo $@ # 5

可以看到shift可以加参数也可以不加,加参数就是从当前参数数组的第几个参数开始截断

$? $0 $@

返回值,参数,默认值等等
${4:-$COMMAND}

declare

声明参数
尤其是声明全局参数

if

判断表达式的用法

1
2
3
4
5
6
7
8
9
10
11
if [ -d /test_dir/ ]; then
# 检测目录是否存在
fi

if [ -f /test_file ]; then
# 检测文件是否存在
fi

if [ -z $TEST_VAL ]; then
# 如果变量为空
fi

比较两个浮点型变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$s1=10
$s2=9

echo $s1'>'$s2 | bc -l
0
echo $s2'>'$s1 | bc -l
1

$s1=10
$s2=10

echo $s1'>'$s2 | bc -l
0
echo $s2'>'$s1 | bc -l
0

trap

1
trap - INT

tr

tr

cut

cut

cat

1
2
cat <<EOM
EOM
1
2
cat <<EOF
EOF

local

local

echo -e

echo -e

case esac

case esac

Solum简介

Posted on 2018-01-07

solum是部署web application的项目。
web app都是跑在各种web server中,所以solum的操作就分为了languagepack和app两个部分。

solum的作用

  • 搭建自动测试系统,并且可以设置在多个版本的runtime环境中进行测试。
  • 自动化部署
  • 应用开发的整个生命周期管理
  • 上述这些都可以和github和docker的特性结合起来,快捷方便
  • CI/CD

下面是部署部署一个app的流程的用到的命令总览:

1
2
3
4
5
6
7
$ solum languagepack create <NAME> <GIT_REPO>
$ solum languagepack show <UUID/Name>
$ solum languagepack logs <UUID>
$ solum languagepack list
$ solum app create --app-file <app_file> [--param-file param_file]
$ solum app show <UUID/Name>
$ curl <application_uri>

languagepack

这个步骤可以创建python、java或其他语言的web应用运行环境。
languagepack需要指定一个git repo,下载Dockerfile和build.sh。

  • Dockerfile用来创建docker image。
1
2
3
4
5
6
7
FROM ubuntu:14.04

RUN apt-get -yqq update
RUN apt-get -yqq install python-pip
RUN apt-get -yqq install python-dev

COPY build.sh /solum/bin/
  • build.sh用来在创建app时执行。
1
2
3
4
5
6
7
8
9
#!/bin/bash

# Check if pip is installed
pip help
[[ $? != 0 ]] && echo python-pip is not installed. && exit 1

# Install dependencies from app requirements file
cd /app
pip install -r requirements.txt

app

创建app会包含一个workflow流程,根据已有的languagepack创建最终的deployment unit(DU),然后用heat去部署.

deployment unit(DU)

DU就是一个打包好的安装了运行环境和application的docker image,可以直接用来创建container运行。
当然这个docker image需要languagepack和app两个步骤最终完成创建。

workflow

  • unittest
  • build
  • deploy

标准的三个步骤,但是这个三个步骤可以选择性的执行,比如只执行unittest和build.

workflow的相关信息都是在appfile.yaml里定义,由参数–app-file指定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
version: 1
name: cherrypy
description: python web app
languagepack: python
source:
repository: https://github.com/rackspace-solum-samples/solum-python-sample-app.git
revision: master
workflow_config:
test_cmd: ./unit_tests.sh # 在unittest步骤里执行什么命令
run_cmd: python app.py # 在build步骤执行什么命令
trigger_actions:
- unittest
- build
- deploy # 就是nova boot的步骤,不过这个依赖nova-docker
ports:
- 80
  • unittest会根据LP去执行docker build,执行unittest脚本,但是不会保存到glance或swift里
  • build这个步骤,根据LP执行docker build,执行build.sh脚本,最终保存到glance或swift里
  • deploy就是通过heat进行nova boot的步骤,依赖nova-docker驱动,从neutron申请IP,从glance下载image。这些取代了直接通过docker的api进行创建容器。
    这个步骤可以和k8s、mesos以及swarm结合使用。
    solum的配置文件中有这个参数:docker_daemon_url = unix://var/run/docker.sock
    solum的对docker的操作,都是通过url的remote API进行请求的。那么,对于docker服务,可以是单独的docker服务,也可以是k8s之类的集群,只要提供和docker一致的API。

https://wiki.openstack.org/wiki/Solum/configurations solum的deploy可以基于docker部署,也可以基于VM

  • docker
    • 设置nova-docker驱动 /etc/nova/nova.conf: compute_driver = novadocker.virt.docker.driver.DockerDriver
    • 把solum的存储项设置为glance /etc/solum/solum.conf image_storage = glance
    • 最后部署的时候需要用basicheat template,https://github.com/openstack/solum/blob/master/etc/solum/templates/basic.yaml
  • VM
    • /etc/nova/nova.conf compute_driver = libvirt.LibvirtDriver
    • /etc/solum/solum.conf image_storage = swift,image_format = vm

当用VM在solum里部署应用时,步骤比较绕

  • 用disk-image-builder创建带有docker的VM image
  • 用这个image创建docker的container,再通过docker的api去安装app的源码,进行测试等操作,最后把image保存到glance
  • 最终用这个image部署在VM上

param_file

在solum app create时也可以用–param-file指定想要inject的参数
这些参数可以通过build步骤里命令脚本去操作

app代码的自动更新部署

app的代码也在git里,而且可以在自己的git里设置hook,在提交代码后,自动向这个web app的地址发送一个POST请求

1
http://10.0.2.15:9777/v1/triggers/<trigger_id>

solum会自动重新build一个新的image然后重新部署app

如果是github的源码,在project的设置里可以设定这个trigger url

devstack开发环境

一共有两种方式,一种用vagrant一种用devstack,直接devstack就可以。

wiki文档地址:https://wiki.openstack.org/wiki/Solum/solum-development-setup

  • local.conf文件直接从它提供的外网地址下载
  • local.conf的配置尤其是密码最好别变,有的服务的密码没有做成可配置,仍然是默认的solum,改动会导致后续的验证失败。
  • nova和neutron先手动下载源码后再git checkout到指定的change id里,应该是最新代码还没测试完。

DCOS和mesos

Posted on 2018-01-07

Mesos

mesos本身的目的是针对当前的各种分布式系统的抽象,拿原始的操作系统进行对比,内核控制各个进程执行某些任务,而到了分布式时代,要从更高层面去看,把每个物理节点当做一个进程,有专门的服务作为抽象的内核对进程进行调控,分配给各个进程去执行任务,就像下面的图,特别像操作系统的概念。
mesos架构

DC/OS

Data Center Operating System
算是mesos的超集,采用了mesos的kernel,然后把mesos中常用的framework(mesos中的概念,表示进程要执行的任务,具体到节点就是mesos的某些agent节点组成的安装的具体的分布式软件)整合到了dcos中,并且提供了良好的界面和CLI,也继承了许多企业级服务如marathon和chronos等,用dcos来完成mesos的data center功能十分高效便捷。

https://support.mesosphere.com/hc/en-us/articles/205097325-How-is-the-Mesosphere-DCOS-different-from-Apache-Mesos-

DC/OS是运行容器的最好方式

https://mesosphere.com/blog/2016/04/19/open-source-dcos/

mesos可以安装运行各种分布式软件,当然也包括docker,不过在最新的mesos1.0中,mesos也实现了自己的容器化技术,就算不安装docker也可以跑容器了。当然,这些容器化技术大概在2015年都统一了标准,互相兼容的。

mesos的手动配置

按照magnum中的部署mesos环境的步骤,手动配置的话模板里会有以下和mesos相关的参数:

magnum部署mesos的流程

  • 首先准备image文件,在image文件会安装好mesos服务所需的zookeeperd、mesos和marathon服务,以及docker-engine服务。
  • 先启动magnum参数所指定的几个master虚拟机,启动完成后会对master节点的服务进行配置,并且启动这些服务。
  • 然后启动agent节点,启动完成后会在节点内部创建/etc/sysconfig/heat-params文件,然后配置agent节点服务,启动服务,最后要等待执行agent_wc_notify操作,并且设置volume服务。

magnum中coe的设计思路

按照magnum里的coe的设计思路,是希望集群里所需要的软件都在image里安装好,之后只需要根据选项进行配置启动就可以。
那么如果把mesos换成dcos,dcos中涉及到的几十个应用也需要提前安装好,在部署完dcos后也可以随时安装卸载对应应用
这就得舍弃dcos提供的安装流程,相当于舍弃已经整合好的安装脚本,换成手动在magnum里重新实现一遍

dcos的安装流程

说下advanced安装方式,在每个节点进行执行的操作来手动执行

  • 先准备两个文件ip-detect和config.yaml,检测IP和进行集群的配置
  • 下载安装脚本文件,这个shell文件里,其实除了脚本还包含了压缩包二进制文件
1
$ curl -O https://downloads.dcos.io/dcos/EarlyAccess/commit/14509fe1e7899f439527fb39867194c7a425c771/dcos_generate_config.sh
  • 执行dcos_generate_config.sh脚本文件,默认的参数就是--genconf,生成了安装的配置信息,文件和路径信息就会如下
1
2
3
4
5
6
7
8
9
10
├── dcos-genconf.<HASH>.tar
├── dcos_generate_config.sh
├── genconf
│ ├── serve
│ │ ├── dcos_install.sh
│ ├── config.yaml
│ ├── ip-detect
│ ├── cluster_packages.json
│ ├── ssh_key
│ ├── state
  • 然后执行docker run,这一步会在bootstrap node启动一个nginx的容器服务,映射端口,并且把./genconf/serve/目录映射到nginx容器里的/usr/share/nginx/html,路径映射的结果就是,可以从其他节点访问nginx服务获取serve目录下的文件
1
$ sudo docker run -d -p <your-port>:80 -v $PWD/genconf/serve:/usr/share/nginx/html:ro nginx
  • 剩下的步骤就是登录到各个节点,master和agent节点,下载下来dcos_install.sh,然后执行安装就可以了
    安装时要指定role,即当前机器为哪类节点,支持master,slave,slave_public
1
2
3
4
$ ssh <master-ip>
$ mkdir /tmp/dcos && cd /tmp/dcos
$ curl -O http://<bootstrap-ip>:<your_port>/dcos_install.sh
$ sudo bash dcos_install.sh master
  • 最后一步就是等待安装完成并且各个节点之间同步完成,如何检测状态,查看Exhibitor服务的信息
1
http://<master-ip>:8181/exhibitor/v1/ui/index.html
  • 现在可以启动DCOS的web界面
1
http://<master-node-public-ip>/

bootstrap node

bootstrap节点是干啥的,在安装过程中都会先启动bootstrap node,把要安装的东西压下载到bootstrap node,生成配置文件,然后进行安装。
安装时也会通过某种方式把配置文件和安装脚本拷贝到master或者agent节点去,然后在具体的节点上执行安装。
文档说bootstrap node是集群的永久性节点,但是个人感觉不是必须的,只是集群必须有一个执行安装程序的节点,卸载时也会需要一个节点来跑执行程序,那么就放到了bootstrap node上,然后bootstrap node也提供了界面化的安装和卸载。
如果把安装放到magnum里去做,那么执行安装程序的操作就交给了magnum的HOT去做,拷贝文件也可以由magnum去做,卸载就是直接删除集群节点,整个流程就用不到bootstrap node了。
另外,在dcos官网的design页面看到,components需要提前下载,并且是在bootstrap node下载,并且build完成,打包,然后再copy到master或agent节点去安装。
那么如果修改的话就方便了,因为dcos_install.sh脚本做的工作就是一个下载,解压,修改配置文件和启动服务。之前的操作放置到DIB里去做。

在安装过程中,master节点,agent节点和bootstrap节点都做了什么具体的工作

参照官网文档:https://dcos.io/docs/1.8/overview/architecture/

DC/OS的安装脚本生成流程,以及安装流程

dcos的源码下载下来后,根目录执行build_local.sh

1
2
3
4
5
# Install the DC/OS tools
./prep_local

# Build a release of DC/OS
release create `whoami` local_build

第一步pre_local会执行setuptools的打包脚本,打包出一些需要的命令,比如release命令(python命令)
第二步就正式执行打包命令

  • 下载packages,编译,保存编译结果
  • 把一些模板文件和配置文件初始化
  • 把上述的文件根据Dockerfile,docker build出docker image的tar包
  • 最终把docker image和脚本文件合并成为dcos_generate_config.sh

dcos_generate_config.sh是最初的安装脚本,由脚本和一个docker image二进制数据共同组成。

  • 脚本由dcos_generate_config.sh.in模板生成
  • docker image由配置的各个文件和Dockerfile,一起docker build后进行docker save的一个tar包。所以不能只看tar包信息,需要看docker build前的原始信息。

执行dcos_generate_config.sh --genconf会生成配置文件,这一步会执行docker run,运行的就是docker image里的内容。那么要看如何生成配置文件,就需要看docker image是如何生成的。
dcos_generate_config.sh --genconf在源码中的entry_point是ext/dcos-installer/cli.py:main

综上,要抽出安装脚本中需要的部分:packages文件、配置文件以及安装脚本
其中packages文件要放到DIB中,配置文件无需改动的放到DIB中,安装脚本和部分需要改动的配置文件放在外面
对应到执行命令,就是dcos_generate_config.sh --genconf这个操作时,会变动的配置文件放到外面,其他的放到DIB中

  • 下载dcos源码,从头制作安装文件
    这种需要重新下载和build各个packages包,还要初始化各个配置文件,耗时长,也有很多不确定因素会导致失败
  • 直接下载编译好的dcos_generate_config.sh
    这种需要执行docker run才能生成配置文件,依赖docker,但是解压文件后都是编译好的packages,节省时间,但是下载整个文件也需要花一定时间。

制作DIB

  • 下载dcos_generate_config.sh,执行dcos_generate_config.sh --genconf,生成配置文件
  • 找到安装过程脚本,单独执行,把packages文件和配置文件放置到对应位置,生成DIB

magnum中的可配置文件

  • 找到生成配置文件的脚本,把ip-detect和cloud-config.yaml所影响的配置文件集中放置在magnum中,初始化这些模板文件后,拷贝到对应位置
  • ext/dcos-installer/cli.py:main

Magnum Bay Create简析

Posted on 2018-01-07

magnum组件只有magnum-api和magnum-conductor两个服务,那么入手点就简单了,请求都传递给magnum-conductor来执行了。
下面是magnum的源码结构,已经去掉了一些不重要的目录

1
2
3
4
5
6
7
8
9
10
11
12
magnum
├── api # magnum-api服务的代码,http服务
├── cmd # 命令行启动服务magnum-api、magnum-conductor或者初始化数据库,还有一个template_manage
├── common # 通用操作
├── conductor # magnum-conductor服务的代码
├── db # 数据库信息
├── drivers # 重点,执行操作都会定位到这里的代码和脚本
├── objects # data model
├── service # 一些额外的操作类,周期服务类等
├── servicegroup # 同上
├── templates # 原先放置heat模板文件的地方,后来统一改成了driver模式,就挪到了drivers目录下
├── tests # 测试

对于magnum bay-create操作,主要涉及conductor和drivers这两个目录的代码,templates还剩下一些东西,不过最终也要弃用。

drivers的目录有下面这些东西

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
drivers/
├── common
│ └── template_def.py # 模板定义的父类
├── k8s_fedora_atomic_v1
│   ├── template_def.py # 定义模板类
│   ├── templates
│   │   ├── elements # 创建image时可能用到的element
│   │   ├── environments # 创建集群环境时,环境的配置
│   │   ├── fragments # 创建集群环境时,可能要在heat模板里执行的一些脚本
│   │   ├── kubecluster.yaml # 具体的heat template,这里是bay具体要执行哪些操作
│   │   ├── kubemaster.yaml
│   │   ├── kubeminion.yaml
│   └── version.py
├── k8s_coreos_v1
├── mesos_ubuntu_v1
└── swarm_fedora_atomic_v1

可以看到当前magnum支持了三种docker集群,一共四种driver

  • k8s_fedora_atomic_v1
  • k8s_coreos_v1
  • mesos_ubuntu_v1
  • mesos_ubuntu_v1

要执行执行哪个driver,是有三个参数来决定的:server_type、os、coe
每个driver里都会有一个template_def.py,这个就是来定义heat template的信息的类,类里主要做了3个操作:

  • get_params # 要给heat template传递什么参数
  • get_env_files # 要在调用heat template时如何设置环境,主要是针对是否load balance时,执行了一些heat的resource_registry操作
  • template_path # 要执行的heat template的文件路径

举个例子,对于{'server_type': 'bm', 'os': 'ubuntu', 'coe': 'mesos'}这样的参数,函数调用的堆栈信息如下:

1
2
3
4
5
magnum/conductor/handlers/bay_conductor.py: Handler:bay-create
magnum/conductor/handlers/bay_conductor.py: _create_stack
magnum/conductor/handlers/bay_conductor.py: _extract_template_definition
magnum/drivers/mesos_ubuntu_v1/template_def.py: TemplateDefinition:extract_definition
最终调用 mesos_ubuntu_v1 对应的模板定义类 UbuntuMesosTemplateDefinition 里的三个函数

参考:
Directory structure
Choosing a coe
troubleshooting-guide


UEFI Secure Boot

Posted on 2018-01-07

linux的boot有一套流程:firware->media->bootloader->kernel(kernel module)->init

  • firmware发现可启动media,加载media(远程启动等)
  • bootloader从boot media加载kernel到RAM里,然后启动(会根据硬盘分区表之类的发现kernel,然后继续加载kernel module之类)
  • kernel会根据bootloader传递给kernel的指令去找到主文件系统
  • 启动文件系统中的init脚本

在第二步,uefi找到硬盘分区表后,发现文件系统,然后会开始加载kernel
如何加载,在按照系统时就已经确定好efi命令文件的路径,然后UEFI会执行这个程序
执行efibootmgr命令可以看到:

1
2
3
4
5
6
7
8
9
# efibootmgr -v
BootCurrent: 0004
Timeout: 5 seconds
BootOrder: 0001,0004,0000,0003,0002
Boot0000* EFI VMware Virtual IDE Hard Drive (IDE 0:0) ACPI(a0341d0,...
Boot0001* EFI VMware Virtual SATA CDROM Drive (1.0) ACPI(a0341d0,...
Boot0002* EFI Network ACPI(a0341d0,0)PCI(12,0)MAC(000c29cf6279,0)
Boot0003* EFI Internal Shell (Unsupported option) MM(b,bee94000,...
Boot0004* Red Hat Enterprise Linux HD(spec)File(\EFI\redhat\shim.efi)

对于readhat来说,efi相关文件结构如下.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# tree /boot/efi
+-- EFI
+-- BOOT
| +-- BOOTX64.EFI
| +-- fallback.efi
+-- redhat
+-- BOOT.CSV
+-- fonts
| +-- unicode.pf2
+-- gcdx64.efi
+-- grub.cfg
+-- grubx64.efi
+-- MokManager.efi
+-- shim.efi
+-- shim-redhat.efi

4 directories, 10 files

而当UEFI启动时,调用程序的流程是UEFI->shim.efi->grubx64.efi->grub.cfg

查看shim.efi里的十六进制信息,可以看到调用grubx64.efi的过程

1
# hexdump -C /boot/efi/EFI/redhat/shim.efi | egrep -i -C 2 'grub|g.r.u.b'

接着查看grubx64.efi

1
2
# strings /boot/efi/EFI/redhat/grubx64.efi | grep grub.cfg
%s/grub.cfg

到最后就到了执行grub的地方,或者叫做Grand Unified Boot Loader
GRUB访问文件系统,找到kernel文件,加载到内存,然后启动kernel,传入一系列参数
kernel需要知道如何找到root目录,才能加载各种库和配置文件等,但是前提是要加载各种驱动后才可以做接下来的操作

那么下一步就是加载/lib/modules下的内核模块了

参考一个中文对linux boot的简介: http://blog.jobbole.com/33224/

Sign Kernel Module for Secure Boot

Posted on 2018-01-07

安装新的nvidia驱动遇到了内核模块签名的问题

在linux系统里安装了nvidia的CUDA,然后在支持UEFI的系统里启动会报错。
检查发现,系统的新安装的驱动,即新添加的一些nvidia相关的kernel module没有被sign,在secure boot启动过程中check failed。

这里检查时主要有两个:一个是fedora文档,一个是nvidia文档

  • fedora文档

  • nvidia文档

1
2
3
# sh ./NVIDIA-Linux-x86-319.12.run -s \
--module-signing-secret-key=/path/to/signing.key \
--module-signing-public-key=/path/to/signing.x509

这里有说明用nvidia的runfile加参数,runfile会自动给你签名,但是安装CUDA的时候下载的runfile报错没有这些参数

顺便一说,CUDA的安装也有两种方式:rpm和runfile
http://developer.download.nvidia.com/compute/cuda/7.5/Prod/docs/sidebar/CUDA_Quick_Start_Guide.pdf

在rpm方式下已经安装成功,因为rpm基本都是下载文件,然后安装文件,最后一步直接yum install cuda完成所有依赖的东西的安装

runfile的话则是先要进行一些配置文件的修改,有些命令会执行失败


手动siging kernel module的流程

需要的tools

  • openssl openssl
  • sign-file kernel-devel
  • perl perl
  • mokutil mokutil
  • keyctl keyutils

其中,openssl、sign-file和perl都是在build system里操作。
openssl用来生成密钥对,perl命令用来执行sign-file这个脚本文件,来给kernel module进行签名

mokutil和keyctl是在Target system执行。
mokutil用来enroll the public key,就是把公钥加到MOK(Machine Owner Key)表里。
keyctl用来显示system key ring里的公钥

在build system里,不需要UEFI Secure Boot被enabled也不需要是一个支持UEFI的系统

kernel module authentication

fedora系统中,内核模块加载后,内核模块的签名signature会用存储在内核的system key ring里的公钥进行检查,包括检查白名单和黑名单。

在启动的时候,内核会从多处加载X.509 keys,加载到system key ring里,以便后面的对内核模块的check。
可以查看具体哪些source: Sources For System Key Rings

  • Embedded in kernel
  • UEFI Secure Boot “db”
  • UEFI Secure Boot “dbx”
  • Embedded in shim.efi boot loader
  • Machine Owner Key (MOK) list

kernel本身用户无法操作,UEFI的处于机器固件层面的,不好操作,就剩下shim.efi和MOK了。

在正常的系统中,shim.efi用户无法直接改动的,但在制作虚拟机镜像的时候,可以直接修改内核的所有文件,这时就可以替换或修改这个efi文件。
而通常情况下,比如在运行中的系统中,一般会用命令去操作MOK表,把前面步骤里生成的key注入到MOK中。

  • 如果uefi secure boot没有启动或系统本身就不支持uefi secure boot,那么内核只会加载keys Embedded in kernel。
  • 黑名单有更高优先级,如果存在于黑名单中了,那么就算内核模块以及签名也没用

下面是几个显示system key ring中密钥列表的命令例子:

UEFI Secure Boot is not enabled

1
2
3
~]# keyctl list %:.system_keyring
1 key in keyring:
61139991: ---lswrv 0 0 asymmetric: Fedora kernel signing key: 1fc9e68f7419556348fdee2fdeb7ff9da6337b

UEFI Secure Boot is enabled

1
2
3
4
5
6
7
8
~]# keyctl list %:.system_keyring
6 keys in keyring:
...asymmetric: Red Hat Enterprise Linux Driver Update Program (key 3): bf57f3e87...
...asymmetric: Red Hat Secure Boot (CA key 1): 4016841644ce3a810408050766e8f8a29...
...asymmetric: Microsoft Corporation UEFI CA 2011: 13adbf4309bd82709c8cd54f316ed...
...asymmetric: Microsoft Windows Production PCA 2011: a92902398e16c49778cd90f99e...
...asymmetric: Red Hat Enterprise Linux kernel signing key: 4249689eefc77e95880b...
...asymmetric: Red Hat Enterprise Linux kpatch signing key: 4d38fd864ebe18c5f0b7...

可以查看kernel console messages,查看密钥是从哪里加载进来的。示例中是搜索从efi文件加载的。

1
2
3
4
~]# dmesg | grep 'EFI: Loaded cert'
[5.160660] EFI: Loaded cert 'Microsoft Windows Production PCA 2011: a9290239...
[5.160674] EFI: Loaded cert 'Microsoft Corporation UEFI CA 2011: 13adbf4309b...
[5.165794] EFI: Loaded cert 'Red Hat Secure Boot (CA key 1): 4016841644ce3a8...

kernel module在启动过程中的规则

kernel module在启动过程中可能被检测,因为还要依托于一个参数module.sig_enforce。

kernel module在启动过程中的整体流程

key是否强制加载,是否找到,是否验证通过,是否支持uefi secure boot,内核模块是否加载成功,内核是否被污染

Kernel Module Authentication Requirements for Loading

生成密钥

  • 用openssl生成X.509密钥对
    执行命令时依赖一个配置文件,要先创建一个配置文件(尖括号括起来的需要手动修改)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
~]# cat << EOF > configuration_file.config
[ req ]
default_bits = 4096
distinguished_name = req_distinguished_name
prompt = no
string_mask = utf8only
x509_extensions = myexts

[ req_distinguished_name ]
O = <Organization>
CN = <Organization signing key>
emailAddress = <E-mail address>

[ myexts ]
basicConstraints=critical,CA:FALSE
keyUsage=digitalSignature
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid
EOF
  • 执行openssl命令
1
2
3
4
~]# openssl req -x509 -new -nodes -utf8 -sha256 -days 36500 \
> -batch -config configuration_file.config -outform DER \
> -out public_key.der \
> -keyout private_key.priv

注意保护私钥

把生成的密钥加入到target system的多种途径

因为内核从多处加载密钥,所以也有多种方式放置密钥

  • 让服务器硬件厂商把你自己生成的密钥加入到他们自己的固件镜像的UEFI Secure Boot key database

    有db和dbx两种database,内核加载是会过滤掉dbx中的失效key(revoked key)

  • Executable Key Enrollment Image Adding Public Key
    没太理解,应该是是编辑一个已有的image

  • 手动把public key加入到MOK list
    MOK是fedora里的一个功能,The MOK facility is supported by shim.efi, MokManager.efi, grubx64.efi, and the Fedora mokutil utility.

1
~]# mokutil --import my_signing_key_pub.der

reboot the machine

MOK key enrollment的请求会被shim.efi注意到,然后它会调用MokManager.efi,从UEFI console完成密钥的登记。这时候你需要输入你刚才mokutil命令输入的密码

对于ironic的user image怎么办??,无法启动,是否会在image加载后,启动时完成enrollment??

Signing Kernel Module with the Private Key

  • 编译出来module(或者其他方式生成的module)
1
~]# make -C /usr/src/kernels/$(uname -r) M=$PWD modules
  • 执行perl脚本,签名
1
2
3
4
5
~]# perl /usr/src/kernels/$(uname -r)/scripts/sign-file \
> sha256 \
> my_signing_key.priv \
> my_signing_key_pub.der \
> my_module.ko
  • 可以用modinfo来查看module的信息,链接

加载signed kernel module

  • 首先确认系统本次启动中内核没有加载密钥,用命令来查看system keyring
1
keyctl list %:.system_keyring
  • 像之前的步骤一样,把公钥登记到MOK中,准确点叫做请求登记
1
~]# mokutil --import my_signing_key_pub.der
  • Reboot, and complete the enrollment at the UEFI console.
  • 重启后,再次检查keyring
1
keyctl list %:.system_keyring
  • 现在则可以正常的加载你的kernel module了
1
2
3
4
~]# modprobe -v my_module
insmod /lib/modules/3.17.4-302.fc21.x86_64/extra/my_module.ko
~]# lsmod | grep my_module
my_module 12425 0

有个疑问,这里内核模块没有签名,则该内核模块加载失败,

kernel modules and their utilities

一些内核相关的命令

1
2
3
4
5
6
lsmod(8) — The manual page for the lsmod command.
modinfo(8) — The manual page for the modinfo command.
modprobe(8) — The manual page for the modprobe command.
rmmod(8) — The manual page for the rmmod command.
ethtool(8) — The manual page for the ethtool command.
mii-tool(8) — The manual page for the mii-tool command.

回到对ironic user image的签名

回到实际的场景,对添加了nvidia kernel module的image进行签名,有以下几种可操作的方法:

  • 使用自签名,那么使用命令操作MOK后,系统文件里就包含密钥了,但是需要把这个密钥最终写入到uefi主板上,这一步需要在系统启动时手动操作,所以无法自动化。
  • 使用已有签名,就是uefi主板的数据库里已经带了默认密钥,是在出厂时就写入的官方公钥。所以如果想想一个内核模块加载成功,就需要这个内核模块被官方的私钥签名,但是这个操作个人是无法做的,只能由fedora官方来做。

如何向openstack提交代码

Posted on 2018-01-07

之前一直在向内网git库提交代码,最近终于要向社区提交了,鼓捣下流程。

提交代码的官方文档:
http://docs.openstack.org/infra/manual/developers.html

大体就是代码修改完成之后,git add,git commit, git review

git review会把代码提交到 https://review.openstack.org/ 进行review,review回归测试跑过了,然后被别人+2后就merge了。

提交前的账号信息准备

注册账号这里有些坑,虽然官方文档写的比较详细,但是仍然会不小心漏掉一点细节,就会导致git review失败。
所以一定要仔细看每一行字:http://docs.openstack.org/infra/manual/developers.html#account-setup

这里列出几处注册账号时必须做的事情:

  • https://launchpad.net/ 网站的账号注册
  • https://www.openstack.org/join/ 账号注册,选择foundation member类型,文档也有说明(一不小心就漏了)
  • https://review.openstack.org/ 注册,其实是和launchpad关联,只用launchpad ID进行单点登录
  • https://review.openstack.org/#/settings/ 用户名设置,设置后不能修改,慎重
  • https://review.openstack.org/#/settings/agreements 同意license协议
  • https://review.openstack.org/#/settings/ssh-keys 如果是ssh提交方式,上传本机ssh-key
  • https://review.openstack.org/#/settings/http-password 如果是https提交方式,生成密码(如果密码字符里有/就再生成一次,因为这个字符在git设置时会出错)

提交代码的验证方式

社区提供了两种提交代码的方式ssh和https
由于国内的网络原因,使用ssh总是会出各种各样的问题,可以直接用https方式来提交,省时省力

先下载一个project的代码

1
2
git clone https://git.openstack.org/openstack/<projectname>.git
cd <projectname>

ssh提交方式,直接提交
https提交方式,则需要设置一下,主要是自己的username和上述步骤中生成的password

1
git remote add gerrit https://<username>:<password>@review.openstack.org/<umbrella repository name>/<repository name>.git

这样在项目的配置remote.gerrit.url就会有值了

如何下载他人或者自己以前的patch

经常会遇到这样的情况,看到别人的patch希望自己下载下来改下,提交自己修改的东西
或者是自己的patch,但是本地文件夹被删除了,希望再次在本地修改

看到网上最简单的一种就是,直接使用git review命令

1
2
3
cd <projectname>
git review -d <review_id>
git review -d <change_id>

还有就是可以根据gerrit网页右上角的Download提供的几种下载命令,把patch下载到本地

Hello World

Posted on 2018-01-01 | Edited on 2018-05-07

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

12

fengbeihong

18 posts
2 tags
© 2019 fengbeihong
Powered by Hexo v3.7.1
|
Theme — NexT.Muse v6.2.0