commit 4c20410fd8ba147cafd20ff21746034c4cef65a1 Author: Kevin Gallagher Date: Sun Oct 16 18:50:37 2016 -0700 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..27d8c59 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.vagrant/* +*.swp +gitian.sigs/* +zcash-binaries/* diff --git a/README.md b/README.md new file mode 100644 index 0000000..734e687 --- /dev/null +++ b/README.md @@ -0,0 +1,104 @@ +Zcash deterministic builds +========================== + +This is a deterministic build environment for [Zcash](https://github.com/zcash/zcash/) that uses [Gitian](https://gitian.org/). + +Gitian provides a way to be reasonably certain that the Zcash executables are really built from the exact source on GitHub and have not been tampered with. It also makes sure that the same, tested dependencies are used and statically built into the executable. + +Multiple developers build from source code by following a specific descriptor ("recipe"), cryptographically sign the result, and upload the resulting signature. These results are compared and only if they match is the build is accepted. + +More independent Gitian builders are needed, which is why this guide exists. + +Requirements +------------ + +4GB of RAM, at least two cores + +It relies upon [Vagrant](https://www.vagrantup.com/downloads.html) and [VirtualBox](https://www.virtualbox.org/wiki/Linux_Downloads) plus [Ansible](https://www.ansible.com/), which can be installed via Python's [pip](https://bootstrap.pypa.io/get-pip.py). Try `sudo pip install -U ansible`. + +If you use Linux, then we recommend obtaining VirtualBox through your package manager instead of the Oracle website. + +How to get started +------------------ + +### Settings in gitian.yml + +```yaml +# URL of repository containing Zcash source code. +zcash_git_repo_url: 'https://github.com/zcash/zcash' + +# Specific tag or branch you want to build. +zcash_version: 'master' + +# The name@ in the e-mail address of your GPG key, alternatively a key ID. +gpg_key_name: '' + +# Equivalent to git --config user.name & user.email +git_name: '' +git_email: '' + +# OPTIONAL set to import your GPG key into the VM. +gpg_key_id: '' + +# OPTIONAL set to import your SSH key into the VM. Example: id_rsa, id_ed25519. Assumed to reside in ~/.ssh +ssh_key_name: '' +``` + +Make sure VirtualBox, Vagrant and Ansible are installed, and then run: + + vagrant up --provision zcash-build + +This will provision a Gitian host virtual machine that uses a Linux container (LXC) guest to perform the actual builds. + +Building Zcash +-------------- + + vagrant ssh zcash-build + ./gitian-build.sh + +The output from `gbuild` is informative. There are some common warnings which can be ignored, e.g. if you get a privileges error related to LXC then just execute the script again. The most important thing is that one reaches the step which says `Running build script (log in var/build.log)`. If not, then something else is wrong and you should let us know. + +Take a look at the variables near the top of `~/gitian-build.sh` and get familiar with its functioning, as it can handle most tasks. + +Generating and uploading signatures +----------------------------------- + +After the build successfully completes, `gsign` will be called. Commit and push your signatures (both the .assert and .assert.sig files) to the [zcash/gitian.sigs](https://github.com/zcash/gitian.sigs) repository, or if that's not possible then create a pull request. + +Working with GPG and SSH +-------------------------- + +We provide two options for automatically importing keys into the VM, or you may choose to copy them manually. Keys are needed A) to sign the manifests which get pushed to [gitian.sigs](https://github.com/zcash/gitian.sigs) and B) to interact with GitHub, if you choose to use an SSH instead of HTTPS remote. The latter would entail always providing your GitHub login and access token in order to push from within the VM. + +Your local SSH agent is automatically forwarded into the VM via a configuration option. If you run ssh-agent, your keys should already be available. + +GPG is trickier, especially if you use a smartcard and can't copy the secret key. We have a script intended to forward the gpg-agent socket into the VM, `forward_gpg_agent.sh`, but it is not currently working. If you want your full keyring to be available, you can use the following workaround involving `sshfs` and synced folders: + + vagrant plugin install vagrant-sshfs + +Uncomment the line beginning with `gitian.vm.synced_folder "~/.gnupg"` in `Vagrantfile`. Ensure the destination mount point is empty. Then run: + + vagrant sshfs --mount zcash-build + +Vagrant synced folders may also work natively with `vboxfs` if you install VirtualBox Guest Additions into the VM from `contrib`, but that's not as easy to setup. + + +Copying files +------------- + +You can use the provided script `scp.sh`. Another way to do it is with a plugin. + + vagrant plugin install vagrant-scp + +To copy files to the VM: `vagrant scp file_on_host.txt :file_on_vm.txt` + +To copy files from the VM: `vagrant scp :file_on_vm.txt file_on_host.txt` + +Other notes +----------- + +Port 2200 on the host machine should be forwarded to port 22 on the guest virtual machine. + +The automation and configuration management assumes that VirtualBox will assign the IP address `10.0.2.15` to the Gitian host Vagrant VM. + +Tested with Ansible 2.1.2 and Vagrant 1.8.6 on Debian GNU/Linux (jessie). diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 0000000..68330ea --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,25 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : +Vagrant.configure(2) do |config| + + config.ssh.forward_agent = true + config.vm.define 'zcash-build', autostart: false do |gitian| + gitian.vm.box = "debian/jessie64" + gitian.vm.network "forwarded_port", guest: 22, host: 2200, auto_correct: true + gitian.vm.provision "ansible" do |ansible| + ansible.playbook = "gitian.yml" + ansible.verbose = 'v' + ansible.raw_arguments = Shellwords.shellsplit(ENV['ANSIBLE_ARGS']) if ENV['ANSIBLE_ARGS'] + end + gitian.vm.provider "virtualbox" do |v| + v.name = "zcash-build" + v.memory = 4096 + v.cpus = 2 + end +# gitian.vm.synced_folder "~/.gnupg", "/home/vagrant/.gnupg", type: "sshfs" +# gitian.vm.synced_folder "./gitian.sigs", "/home/vagrant/gitian.sigs", create: true +# gitian.vm.synced_folder "./zcash-binaries", "/home/vagrant/zcash-binaries", create: true + gitian.vm.post_up_message = "Zcash deterministic build environment started." + end + +end diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..6551ea0 --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,11 @@ +[defaults] +inventory = inventory +retry_files_enabled = False +roles_path = roles +host_key_checking = False +timeout = 60 + +[ssh_connection] +ssh_args = -o ControlMaster=auto -o ControlPersist=300s -o ConnectTimeout=60 +pipelining = True +scp_if_ssh = True diff --git a/forward_gpg_agent.sh b/forward_gpg_agent.sh new file mode 100755 index 0000000..b6e792c --- /dev/null +++ b/forward_gpg_agent.sh @@ -0,0 +1,13 @@ +#!/bin/bash -e + +GPG_SOCK=$(echo "$GPG_AGENT_INFO" | cut -d: -f1) +if [ -z "$GPG_SOCK" ] ; then + echo "No GPG agent configured - this won't work out." >&2 + exit 1 +fi + +vagrant ssh zcash-build -- rm -f /home/vagrant/.gnupg/S.gpg-agent +vagrant ssh zcash-build -- -t \ + -R /home/vagrant/.gnupg/S.gpg-agent:$GPG_SOCK \ + -o StreamLocalBindUnlink=yes \ + -o ExitOnForwardFailure=yes diff --git a/gitian.yml b/gitian.yml new file mode 100644 index 0000000..e5b2fea --- /dev/null +++ b/gitian.yml @@ -0,0 +1,17 @@ +--- +- name: Apply the Zcash Gitian builder role. + become: yes + hosts: localhost:zcash-build + vars: + zcash_git_repo_url: https://github.com/zcash/zcash + zcash_version: v1.0.0-rc1 + gpg_key_name: '' + git_name: '' + git_email: '' + gpg_key_id: '' # optional + ssh_key_name: '' # optional + roles: + - role: common + tags: common + - role: gitian + tags: gitian diff --git a/roles/common/defaults/main.yml b/roles/common/defaults/main.yml new file mode 100644 index 0000000..14d190c --- /dev/null +++ b/roles/common/defaults/main.yml @@ -0,0 +1,19 @@ +--- +zcash_swapfile_size: 2G +zcash_vm_swappiness: 10 +zcash_common_packages: + - apt-show-versions + - apt-transport-https + - curl + - git-core + - haveged + - htop + - ntp + - ntpdate + - python-pip + - rsync + - screen + - sudo + - tmux + - tree + - vim diff --git a/roles/common/files/02periodic b/roles/common/files/02periodic new file mode 100644 index 0000000..9356221 --- /dev/null +++ b/roles/common/files/02periodic @@ -0,0 +1,5 @@ +APT::Periodic::Enable "1"; +APT::Periodic::Update-Package-Lists "1"; +APT::Periodic::Download-Upgradeable-Packages "1"; +APT::Periodic::Unattended-Upgrade "1"; +APT::Periodic::AutocleanInterval "7"; diff --git a/roles/common/files/50unattended-upgrades b/roles/common/files/50unattended-upgrades new file mode 100644 index 0000000..5d19d2d --- /dev/null +++ b/roles/common/files/50unattended-upgrades @@ -0,0 +1,6 @@ +Unattended-Upgrade::Origins-Pattern { + "o=Debian,n=jessie-updates"; + "o=Debian,n=jessie,l=Debian-Security"; +}; +Unattended-Upgrade::Remove-Unused-Dependencies "true"; +Unattended-Upgrade::Automatic-Reboot "false"; diff --git a/roles/common/handlers/main.yml b/roles/common/handlers/main.yml new file mode 100644 index 0000000..c81bf82 --- /dev/null +++ b/roles/common/handlers/main.yml @@ -0,0 +1,3 @@ +--- +- name: update timezone + command: dpkg-reconfigure --frontend noninteractive tzdata diff --git a/roles/common/tasks/add_github_ssh_hostkey.yml b/roles/common/tasks/add_github_ssh_hostkey.yml new file mode 100644 index 0000000..1769b58 --- /dev/null +++ b/roles/common/tasks/add_github_ssh_hostkey.yml @@ -0,0 +1,14 @@ +--- +- name: Look up GitHub SSH host key. + local_action: command ssh-keyscan -t rsa github.com + register: github_ssh_keyscan_result + changed_when: false + always_run: yes + run_once: yes + become: no + +- name: Ensure github.com is a known host. + known_hosts: + path: /etc/ssh/ssh_known_hosts + name: github.com + key: "{{ github_ssh_keyscan_result.stdout }}" diff --git a/roles/common/tasks/auto_upgrades.yml b/roles/common/tasks/auto_upgrades.yml new file mode 100644 index 0000000..9c9ef5c --- /dev/null +++ b/roles/common/tasks/auto_upgrades.yml @@ -0,0 +1,14 @@ +--- +- name: Copy unattended-upgrades configuration. + copy: + dest: /etc/apt/apt.conf.d/ + src: "{{ item }}" + mode: "0640" + owner: root + group: root + with_items: + - 02periodic + - 50unattended-upgrades + +- name: Enable automatic updates in unattended-upgrades package config. + shell: echo unattended-upgrades unattended-upgrades/enable_auto_updates boolean true | debconf-set-selections diff --git a/roles/common/tasks/hostname.yml b/roles/common/tasks/hostname.yml new file mode 100644 index 0000000..0150ff8 --- /dev/null +++ b/roles/common/tasks/hostname.yml @@ -0,0 +1,11 @@ +--- +- name: Set hostname. + hostname: + name: "zcash-build" + +- name: Build /etc/hosts file. + lineinfile: + dest: /etc/hosts + regexp: '^127.0.1.1' + line: "127.0.1.1 zcash-build" + state: present diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml new file mode 100644 index 0000000..2a331ea --- /dev/null +++ b/roles/common/tasks/main.yml @@ -0,0 +1,8 @@ +--- +- include: update_everything.yml +- include: packages.yml +- include: make_swap.yml +- include: add_github_ssh_hostkey.yml +- include: hostname.yml +- include: motd.yml +- include: auto_upgrades.yml diff --git a/roles/common/tasks/make_swap.yml b/roles/common/tasks/make_swap.yml new file mode 100644 index 0000000..b78fc2d --- /dev/null +++ b/roles/common/tasks/make_swap.yml @@ -0,0 +1,37 @@ +--- +- name: Check whether swap file already exists. + stat: + path: /swapfile + register: existing_swapfile_result + +- name: Allocate swapfile. + command: "fallocate -l {{ zcash_swapfile_size }} /swapfile" + when: not existing_swapfile_result.stat.exists + +- name: Set permissions of swapfile. + file: + path: /swapfile + owner: root + group: root + mode: "0600" + state: touch + +- name: Set up the swapfile. + command: mkswap /swapfile + when: not existing_swapfile_result.stat.exists + +- name: Enable the swapfile. + command: swapon /swapfile + when: not existing_swapfile_result.stat.exists + +- name: Make the swapfile persistent. + lineinfile: + dest: /etc/fstab + regexp: "^/swapfile" + line: "/swapfile none swap sw 0 0" + +- name: Set vm.swappiness in sysctl. + sysctl: + name: vm.swappiness + value: "{{ zcash_vm_swappiness }}" + state: present diff --git a/roles/common/tasks/motd.yml b/roles/common/tasks/motd.yml new file mode 100644 index 0000000..597d29a --- /dev/null +++ b/roles/common/tasks/motd.yml @@ -0,0 +1,12 @@ +--- +- name: Get the current kernel version string. + command: uname -a + register: kernel_version_string + +- name: Install motd (message of the day). + template: + src: motd.j2 + dest: /etc/motd + owner: root + group: root + mode: "0644" diff --git a/roles/common/tasks/packages.yml b/roles/common/tasks/packages.yml new file mode 100644 index 0000000..645d0b5 --- /dev/null +++ b/roles/common/tasks/packages.yml @@ -0,0 +1,8 @@ +--- +- name: Install some common packages. + apt: + name: "{{ item }}" + state: present + update_cache: yes + cache_valid_time: 3600 + with_items: "{{ zcash_common_packages }}" diff --git a/roles/common/tasks/update_everything.yml b/roles/common/tasks/update_everything.yml new file mode 100644 index 0000000..77f0ce2 --- /dev/null +++ b/roles/common/tasks/update_everything.yml @@ -0,0 +1,50 @@ +--- +- name: Check if sudo is installed. + command: dpkg-query -l sudo + register: sudo_installed_result + # dpkg returns 1 if package not found, + # so disable the scary red text by setting no-fail mode. + # The output from the command is checked in the next task. + failed_when: false + changed_when: false + # Necessary to support --check mode + always_run: true + +- name: Install sudo. + apt: + name: sudo + state: present + update_cache: yes + cache_valid_time: 3600 + when: "'no packages found' in sudo_installed_result.stderr" + +- name: Update apt cache. + apt: + update_cache: yes + cache_valid_time: 3600 + +- name: Install aptitude. + apt: + name: aptitude + state: present + update_cache: yes + cache_valid_time: 3600 + +- name: Perform aptitude safe-upgrade. + apt: + upgrade: safe + update_cache: yes + cache_valid_time: 3600 + tags: apt + +- name: Remove unneeded packages. + command: apt-get autoremove -y + register: autoremove_result + changed_when: "'0 upgraded' not in autoremove_result.stdout" + tags: apt + +- name: Clean the apt cache. + command: apt-get autoclean + register: autoclean_result + changed_when: "'Del' in autoclean_result.stdout" + tags: apt diff --git a/roles/common/templates/log-core-dump.j2 b/roles/common/templates/log-core-dump.j2 new file mode 100644 index 0000000..c8d48ac --- /dev/null +++ b/roles/common/templates/log-core-dump.j2 @@ -0,0 +1,37 @@ +#!/bin/bash +# Handler for processing coredumps. Should be invoked only by system +# via the `kernel.core_pattern` in pipe mode, not run interactively. +# It assumes that filename, executable, and uid will be passed as args. + + +coredump_filename=$1 +coredump_executable=$2 +coredump_uid=$3 + +# Ensure we're running as root. +if [ $EUID -ne 0 ]; then + echo "Only root may run this script." 1>&2 + exit 1 +fi + +# Ensure script is running as part of pipe, receiving stdin. +# If script is run from an interactive terminal, exit. +if [ -t 0 ]; then + echo "No stdin pipe detected, exiting." 1>&2 + exit 1 +fi + +# Check for required arguments for logging and dumping core. +if [ -z $coredump_filename ] || [ -z $coredump_executable ] || [ -z $coredump_uid ]; then + echo "Missing required arguments for handling core dump." 1>&2 + exit 1 +fi + +# Log coredump event to syslog. +/usr/bin/logger "Core dump detected: ${coredump_executable} owned by uid ${coredump_uid}" + +# Ensure files are 0600 root:root. +umask 277 + +# Redirect core dump content from stdin to target file. +cat - > "{{ coredumps_directory }}/${coredump_filename}" diff --git a/roles/common/templates/motd.j2 b/roles/common/templates/motd.j2 new file mode 100644 index 0000000..761097e --- /dev/null +++ b/roles/common/templates/motd.j2 @@ -0,0 +1,10 @@ +{{ kernel_version_string.stdout }} + _____ _ +|__ /___ __ _ ___| |__ + / // __/ _` / __| '_ \ + / /| (_| (_| \__ \ | | | +/____\___\__,_|___/_| |_| + +Hostname: {{ ansible_fqdn }} +IP address: {{ ansible_default_ipv4.address }} + diff --git a/roles/gitian/defaults/main.yml b/roles/gitian/defaults/main.yml new file mode 100644 index 0000000..d02e2f0 --- /dev/null +++ b/roles/gitian/defaults/main.yml @@ -0,0 +1,10 @@ +--- +gitian_user: vagrant +download_directory: /tmp/gitian +vm_builder_name: 'vm-builder-0.12.4+bzr494' +vm_builder_url: 'http://archive.ubuntu.com/ubuntu/pool/universe/v/vm-builder/vm-builder_0.12.4+bzr494.orig.tar.gz' +zcash_git_repo_url: https://github.com/zcash/zcash +zcash_gitian_sigs_repo: https://github.com/zcash/gitian.sigs +zcash_version: v1.0.0-beta2 +gitian_host_ip: 10.0.2.15 +lxc_guest_ip: 10.0.3.5 diff --git a/roles/gitian/meta/main.yml b/roles/gitian/meta/main.yml new file mode 100644 index 0000000..50d980a --- /dev/null +++ b/roles/gitian/meta/main.yml @@ -0,0 +1,15 @@ +--- +galaxy_info: + author: Kevin Gallagher (@ageis) + description: Sets up a deterministic Gitian builder VM for Zcash. + company: Zcash + galaxy_tags: [] + license: GPLv2 + min_ansible_version: 2.1.2 + platforms: + - name: Debian + versions: + - jessie + categories: + - system +dependencies: [] diff --git a/roles/gitian/tasks/gpg.yml b/roles/gitian/tasks/gpg.yml new file mode 100644 index 0000000..7062f2c --- /dev/null +++ b/roles/gitian/tasks/gpg.yml @@ -0,0 +1,55 @@ +--- +- name: Check that the secret key exists. + local_action: "command gpg2 --list-secret-keys | grep {{ gpg_key_id }}" + register: gpg_list_keys_result + environment: + GNUPGHOME: "{{ lookup('env', 'HOME') }}/.gnupg" + +- name: Export the GPG private key from the local keyring. + local_action: "command gpg2 --armor --export-secret-key {{ gpg_key_id }}" + register: gpg_private_key + changed_when: false + environment: + GNUPGHOME: "{{ lookup('env', 'HOME') }}/.gnupg" + when: gpg_list_keys_result.stdout != '' + no_log: True + +- name: Write the private key to a temp file. + copy: + dest: "/tmp/{{ gpg_key_id }}.sec" + content: "{{ gpg_private_key.stdout }}" + owner: "{{ gitian_user }}" + group: "{{ gitian_user }}" + mode: "0400" + when: gpg_list_keys_result.stdout != '' + no_log: True + +- name: Make GnuPG home directory. + file: + path: "/home/{{ gitian_user }}/.gnupg" + state: directory + mode: "0700" + owner: "{{ gitian_user }}" + group: "{{ gitian_user }}" + +- name: Write GnuPG configuration. + template: + src: gpg.conf + dest: "/home/{{ gitian_user }}/.gnupg/gpg.conf" + mode: "0600" + owner: "{{ gitian_user }}" + group: "{{ gitian_user }}" + +- name: Import the GPG private key to the Vagrant user. + command: "gpg2 --import /tmp/{{ gpg_key_id }}.sec" + become_user: "{{ gitian_user }}" + when: gpg_list_keys_result.stdout != '' and gpg_private_key.stdout is defined + no_log: True + register: gpg_output + changed_when: "'secret key imported' in gpg_output.stderr" + failed_when: gpg_output.rc != 0 and 'already in secret keyring' not in gpg_output.stderr + +- name: Clean up secret key file in /tmp. + file: + path: "/tmp/{{ gpg_key_id }}.sec" + state: absent diff --git a/roles/gitian/tasks/main.yml b/roles/gitian/tasks/main.yml new file mode 100644 index 0000000..311e506 --- /dev/null +++ b/roles/gitian/tasks/main.yml @@ -0,0 +1,223 @@ +--- +- name: Check that custom git variables are defined. + assert: + that: + - "gpg_key_name is defined" + - "gpg_key_name != ''" + - "git_name is defined" + - "git_name != ''" + - "git_email is defined" + - "git_email != ''" + msg: Please set your gpg_key_name, git_name and git_email in gitian.yml. + +- name: Install Gitian build dependencies. + apt: + name: "{{ item }}" + state: present + update_cache: yes + with_items: + - apt-cacher-ng + - bridge-utils + - curl + - debootstrap + - git-core + - kpartx + - make + - parted + - python-cheetah + - qemu-utils + - ruby + - sudo + +- name: Set up the Gitian build user with sudo. + user: + name: "{{ gitian_user }}" + shell: /bin/bash + groups: sudo + state: present + +- name: Install /etc/rc.local. + template: + src: rc.local + dest: /etc/rc.local + owner: root + group: root + mode: "0755" + +- name: Enable IP forwarding, etc. + sysctl: + name: "{{ item }}" + value: 1 + sysctl_set: yes + state: present + reload: yes + with_items: + - net.ipv4.ip_forward + - kernel.unprivileged_userns_clone + +- name: Enable cgroup clone_children. + command: "echo 1 > /sys/fs/cgroup/cpuset/cgroup.clone_children" + +- name: Add cgroup fs for LXC. + lineinfile: + dest: /etc/fstab + regexp: '^cgroup' + line: 'cgroup /sys/fs/cgroup cgroup defaults 0 0' + state: present + +- name: Install profile with environment variables. + template: + src: profile + dest: "/home/{{ gitian_user }}/.profile" + owner: "{{ gitian_user }}" + group: "{{ gitian_user }}" + mode: "0644" + +- name: Install sudoers file for LXC. + template: + src: gitian-lxc + dest: /etc/sudoers.d/gitian-lxc + owner: root + group: root + mode: "0644" + +- name: Create directory for downloaded files. + file: + state: directory + dest: "{{ download_directory }}" + mode: "0755" + +- name: Download and extract VM builder source code. + unarchive: + src: "{{ vm_builder_url }}" + dest: "{{ download_directory }}" + copy: no + remote_src: yes + +- name: Install VM builder Python module. + command: "python setup.py install" + args: + chdir: "/tmp/gitian/{{ vm_builder_name }}" + +- name: Install lxc-net configuration. + template: + src: lxc-net + dest: /etc/default/lxc-net + owner: root + group: root + mode: "0644" + +- name: Set up jessie-backports. + apt_repository: + repo: 'deb http://httpredir.debian.org/debian/ jessie-backports main' + state: present + +- name: Install updated version of LXC. + apt: + name: lxc + state: latest + default_release: jessie-backports + update_cache: yes + cache_valid_time: 3600 + +- name: Clone git repository for Gitian builder. + git: + repo: "https://github.com/ageis/gitian-builder" + dest: "/home/{{ gitian_user }}/gitian-builder" + version: "master" + force: yes + depth: 1 + ignore_errors: yes + become_user: "{{ gitian_user }}" + +- name: Clone git repository for Zcash. + git: + repo: "{{ zcash_git_repo_url }}" + dest: "/home/{{ gitian_user }}/zcash" + version: "{{ zcash_version }}" + force: yes + depth: 1 + ignore_errors: yes + become_user: "{{ gitian_user }}" + +- name: Clone git repository for Gitian signatures. + git: + repo: "{{ zcash_gitian_sigs_repo }}" + dest: "/home/{{ gitian_user }}/gitian.sigs" + version: master + force: yes + depth: 1 + ignore_errors: yes + become_user: "{{ gitian_user }}" + +- name: Reboot. + shell: sleep 3 && shutdown -r now "Rebooting..." + async: 1 + poll: 0 + ignore_errors: true + become: yes + +- name: Figure out the Vagrant VM's SSH port number. + local_action: "shell vagrant ssh-config zcash-build | grep Port | awk {'print $2'}" + register: vagrant_ssh_port + become: no + +- name: Wait for virtual machine to come back. + local_action: wait_for + host={{ ansible_host | default('localhost') }} + port={{ vagrant_ssh_port.stdout | int }} + delay=30 + state=started + become: no + +- name: Wait extra time for server to come back up. + pause: + seconds: 10 + +- name: Set Git username. + command: "git config --global user.name '{{ git_name }}'" + become_user: "{{ gitian_user }}" + +- name: Set Git email address. + command: "git config --global user.email '{{ git_email }}'" + become_user: "{{ gitian_user }}" + +- name: Copy Gitian build script. + template: + src: gitian-build.sh + dest: "/home/{{ gitian_user }}/gitian-build.sh" + owner: "{{ gitian_user }}" + group: "{{ gitian_user }}" + mode: "0755" + tags: script + +- name: Check for presence of Gitian LXC image. + stat: + path: "/home/{{ gitian_user }}/gitian-builder/base-jessie-amd64" + register: gitian_lxc_image + +- name: Set up the Gitian LXC image. + shell: "source ~/.profile && /home/{{ gitian_user }}/gitian-builder/bin/make-base-vm --lxc --arch amd64 --distro debian --suite jessie" + when: gitian_lxc_image.stat.exists == false + become: yes + become_user: "{{ gitian_user }}" + args: + chdir: "/home/{{ gitian_user }}/gitian-builder" + executable: /bin/bash + +- include: gpg.yml + tags: gpg + become: no + when: gpg_key_id is defined and gpg_key_id != '' + +- include: ssh.yml + tags: ssh + become: no + when: ssh_key_name is defined and ssh_key_name != '' + +- name: Display help message. + debug: + msg: >- + Finished bootstrapping the Gitian host VM! + To enter the environment, run `vagrant ssh zcash-build` + And then use `./gitian-build.sh` to kick off a build. diff --git a/roles/gitian/tasks/ssh.yml b/roles/gitian/tasks/ssh.yml new file mode 100644 index 0000000..14d61a4 --- /dev/null +++ b/roles/gitian/tasks/ssh.yml @@ -0,0 +1,23 @@ +--- +- name: Check that the SSH key exists locally. + local_action: "stat path={{ lookup('env', 'HOME') }}/.ssh/{{ ssh_key_name }}" + register: ssh_key + +- name: Make SSH home directory. + file: + path: "/home/{{ gitian_user }}/.ssh" + state: directory + mode: "0700" + owner: "{{ gitian_user }}" + group: "{{ gitian_user }}" + +- name: Copy the SSH public and private key. + synchronize: + src: "{{ lookup('env', 'HOME') }}/.ssh/{{ item }}" + dest: "/home/{{ gitian_user }}/.ssh/{{ item }}" + archive: yes + owner: yes + with_items: + - "{{ ssh_key_name }}" + - "{{ ssh_key_name }}.pub" + when: ssh_key.stat.exists diff --git a/roles/gitian/templates/gitian-build.sh b/roles/gitian/templates/gitian-build.sh new file mode 100644 index 0000000..3cc0a01 --- /dev/null +++ b/roles/gitian/templates/gitian-build.sh @@ -0,0 +1,248 @@ +# Copyright (c) 2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# What to do +sign=false +verify=false +build=true + +# Systems to build +linux=true + +# Other Basic variables +SIGNER="{{ gpg_key_name }}" +VERSION={{ zcash_version }} +commit=false +url={{ zcash_git_repo_url }} +proc=2 +mem=3072 +lxc=true +scriptName=$(basename -- "$0") +signProg="gpg2 --detach-sign" +commitFiles=true + +# Help Message +read -d '' usage <<- EOF +Usage: $scriptName [-c|u|v|b|s|B|o|h|j|m|] signer version + +Run this script from the directory containing the zcash, gitian-builder, and gitian.sigs repositories. + +Arguments: +signer GPG signer to sign each build assert file +version Version number, commit, or branch to build. If building a commit or branch, the -c option must be specified + +Options: +-c|--commit Indicate that the version argument is for a commit or branch +-u|--url Specify the URL of the repository. Default is {{ zcash_git_repo_url }} +-v|--verify Verify the gitian build +-b|--build Do a gitian build +-s|--sign Make signed binaries +-B|--buildsign Build both signed and unsigned binaries +-j Number of processes to use. Default 2 +-m Memory to allocate in MiB. Default 3072 +--detach-sign Create the assert file for detached signing. Will not commit anything. +--no-commit Do not commit anything to git +-h|--help Print this help message +EOF + +# Get options and arguments +while :; do + case $1 in + # Verify + -v|--verify) + verify=true + ;; + # Build + -b|--build) + build=true + ;; + # Sign binaries + -s|--sign) + sign=true + ;; + # Build then Sign + -B|--buildsign) + sign=true + build=true + ;; + # PGP Signer + -S|--signer) + if [ -n "$2" ] + then + SIGNER=$2 + shift + else + echo 'Error: "--signer" requires a non-empty argument.' + exit 1 + fi + ;; + # Help message + -h|--help) + echo "$usage" + exit 0 + ;; + # Commit or branch + -c|--commit) + commit=true + ;; + # Number of Processes + -j) + if [ -n "$2" ] + then + proc=$2 + shift + else + echo 'Error: "-j" requires an argument' + exit 1 + fi + ;; + # Memory to allocate + -m) + if [ -n "$2" ] + then + mem=$2 + shift + else + echo 'Error: "-m" requires an argument' + exit 1 + fi + ;; + # URL + -u) + if [ -n "$2" ] + then + url=$2 + shift + else + echo 'Error: "-u" requires an argument' + exit 1 + fi + ;; + # Detach sign + --detach-sign) + signProg="true" + commitFiles=false + ;; + # Commit files + --no-commit) + commitFiles=false + ;; + *) # Default case: If no more options then break out of the loop. + break + esac + shift +done + +# Set up LXC +if [[ $lxc = true ]] +then + source ~/.profile +fi + +# Get version +if [[ -n "$1" ]] +then + VERSION=$1 + COMMIT=$VERSION + shift +fi + +# Check that a signer is specified +if [[ $SIGNER == "" ]] +then + echo "$scriptName: Missing signer." + echo "Try $scriptName --help for more information" + exit 1 +fi + +# Check that a version is specified +if [[ $VERSION == "" ]] +then + echo "$scriptName: Missing version." + echo "Try $scriptName --help for more information" + exit 1 +fi + +# Add a "v" if no -c +if [[ $commit = false ]] +then + COMMIT="${VERSION}" +fi +echo ${COMMIT} + +# Set up build +pushd ./zcash +git fetch +git checkout ${COMMIT} +popd + +# Build +if [[ $build = true ]] +then + # Make output folder + mkdir -p ./zcash-binaries/${VERSION} + + # Build Dependencies + echo "" + echo "Building Dependencies" + echo "" + pushd ./gitian-builder + mkdir -p inputs + make -C ../zcash/depends download SOURCES_PATH=`pwd`/cache/common + + # Linux + if [[ $linux = true ]] + then + echo "" + echo "Compiling ${VERSION} Linux" + echo "" + ./bin/gbuild -j ${proc} -m ${mem} --commit zcash=${COMMIT} --url zcash=${url} ../zcash/contrib/gitian-descriptors/gitian-linux.yml + ./bin/gsign -p "$signProg" --signer "$SIGNER" --release ${VERSION} --destination ../gitian.sigs/ ../zcash/contrib/gitian-descriptors/gitian-linux.yml + mv build/out/zcash-*.tar.gz build/out/src/zcash-*.tar.gz ../zcash-binaries/${VERSION} + fi + popd + + if [[ $commitFiles = true ]] + then + # Commit to gitian.sigs repo + echo "" + echo "Committing ${VERSION} Unsigned Sigs" + echo "" + pushd gitian.sigs + git add ${VERSION}/${SIGNER} + git commit -a -m "Add ${VERSION} unsigned sigs for ${SIGNER}" + popd + fi +fi + +# Verify the build +if [[ $verify = true ]] +then + # Linux + pushd ./gitian-builder + echo "" + echo "Verifying v${VERSION} Linux" + echo "" + ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION} ../zcash/contrib/gitian-descriptors/gitian-linux.yml + popd +fi + +# Sign binaries +if [[ $sign = true ]] +then + + pushd ./gitian-builder + popd + + if [[ $commitFiles = true ]] + then + # Commit Sigs + pushd gitian.sigs + echo "" + echo "Committing ${VERSION} Signed Sigs" + echo "" + git commit -a -m "Add ${VERSION} signed binary sigs for ${SIGNER}" + popd + fi +fi diff --git a/roles/gitian/templates/gitian-lxc b/roles/gitian/templates/gitian-lxc new file mode 100644 index 0000000..3ad6406 --- /dev/null +++ b/roles/gitian/templates/gitian-lxc @@ -0,0 +1,3 @@ +{{ gitian_user }} ALL=(ALL:ALL) NOPASSWD: ALL +%sudo ALL=NOPASSWD: /usr/bin/lxc-start +%sudo ALL=NOPASSWD: /usr/bin/lxc-execute diff --git a/roles/gitian/templates/gpg.conf b/roles/gitian/templates/gpg.conf new file mode 100644 index 0000000..d49c631 --- /dev/null +++ b/roles/gitian/templates/gpg.conf @@ -0,0 +1,8 @@ +no-greeting +default-key {{ gpg_key_id }} +require-cross-certification +charset utf-8 +keyserver hkp://keys.gnupg.net +use-agent +keyid-format 0xlong +no-emit-version diff --git a/roles/gitian/templates/lxc-net b/roles/gitian/templates/lxc-net new file mode 100644 index 0000000..a9ab5fd --- /dev/null +++ b/roles/gitian/templates/lxc-net @@ -0,0 +1,7 @@ +USE_LXC_BRIDGE="true" +LXC_BRIDGE="lxcbr0" +LXC_ADDR="10.0.3.1" +LXC_NETMASK="255.255.255.0" +LXC_NETWORK="10.0.3.0/24" +LXC_DHCP_RANGE="10.0.3.2,10.0.3.254" +LXC_DHCP_MAX="253" diff --git a/roles/gitian/templates/profile b/roles/gitian/templates/profile new file mode 100644 index 0000000..bfae8bf --- /dev/null +++ b/roles/gitian/templates/profile @@ -0,0 +1,32 @@ +# ~/.profile: executed by the command interpreter for login shells. +# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login +# exists. +# see /usr/share/doc/bash/examples/startup-files for examples. +# the files are located in the bash-doc package. + +# the default umask is set in /etc/profile; for setting the umask +# for ssh logins, install and configure the libpam-umask package. +#umask 022 + +# if running bash +if [ -n "$BASH_VERSION" ]; then + # include .bashrc if it exists + if [ -f "$HOME/.bashrc" ]; then + . "$HOME/.bashrc" + fi +fi + +# set PATH so it includes user's private bin if it exists +if [ -d "$HOME/bin" ] ; then + PATH="$HOME/bin:$PATH" +fi + +alias gpg='gpg2' +export DISTRO=debian +export SUITE=jessie +export ARCH=amd64 +export USE_LXC=1 +export LXC_BRIDGE=lxcbr0 +export GITIAN_HOST_IP={{ gitian_host_ip }} +export LXC_GUEST_IP={{ lxc_guest_ip }} +export MIRROR_HOST={{ gitian_host_ip }} diff --git a/roles/gitian/templates/rc.local b/roles/gitian/templates/rc.local new file mode 100755 index 0000000..e75171c --- /dev/null +++ b/roles/gitian/templates/rc.local @@ -0,0 +1,7 @@ +#!/bin/sh -e + +echo 1 > /sys/fs/cgroup/cpuset/cgroup.clone_children +echo 1 > /proc/sys/kernel/unprivileged_userns_clone +echo 1 > /proc/sys/net/ipv4/ip_forward + +exit 0 diff --git a/scp.sh b/scp.sh new file mode 100755 index 0000000..3ff85f6 --- /dev/null +++ b/scp.sh @@ -0,0 +1,3 @@ +#!/bin/sh +OPTIONS=`vagrant ssh-config zcash-build | awk -v ORS=' ' '{print "-o " $1 "=" $2}'` +scp ${OPTIONS} "$@" || echo "Transfer failed."