2016-04-01 13:48:58 -07:00
|
|
|
# Iconograph
|
|
|
|
|
|
2016-04-01 21:07:23 -07:00
|
|
|
Iconograph ("icon") is a system for building and deploying Ubuntu system images.
|
2016-04-01 13:48:58 -07:00
|
|
|
It allows you to distribute your software intended to run on real hardware or
|
|
|
|
|
inside a container as a single unit with its system dependencies, and to roll
|
2016-04-01 20:46:20 -07:00
|
|
|
forward and backward in a secure, repeatable, staged manner.
|
2016-04-01 13:48:58 -07:00
|
|
|
|
2016-04-02 13:44:54 -07:00
|
|
|
## Overview
|
|
|
|
|
|
2016-04-02 13:45:15 -07:00
|
|
|
```
|
2016-04-02 13:44:54 -07:00
|
|
|
+-------------------------------------------------------------+
|
|
|
|
|
| Physical disk |
|
|
|
|
|
| +-----------------------------------------+ +-------------+ |
|
|
|
|
|
| | /boot | | /persistent | |
|
|
|
|
|
| | +-----------------+ +-----------------+ | | | |
|
|
|
|
|
| | | 1459629471.iso | | 1459629717.iso | | | | |
|
|
|
|
|
| | | | | | | | | |
|
|
|
|
|
| | | kernel | | kernel | | | | |
|
|
|
|
|
| | | initrd | | initrd | | | | |
|
|
|
|
|
| | | | | | | | | |
|
|
|
|
|
| | | +-------------+ | | +-------------+ | | | | |
|
|
|
|
|
| | | | squashfs | | | | squashfs | | | | | |
|
|
|
|
|
| | | | / (root) fs | | | | / (root) fs | | | | | |
|
|
|
|
|
| | | +-------------+ | | +-------------+ | | | | |
|
|
|
|
|
| | +-----------------+ +-----------------+ | | | |
|
|
|
|
|
| +-----------------------------------------+ +-------------+ |
|
|
|
|
|
+-------------------------------------------------------------+
|
2016-04-02 13:45:15 -07:00
|
|
|
```
|
2016-04-02 13:44:54 -07:00
|
|
|
|
2016-04-02 13:52:22 -07:00
|
|
|
Icon supports multiple image options at boot time by building Live CD-style ISO
|
|
|
|
|
images. It writes multiple ISO images to a /boot partition, and uses grub to
|
|
|
|
|
select between them at boot time (with hotkeys for headless selection). A second
|
|
|
|
|
grub instance runs inside the ISO to allow further customization (e.g. running
|
|
|
|
|
and upgrading memtest86).
|
2016-04-02 13:50:48 -07:00
|
|
|
|
|
|
|
|
Images utilize a tmpfs overlay filesystem, so by default filesystem changes
|
|
|
|
|
are discarded on reboot or upgrade. An optional /persistent filesystem allows
|
|
|
|
|
data storage across reboots and upgrades/downgrades.
|
|
|
|
|
|
|
|
|
|
Images optionally self-upgrade by fetching new images from an HTTP(S) source
|
|
|
|
|
and updating the configuration of the outer grub instance. This removes the
|
|
|
|
|
need for a separate OS instance to perform upgrades (and avoids figuring out
|
|
|
|
|
how to upgrade that instance).
|
|
|
|
|
|
2016-04-01 13:48:58 -07:00
|
|
|
## Setup
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
sudo apt-get install --assume-yes git grub-pc xorriso squashfs-tools openssl python3-openssl debootstrap
|
|
|
|
|
git clone https://github.com/robot-tools/iconograph.git
|
|
|
|
|
cd iconograph
|
|
|
|
|
```
|
2016-04-01 20:46:20 -07:00
|
|
|
|
|
|
|
|
## Image creation
|
|
|
|
|
|
2016-04-02 13:44:54 -07:00
|
|
|
### Image composition
|
2016-04-01 20:46:20 -07:00
|
|
|
|
|
|
|
|
Icon creates images by merging the kernel and boot system of a desktop live CD
|
|
|
|
|
with a server/custom filesystem. You'll need to download the desktop live CD
|
2016-04-01 21:03:57 -07:00
|
|
|
ISO for the version that you're building. You can get them [here](http://mirror.pnl.gov/releases/).
|
2016-04-01 20:46:20 -07:00
|
|
|
|
|
|
|
|
### Serving
|
|
|
|
|
|
|
|
|
|
Images are fetched via HTTP. You should write images to a directory accessible
|
2016-04-01 21:03:57 -07:00
|
|
|
via HTTP. Install apache2 if need be.
|
2016-04-01 20:46:20 -07:00
|
|
|
|
|
|
|
|
### Simple image build
|
|
|
|
|
|
2016-04-02 10:54:46 -07:00
|
|
|
build_image.py will call debootstrap, which will fetch packages from Ubuntu
|
|
|
|
|
servers. You may want to
|
|
|
|
|
[set up caching](https://medium.com/where-the-flamingcow-roams/apt-caching-for-debootstrap-bac499deebd5#.dvevbcc9z)
|
|
|
|
|
to make this process fast on subsequent runs.
|
|
|
|
|
|
2016-04-01 20:46:20 -07:00
|
|
|
```bash
|
|
|
|
|
# Must run as sudo to mount/umount images, tmpfs, and overlayfs
|
|
|
|
|
sudo server/build_image.py --image-dir=/output/path --release=trusty --source-iso=path/to/ubuntu-14.04.4-desktop-amd64.iso
|
|
|
|
|
```
|
2016-04-01 21:03:57 -07:00
|
|
|
|
2016-04-02 13:32:27 -07:00
|
|
|
## Modules
|
2016-04-01 21:03:57 -07:00
|
|
|
|
2016-04-01 21:07:23 -07:00
|
|
|
Modules are scripts that run after the chroot has been created. They can install
|
|
|
|
|
packages, do configuration, etc. Icon has several stock modules, but you can
|
2016-04-01 21:03:57 -07:00
|
|
|
also create your own using them as examples. You can pass multiple --module
|
|
|
|
|
flags to build_image.py as long as the modules are compatible with each other.
|
|
|
|
|
|
2016-04-01 21:07:23 -07:00
|
|
|
Stock modules:
|
|
|
|
|
|
2016-04-06 22:59:57 -07:00
|
|
|
### autoimage.py
|
|
|
|
|
|
|
|
|
|
Build an image that will partition, mkfs, and install an image from a different
|
|
|
|
|
URL onto a target system. Used to create install USB drives, PXE boot, etc.
|
|
|
|
|
Use the build_image.py flag:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
--module="server/modules/autoimage.py --base-url=http://yourhost/ --ca-cert=/path/to/signing/cert.pem --device=/dev/sdx --persistent-percent=50"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
`--device` specifies the device to partition and install to on the target
|
|
|
|
|
system.
|
|
|
|
|
|
|
|
|
|
Optional flags:
|
|
|
|
|
|
|
|
|
|
`--persistent-percent`, if non-zero, specifies the percent of the target
|
|
|
|
|
device to allocate to a LABEL=PERSISTENT filesystem. If the inner image uses
|
|
|
|
|
persistent.py, this filesystem will be automatically mounted.
|
|
|
|
|
|
|
|
|
|
`--https-ca-cert` specifies a local path to a PEM-encoded certificate to
|
|
|
|
|
validate the HTTPS image server cert against. This differs from `--ca-cert`,
|
|
|
|
|
which is used to validate the manifest.json signature.
|
|
|
|
|
|
|
|
|
|
`--https-client-cert` and `--https-client-key` are used together to specify
|
|
|
|
|
local paths to a PEM-encoded certificate and key pair that will be provided
|
|
|
|
|
to the server over HTTPS. This can be used to limit image availability.
|
|
|
|
|
|
2016-04-06 23:06:43 -07:00
|
|
|
### certclient.py
|
|
|
|
|
|
|
|
|
|
Use a local master key/cert pair to authenticate to a
|
2016-04-06 23:07:50 -07:00
|
|
|
[certserver](https://github.com/robot-tools/certserver) instance and retrieve
|
2016-04-06 23:06:43 -07:00
|
|
|
a system-specific key. Mainly intended to be used with autoimage.py and
|
|
|
|
|
systemid.py.
|
|
|
|
|
|
|
|
|
|
Use the build_image.py flag:
|
|
|
|
|
|
|
|
|
|
```bash
|
2016-04-07 20:39:50 +00:00
|
|
|
--module="server/modules/certclient.py --server=https://certserver/ --ca-cert=/path/to/server/cert.pem --client-cert=/path/to/client/cert.pem --client-key=/path/to/client/key.pem --tag=www --subject='/C=US/ST=California/O=XXXX/OU=XXXX Test/CN=SYSTEMID'"
|
2016-04-06 23:06:43 -07:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The new key and cert are saved to /systemid
|
|
|
|
|
|
|
|
|
|
`--tag` specifies a value added to the filename, so certclient.py can be
|
|
|
|
|
used more than once with different servers (e.g. once for an HTTPS client
|
|
|
|
|
key/cert pair, and once for an EAP-TLS key/cert pair).
|
|
|
|
|
|
2016-04-07 20:39:50 +00:00
|
|
|
`--subject` specifics the subject string passed to openssl. `SYSTEMID` is
|
2016-04-06 23:06:43 -07:00
|
|
|
replaced with the system hostname, possibly as set by systemid.py
|
|
|
|
|
|
2016-04-02 13:32:27 -07:00
|
|
|
### iconograph.py
|
2016-04-01 21:03:57 -07:00
|
|
|
|
|
|
|
|
Install icon inside the image. This allows the image to auto-update over HTTP.
|
|
|
|
|
Use the build_image.py flag:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
--module="server/modules/iconograph.py --base-url=http://yourhost/ --ca-cert=/path/to/signing/cert.pem"
|
|
|
|
|
```
|
|
|
|
|
|
2016-04-02 13:22:24 -07:00
|
|
|
Optional flags:
|
|
|
|
|
|
2016-04-06 22:59:57 -07:00
|
|
|
`--https-ca-cert` specifies a local path to a PEM-encoded certificate to
|
|
|
|
|
validate the HTTPS image server cert against. This differs from `--ca-cert`,
|
|
|
|
|
which is used to validate the manifest.json signature.
|
|
|
|
|
|
2016-04-02 13:22:24 -07:00
|
|
|
`--max-images` sets the number of recent images to keep. Older images are
|
|
|
|
|
deleted. Defaults to 5. 0 means unlimited.
|
|
|
|
|
|
2016-04-02 13:32:27 -07:00
|
|
|
### persistent.py
|
2016-04-01 21:03:57 -07:00
|
|
|
|
|
|
|
|
Mount a /persistent partition from a filesystem with LABEL=PERSISTENT. Allows
|
|
|
|
|
data to persist across reboots, when it would normally be wiped by tmpfs.
|
|
|
|
|
Use the build_image.py flag:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
--module="server/modules/persistent.py"
|
|
|
|
|
```
|
|
|
|
|
|
2016-04-06 22:59:57 -07:00
|
|
|
See [imager/image.py](imager/image.py)'s or
|
|
|
|
|
[server/module/autoimage.py](autoimage.py)'s `--persistent-percent` flag to
|
|
|
|
|
create this partition.
|
2016-04-01 21:03:57 -07:00
|
|
|
|
2016-04-06 22:59:57 -07:00
|
|
|
### systemid.py
|
|
|
|
|
|
|
|
|
|
Mount a /systemid partition from a filesystem with LABEL=SYSTEMID. This is
|
|
|
|
|
intended to a be separate device (possibly a USB flash drive, SD card, etc.)
|
|
|
|
|
which contains data that persists across re-images and identifies the system,
|
|
|
|
|
including system-specific keys and certificates.
|
2016-04-01 21:03:57 -07:00
|
|
|
|
2016-04-06 23:06:43 -07:00
|
|
|
It also sets the hostname to the value found in the systemid config on the
|
|
|
|
|
device.
|
|
|
|
|
|
2016-04-01 21:03:57 -07:00
|
|
|
```bash
|
2016-04-06 22:59:57 -07:00
|
|
|
--module="server/modules/systemid.py"
|
2016-04-01 21:03:57 -07:00
|
|
|
```
|
|
|
|
|
|
2016-04-02 13:34:02 -07:00
|
|
|
## Module API
|
|
|
|
|
|
|
|
|
|
Modules are passed the following long-style arguments:
|
|
|
|
|
|
|
|
|
|
`--chroot-path` specifies the absolute path to the root of the debootstrap
|
|
|
|
|
chroot that will become the root filesystem of the inner image.
|
|
|
|
|
|
2016-04-02 13:31:45 -07:00
|
|
|
## Manifests
|
2016-04-01 21:13:50 -07:00
|
|
|
|
|
|
|
|
Clients download a manifest file to determine available images and to verify
|
|
|
|
|
authenticity and integrity of the image. You'll need to generate one on the
|
|
|
|
|
server after each new image is built.
|
|
|
|
|
|
|
|
|
|
Manifest files are signed using OpenSSL. You should run your own CA to do this;
|
|
|
|
|
do NOT use a public CA cert. You can find instructions for setting up a CA
|
|
|
|
|
[here](https://medium.com/where-the-flamingcow-roams/elliptic-curve-certificate-authority-bbdb9c3855f7#.7v40ox70s).
|
|
|
|
|
|
|
|
|
|
To build a manifest, run:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
server/publish_manifest.py --cert=/path/to/signing/cert.pem --key=/path/to/signing/key.pem --image-dir=/image/path
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Optional flags:
|
|
|
|
|
|
|
|
|
|
`--default-rollout` specifies the percentage rollout for new images; it
|
|
|
|
|
defaults to zero. The units are
|
|
|
|
|
[basis points](https://en.wikipedia.org/wiki/Basis_point); 10000 means 100%.
|
|
|
|
|
|
2016-04-02 13:16:06 -07:00
|
|
|
`--max-images` sets the number of recent images to keep. Older images are
|
2016-04-02 13:22:24 -07:00
|
|
|
deleted. Defaults to 0, meaning unlimited.
|
2016-04-02 13:16:06 -07:00
|
|
|
|
|
|
|
|
`--other-cert` specifies a chain certificate, such as your intermediate cert.
|
|
|
|
|
It may be specified more than once.
|
|
|
|
|
|
2016-04-01 21:17:25 -07:00
|
|
|
To push a rollout to more targets, edit /image/path/manifest.json.unsigned,
|
|
|
|
|
and change rollout_\u2031 (u2031 is ‱, the symbol for basis point). Save,
|
|
|
|
|
then re-run publish_manifest.py to generate the signed version.
|
|
|
|
|
|
2016-04-02 15:55:12 -07:00
|
|
|
## Testing with qemu
|
|
|
|
|
|
|
|
|
|
You can boot images for testing and issue reproduction using qemu.
|
|
|
|
|
|
|
|
|
|
```base
|
|
|
|
|
sudo apt-get install qemu-system-x86_64
|
|
|
|
|
sudo kvm_ok
|
|
|
|
|
# The above must "KVM acceleration can be used" to be able to get reasonable performance
|
|
|
|
|
sudo qemu-system-x86_64 --curses --smp 2 --m 4G --netdev user,id=vmnic --device virtio-net,netdev=vmnic --enable-kvm --cdrom /path/to/image.iso
|
|
|
|
|
```
|
|
|
|
|
|
2016-04-02 13:31:45 -07:00
|
|
|
## Imaging
|
2016-04-01 21:13:50 -07:00
|
|
|
|
|
|
|
|
You can write created images to flash drives for installation on other systems,
|
|
|
|
|
or manually write them to a drive. To do so:
|
|
|
|
|
|
|
|
|
|
```bash
|
2016-04-01 21:21:12 -07:00
|
|
|
# Needs sudo to partition and mkfs devices
|
|
|
|
|
sudo imager/image.py --base-url=http://yourhost/ --ca-cert=/path/to/signing/cert.pem --device=/dev/sdx --persistent-percent=50
|
2016-04-01 21:13:50 -07:00
|
|
|
```
|
2016-04-06 22:59:57 -07:00
|
|
|
|
|
|
|
|
Optional flags:
|
|
|
|
|
|
|
|
|
|
`--https-ca-cert` specifies a local path to a PEM-encoded certificate to
|
|
|
|
|
validate the HTTPS image server cert against. This differs from `--ca-cert`,
|
|
|
|
|
which is used to validate the manifest.json signature.
|
|
|
|
|
|
|
|
|
|
`--https-client-cert` and `--https-client-key` are used together to specify
|
|
|
|
|
local paths to a PEM-encoded certificate and key pair that will be provided
|
|
|
|
|
to the server over HTTPS. This can be used to limit image availability.
|