Cloud-init with netplan

I figured out how to do what I needed, which was specifically:

  • build a core image for the pi3
  • that uses cloud-init
  • to install a netplan file
  • with eth0 set to a working static IP
  • with a wifi access point declared with passphrase and auto-connecting
  • with console-conf disabled
  • and a system-user imported from a usb key on first boot

I made and use below some helper scripts, some of which are used: https://github.com/knitzsche/core-build-scripts

== Assume a model.json file:

{
  "type": "model",
  "system-user-authority": "*",
  "authority-id": "MYSSOACOUNTID", <- NOT a real id
  "brand-id": "MYSSOACCOUNTID", <- NOT real
  "series": "16",
  "model": "testmodel",
  "architecture": "armhf",
  "kernel": "pi2-kernel",
  "gadget": "pi3",
  "timestamp": "2017-07-11T15:55:59+00:00"
}

== Make the model assertion using “model” key (see -h)

$ ./make-model-assertion.sh model-pi3.json model > model.assertion

You need a passphrase to unlock the secret key for
user: "model"
4096-bit RSA key, ID C215EA0F, created 2017-01-01

== Make the image and put it in img-test:

$ sudo ./make-img.sh model.assertion stable img-test
Fetching core
Fetching pi2-kernel
Fetching pi3
built: img-test, with model: model.assertion, from channel: stable

== Enable the image for cloud-init

$ sudo ./enable-cloud-init.sh img-test/pi3.img 
loop_path: /dev/mapper/loop17p2
Removing cloud-init.disabled file
done: img-test/pi3.img

== Disable console-conf

$ sudo ./disable-console-conf.sh img-test/pi3.img 
loop_path: /dev/mapper/loop17p2
done: img-test/pi3.img

== Mount the writable partition of the image

$ sudo ./mount-do-nothing.sh img-test/pi3.img 
loop_path: /dev/mapper/loop17p2
The image is now mounted in mnt/
Press any key to unmount and complete

== In another terminal in same dir, copy a netplan file like this to the correct place in the mounted partition

The netplan file

$ cat mynetplan.yaml 
network:
  version: 2
  ethernets:
    eth0:
      addresses:
        - 10.0.0.244/24
      gateway4:
        10.0.0.1
  wifis:
    wlan0:
      dhcp4:
        true
      access-points:
        "myap":
          password:
            "mypassword"

Make the dir in the mounted partition, and copy the netplan file in

$ sudo mkdir  mnt/system-data/etc/netplan
$ sudo cp mynetplan.yaml mnt/system-data/etc/netplan/01-custom.yaml

=== In previous terminal press Enter to unmount

$ sudo ./mount-do-nothing.sh img-test/pi3.img 
loop_path: /dev/mapper/loop17p2
The image is now mounted in mnt/
Press any key to unmount and complete
[ENTER]
$ 

== dd the image to SD card inserted and mounted to /dev/sdb

WARNING: This script assumes SD is on sdb. It will erase all data on sdb. So you might want to do it manually!

$ sudo ./dd-to-sdb.sh img-test/pi3.img 
19+1 records in
19+1 records out
634260480 bytes (634 MB, 605 MiB) copied, 7.7398 s, 81.9 MB/s
$ 

== Unmount the two partitions on sdb

$ sudo umount /dev/sdb1
$ sudo umount /dev/sdb2

== Remove the SD card

== Make a system-user assertion

$ snap install make-system-user

See make-system-user.run -h to see how to fill in fields

Run it perhaps like this, given the above model.json and the existence of a snapcraft key named “kykey”

$ make-system-user.run -b MYSSOACCOUNTID -m testmodel -u ubuntu -p ubuntu -k mykey

You need a passphrase to unlock the secret key for
user: "mykey"
4096-bit RSA key, ID C375E301, created 2016-01-01

Done. You may copy auto-import.assert to a USB stick and insert it into an unmanaged Core system, after which you can log in using the username and password you provided.

And copy the generated auto-import.assert file to the root dir of your USB key.

== Insert SD, USB and boot

Should work as expected (although nothing yet creates the /etc/cloud/cloud-init.disabled command after first boot, so cloud init would run on every boot, a solvable problem, maybe with a custom systemd unit)

2 Likes