{"id":520,"date":"2025-04-10T03:59:37","date_gmt":"2025-04-10T03:59:37","guid":{"rendered":"https:\/\/blog.ngocha.biz\/?p=520"},"modified":"2025-04-10T03:59:37","modified_gmt":"2025-04-10T03:59:37","slug":"linux-capabilities","status":"publish","type":"post","link":"https:\/\/blog.ngocha.biz\/?p=520","title":{"rendered":"Linux Capabilities In Containers &#038; Kubernetes"},"content":{"rendered":"<p>In this blog, we will look a little deeper into Linux Capabilities to understand how they relate to containers and Kubernetes using practical examples.<\/p>\n<p>By the end of the guide, you will understand<\/p>\n<ol>\n<li>What Are Linux Capabilities?<\/li>\n<li>Linux Capabilities in Containers<\/li>\n<li>Adding Linux Capabilities in Kubernetes pods<\/li>\n<li>Analyzing Capabilities using systemd<\/li>\n<\/ol>\n<p>In our&nbsp;container non-root blog, I mentioned the concepts of Linux Capabilities.<\/p>\n<p>It is an overlooked security feature that plays a key role in container security and Kubernetes configurations.<\/p>\n<p><!--kg-card-begin: html--><br \/>\n<iframe loading=\"lazy\" src=\"https:\/\/embeds.beehiiv.com\/9609b85d-3984-4e0b-9f0e-1a9c14da8c36\" data-test-id=\"beehiiv-embed\" width=\"100%\" height=\"320\" frameborder=\"0\" scrolling=\"no\" style=\"border-radius: 4px; border: 2px solid #e5e7eb; margin: 0; background-color: transparent;\"><\/iframe><br \/>\n<!--kg-card-end: html--><\/p>\n<h2 id=\"what-are-linux-capabilities\">What Are Linux Capabilities?<\/h2>\n<p>In traditional Linux, a process is either&nbsp;<strong>root<\/strong>&nbsp;(superuser) or&nbsp;<strong>non-root<\/strong>&nbsp;(restricted). A concept you all know.<\/p>\n<p>Linux Capabilities was introduced in kernel 2.2. Before that,<\/p>\n<ul>\n<li>Processes either had root privileges (<strong>Privileged processes (UID=0)<\/strong>: Full root access.)<\/li>\n<li>Regular user privileges (<strong>Non-privileged processes (UID\u22600)<\/strong>: Limited permissions.<\/li>\n<\/ul>\n<p>The problem with this approach was if a non-root user program needed to run one privileged operation, it had to run with full root access. For example, binding to a ports below 1024 that require root privileges.<\/p>\n<p>What if there is a way to give a non-root user privileged access to just that one operation?<\/p>\n<p>That is what Linux Capabilities solve.<\/p>\n<p>Linux capabilities solve this by segregating root privileges into separate units that can be given access individually.<\/p>\n<p>For example,<\/p>\n<ol>\n<li><strong>CAP_NET_BIND_SERVICE:<\/strong>&nbsp;To grant the permission to bind to privileged ports.<\/li>\n<li><strong>CAP_NET_ADMIN<\/strong>: Allows modifying network interfaces, routing tables, and other network configurations.<\/li>\n<li><strong>CAP_SYS_TIME<\/strong>: To modify the system clock.<\/li>\n<li><strong>CAP_DAC_OVERRIDE:<\/strong> Bypasses discretionary access control (DAC), allowing a process to ignore file permission checks.<\/li>\n<li><strong>CAP_CHOWN:<\/strong> Allows changing the ownership of files, bypassing normal user restrictions.<\/li>\n<li><strong>CAP_NET_RAW:<\/strong> Allows sending and receiving raw packets (e.g., crafting custom network packets). Used in tools like <code>ping<\/code> and <code>tcpdump<\/code>.<\/li>\n<\/ol>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/blog.techiescamp.com\/content\/images\/2025\/01\/image-98.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"683\" height=\"743\"><\/figure>\n<p>With this, a non-root user can be granted only&nbsp;<strong>CAP_NET_BIND_SERVICE<\/strong>&nbsp;to bind to a privileged port while blocking all the other root related access.<\/p>\n<p>Just run the following command to list all the supported capabilities in Linux.<\/p>\n<pre><code class=\"language-bash\">man capabilities<\/code><\/pre>\n<p>There are 50 different capabilities in today&#8217;s Linux kernel (I tested this on an Ubuntu server).<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/blog.techiescamp.com\/content\/images\/2025\/01\/image-99.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"960\" height=\"918\"><\/figure>\n<p>Now that we have an understanding of Linux capabilities, let&#8217;s understand how containers and Kubernetes use them.<\/p>\n<h2 id=\"linux-capabilities-containers\">Linux Capabilities &amp; Containers<\/h2>\n<p>By default, containers run as root (unless you run as non-root).<\/p>\n<p>But this doesn\u2019t mean they have full root privileges on the host.<\/p>\n<p>Docker and other container runtimes&nbsp;<strong>use Linux Capabilities to restrict container permissions<\/strong>&nbsp;for enhanced security. This make the container environment more secure, even though the user ID (UID 0) remains the same inside the container and on the host.<\/p>\n<p>Docker, for instance, drops many Capabilities by default and uses only the required Capabilities.<\/p>\n<p>Containerd code shows these&nbsp;default allowed capabilities.the <\/p>\n<p>CRIO has the following defaults.&nbsp;<a href=\"https:\/\/github.com\/cri-o\/cri-o\/blob\/main\/docs\/crio.conf.5.md??ref=devopscube.com\" rel=\"noreferrer\">Refer doc here.<\/a><\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/blog.techiescamp.com\/content\/images\/2025\/01\/image-100.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"960\" height=\"678\"><\/figure>\n<p>Let&#8217;s look at an example using Docker.<\/p>\n<p>Let&#8217;s try to create a BusyBox container to create a dummy network interface.<\/p>\n<pre><code class=\"language-bash\">$ docker run --rm -it \\\n    --name test_no_cap busybox sh\n\n\/ # ip link add dummy0 type dummy\nip: RTNETLINK answers: Operation not permitted<\/code><\/pre>\n<p>As you can see, the container lacks&nbsp;<code>CAP_NET_ADMIN<\/code>, so it cannot modify network interfaces.<\/p>\n<p>The  <code>--cap-add<\/code> is used to grant additional Linux capabilities to a container.<\/p>\n<p>Now, run the same container but with the required capability using&nbsp;<code>--cap-add=NET_ADMIN<\/code>&nbsp;flag.<\/p>\n<pre><code class=\"language-bash\">$ docker run --rm -it --cap-add=NET_ADMIN \\\n    --name test_with_cap busybox sh\n\n\/ # ip link add dummy0 type dummy\n\/ # ip link show dummy0\n2: dummy0: &lt;BROADCAST,NOARP&gt; mtu 1500 qdisc noop qlen 1000\n    link\/ether 0a:0c:31:af:1e:0b brd ff:ff:ff:ff:ff:ff<\/code><\/pre>\n<p>Since the container has&nbsp;<code>CAP_NET_ADMIN<\/code>, it&nbsp;<strong>can<\/strong>&nbsp;create network interfaces.<\/p>\n<h2 id=\"kubernetes-and-linux-capabilities\">Kubernetes and Linux Capabilities<\/h2>\n<p>When it comes to kubernetes, You can&nbsp;<strong>add<\/strong>&nbsp;or&nbsp;<strong>drop<\/strong>&nbsp;Linux capabilities in your&nbsp;<code>SecurityContext<\/code>&nbsp;to reduce attack surfaces.<\/p>\n<p>Let&#8217;s understand this with an example.<\/p>\n<p>When you run a pod with a&nbsp;<code>BusyBox<\/code>&nbsp;image, by default, you will be able to use&nbsp;<code>ping<\/code>.<\/p>\n<p>For example:<\/p>\n<pre><code class=\"language-bash\">$ kubectl run ping-pod \\\n      --image=busybox --restart=Never \\\n      -it -- sh -c \"ping 8.8.8.8\"\n\n64 bytes from 8.8.8.8: seq=1 ttl=61 time=13.500 ms\n64 bytes from 8.8.8.8: seq=2 ttl=61 time=16.598 ms\n64 bytes from 8.8.8.8: seq=3 ttl=61 time=16.262 ms<\/code><\/pre>\n<p>Now, let&#8217;s say you don&#8217;t want to allow the BusyBox pod to perform&nbsp;<code>ping<\/code>.<\/p>\n<p>In this case, we&nbsp;<strong>drop<\/strong>&nbsp;the&nbsp;<code>NET_RAW<\/code>&nbsp;capability using the&nbsp;<strong>Security Context<\/strong>.<\/p>\n<blockquote><p>The NET_RAW capability allows a container to create and use raw network sockets. This is required for commands like ping and some network debugging tools.<\/p>\n<p>By dropping NET_RAW, we prevent the container from sending raw packets<\/p><\/blockquote>\n<p>For example, <\/p>\n<pre><code class=\"language-YAML\">apiVersion: v1\nkind: Pod\nmetadata:\n  name: busybox-ping\nspec:\n  containers:\n  - name: busybox\n    image: busybox:latest\n    command: [\"sleep\", \"3600\"]\n    securityContext:\n      capabilities:\n        drop:\n          - NET_RAW<\/code><\/pre>\n<p>If you deploy this pod and try ping, you will get the following error.<\/p>\n<pre><code class=\"language-bash\">$ kubectl exec -it busybox-secure -- ping 8.8.8.8\n\nPING 8.8.8.8 (8.8.8.8): 56 data bytes\nping: permission denied (are you root?)\ncommand terminated with exit code 1<\/code><\/pre>\n<h2 id=\"analyze-capabilities-with-systemd\">Analyze Capabilities With Systemd<\/h2>\n<p>In Linux systems, the command <strong><code>systemd-analyze security<\/code><\/strong> is used to <strong>evaluate the security of systemd services<\/strong> by analyzing their sandboxing and security features.<\/p>\n<p>It inspects how a service is configured in terms of Capability restrictions (e.g., <code>CAP_NET_ADMIN<\/code>, <code>CAP_DAC_OVERRIDE<\/code>) and more.<\/p>\n<p>Here is an example output of <code>systemd-analyze security<\/code>command.<\/p>\n<figure class=\"kg-card kg-image-card kg-card-hascaption\"><img decoding=\"async\" src=\"https:\/\/blog.techiescamp.com\/content\/images\/2025\/02\/image-2.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"1280\" height=\"918\"><figcaption><span style=\"white-space: pre-wrap;\"> c<\/span><\/figcaption><\/figure>\n<p>You can further analyse a specific service using the unit name.<\/p>\n<p>For example,<\/p>\n<pre><code class=\"language-bash\">systemd-analyze security apache2.service<\/code><\/pre>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/blog.techiescamp.com\/content\/images\/2025\/02\/image-3.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"1454\" height=\"822\"><\/figure>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>Linux capabilities play an important role in enforcing the&nbsp;<strong>principle of least privilege<\/strong>&nbsp;by allowing fine-grained control over what processes can do.<\/p>\n<p>For&nbsp;<strong>DevOps engineers<\/strong>, being&nbsp;<strong>proactive<\/strong>&nbsp;about these best practices is important.<\/p>\n<p>Security should not be an afterthought.<\/p>\n<p>I\u2019ve seen teams rushing to fix clusters after a security audit when issues could have been prevented earlier.<\/p>\n<p>By taking&nbsp;<strong>small but smart security steps&nbsp;<\/strong>wherever necessary<strong>,&nbsp;<\/strong>you can avoid last-minute surprises and keep your infrastructure safe from the start.<\/p>\n<p>If you have any doubts about this blog, drop it on the comment!<\/p>\n<p>Want to Stay Ahead in DevOps &amp; Cloud? Join the Free Newsletter Below.<\/p>\n<hr>\n<p><strong>Ngu\u1ed3n:<\/strong> <a href=\"https:\/\/devopscube.com\/linux-capabilities\/\" target=\"_blank\" rel=\"noopener noreferrer\">Linux Capabilities In Containers &amp; Kubernetes \u2014 DevOpsCube<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Source: https:\/\/devopscube.com\/linux-capabilities\/<\/p>\n","protected":false},"author":1,"featured_media":521,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-520","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops"],"_links":{"self":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/520","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=520"}],"version-history":[{"count":0,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/520\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/media\/521"}],"wp:attachment":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=520"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=520"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=520"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}