mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-06-09 19:13:26 +03:00
lxc: added option for unprivileged containers.
Added extra option to enable unprivileged containers. This includes a patch to remove the hard-coded path to `lxc-user-nic` and a new security wrapper to set SUID to `lxc-user-nic`.
This commit is contained in:
parent
056b6a1f40
commit
389de87aed
6 changed files with 205 additions and 3 deletions
|
@ -23,6 +23,8 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
unprivilegedContainers = lib.mkEnableOption "support for unprivileged users to launch containers";
|
||||||
|
|
||||||
systemConfig =
|
systemConfig =
|
||||||
lib.mkOption {
|
lib.mkOption {
|
||||||
type = lib.types.lines;
|
type = lib.types.lines;
|
||||||
|
@ -53,6 +55,15 @@ in
|
||||||
administration access in LXC. See {manpage}`lxc-usernet(5)`.
|
administration access in LXC. See {manpage}`lxc-usernet(5)`.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bridgeConfig =
|
||||||
|
lib.mkOption {
|
||||||
|
type = lib.types.lines;
|
||||||
|
default = "";
|
||||||
|
description = ''
|
||||||
|
This is the config file for override lxc-net bridge default settings.
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
###### implementation
|
###### implementation
|
||||||
|
@ -62,6 +73,8 @@ in
|
||||||
environment.etc."lxc/lxc.conf".text = cfg.systemConfig;
|
environment.etc."lxc/lxc.conf".text = cfg.systemConfig;
|
||||||
environment.etc."lxc/lxc-usernet".text = cfg.usernetConfig;
|
environment.etc."lxc/lxc-usernet".text = cfg.usernetConfig;
|
||||||
environment.etc."lxc/default.conf".text = cfg.defaultConfig;
|
environment.etc."lxc/default.conf".text = cfg.defaultConfig;
|
||||||
|
environment.etc."lxc/lxc-net".text = cfg.bridgeConfig;
|
||||||
|
environment.pathsToLink = [ "/share/lxc" ];
|
||||||
systemd.tmpfiles.rules = [ "d /var/lib/lxc/rootfs 0755 root root -" ];
|
systemd.tmpfiles.rules = [ "d /var/lib/lxc/rootfs 0755 root root -" ];
|
||||||
|
|
||||||
security.apparmor.packages = [ cfg.package ];
|
security.apparmor.packages = [ cfg.package ];
|
||||||
|
@ -73,5 +86,30 @@ in
|
||||||
include ${cfg.package}/etc/apparmor.d/lxc-containers
|
include ${cfg.package}/etc/apparmor.d/lxc-containers
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# We don't need the `lxc-user` group, unless the unprivileged containers are enabled.
|
||||||
|
users.groups = lib.mkIf cfg.unprivilegedContainers { lxc-user = {}; };
|
||||||
|
|
||||||
|
# `lxc-user-nic` needs suid to attach to bridge for unpriv containers.
|
||||||
|
security.wrappers = lib.mkIf cfg.unprivilegedContainers {
|
||||||
|
lxcUserNet = {
|
||||||
|
source = "${pkgs.lxc}/libexec/lxc/lxc-user-nic";
|
||||||
|
setuid = true;
|
||||||
|
owner = "root";
|
||||||
|
group = "lxc-user";
|
||||||
|
program = "lxc-user-nic";
|
||||||
|
permissions = "u+rx,g+x,o-rx";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Add lxc-net service if unpriv mode is enabled.
|
||||||
|
systemd.packages = lib.mkIf cfg.unprivilegedContainers [ pkgs.lxc ];
|
||||||
|
systemd.services = lib.mkIf cfg.unprivilegedContainers {
|
||||||
|
lxc-net = {
|
||||||
|
enable = true;
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
path = [ pkgs.iproute2 pkgs.iptables pkgs.getent pkgs.dnsmasq ];
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -538,6 +538,7 @@ in {
|
||||||
loki = handleTest ./loki.nix {};
|
loki = handleTest ./loki.nix {};
|
||||||
luks = handleTest ./luks.nix {};
|
luks = handleTest ./luks.nix {};
|
||||||
lvm2 = handleTest ./lvm2 {};
|
lvm2 = handleTest ./lvm2 {};
|
||||||
|
lxc = handleTest ./lxc {};
|
||||||
lxd = pkgs.recurseIntoAttrs (handleTest ./lxd { inherit handleTestOn; });
|
lxd = pkgs.recurseIntoAttrs (handleTest ./lxd { inherit handleTestOn; });
|
||||||
lxd-image-server = handleTest ./lxd-image-server.nix {};
|
lxd-image-server = handleTest ./lxd-image-server.nix {};
|
||||||
#logstash = handleTest ./logstash.nix {};
|
#logstash = handleTest ./logstash.nix {};
|
||||||
|
|
|
@ -16,8 +16,12 @@ import ../make-test-python.nix (
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
container-image-metadata = "${releases.incusContainerMeta.${pkgs.stdenv.hostPlatform.system}}/tarball/nixos-system-${pkgs.stdenv.hostPlatform.system}.tar.xz";
|
container-image-metadata = "${
|
||||||
container-image-rootfs = "${releases.incusContainerImage.${pkgs.stdenv.hostPlatform.system}}/nixos-lxc-image-${pkgs.stdenv.hostPlatform.system}.squashfs";
|
releases.incusContainerMeta.${pkgs.stdenv.hostPlatform.system}
|
||||||
|
}/tarball/nixos-system-${pkgs.stdenv.hostPlatform.system}.tar.xz";
|
||||||
|
container-image-rootfs = "${
|
||||||
|
releases.incusContainerImage.${pkgs.stdenv.hostPlatform.system}
|
||||||
|
}/nixos-lxc-image-${pkgs.stdenv.hostPlatform.system}.squashfs";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
name = "incusd-options";
|
name = "incusd-options";
|
||||||
|
|
124
nixos/tests/lxc/default.nix
Normal file
124
nixos/tests/lxc/default.nix
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
import ../make-test-python.nix (
|
||||||
|
{ pkgs, lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
releases = import ../../release.nix {
|
||||||
|
configuration = {
|
||||||
|
# Building documentation makes the test unnecessarily take a longer time:
|
||||||
|
documentation.enable = lib.mkForce false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
lxc-image-metadata = releases.lxdContainerMeta.${pkgs.stdenv.hostPlatform.system};
|
||||||
|
lxc-image-rootfs = releases.lxdContainerImage.${pkgs.stdenv.hostPlatform.system};
|
||||||
|
|
||||||
|
in
|
||||||
|
{
|
||||||
|
name = "lxc-container-unprivileged";
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
maintainers = lib.teams.lxc.members;
|
||||||
|
};
|
||||||
|
|
||||||
|
nodes.machine =
|
||||||
|
{ lib, pkgs, ... }:
|
||||||
|
{
|
||||||
|
virtualisation = {
|
||||||
|
diskSize = 6144;
|
||||||
|
cores = 2;
|
||||||
|
memorySize = 512;
|
||||||
|
writableStore = true;
|
||||||
|
|
||||||
|
lxc = {
|
||||||
|
enable = true;
|
||||||
|
unprivilegedContainers = true;
|
||||||
|
systemConfig = ''
|
||||||
|
lxc.lxcpath = /tmp/lxc
|
||||||
|
'';
|
||||||
|
defaultConfig = ''
|
||||||
|
lxc.net.0.type = veth
|
||||||
|
lxc.net.0.link = lxcbr0
|
||||||
|
lxc.net.0.flags = up
|
||||||
|
lxc.net.0.hwaddr = 00:16:3e:xx:xx:xx
|
||||||
|
lxc.idmap = u 0 100000 65536
|
||||||
|
lxc.idmap = g 0 100000 65536
|
||||||
|
'';
|
||||||
|
# Permit user alice to connect to bridge
|
||||||
|
usernetConfig = ''
|
||||||
|
@lxc-user veth lxcbr0 10
|
||||||
|
'';
|
||||||
|
bridgeConfig = ''
|
||||||
|
LXC_IPV6_ADDR=""
|
||||||
|
LXC_IPV6_MASK=""
|
||||||
|
LXC_IPV6_NETWORK=""
|
||||||
|
LXC_IPV6_NAT="false"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Needed for lxc
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
pkgs.wget
|
||||||
|
pkgs.dnsmasq
|
||||||
|
];
|
||||||
|
|
||||||
|
# Create user for test
|
||||||
|
users.users.alice = {
|
||||||
|
isNormalUser = true;
|
||||||
|
password = "test";
|
||||||
|
description = "Lxc unprivileged user with access to lxcbr0";
|
||||||
|
extraGroups = [ "lxc-user" ];
|
||||||
|
subGidRanges = [
|
||||||
|
{
|
||||||
|
startGid = 100000;
|
||||||
|
count = 65536;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
subUidRanges = [
|
||||||
|
{
|
||||||
|
startUid = 100000;
|
||||||
|
count = 65536;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
users.users.bob = {
|
||||||
|
isNormalUser = true;
|
||||||
|
password = "test";
|
||||||
|
description = "Lxc unprivileged user without access to lxcbr0";
|
||||||
|
subGidRanges = [
|
||||||
|
{
|
||||||
|
startGid = 100000;
|
||||||
|
count = 65536;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
subUidRanges = [
|
||||||
|
{
|
||||||
|
startUid = 100000;
|
||||||
|
count = 65536;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
machine.wait_for_unit("lxc-net.service")
|
||||||
|
|
||||||
|
# Copy config files for alice
|
||||||
|
machine.execute("su -- alice -c 'mkdir -p ~/.config/lxc'")
|
||||||
|
machine.execute("su -- alice -c 'cp /etc/lxc/default.conf ~/.config/lxc/'")
|
||||||
|
machine.execute("su -- alice -c 'cp /etc/lxc/lxc.conf ~/.config/lxc/'")
|
||||||
|
|
||||||
|
machine.succeed("su -- alice -c 'lxc-create -t local -n test -- --metadata ${lxc-image-metadata}/*/*.tar.xz --fstree ${lxc-image-rootfs}/*/*.tar.xz'")
|
||||||
|
machine.succeed("su -- alice -c 'lxc-start test'")
|
||||||
|
machine.succeed("su -- alice -c 'lxc-stop test'")
|
||||||
|
|
||||||
|
# Copy config files for bob
|
||||||
|
machine.execute("su -- bob -c 'mkdir -p ~/.config/lxc'")
|
||||||
|
machine.execute("su -- bob -c 'cp /etc/lxc/default.conf ~/.config/lxc/'")
|
||||||
|
machine.execute("su -- bob -c 'cp /etc/lxc/lxc.conf ~/.config/lxc/'")
|
||||||
|
|
||||||
|
machine.fail("su -- bob -c 'lxc-start test'")
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
)
|
|
@ -48,16 +48,37 @@ stdenv.mkDerivation (finalAttrs: {
|
||||||
patches = [
|
patches = [
|
||||||
# fix docbook2man version detection
|
# fix docbook2man version detection
|
||||||
./docbook-hack.patch
|
./docbook-hack.patch
|
||||||
|
|
||||||
|
# Fix hardcoded path of lxc-user-nic
|
||||||
|
# This is needed to use unprivileged containers
|
||||||
|
./user-nic.diff
|
||||||
];
|
];
|
||||||
|
|
||||||
mesonFlags = [
|
mesonFlags = [
|
||||||
"-Dinstall-init-files=false"
|
"-Dinstall-init-files=true"
|
||||||
"-Dinstall-state-dirs=false"
|
"-Dinstall-state-dirs=false"
|
||||||
"-Dspecfile=false"
|
"-Dspecfile=false"
|
||||||
"-Dtools-multicall=true"
|
"-Dtools-multicall=true"
|
||||||
"-Dtools=false"
|
"-Dtools=false"
|
||||||
|
"-Dusernet-config-path=/etc/lxc/lxc-usernet"
|
||||||
|
"-Ddistrosysconfdir=${placeholder "out"}/etc/lxc"
|
||||||
|
"-Dsystemd-unitdir=${placeholder "out"}/lib/systemd/system"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
# /run/current-system/sw/share
|
||||||
|
postInstall = ''
|
||||||
|
substituteInPlace $out/etc/lxc/lxc --replace-fail "$out/etc/lxc" "/etc/lxc"
|
||||||
|
substituteInPlace $out/libexec/lxc/lxc-net --replace-fail "$out/etc/lxc" "/etc/lxc"
|
||||||
|
|
||||||
|
substituteInPlace $out/share/lxc/templates/lxc-download --replace-fail "$out/share" "/run/current-system/sw/share"
|
||||||
|
substituteInPlace $out/share/lxc/templates/lxc-local --replace-fail "$out/share" "/run/current-system/sw/share"
|
||||||
|
substituteInPlace $out/share/lxc/templates/lxc-oci --replace-fail "$out/share" "/run/current-system/sw/share"
|
||||||
|
|
||||||
|
substituteInPlace $out/share/lxc/config/common.conf --replace-fail "$out/share" "/run/current-system/sw/share"
|
||||||
|
substituteInPlace $out/share/lxc/config/userns.conf --replace-fail "$out/share" "/run/current-system/sw/share"
|
||||||
|
substituteInPlace $out/share/lxc/config/oci.common.conf --replace-fail "$out/share" "/run/current-system/sw/share"
|
||||||
|
'';
|
||||||
|
|
||||||
enableParallelBuilding = true;
|
enableParallelBuilding = true;
|
||||||
|
|
||||||
doCheck = true;
|
doCheck = true;
|
||||||
|
@ -66,6 +87,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||||
tests = {
|
tests = {
|
||||||
incus-legacy-init = nixosTests.incus.container-legacy-init;
|
incus-legacy-init = nixosTests.incus.container-legacy-init;
|
||||||
incus-systemd-init = nixosTests.incus.container-systemd-init;
|
incus-systemd-init = nixosTests.incus.container-systemd-init;
|
||||||
|
lxc = nixosTests.lxc;
|
||||||
lxd = nixosTests.lxd.container;
|
lxd = nixosTests.lxd.container;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
13
pkgs/by-name/lx/lxc/user-nic.diff
Normal file
13
pkgs/by-name/lx/lxc/user-nic.diff
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
diff --git a/src/lxc/network.c b/src/lxc/network.c
|
||||||
|
index 0a99d32..850e975 100644
|
||||||
|
--- a/src/lxc/network.c
|
||||||
|
+++ b/src/lxc/network.c
|
||||||
|
@@ -2940,7 +2940,7 @@ int lxc_find_gateway_addresses(struct lxc_handler *handler)
|
||||||
|
|
||||||
|
#ifdef IN_LIBLXC
|
||||||
|
|
||||||
|
-#define LXC_USERNIC_PATH LIBEXECDIR "/lxc/lxc-user-nic"
|
||||||
|
+#define LXC_USERNIC_PATH "/run/wrappers/bin/lxc-user-nic"
|
||||||
|
static int lxc_create_network_unpriv_exec(const char *lxcpath,
|
||||||
|
const char *lxcname,
|
||||||
|
struct lxc_netdev *netdev, pid_t pid,
|
Loading…
Add table
Add a link
Reference in a new issue