package io.fathom.cloud.compute.scheduler; import java.util.List; import com.google.common.base.Strings; import com.google.common.collect.Lists; public class LxcConfigBuilder { public String hostname; public String ipv4; public String ipv4Gateway; public String ipv6; public String ipv6Gateway; public String rootfs; public String configDir; public String bridge; public Integer memoryLimitMB; public Integer swapMemoryLimitMB; public Integer cpuShares; public List<Volume> volumes = Lists.newArrayList(); public static class Volume { public String hostPath; public String instancePath; } private StringBuilder sb; public String hwaddr; private void a(String s) { sb.append(s + "\n"); } private void a(String k, String v) { if (v == null) { return; } a(k + " = " + v); } private void a() { a(""); } public synchronized String build() { // We try to mirror what docker does, to maximize compatibility sb = new StringBuilder(); a("# hostname"); a("lxc.utsname = " + hostname); a(); // #lxc.aa_profile = unconfined a("# network configuration"); a("lxc.network.type = veth"); a("lxc.network.flags = up"); a("lxc.network.link", bridge); a("lxc.network.name = eth0"); a("lxc.network.mtu = 1500"); a("lxc.network.ipv4", ipv4); a("lxc.network.ipv4.gateway", ipv4Gateway); a("lxc.network.ipv6", ipv6); a("lxc.network.ipv6.gateway", ipv6Gateway); if (!Strings.isNullOrEmpty(hwaddr)) { a("lxc.network.hwaddr", hwaddr); } a(); a("# root filesystem"); a("lxc.rootfs", rootfs); a(); a("# use a dedicated pts for the container (and limit the number of pseudo terminal available)"); a("lxc.pts", "1024"); a(); a("# disable the main console"); a("lxc.console = none"); a(); a("# no controlling tty at all"); a("lxc.tty = 1"); a(); a("# no implicit access to devices"); a("lxc.cgroup.devices.deny = a"); a(); a("# /dev/null and zero"); a("lxc.cgroup.devices.allow = c 1:3 rwm"); a("lxc.cgroup.devices.allow = c 1:5 rwm"); a(); a("# consoles"); a("lxc.cgroup.devices.allow = c 5:1 rwm"); a("lxc.cgroup.devices.allow = c 5:0 rwm"); a("lxc.cgroup.devices.allow = c 4:0 rwm"); a("lxc.cgroup.devices.allow = c 4:1 rwm"); a(); a("# /dev/urandom,/dev/random"); a("lxc.cgroup.devices.allow = c 1:9 rwm"); a("lxc.cgroup.devices.allow = c 1:8 rwm"); a(); a("# /dev/pts/* - pts namespaces are 'coming soon'"); a("lxc.cgroup.devices.allow = c 136:* rwm"); a("lxc.cgroup.devices.allow = c 5:2 rwm"); a(); a("# tuntap"); a("lxc.cgroup.devices.allow = c 10:200 rwm"); a(); // # fuse // #lxc.cgroup.devices.allow = c 10:229 rwm // # rtc // #lxc.cgroup.devices.allow = c 254:0 rwm a("# standard mount point"); a("# WARNING: procfs is a known attack vector and should probably be disabled"); a("# if your userspace allows it. eg. see http://blog.zx2c4.com/749"); a("lxc.mount.entry = proc " + rootfs + "/proc proc nosuid,nodev,noexec 0 0"); a("# WARNING: sysfs is a known attack vector and should probably be disabled"); a("# if your userspace allows it. eg. see http://bit.ly/T9CkqJ"); a("lxc.mount.entry = sysfs " + rootfs + "/sys sysfs nosuid,nodev,noexec 0 0"); a("lxc.mount.entry = devpts " + rootfs + "/dev/pts devpts newinstance,ptmxmode=0666,nosuid,noexec 0 0"); // #lxc.mount.entry = varrun {{$ROOTFS}}/var/run tmpfs // mode=755,size=4096k,nosuid,nodev,noexec 0 0 // #lxc.mount.entry = varlock {{$ROOTFS}}/var/lock tmpfs // size=1024k,nosuid,nodev,noexec 0 0 // #lxc.mount.entry = shm {{$ROOTFS}}/dev/shm tmpfs // size=65536k,nosuid,nodev,noexec 0 0 a("lxc.console = " + join(configDir, "console.log")); for (Volume volume : volumes) { String entry = volume.hostPath + " " + join(rootfs, volume.instancePath) + " none bind,rw 0 0"; a("lxc.mount.entry", entry); } a(); a("# drop linux capabilities (apply mainly to the user root in the container)"); a("# (Note: 'lxc.cap.keep' is coming soon and should replace this under the"); a("# security principle 'deny all unless explicitly permitted', see"); a("# http://sourceforge.net/mailarchive/message.php?msg_id=31054627 )"); a("lxc.cap.drop = audit_control audit_write mac_admin mac_override mknod setfcap setpcap sys_admin sys_boot sys_module sys_nice sys_pacct sys_rawio sys_resource sys_time sys_tty_config"); a(); a("# limits"); if (memoryLimitMB != null) { a("lxc.cgroup.memory.limit_in_bytes", memoryLimitMB + "M"); a("lxc.cgroup.memory.soft_limit_in_bytes", memoryLimitMB + "M"); } if (swapMemoryLimitMB != null) { a("lxc.cgroup.memory.memsw.limit_in_bytes", swapMemoryLimitMB + "M"); } if (cpuShares != null) { a("lxc.cgroup.cpu.shares", cpuShares + ""); } a(); return sb.toString(); } private static String join(String base, String extension) { StringBuilder s = new StringBuilder(); s.append(base); if (!base.endsWith("/")) { s.append("/"); } if (extension.startsWith("/")) { s.append(extension.substring(1)); } else { s.append(extension); } return s.toString(); } }