Bối cảnh & Nguyên nhân cốt lõi
Bạn vừa mount thư mục code từ máy host vào Docker container. Bạn gõ git status và nhận ngay một gáo nước lạnh:
fatal: detected dubious ownership in repository at '/workspace/my-app'
To add an exception for this directory, call:
git config --global --add safe.directory /workspace/my-app
Tình huống này cũng rất quen thuộc khi bạn SSH vào server staging có 4-5 dev cùng dùng chung.
Repo không hề hỏng. Git cũng không bị lỗi. Đây là cơ chế bảo mật được thêm vào từ bản vá CVE-2022-24765 (tháng 4/2022).
Trước bản vá, Git luôn lùi dần lên các thư mục cha để tìm thư mục .git. Trên máy chủ nhiều user, kẻ xấu có thể tạo sẵn một repo giả ở thư mục dùng chung như /tmp hoặc /var/www. Trong file cấu hình .git/config đó, họ chèn hook độc hại hoặc cấu hình core.fsmonitor trỏ tới một script nguy hiểm. Khi bạn đứng ở thư mục con và gõ lệnh Git bất kỳ, mã độc sẽ lập tức chạy dưới quyền tài khoản của bạn.
Để bịt lỗ hổng, Git đặt ra quy tắc mới: User thực thi lệnh phải sở hữu chính thư mục repo đó.
Vấn đề phát sinh khi bạn dùng Docker. Mã nguồn trên máy host thuộc sở hữu của user bình thường (thường là UID 1000). Nhưng container lại chạy mặc định bằng root (UID 0). Hai UID lệch nhau hoàn toàn. Git lập tức chặn đứng thao tác để phòng ngừa rủi ro.
Kiểm tra phiên bản Git
Cơ chế safe.directory có sẵn từ Git 2.35.2. Đầu tiên, hãy kiểm tra phiên bản trên máy hoặc bên trong container:
git --version
Nếu phiên bản thấp hơn, bạn cần nâng cấp gói. Trên Ubuntu/Debian:
sudo apt update && sudo apt install -y git
Trên Alpine Linux (image phổ biến cho Docker):
apk update && apk add --no-cache git
4 Cách xử lý từ an toàn đến triệt để
Đừng vội copy bừa lệnh trên mạng. Bạn nên chọn giải pháp phù hợp với môi trường thực tế của mình.
1. Whitelist từng thư mục cụ thể (Khuyên dùng)
Cách đơn giản nhất là báo cho Git biết thư mục này tuyệt đối an toàn:
git config --global --add safe.directory /workspace/my-app
Lệnh này ghi một dòng vào file ~/.gitconfig của user hiện tại. Nếu đang đứng trong container chạy quyền root, file được ghi là /root/.gitconfig.
2. Cấu hình sẵn trong Dockerfile hoặc Compose
Khi build dev-container hoặc CI/CD runner (như GitLab CI, Jenkins), container dựng mới liên tục sẽ làm mất config. Hãy đưa thẳng vào Dockerfile:
FROM node:20-alpine
WORKDIR /app
# Cài git và whitelist thư mục làm việc
RUN apk add --no-cache git \
&& git config --global --add safe.directory /app
CMD ["npm", "run", "dev"]
Nếu dùng docker-compose.yml cho môi trường local dev, bạn có thể chạy lệnh này ở phần entrypoint hoặc command:
version: '3.8'
services:
api:
image: python:3.11-slim
working_dir: /code
volumes:
- .:/code
command: >
sh -c "git config --global --add safe.directory /code &&
python main.py"
3. Đồng bộ UID giữa Host và Container (Chuẩn bài nhất cho Dev)
Bản chất lỗi nằm ở sự lệch pha UID (1000 vs 0). Khắc phục tận gốc bằng cách ép container chạy bằng chính UID/GID của bạn:
docker run -it --rm \
-u $(id -u):$(id -g) \
-v $(pwd):/workspace \
-w /workspace \
node:20-alpine sh
Lợi ích kép: Git không còn báo lỗi dubious ownership. Đồng thời, các file do container sinh ra (như node_modules, cache) cũng không bị biến thành quyền root trên máy host.
4. Sửa quyền sở hữu thư mục trên Linux
Trên server dùng chung, lỗi thường do một đồng nghiệp lỡ gõ sudo git clone hoặc sudo git pull. Bạn chỉ cần trả lại quyền sở hữu cho tài khoản cá nhân:
sudo chown -R $USER:$USER /var/www/my-app
Cảnh báo: Tránh xa wildcard ‘*’
Nhiều câu trả lời trên Stack Overflow khuyên bạn chạy lệnh này cho tiện:
# NGUY HIỂM: TUYỆT ĐỐI TRÁNH TRÊN MÁY THẬT
git config --global --add safe.directory '*'
Dấu * vô hiệu hóa hoàn toàn cơ chế bảo vệ của CVE-2022-24765 trên mọi ngóc ngách của hệ thống. Bạn chỉ nên cân nhắc dùng nó bên trong container CI/CD chạy tạm thời rồi hủy ngay (ephemeral runner). Đừng bao giờ áp dụng trên máy cá nhân hay server production.
Kiểm tra và Dọn dẹp
Sau khi thiết lập, bạn nên kiểm tra lại xem Git đã nhận cấu hình hay chưa.
Xem danh sách safe.directory hiện tại
git config --global --get-all safe.directory
Nếu muốn kiểm tra vị trí file lưu config (system, global hay local), thêm cờ --show-origin:
git config --list --show-origin | grep safe.directory
Xác nhận trạng thái
Chạy thử lệnh quen thuộc trong thư mục dự án:
git status
Nếu Git hiển thị nhánh và commit bình thường mà không kèm cảnh báo đỏ, bạn đã hoàn tất.
Xóa đường dẫn không còn dùng
Khi xóa dự án cũ, bạn nên dọn dẹp cấu hình để file ~/.gitconfig luôn gọn gàng:
git config --global --unset-all safe.directory /workspace/my-app
Hiểu đúng cơ chế UID và safe.directory giúp bạn xử lý lỗi phân quyền trong 30 giây mà không cần đánh đổi tính an toàn của hệ thống.
