3

What options are available to accomplish the following boot scenario?

On boot (before boot) contact a defined webserver and ask what to boot (normal answer: boot from local hard drive; alternative answer: boot image XYZ)

The goal is to be able to reinstall the clients without the need of a user interaction at the clients. The logical way to do this would be PXE booting but as we don't control the environment defaulting to regular booting PXE is insecure as it would open an attack vector.

What I have found and tried so far is the following: Starting Grub2 from local hard drive and chainloading iPXE. iPXE then contacts the defined webserver over http and gets an iPXE script back. But from there I haven't yet found a way to boot from the local drive (except for starting Grub again and ending in an endless loop). The OS I would like to boot is on partition 2 of the same hard drive as Grub/iPXE is started from.

  1. Is there an alternative way to accomplish what we try to accomplish?
  2. Is there a way to tell Grub to select a different option on the second start (comming back from iPXE) or to tell iPXE to boot from partition 2?

Side note: Partition 2 contains a Windows Boatloader and can be booted from the Grub Menu.

  • ...just thinking out-loud, assuming all clients MAY be different. Can you save the normal boot info in the grubenv and load that when pxe boot occurs. Then on the pxe server “If no update boot ‘normal_boot’”... – jc__ Feb 15 '16 at 16:21
  • Good idea! grubenv seems to be a possible solution. I'm able to set saved_entry to the desired value from Ubuntu using the "grub-set-default" command. However, I have been unable to change this value from within grub using the "save_env" command. If I invoke "save_env saved_entry=XYX" in the grub command line it looks like it worked but list_env then still shows to old value. Am I missing something here? – Pascal Mages Feb 16 '16 at 10:40
  • I just posted another question (http://unix.stackexchange.com/questions/263600/how-is-the-grub-command-save-env-supposed-to-work) concerning the Grub save_env issue. – Pascal Mages Feb 16 '16 at 11:26
  • I found the solution to my Grub save_env issue. And now it works. I'll post my solution as answer. – Pascal Mages Feb 17 '16 at 08:15

3 Answers3

0

I have used the following technique upgrading a remote system, which might help you as well. On that system I could only initiate a reset, not look at the (boot) screen. The system booted into grub (on Ubuntu 12.04) and had a both an extra partition and a data partition. The trick is to insert in /etc/default/grub:

GRUB_DEFAULT=saved
GRUB_SAVEDEFAULT=false

That you always boot into the 0 entry (Ubuntu 12.04) unless:

  • someone at the console selects something else
  • you run grub-reboot X while logged into Ubuntu, and reboot

From Ubuntu I would download and etract a tar file to the extra partition (or make small changes by hand), then run update-grub to update the grub menu (which scanned the newly filled extra partition and created menu entries for its OS), then use grub-reboot and reboot.

If the machine would not come back (i.e. could not ssh after a grace period), I could reset the machine and it would reboot in Ubuntu ready for analysis what went wrong and the next cycle.

With the appropriate program run on boot you could check what the next "image" is you need to download, see if you already have that (if not download) and install. Then reboot as above.

With a lean systemd based distribution the reboot process should be relatively quick, and downloading/installing an alternative OS/distro would take the major part of the time.

Anthon
  • 78,313
  • 42
  • 165
  • 222
  • Thanks for your suggestion. Looks like an interesting way. We might end up using a similar setup. But for now, I still hope to find a way to ask our server what to boot without any user interaction. – Pascal Mages Feb 16 '16 at 09:23
  • @pascal, you don't need any user interaction once this is set up. The only thing you need is a program (on Ubuntu) that checks if there is something new to install in the alternative boot partition. The download of that can be done securily e.g. using HTTPS as long as you check the certificate to be valid, or with ssh and a private/public keypair – Anthon Feb 16 '16 at 10:34
  • yes your right. The problem in our case is, that the clients will run Windows all the time. Unless we boot Ubuntu (or something else) to actually reinstall the Windows image. So what we need is a way to boot into Ubuntu insteads of Windows on demand without user interaction. Unfortunately it's not an option to set the Ubuntu boot from within Windows as in the case of a broken Windows (which is likely the reason for need to boot Ubuntu) we wouldn't be able to do that anymore. – Pascal Mages Feb 16 '16 at 11:10
  • Would it be an option to have 3 partitions (ubuntu, windows, and experiment). Your default boot into "ubuntu" programmatically check there is notification on some website, if so update experiment (if not already done) and reboot into experiment, if no notification reboot into windows. Then the only thing a customer needs to do is reboot his/her machine if you have update your notifications. You could make those individual (based on something unique that the startup script in Linux passes along, like the MAC address). – Anthon Feb 16 '16 at 11:40
  • Probably yes, but this would delay the boot process a little too much. So we need a very slim boot solution. I'm currently investigating the solution propose by @jc__ but I'm stuck with save_env not working in my Grub (see http://unix.stackexchange.com/questions/263600/how-is-the-grub-command-save-env-supposed-to-work) – Pascal Mages Feb 16 '16 at 13:22
0

I found a way to accomplish what we were looking for. Thanks go @jc__ for the hint with grubenv and as well as to @Anthon.

So here is my solution: Put a iPXE kernel binary (.lkrn) with the custom script to contact the boot control server into /boot

Then setup Grub

1- to use variable from grubenv

GRUB_DEFAULT=saved

2- Chain load iPXE on /boot from Grub and include the following command before booting iPXE

set saved_entry='<menuentry to boot from local drive>'
save_env saved_entry

3- Prepend the Grub menuentry which loads the OS from local drive with

set saved_entry='<menuentry iPXE>'
save_env saved_entry

4- If nothing needs to be done the boot control server instructs iPXE to boot from the local drive with

sanboot --no-describe --drive 0x80

5- Grub is loaded again and boots into local drive, setting up next boot to be iPXE again.

The boot time into Windows 10 including asking boot control server is about 25 seconds. So actually quite fast. :)

0

There are at least two ways to accomplish this:

  1. Take a look at http://ipxe.org/appnote/work_around_bios_halting_on_ipxe_exit#examples, one of these commands could work for you:

    chain ${server}/grub4dos.exe --config-file="find --set-root /BOOTMGR;chainloader /BOOTMGR"
    chain ${server}/grub4dos.exe --config-file="root (hd0,1);chainloader +1"
    
  2. I am currently using the following as I built this before I found that page on GRUB4DOS on the iPXE site. Create an ISO image containing ISOLINUX and this config:

    NOESCAPE 1
    PROMPT 0
    ALLOWOPTIONS 0
    
    DEFAULT chain-hd0-2
    LABEL chain-hd0-2
    SAY Chaining hd0 2...
    COM32 chain.c32
    APPEND hd0 2
    

    And boot it using (you have to use 0x81 here because it uses 0x80 by default which would override the local disk):

    sanboot --drive 0x81 ${server}/chain-hd0-2.iso
    
Julian
  • 101
  • 3
  • As iPXE also has support for SYSLINUX COM32 files, I think it should also be possible, to load chain.c32 directly from iPXE but I didn't manage to get this working so far. At least one problem seems to be that chain.c32 depends on other *.c32 files from SYSLINUX. – Julian May 08 '16 at 16:38
  • thanks for the hint with Grub4DOS. It looks like an interesting approach to our challenge. I'll try and will report back here. Currently I'm also experimenting with PXELINUX. – Pascal Mages May 12 '16 at 14:56