# Securing Celery for Production

Running Celery in production requires careful attention to security, as workers often execute code based on messages received from a network service. If compromised, a worker can lead to Remote Code Execution (RCE).

## 1. Never Run as Root

**Rule #1:** Never run the Celery worker as the `root` user. If a task is compromised, the attacker gains root access to your server.

Create a dedicated user for the application:

```bash
useradd -m -s /bin/bash celery_user
```

When using **systemd** or **supervisord**, specify this user in the configuration.

**Example (systemd):**
```ini
[Service]
User=celery_user
Group=celery_user
ExecStart=/path/to/venv/bin/celery -A proj worker
```

## 2. Avoid Pickle Serialization

By default, older versions of Celery used `pickle` for serialization. `pickle` is insecure because it allows arbitrary code execution during deserialization. If an attacker can inject a message into your broker, they can execute any code on your worker.

**Solution:** Use `json` (default in modern Celery) or `msgpack`.

Explicitly disable pickle in your configuration:

```python
# settings.py or celery.py
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
```

## 3. Secure the Broker

The broker (Redis, RabbitMQ) is the communication hub. If it is exposed, anyone can queue tasks.

### Redis
1.  **Password Protection:** Enable `requirepass` in `redis.conf`.
2.  **Network Binding:** Bind Redis to `127.0.0.1` or a private VPC IP. Never expose it to `0.0.0.0` without a firewall.
3.  **TLS:** Use `rediss://` (note the extra 's') to encrypt traffic between the worker and the broker.

```python
CELERY_BROKER_URL = 'rediss://:password@hostname:6379/0'
```

### RabbitMQ
1.  **Delete Guest:** The default `guest/guest` user has full admin rights. Delete it.
2.  **Virtual Hosts:** Isolate environments using vhosts.
3.  **TLS:** Configure RabbitMQ with SSL certificates and use `amqps://`.

## 4. Input Validation

Treat task arguments as **untrusted input**. Even if the message comes from your own web app, a vulnerability there could lead to malicious payloads in Celery.

*   **Bad:** Passing a raw shell command to a task.
*   **Good:** Passing an ID and looking up the data in the database.

```python
# UNSAFE
@app.task
def backup_files(cmd):
    os.system(cmd)

# SAFE
@app.task
def backup_files(user_id):
    user = User.objects.get(id=user_id)
    # ... logic using user.path ...
```

## 5. Process Isolation

If you have tasks with different security levels (e.g., one processes public user uploads, another handles billing), run them on **separate worker instances** consuming from **separate queues**.

```bash
# Worker 1 (High Security)
celery -A proj worker -Q billing

# Worker 2 (Low Security)
celery -A proj worker -Q uploads
```

This limits the blast radius if a worker processing risky content is compromised.

[[programming/python/celery]]