Thursday, August 8, 2019

Creating an LXD container on my Ubuntu 19.04 host

I just finished setting up LXD on my Ubuntu 19.04 server, and I'm ready to create a container.

Installing the service into the container is a separate step - this is just setting up and configuring the container itself.

Creating a disposable container:

Actually, we did this already with our test container:

    me@host:~$ lxc launch -p lanprofile ubuntu:disco test

Let's see if that container is still there:

    me@host:~$ lxc list
        +----------------+---------+---------------------+-----------------------------------------------+------------+-----------+
        |      NAME      |  STATE  |        IPV4         |                     IPV6                      |    TYPE    | SNAPSHOTS |
        +----------------+---------+---------------------+-----------------------------------------------+------------+-----------+
        | test           | RUNNING | 192.168.1.124 (eth0)| 2615:a000:141f:e267:215:3eef:fe2a:c55d (eth0) | PERSISTENT | 0         
        |
        +----------------+---------+---------------------+-----------------------------------------------+------------+-----------+

We can enter the container to run commands on it's shell. Note that root inside the container is not root (unprivileged) on the host. The container comes with a default "ubuntu" user, but we have root so we don't seem to need the user.

    me@host:~$ lxc shell test
        mesg: ttyname failed: No such device  // Ignore this message
        root@test:~#                          // Look, a root prompt within the container!
        root@test:~# exit
            logout
    me@host:~$                                // Back to the host

We can stop and then restart containers. No sudo needed, these are unprivileged containers:

    me@host:~$ lxc stop test
    me@host:~$ lxc stop test

And when we are done we can destroy the container:

    me@host:~$ lxc stop test
    me@host:~$ lxc destroy test

Creating a long-term container:

Now I want to create a container for a long-term service. Now we add security: This means adding non-root users, independent ssh access, and package upgrades. This container can function like a lightweight VM, though with rather less overhead.

    me@host:~$ lxc launch -p lanprofile ubuntu:disco test_2

We can login to our LAN router, and see the test_2 device on the network. This is a good opportunity to assign it a consistent IP address, so you can always find the container again. Stop and restart the container so it picks up the new IP address.

Let's create a user for me with ssh access

    me@host:~$ lxc shell test_2
        mesg: ttyname failed: No such device     // Ignore this message

        root@test_2:~# adduser me                // Includes creating a password
        root@test_2:~# adduser me sudo           // Add me to the "sudo" group for easy remote administration via ssh
        root@test_2:~# nano /etc/ssh/sshd_config

           PasswordAuthentication yes            // Temporary while we set up ssh keys

        root@test_2:~# systemctl restart sshd
        root@test_2:~# exit

Copy my key. Remember to do this from ALL systems you are going to SSH into this container from:

    me@desktop:~$ ssh-copy-id me@192.168.1.124

Now I can ssh directly into the container using keys, so let's end password login.

    me@test_2:~$ sudo nano /etc/ssh/sshd_config

           PermitRootLogin no
           PasswordAuthentication no

    me@test_2:~$ sudo systemctl restart sshd

Remove the default "ubuntu" user, since we won't be using it.

    me@test_2:~$ sudo deluser ubuntu
    me@test_2:~$ sudo rm -r /home/ubuntu

Moving on to package management, simplify the apt sources so only -main and -universe are seen in -updates and -security. We only need what the installed service requires.

    me@test_2:~$ sudo nano /etc/apt/sources.list

        deb http://archive.ubuntu.com/ubuntu disco main universe
        deb http://archive.ubuntu.com/ubuntu disco-updates main universe
        deb http://security.ubuntu.com/ubuntu disco-security main universe

    me@test_2:~$ sudo apt update                        // Since the sources have changed
    me@test_2:~$ sudo apt upgrade                       // Now is a good time

Finally, let's install unattended-upgrades and configure it to upgrade ALL packages from our limited apt sources. This means we are less likely to discover months of unapplied upgrades and security fixes. This is optional, merely my preference:

    me@test_2:~$ sudo apt install unattended-upgrades
    me@test_2:~$ sudo nano /etc/apt/apt.conf.d/50unattended-upgrades

        // Uncomment the following two lines:
        "${distro_id}:${distro_codename}-security";
        "${distro_id}:${distro_codename}-updates";

And there we have it - a long-term container that is easily (but securely) accessed via ssh for maintenance and automatically pulls package updates. Lightweight VM-like behavior with a consistent IP address. Note that "lxc shell" on the host will still give a root prompt, but recall that the purpose of a container is to keep the service from getting out, not to keep host from getting in. Also note that, due to macvlan networking, the container cannot communicate across the networkk with the host.

No comments: