Skip to content

Instantly share code, notes, and snippets.

@EnigmaCurry
Last active December 12, 2022 11:49
Show Gist options
  • Save EnigmaCurry/7895407 to your computer and use it in GitHub Desktop.
Save EnigmaCurry/7895407 to your computer and use it in GitHub Desktop.
Linux Containers mini-HOWTO on Ubuntu

This is a mini-HOWTO for setting up Linux Containers (LXC) on Ubuntu. This guide focuses on the creation of a web server with good process isolation and firewalling.

Dependencies

apt-get install lxc

Create a container

lxc-create -t ubuntu -n my_server

Configure Networking

LXC automatically creates a lxcbr0 bridge on the host, with an IP of 10.0.3.1. By default, there is no DHCP server, so you have to manually set an ip address on the guest container.

Put something like this in /var/lib/lxc/my_server/rootfs/etc/network/interfaces:

auto eth0
iface eth0 inet static
    address 10.0.3.10
    netmask 255.255.255.0
    gateway 10.0.3.1

Startup

Manually:

lxc-start -n my_server -d

Automatically on host startup:

ln -s /var/lib/lxc/my_server/config /etc/lxc/auto/my_server.conf

List all containers

lxc-ls --fancy

Connect to the container

lxc-attach -n my_server

You will see your prompt has changed to indicate you are connected as root@my_server. Press ctrl-d to get back to the host system when done.

Guest Container Security

Delete the ubuntu user. You don't need it.

deluser ubuntu
rm -rf /home/ubuntu

By default, the ubuntu template starts up an SSH server. That's probably unnecessary, so just uninstall it:

apt-get remove openssh-server

Linux Containers are lightweight, meaning that processes from all guests are running under the same kernel. You need to make sure that user and group ids are not colliding between the host and guests, otherwise any processes or files with the same user/group id used in the other system, be they on the host, or one of the guests, can be killed or deleted by the user from that other system.

You can modify each system's uid and gid range inside /etc/adduser.conf. The settings shown here is for the first LXC guest. It uses 2000-2199 as the system id range and 2200-2999 as the user id range. The second LXC guest would start at 3000, and so on:

FIRST_SYSTEM_UID=2000
LAST_SYSTEM_UID=2199
FIRST_SYSTEM_GID=2000
LAST_SYSTEM_GID=2199
FIRST_UID=2200
LAST_UID=2999
FIRST_GID=2200
LAST_GID=2999

Note, that for users created before making this change, you will need to change those user's uid/gid, as well as all file permissions for those users, manually:

usermod -u <NEWUID> <LOGIN>
groupmod -g <NEWGID> <GROUP>
find / -uid <OLDUID> -exec chown -h <NEWUID> '{}' \+
find / -gid <OLDGID> -exec chgrp -h <NEWGID> '{}' \+

I personally see no reason to change the ids of the default system users that ubuntu ships with, unless you're planning to give root access to an untrusted person. However, LXC may not be the best choice if you don't trust your users.

Firewall

Here's a suitable set of iptables rules for a machine hosting linux containers. It has the following features:

  • Allows pinging the host machine.
  • Allows SSH to the host machine.
  • Setup IP masquerading for the guest containers, so they can reach the net.
  • Opens a single port, port 80, and forwards it to the guest container.
  • Logs denied packets. Useful for debugging your rules, as well as intrusion detection.

Put your rules in /etc/iptables.up.rules :

*filter

# Accepts all established inbound connections
 -A INPUT   -m state --state ESTABLISHED,RELATED -j ACCEPT
 -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allows all outbound traffic:
 -A OUTPUT -j ACCEPT

# Allow all outbound traffic from Linux Containers:
 -A FORWARD -i lxcbr0 -j ACCEPT

# Allow HTTP traffic (to be forwarded to the Linux Container hosting the server) :
 -A INPUT   -i eth0 -p tcp --dport 80 -j ACCEPT
 -A FORWARD -i eth0 -p tcp --dport 80 -j ACCEPT

# Allows SSH to the host:
 -A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT

# Allow ping
 -A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT

# log iptables denied calls (access via 'dmesg' command)
 -A INPUT   -m limit --limit 5/min -j LOG --log-prefix "iptables INPUT denied: " --log-level 7
 -A OUTPUT  -m limit --limit 5/min -j LOG --log-prefix "iptables OUTPUT denied: " --log-level 7
 -A FORWARD -m limit --limit 5/min -j LOG --log-prefix "iptables FORWARD denied: " --log-level 7

# Reject all other inbound - default deny unless explicitly allowed policy:
 -A INPUT   -j REJECT
 -A FORWARD -j REJECT

COMMIT

*nat

# Forward HTTP traffic to the Linux Container running it:
-A PREROUTING  -i eth0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.0.3.10:80

# Allow LXC subnet net access.
-A POSTROUTING -s 10.0.3.0/24 -j MASQUERADE

COMMIT

To load these rules on boot, you can create /etc/network/if-up.d/iptables :

#!/bin/sh
iptables-restore /etc/iptables.up.rules

And make it executable:

chmod +x /etc/network/if-up.d/iptables

Related Articles

@lpvm
Copy link

lpvm commented Jun 27, 2017

Allow LXC subnet net access.

-A POSTROUTING -s 10.0.3.0/24 -j MASQUERADE

returns an error:
iptables: No chain/target/match by that name.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment