# How to Manage Linux Capabilities in Apple Container: `--cap-add` and `--cap-drop` Explained

> Learn to manage Linux capabilities in Apple Container using --cap-add and --cap-drop. Grant or remove specific capabilities easily with this guide.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: how-to-guide
- Published: 2026-06-20

---

**Use `--cap-add` to grant specific Linux capabilities and `--cap-drop` to remove them from the default set, with both flags supporting case-insensitive names, optional `CAP_` prefixes, and the special `ALL` token to toggle the complete capability set.**

The `apple/container` repository provides a lightweight container runtime that executes workloads inside virtual machines with a reduced Linux capability set for security hardening. Understanding how to manage Linux capabilities using `--cap-add` and `--cap-drop` commands allows you to implement precise least-privilege access controls while ensuring your applications have the specific kernel permissions they require.

## Understanding the Default Capability Set

By default, containers run with a restricted subset of Linux capabilities rather than the full root privilege set. The default configuration includes capabilities such as **CAP_NET_RAW** and **CAP_SETUID**, but excludes many administrative privileges. You can view the complete default list in the project documentation at [`docs/how-to.md`](https://github.com/apple/container/blob/main/docs/how-to.md) (lines 70-76).

This reduced set ensures that containers operate with minimal privileges, following the principle of least privilege. When your workload requires additional kernel permissions—such as network administration or process ownership changes—you must explicitly grant those capabilities using the command-line interface.

## Command-Line Syntax and Normalization

The container runtime exposes two primary flags for capability management, defined in [`Sources/Services/ContainerAPIService/Client/Flags.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Client/Flags.swift) (lines 31-41):

- **`--cap-add <cap>`**: Adds a capability to the container's effective set
- **`--cap-drop <cap>`**: Removes a capability from the default set

Both flags accept capability names in a flexible format. The parser in [`Sources/Services/ContainerAPIService/Client/Parser.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Client/Parser.swift) (lines 1009-1024) automatically normalizes input by converting strings to uppercase and prepending `CAP_` if missing. For example, `net_admin`, `NET_ADMIN`, and `CAP_NET_ADMIN` are all valid representations of the same capability.

The parser validates each capability against the `CapabilityName` enum (lines 1019-1022 in [`Parser.swift`](https://github.com/apple/container/blob/main/Parser.swift)). If you provide an invalid capability name, the command aborts immediately with an "invalid argument" error.

## Processing Order and the ALL Token

Capability modifications follow a specific processing sequence that affects the final permission set. According to the documentation in [`docs/how-to.md`](https://github.com/apple/container/blob/main/docs/how-to.md) (lines 98-100), the runtime processes all `--cap-drop` entries first, then applies all `--cap-add` entries. This ordering means that **adds override drops** when both flags target the same capability or use the `ALL` token.

The special token `ALL` represents the complete capability set:

- **`--cap-add ALL`**: Grants every available Linux capability
- **`--cap-drop ALL`**: Removes all capabilities, starting from an empty set

Because drops are processed before adds, the combination `--cap-drop ALL --cap-add ALL` results in a container with full capabilities, not an empty set.

## Practical Usage Examples

### Granting Additional Capabilities

Add specific capabilities when your application requires elevated privileges beyond the defaults:

```bash

# Add network administration capability

container run --cap-add NET_ADMIN alpine ip link set lo down

# Add multiple capabilities for user/group management

container run --cap-add SETUID --cap-add SETGID alpine id

```

### Removing Default Capabilities

Drop specific capabilities to further restrict container permissions:

```bash

# Remove the chown capability to prevent ownership changes

container run --cap-drop CHOWN alpine sh -c 'touch /tmp/file'

```

### Implementing Least Privilege

Start with no capabilities and add only what is necessary:

```bash

# Drop all defaults, then add back only specific requirements

container run --cap-drop ALL --cap-add SETUID --cap-add SETGID alpine id

```

### Using Deny-List Approach

Grant all capabilities except specific restricted ones:

```bash

# Give all capabilities except network administration

container run --cap-add ALL --cap-drop NET_ADMIN alpine sh

```

### Understanding Order Effects

Demonstrate how processing order affects the final capability set:

```bash

# Results in ALL capabilities because add is processed after drop

container run --cap-drop ALL --cap-add ALL alpine sh

```

## Implementation Details

The capability management system spans several key source files:

- **[`Sources/Services/ContainerAPIService/Client/Flags.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Client/Flags.swift)**: Defines the CLI flag structure for `--cap-add` and `--cap-drop` (lines 31-41)
- **[`Sources/Services/ContainerAPIService/Client/Parser.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Client/Parser.swift)**: Implements the parsing logic, normalization rules, and validation against the `CapabilityName` enum (lines 1009-1024)
- **[`docs/how-to.md`](https://github.com/apple/container/blob/main/docs/how-to.md)**: Documents the default capability set and processing order semantics (lines 70-76, 98-100)
- **[`docs/command-reference.md`](https://github.com/apple/container/blob/main/docs/command-reference.md)**: Provides the command reference table for these flags (lines 47-50)

## Summary

- The `apple/container` runtime runs workloads in lightweight VMs with a reduced default capability set including **CAP_NET_RAW** and **CAP_SETUID**.
- Use **`--cap-add`** to grant capabilities and **`--cap-drop`** to remove them; both support case-insensitive names with optional `CAP_` prefixes.
- The parser validates capabilities against the `CapabilityName` enum in [`Parser.swift`](https://github.com/apple/container/blob/main/Parser.swift) and aborts on invalid input.
- **Processing order matters**: All `--cap-drop` entries are processed before `--cap-add` entries, meaning additions override removals.
- The **`ALL`** token represents the complete capability set and can be used with either flag to grant or remove every capability.

## Frequently Asked Questions

### What capabilities are included in the default set?

The default capability set includes commonly required permissions such as **CAP_NET_RAW** for raw socket access and **CAP_SETUID** for changing user IDs, but excludes administrative capabilities like **CAP_NET_ADMIN** or **CAP_SYS_ADMIN**. The complete list is documented in [`docs/how-to.md`](https://github.com/apple/container/blob/main/docs/how-to.md) lines 70-76 of the `apple/container` repository.

### Can I use lowercase when specifying capability names?

Yes. The parser automatically normalizes capability names to uppercase and adds the `CAP_` prefix if you omit it. You can specify `net_admin`, `NET_ADMIN`, or `CAP_NET_ADMIN` interchangeably, and the parser in [`Sources/Services/ContainerAPIService/Client/Parser.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Client/Parser.swift) will handle them identically.

### What happens if I combine --cap-add and --cap-drop in the same command?

The runtime processes all `--cap-drop` entries first, then applies all `--cap-add` entries. This means that if you specify `--cap-drop ALL --cap-add NET_ADMIN`, the container starts with no capabilities, then gains only `CAP_NET_ADMIN`. Conversely, `--cap-drop ALL --cap-add ALL` results in a container with all capabilities because the final add operation restores the full set.

### How do I run a container with absolutely no capabilities?

Use the **`ALL`** token with `--cap-drop` to start from an empty capability set. The command `container run --cap-drop ALL alpine sh` creates a container with no Linux capabilities, providing the maximum security isolation. You can then selectively add back specific capabilities using `--cap-add` if your workload requires them.