confd: add limited support for container capabilities

This change adds limited support for container capabilities.  It allows
a more fine-grained control than priviliged mode does.

Fixes #365

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2024-04-03 16:08:37 +02:00
parent da56c95930
commit fad75575e4
4 changed files with 104 additions and 17 deletions
+12 -2
View File
@@ -103,8 +103,8 @@ create()
logging="--log-driver k8s-file --log-opt path=/run/containers/$name.fifo"
fi
args="$args --cgroup-parent=containers"
args="$args --restart=$restart --systemd=false --tz=local $privileged --replace --quiet"
args="$args --replace --quiet --cgroup-parent=containers $caps"
args="$args --restart=$restart --systemd=false --tz=local $privileged"
args="$args $ro $vol $mount $hostname $entrypoint $env $port $logging"
pidfn=/run/container:${name}.pid
@@ -226,6 +226,8 @@ options:
-a, --all Show all, of something
--dns NAMESERVER Set nameserver(s) when creating a container
--dns-search LIST Set host lookup search list when creating container
--cap-add CAP Add capability to unprivileged container
--cap-drop CAP Drop capability, for privileged containter
-c, --creds USR[:PWD] Credentials to pass to curl -u for remote ops
-d, --detach Detach a container started with 'run IMG [CMD]'
-e, --env FILE Environment variables when creating container
@@ -276,6 +278,14 @@ while [ "$1" != "" ]; do
-a | --all)
all="-a"
;;
--cap-add)
shift
caps="$caps --cap-add=$1"
;;
--cap-drop)
shift
caps="$caps --cap-drop=$1"
;;
-c | --creds)
shift
creds="-u $1"
+38 -8
View File
@@ -44,20 +44,24 @@ container networking in podman.
Caution
-------
A word of warning, containers can run on your system in privileged mode,
as `root`. This gives them full access to devices on your system. But
even when though unprivileged containers are fenced from the host with
Linux namespaces, and resource limited using Linux cgroups, which scope
container applications from seeing and accessing the complete system,
there is no guarantee that an application cannot ever break out of this
confinement.
A word of warning. Containers can run on your system in privileged
mode, as `root`, giving them full access to devices on your system.
Even though containers are fenced from the host with Linux namespaces,
resource limited using cgroups, and normally run with capped privileges,
a privileged container is relatively easy to break out of. A trivial
example is given in the [Advanced](#advanced) section of this document.
We recommend avoiding privileged containers, if possible (they do have
valid use-cases) and instead use [capabilities](#capabilities).
Remember:
- If the system is compromised, containers can be used to easily
install malicious software in your system and over the network
- Your system is as secure as anything you run in the container
- If you run containers, there is no security guarantee of any kind
- Running 3rd party container images on your system could open a
security hole/attack vector/attack surface
security hole/attack vector/surface
- An expert with knowledge how to build exploits will be able to
jailbreak/elevate to root even if best practices are followed
@@ -258,6 +262,31 @@ the upgrade command as
7ab4a07ee0c6039837419b7afda4da1527a70f0c60c0f0ac21cafee05ba24b52
Capabilities
-------------
An unprivileged container works for almost all use-cases, but there are
occasions where they are too restricted and users being looking for the
`privileged` flag. Capabilities offers a middle ground.
For example, a system container from which `ping` does not work:
admin@example:/config/container/system/> edit capabilities
admin@example:/config/container/system/capabilities/> set add net_raw
admin@example:/config/container/system/capabilities/> end
admin@infix-00-00-00:/config/container/system/> show
...
capabilities {
add net_raw;
}
...
Infix supports a subset of all [capabilities][6] that are relevant for
containers. Please note, that this is and advanced topic and will
require time and analysis of your container application to figure out
which capabilities you need.
Networking and Containers
-------------------------
@@ -645,4 +674,5 @@ control an Infix system this way, see [Scripting Infix](scriptiong.md).
[3]: https://github.com/opencontainers/image-spec/blob/main/image-layout.md
[4]: system.md#ssh-authorized-key
[5]: https://docs.docker.com/build/exporters/oci-docker/
[6]: https://man7.org/linux/man-pages/man7/capabilities.7.html
[podman]: https://podman.io
+15 -7
View File
@@ -23,7 +23,7 @@
#define LOGGER "logger -t container -p local1.notice"
static const struct srx_module_requirement reqs[] = {
{ .dir = YANG_PATH_, .name = MODULE, .rev = "2024-02-01" },
{ .dir = YANG_PATH_, .name = MODULE, .rev = "2024-03-27" },
{ NULL }
};
@@ -31,7 +31,7 @@ static int add(const char *name, struct lyd_node *cif)
{
const char *image = lydx_get_cattr(cif, "image");
const char *restart_policy, *string;
struct lyd_node *node, *network;
struct lyd_node *node, *nets, *caps;
FILE *fp, *ap;
fp = fopenf("w", "%s/%s.sh", INBOX_QUEUE, name);
@@ -61,6 +61,14 @@ static int add(const char *name, struct lyd_node *cif)
if (lydx_is_enabled(cif, "privileged"))
fprintf(fp, " --privileged");
caps = lydx_get_descendant(lyd_child(cif), "capabilities", NULL);
if (caps) {
LYX_LIST_FOR_EACH(lyd_child(caps), node, "add")
fprintf(fp, " --cap-add %s", lyd_get_value(node));
LYX_LIST_FOR_EACH(lyd_child(caps), node, "drop")
fprintf(fp, " --cap-drop %s", lyd_get_value(node));
}
LYX_LIST_FOR_EACH(lyd_child(cif), node, "volume")
fprintf(fp, " -v %s-%s:%s", name, lydx_get_cattr(node, "name"),
lydx_get_cattr(node, "target"));
@@ -126,12 +134,12 @@ static int add(const char *name, struct lyd_node *cif)
fprintf(fp, " -e /run/containers/args/%s.env", name);
}
network = lydx_get_descendant(lyd_child(cif), "network", NULL);
if (network) {
if (lydx_is_enabled(network, "host")) {
nets = lydx_get_descendant(lyd_child(cif), "network", NULL);
if (nets) {
if (lydx_is_enabled(nets, "host")) {
fprintf(fp, " --net host");
} else {
LYX_LIST_FOR_EACH(lyd_child(network), node, "interface") {
LYX_LIST_FOR_EACH(lyd_child(nets), node, "interface") {
struct lyd_node *opt;
const char *name;
int first = 1;
@@ -146,7 +154,7 @@ static int add(const char *name, struct lyd_node *cif)
}
}
LYX_LIST_FOR_EACH(lyd_child(network), node, "publish")
LYX_LIST_FOR_EACH(lyd_child(nets), node, "publish")
fprintf(fp, " -p %s", lyd_get_value(node));
}
}
@@ -22,6 +22,11 @@ module infix-containers {
prefix infix-if;
}
revision 2024-03-27 {
description "Add support for capabilities.";
reference "internal";
}
revision 2024-02-01 {
description "Initial revision";
reference "internal";
@@ -61,6 +66,26 @@ module infix-containers {
}
}
typedef capabilities {
type enumeration {
enum dac_override;
enum fsetid;
enum net_admin;
enum net_bind_service;
enum net_raw;
enum setgid;
enum setuid;
enum setpcap;
enum syslog;
enum sys_admin;
enum sys_chroot;
enum sys_module;
enum sys_ptrace;
enum sys_rawio;
enum sys_time;
}
}
/*
* Data Nodes
*/
@@ -217,6 +242,20 @@ module infix-containers {
type boolean;
}
container capabilities {
description "Capabilities to add for unprivileged and drop for privileged containers.";
leaf-list add {
type capabilities;
description "List of capabilities to add to (an unprivileged) container.";
}
leaf-list drop {
type capabilities;
description "List of capabilities to drop from (a privileged) container.";
}
}
list mount {
description "Files, content, and directories to mount inside container.";
key name;