Cómo agregar o eliminar capacidades utilizando comandos de Docker

DockerDockerBeginner
Practicar Ahora

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introduction

Docker is a powerful tool for containerizing applications, and understanding how to manage container capabilities is crucial for optimizing security and performance. This tutorial will guide you through the process of adding and removing capabilities using Docker commands, helping you tailor your container environment to specific needs.

In this lab, you will learn what Docker capabilities are, how they enhance container security, and how to effectively manage them. By the end of this tutorial, you will be able to confidently add and remove capabilities from your Docker containers.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL docker(("Docker")) -.-> docker/ContainerOperationsGroup(["Container Operations"]) docker/ContainerOperationsGroup -.-> docker/run("Run a Container") docker/ContainerOperationsGroup -.-> docker/rm("Remove Container") docker/ContainerOperationsGroup -.-> docker/exec("Execute Command in Container") docker/ContainerOperationsGroup -.-> docker/inspect("Inspect Container") subgraph Lab Skills docker/run -.-> lab-411502{{"Cómo agregar o eliminar capacidades utilizando comandos de Docker"}} docker/rm -.-> lab-411502{{"Cómo agregar o eliminar capacidades utilizando comandos de Docker"}} docker/exec -.-> lab-411502{{"Cómo agregar o eliminar capacidades utilizando comandos de Docker"}} docker/inspect -.-> lab-411502{{"Cómo agregar o eliminar capacidades utilizando comandos de Docker"}} end

Understanding Docker Capabilities

Docker capabilities are a security feature that allows you to grant or revoke specific Linux kernel permissions to a container. Before we start experimenting with capabilities, let us understand what they are and why they matter.

What are Docker Capabilities?

Capabilities in Docker are based on the Linux kernel's capability system, which divides the privileges traditionally associated with the root user into distinct units. This approach is more secure than the traditional all-or-nothing root privilege model.

By default, Docker containers run with a limited set of capabilities, providing a reasonable balance between functionality and security. However, you may need to add or remove capabilities based on your application requirements.

Let us examine the default capabilities of a Docker container. Run the following command to start a container and view its capabilities:

docker run --rm -it ubuntu:22.04 capsh --print

You should see output similar to this:

Current: cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap=ep
Bounding set =cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap
Ambient set =
Current IAB: cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap=ep
Securebits: 00/0x0/1'b0
 secure-noroot: no (unlocked)
 secure-no-suid-fixup: no (unlocked)
 secure-keep-caps: no (unlocked)
 secure-no-ambient-raise: no (unlocked)
uid=0(root) gid=0(root) groups=0(root)

This output shows the capabilities granted to the container by default. These capabilities control what the container can do within the system.

Why Capabilities Matter

Properly managing Docker capabilities is crucial for:

  1. Enhanced Security: By limiting capabilities, you reduce the potential damage if a container is compromised.
  2. Fine-Grained Control: You can allow specific privileged operations without granting full root access.
  3. Principle of Least Privilege: Containers should only have the capabilities they need to function properly.

Next, let us explore how to add capabilities to Docker containers.

Adding Capabilities to Docker Containers

In this step, we will learn how to add specific capabilities to a Docker container using the --cap-add flag. This is useful when your application requires certain privileges that are not included in the default set.

Basic Syntax for Adding Capabilities

The basic syntax for adding a capability to a Docker container is:

docker run --cap-add=<CAPABILITY> <IMAGE> <COMMAND>

Let us try adding the NET_ADMIN capability, which allows the container to perform various network-related operations:

docker run --rm -it --cap-add=NET_ADMIN ubuntu:22.04 capsh --print

The output will show that the NET_ADMIN capability has been added to the container:

Current: cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap,cap_net_admin=ep

Note the addition of cap_net_admin at the end of the capabilities list.

Adding Multiple Capabilities

Often, you may need to add multiple capabilities to a container. You can do this by specifying the --cap-add flag multiple times:

docker run --rm -it --cap-add=NET_ADMIN --cap-add=SYS_TIME ubuntu:22.04 capsh --print

This command adds both the NET_ADMIN and SYS_TIME capabilities to the container. The SYS_TIME capability allows the container to modify the system clock.

Practical Example: Modifying Network Interfaces

To demonstrate a practical use of capabilities, let us create a container with the NET_ADMIN capability and attempt to modify network interface settings:

docker run --rm -it --cap-add=NET_ADMIN ubuntu:22.04 /bin/bash

You are now inside the container with a bash shell. Let us install the iproute2 package to work with network interfaces:

apt-get update && apt-get install -y iproute2

Now, try to create a dummy network interface:

ip link add dummy0 type dummy
ip link show dummy0

You should see output showing the newly created dummy network interface:

6: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 2a:d5:cd:70:91:f4 brd ff:ff:ff:ff:ff:ff

This operation would fail without the NET_ADMIN capability. You can exit the container by typing exit.

Viewing Container Capabilities

To inspect the capabilities of a running container, you can use the docker inspect command. First, let us start a container with added capabilities in detached mode:

docker run -d --name cap-test --cap-add=NET_ADMIN ubuntu:22.04 sleep 3600

Now, inspect the container to view its capabilities:

docker inspect cap-test | grep -A 20 CapAdd

The output will show that the NET_ADMIN capability has been added:

            "CapAdd": [
                "NET_ADMIN"
            ],

Remember to clean up after this step:

docker stop cap-test
docker rm cap-test

Understanding how to add capabilities to Docker containers gives you more control over what your containers can do, while still maintaining security.

Removing Capabilities from Docker Containers

In this step, we will learn how to remove capabilities from Docker containers using the --cap-drop flag. This is an important security practice that follows the principle of least privilege - containers should only have the capabilities they absolutely need.

Basic Syntax for Removing Capabilities

The basic syntax for removing a capability from a Docker container is:

docker run --cap-drop=<CAPABILITY> <IMAGE> <COMMAND>

Let us try removing the CHOWN capability, which allows changing file ownership:

docker run --rm -it --cap-drop=CHOWN ubuntu:22.04 capsh --print

In the output, you will notice that cap_chown is no longer listed among the capabilities:

Current: cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap=ep

Removing Multiple Capabilities

You can remove multiple capabilities by specifying the --cap-drop flag multiple times:

docker run --rm -it --cap-drop=CHOWN --cap-drop=NET_RAW ubuntu:22.04 capsh --print

This command removes both the CHOWN and NET_RAW capabilities from the container.

Practical Example: Testing Capability Restrictions

Let us create a container with the CHOWN capability dropped and attempt to change file ownership:

docker run --rm -it --cap-drop=CHOWN ubuntu:22.04 /bin/bash

Inside the container, let us create a test file and try to change its ownership:

touch test_file
ls -l test_file
chown nobody:nogroup test_file

You should see an error message indicating that the operation is not permitted:

chown: changing ownership of 'test_file': Operation not permitted

This demonstrates that removing the CHOWN capability prevents the container from changing file ownership, even though the container is running as root. Type exit to leave the container.

Using Both --cap-add and --cap-drop

You can use both --cap-add and --cap-drop flags in the same command to precisely control the capabilities of your container:

docker run --rm -it --cap-add=NET_ADMIN --cap-drop=CHOWN ubuntu:22.04 capsh --print

This command adds the NET_ADMIN capability while removing the CHOWN capability.

Dropping All Capabilities and Adding Specific Ones

For maximum security, you can drop all capabilities and then add only the specific ones your application needs:

docker run --rm -it --cap-drop=ALL --cap-add=NET_BIND_SERVICE ubuntu:22.04 capsh --print

This command creates a container with only the NET_BIND_SERVICE capability, which allows binding to privileged ports (below 1024).

Testing a Container with All Capabilities Dropped

Let us create a container with all capabilities dropped and observe the restrictions:

docker run -d --name no-caps --cap-drop=ALL ubuntu:22.04 sleep 3600

Now, let us attach to the container and try to perform various operations:

docker exec -it no-caps /bin/bash

Inside the container, try to ping an external host:

apt-get update && apt-get install -y iputils-ping
ping -c 1 google.com

You will likely see an error because the container does not have the necessary capabilities to create raw network sockets required for ping.

Exit the container by typing exit, and then clean up:

docker stop no-caps
docker rm no-caps

By understanding how to remove capabilities from Docker containers, you can significantly enhance the security of your containerized applications by strictly limiting what each container can do.

Combining Capabilities Management with Security Best Practices

In this final step, we will explore how to combine Docker capabilities management with other security best practices to create secure, least-privilege containers.

Creating a Container with Custom Capabilities Profile

Let us create a more complex example that combines capability management with other security features:

docker run -d --name secure-container \
  --cap-drop=ALL \
  --cap-add=NET_BIND_SERVICE \
  --read-only \
  --tmpfs /tmp \
  ubuntu:22.04 sleep 3600

This command:

  • Drops all capabilities
  • Adds only the NET_BIND_SERVICE capability
  • Makes the container filesystem read-only
  • Creates a temporary filesystem at /tmp for write operations

Let us inspect this container to see its configuration:

docker inspect secure-container | grep -A 5 CapAdd
docker inspect secure-container | grep -A 5 CapDrop
docker inspect secure-container | grep ReadonlyRootfs

You should see output confirming these security settings:

            "CapAdd": [
                "NET_BIND_SERVICE"
            ],
            "CapDrop": [
                "ALL"
            ],
"ReadonlyRootfs": true,

Testing the Restrictions

Let us connect to our secure container and test the restrictions:

docker exec -it secure-container /bin/bash

In the container, try to modify a system file:

echo "test" > /etc/test

You should see an error because the filesystem is read-only:

bash: /etc/test: Read-only file system

Now, try to write to the /tmp directory:

echo "test" > /tmp/test
cat /tmp/test

This should work because we mounted a writable tmpfs at /tmp:

test

Exit the container by typing exit.

Using Capabilities with Non-Root Users

For additional security, you can run containers as non-root users while still managing capabilities. First, let us create a new container that combines a non-root user with specific capabilities:

docker run -d --name nonroot-container \
  --cap-drop=ALL \
  --cap-add=NET_BIND_SERVICE \
  --user 1000:1000 \
  ubuntu:22.04 sleep 3600

Note that even though we added the NET_BIND_SERVICE capability and are running as a non-root user, Linux capabilities are only applied to processes running as root by default. To allow non-root users to use capabilities, additional configurations like setuid binaries or ambient capabilities would be needed.

Capabilities in docker-compose

If you use docker-compose for managing multiple containers, you can specify capabilities in your docker-compose.yml file:

version: "3"
services:
  webapp:
    image: ubuntu:22.04
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
    read_only: true
    tmpfs:
      - /tmp

This provides a consistent way to manage capabilities across your container deployments.

Cleaning Up

Let us clean up the containers we created:

docker stop secure-container nonroot-container
docker rm secure-container nonroot-container

Best Practices Summary

Here are some best practices for managing Docker capabilities:

  1. Drop all capabilities and add only what you need
  2. Combine capability management with other security features:
    • Read-only filesystem
    • Non-root users
    • Seccomp profiles
    • AppArmor or SELinux
  3. Regularly audit container capabilities
  4. Keep Docker and container images updated
  5. Use container vulnerability scanning tools

By following these practices, you can significantly improve the security of your Docker containers.

Summary

In this lab, you have learned how to effectively manage Docker container capabilities to enhance security and functionality. Here is a recap of what you accomplished:

  1. You understood what Docker capabilities are and why they are important for container security.
  2. You learned how to add capabilities to containers using the --cap-add flag, enabling containers to perform specific privileged operations.
  3. You practiced removing capabilities with the --cap-drop flag, implementing the principle of least privilege.
  4. You explored best practices for combining capability management with other security features to create secure container environments.

By applying these techniques, you can create containers that have precisely the permissions they need, no more and no less. This approach significantly reduces the potential attack surface of your containerized applications while ensuring they have the necessary functionality to operate correctly.

Continue exploring Docker security features and remember to regularly audit and update your container configurations to maintain a strong security posture in your containerized environments.