創(chuàng)建文件夾權(quán)限不足:從權(quán)限模型到實(shí)戰(zhàn)解決)
1. 權(quán)限不足這件事幾乎每個(gè)Linux普通用戶(hù)都踩過(guò)剛接觸Linux那會(huì)兒我用的是一臺(tái)共享的開(kāi)發(fā)服務(wù)器賬號(hào)是運(yùn)維統(tǒng)一分配的普通用戶(hù)。第一次想在自己的家目錄下建個(gè)項(xiàng)目文件夾敲下mkdir myproject終端直接甩回來(lái)一句mkdir: cannot create directory myproject: Permission denied。當(dāng)時(shí)第一反應(yīng)是我自己的目錄我還建不了文件夾后來(lái)才明白問(wèn)題根本不在我能不能建而在于我在哪個(gè)目錄下建、這個(gè)目錄歸誰(shuí)、我有沒(méi)有寫(xiě)權(quán)限。這個(gè)場(chǎng)景太典型了。不管你是剛裝完Linux系統(tǒng)的新手還是在公司服務(wù)器上干活的運(yùn)維、開(kāi)發(fā)只要用的是普通用戶(hù)賬號(hào)遲早會(huì)撞上創(chuàng)建文件夾權(quán)限不足這堵墻。它可能出現(xiàn)在家目錄、/opt、/usr/local、/var/www也可能出現(xiàn)在掛載的移動(dòng)硬盤(pán)、共享目錄、Docker數(shù)據(jù)卷里。表現(xiàn)都一樣mkdir報(bào)Permission denied或者圖形界面里右鍵新建文件夾是灰的再或者touch建文件也失敗。這篇內(nèi)容就是圍繞Linux普通用戶(hù)創(chuàng)建文件夾權(quán)限不足這一個(gè)具體問(wèn)題展開(kāi)的。我會(huì)把權(quán)限模型講清楚把常見(jiàn)場(chǎng)景一個(gè)個(gè)拆開(kāi)給出可以直接抄的命令也會(huì)分享一些我這些年踩過(guò)的坑和排查思路。適合剛上手Linux的新手也適合想系統(tǒng)梳理權(quán)限知識(shí)的運(yùn)維和開(kāi)發(fā)。看完之后你至少能做到看到Permission denied不再慌知道從哪幾個(gè)方向去查、去改、去規(guī)避。2. 先把Linux權(quán)限模型吃透不然改權(quán)限就是瞎改2.1 一個(gè)文件夾能不能建取決于三個(gè)身份和三種權(quán)限Linux的權(quán)限體系說(shuō)復(fù)雜也復(fù)雜說(shuō)簡(jiǎn)單其實(shí)就一句話(huà)每個(gè)文件/目錄都有屬主owner、屬組group、其他人others三類(lèi)身份每類(lèi)身份各有讀r、寫(xiě)w、執(zhí)行x三種權(quán)限。對(duì)于目錄來(lái)說(shuō)這三個(gè)權(quán)限的含義和普通文件不一樣這點(diǎn)很多人搞混r讀能列出目錄里的內(nèi)容也就是能ls。w寫(xiě)能在目錄里創(chuàng)建、刪除、重命名文件或子目錄。注意刪除一個(gè)文件看的是父目錄有沒(méi)有寫(xiě)權(quán)限而不是文件本身。x執(zhí)行能進(jìn)入這個(gè)目錄也就是能cd能訪(fǎng)問(wèn)目錄里的文件。沒(méi)有x即使有r也只能看到文件名進(jìn)不去。所以創(chuàng)建文件夾權(quán)限不足的本質(zhì)就是你對(duì)目標(biāo)父目錄沒(méi)有寫(xiě)權(quán)限w。這一點(diǎn)必須先釘死后面所有排查都圍繞它展開(kāi)。用ls -ld看一眼目標(biāo)目錄輸出類(lèi)似drwxr-xr-x 2 root root 4096 Jan 10 10:00 /opt/app拆開(kāi)看第一個(gè)字符d表示目錄接著rwx是屬主權(quán)限r(nóng)-x是屬組權(quán)限r(nóng)-x是其他人權(quán)限。屬主是root屬組是root。如果你當(dāng)前登錄的是普通用戶(hù)tom既不是root也不在root組那你就是其他人只有r-x沒(méi)有w自然建不了文件夾。2.2 為什么普通用戶(hù)在家目錄能建在/opt就建不了這是新手最容易困惑的地方。原因在于目錄的屬主不同你的家目錄/home/tom屬主是tom權(quán)限通常是drwx------或drwxr-xr-x屬主那一欄有w所以你能隨便建。/opt、/usr/local、/etc這些系統(tǒng)目錄屬主是root普通用戶(hù)是其他人通常只有r-x沒(méi)有w所以建不了。這不是系統(tǒng)針對(duì)你而是Linux的多用戶(hù)設(shè)計(jì)系統(tǒng)目錄歸管理員管普通用戶(hù)不該隨便動(dòng)。理解了這一點(diǎn)你就知道解決思路無(wú)非兩條——要么換個(gè)你有寫(xiě)權(quán)限的目錄建要么想辦法讓自己獲得寫(xiě)權(quán)限。2.3 權(quán)限數(shù)字表示法改權(quán)限前必須會(huì)算chmod用數(shù)字改權(quán)限時(shí)r4、w2、x1三類(lèi)身份相加權(quán)限組合數(shù)字含義rwx7讀寫(xiě)執(zhí)行rw-6讀寫(xiě)r-x5讀執(zhí)行r--4只讀-wx3寫(xiě)執(zhí)行-w-2只寫(xiě)--x1只執(zhí)行---0無(wú)權(quán)限比如chmod 755 dir就是屬主rwx、屬組r-x、其他人r-x。想讓某個(gè)目錄對(duì)所有人可寫(xiě)就是chmod 777但生產(chǎn)環(huán)境千萬(wàn)別隨便777后面會(huì)專(zhuān)門(mén)講為什么。3. 按場(chǎng)景對(duì)癥下藥五種最常見(jiàn)的權(quán)限不足及解決方式3.1 場(chǎng)景一在系統(tǒng)目錄下建文件夾被拒這是最典型的。比如你想在/opt下建個(gè)自己的項(xiàng)目目錄mkdir /opt/myapp # mkdir: cannot create directory /opt/myapp: Permission denied解決方式有三種按推薦程度排序方式一最推薦換到自己的家目錄或指定工作目錄。大多數(shù)情況下你根本不需要往/opt里塞東西~/projects/myapp完全夠用。這是最省事、最不惹麻煩的做法。方式二用sudo臨時(shí)提權(quán)創(chuàng)建然后改屬主。如果你確實(shí)需要放在系統(tǒng)目錄比如部署服務(wù)sudo mkdir /opt/myapp sudo chown -R $USER:$USER /opt/myapp這里$USER會(huì)自動(dòng)展開(kāi)成當(dāng)前用戶(hù)名。chown -R把目錄及內(nèi)部所有內(nèi)容的屬主改成你自己之后你就能正常讀寫(xiě)了。注意先sudo mkdir再chown兩步缺一不可。只sudo mkdir不改屬主目錄還是root的你照樣建不了子文件夾。方式三把用戶(hù)加入目標(biāo)目錄的屬組。如果目錄屬組是developers而你是開(kāi)發(fā)組成員可以讓管理員把你加進(jìn)去sudo usermod -aG developers tom加完組后必須重新登錄才生效這點(diǎn)后面會(huì)細(xì)說(shuō)。3.2 場(chǎng)景二目錄屬主是別人但你需要長(zhǎng)期協(xié)作團(tuán)隊(duì)協(xié)作時(shí)經(jīng)常遇到一個(gè)共享目錄/data/shared屬主是同事A你想在里面建文件夾。這時(shí)候改屬主不合適會(huì)影響別人更合理的做法是用屬組權(quán)限# 把目錄屬組改成團(tuán)隊(duì)組并給屬組寫(xiě)權(quán)限 sudo chgrp -R devteam /data/shared sudo chmod -R 775 /data/shared775意味著屬主和屬組都有rwx其他人只有r-x。團(tuán)隊(duì)成員都在devteam組里就都能建文件夾了。為了讓新建的子目錄自動(dòng)繼承屬組還可以設(shè)置SGID位sudo chmod gs /data/shared設(shè)置后在這個(gè)目錄里新建的任何子目錄屬組都會(huì)自動(dòng)跟隨父目錄而不是創(chuàng)建者的主組。這個(gè)技巧在共享目錄場(chǎng)景里非常實(shí)用能避免我建的文件別人改不了的尷尬。3.3 場(chǎng)景三掛載的磁盤(pán)或移動(dòng)硬盤(pán)權(quán)限不對(duì)插上U盤(pán)或掛載新分區(qū)后發(fā)現(xiàn)普通用戶(hù)建不了文件夾ls -ld一看屬主是root。這通常是掛載時(shí)沒(méi)指定屬主。解決辦法是在/etc/fstab里加掛載選項(xiàng)# 在fstab對(duì)應(yīng)行加上uid和gid /dev/sdb1 /mnt/data ext4 defaults,uid1000,gid1000 0 0uid1000和gid1000是普通用戶(hù)的ID用id命令可以查到自己是多少。對(duì)于NTFS、FAT這類(lèi)不支持Linux權(quán)限的文件系統(tǒng)uid/gid選項(xiàng)幾乎是唯一辦法。改完fstab后執(zhí)行sudo mount -a重新掛載生效。3.4 場(chǎng)景四Docker容器里創(chuàng)建目錄失敗容器里跑應(yīng)用時(shí)經(jīng)常遇到掛載的宿主機(jī)目錄權(quán)限不對(duì)。比如容器內(nèi)進(jìn)程以非root用戶(hù)運(yùn)行掛載的目錄屬主是root就會(huì)報(bào)權(quán)限不足。解決思路# 查看宿主機(jī)目錄屬主 ls -ld /host/data # 改成容器內(nèi)用戶(hù)對(duì)應(yīng)的uid sudo chown -R 1000:1000 /host/data或者在docker run時(shí)用--user指定用戶(hù)保證容器內(nèi)外uid一致。這個(gè)坑我在部署時(shí)踩過(guò)好幾次本質(zhì)還是uid映射問(wèn)題。3.5 場(chǎng)景五圖形界面右鍵新建文件夾是灰的桌面環(huán)境下右鍵菜單灰掉本質(zhì)和命令行一樣還是父目錄沒(méi)寫(xiě)權(quán)限。只是圖形界面不給你報(bào)錯(cuò)直接禁用菜單。排查方法一樣打開(kāi)終端ls -ld看目標(biāo)目錄權(quán)限。解決方式也一致改權(quán)限或換目錄。別以為是桌面環(huán)境壞了九成是權(quán)限問(wèn)題。4. 手把手實(shí)操?gòu)膱?bào)錯(cuò)到解決完整走一遍4.1 第一步確認(rèn)當(dāng)前身份和目標(biāo)目錄排查權(quán)限問(wèn)題的第一件事永遠(yuǎn)是搞清楚我是誰(shuí)和目錄歸誰(shuí)whoami # 當(dāng)前用戶(hù)名 id # 當(dāng)前用戶(hù)的uid、gid、所屬組 ls -ld /目標(biāo)目錄 # 目標(biāo)目錄的屬主、屬組、權(quán)限這三條命令是排查的黃金組合。我見(jiàn)過(guò)太多人一上來(lái)就chmod 777結(jié)果連問(wèn)題出在哪都沒(méi)搞清。先看再改這是鐵律。4.2 第二步判斷你到底缺哪種權(quán)限拿到ls -ld的輸出后對(duì)照下表判斷你的身份目錄權(quán)限對(duì)應(yīng)段有w嗎能否建文件夾屬主第2-4位有w才行有w可建屬組成員第5-7位有w才行有w可建其他人第8-10位有w才行有w可建判斷規(guī)則先看你是不是屬主是就看屬主段不是屬主再看你在不在屬組在就看屬組段都不在就看其他人段。只要對(duì)應(yīng)段里有w就能建文件夾。沒(méi)有就是權(quán)限不足。4.3 第三步選擇合適的修改方案根據(jù)前面的場(chǎng)景方案選擇可以總結(jié)成一張決策表情況推薦方案命令示例個(gè)人臨時(shí)用換到家目錄mkdir ~/work/xxx需要放系統(tǒng)目錄sudo建chownsudo mkdir /opt/x sudo chown $USER /opt/x團(tuán)隊(duì)共享改屬組775SGIDchgrp devteam d chmod 2775 d掛載盤(pán)fstab加uid/giddefaults,uid1000,gid1000容器掛載對(duì)齊uidchown -R 1000:1000 /host/data4.4 第四步驗(yàn)證修改是否生效改完之后一定要驗(yàn)證別改完就跑# 重新查看權(quán)限 ls -ld /目標(biāo)目錄 # 實(shí)際測(cè)試創(chuàng)建 mkdir /目標(biāo)目錄/testdir echo 創(chuàng)建成功 # 清理測(cè)試目錄 rmdir /目標(biāo)目錄/testdir能建能刪才算真正解決。如果還報(bào)錯(cuò)回到第一步重新排查很可能是改錯(cuò)了對(duì)象或者組沒(méi)生效。4.5 第五步讓權(quán)限修改持久化有些修改是臨時(shí)的重啟就沒(méi)了要注意chmod、chown改的是文件系統(tǒng)屬性持久有效重啟不丟。usermod -aG加組需要重新登錄才生效當(dāng)前會(huì)話(huà)不會(huì)立即生效。fstab里的掛載選項(xiàng)重啟后自動(dòng)生效但改完要mount -a測(cè)試。臨時(shí)mount命令掛載的重啟就沒(méi)了必須寫(xiě)進(jìn)fstab。5. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄5.1 為什么我加了組還是權(quán)限不足這是最高頻的疑問(wèn)。usermod -aG加組后當(dāng)前已登錄的會(huì)話(huà)不會(huì)自動(dòng)獲得新組權(quán)限。因?yàn)橛脩?hù)所屬組信息是在登錄時(shí)確定的加組只改了配置文件。解決辦法# 方法一完全退出重新登錄 exit # 方法二用newgrp臨時(shí)切換主組 newgrp devteam # 方法三用sg在指定組下執(zhí)行命令 sg devteam -c mkdir /data/shared/newdir我一般推薦直接重新登錄最干凈。newgrp會(huì)開(kāi)一個(gè)子shell退出后失效適合臨時(shí)用。5.2 chmod 777 真的能解決所有問(wèn)題嗎能但強(qiáng)烈不推薦。777意味著任何人包括系統(tǒng)里其他普通用戶(hù)、被入侵的進(jìn)程都能在這個(gè)目錄里增刪改。生產(chǎn)環(huán)境里給目錄777等于把門(mén)敞開(kāi)。正確的做法是最小權(quán)限原則需要誰(shuí)寫(xiě)就給誰(shuí)寫(xiě)其他人只讀甚至無(wú)權(quán)限。比如團(tuán)隊(duì)目錄用775個(gè)人目錄用700比777安全得多。5.3 目錄有寫(xiě)權(quán)限為什么還是建不了這種情況少見(jiàn)但存在排查方向磁盤(pán)滿(mǎn)了df -h看下滿(mǎn)了會(huì)報(bào)No space left on device不是權(quán)限問(wèn)題但表現(xiàn)類(lèi)似。inode用盡df -i檢查inode耗盡也建不了新文件。文件系統(tǒng)只讀mount | grep 目標(biāo)分區(qū)看是不是ro掛載只讀文件系統(tǒng)誰(shuí)都建不了。SELinux或AppArmor攔截getenforce看SELinux狀態(tài)強(qiáng)制模式下即使權(quán)限對(duì)也可能被攔。臨時(shí)排查可以setenforce 0測(cè)試但生產(chǎn)環(huán)境要謹(jǐn)慎。父目錄沒(méi)有x權(quán)限沒(méi)有x進(jìn)不去目錄自然也建不了ls -ld看下有沒(méi)有x。5.4 常見(jiàn)報(bào)錯(cuò)速查表報(bào)錯(cuò)信息可能原因排查命令Permission denied父目錄無(wú)w權(quán)限ls -ld 父目錄No space left on device磁盤(pán)或inode滿(mǎn)df -h/df -iRead-only file system分區(qū)只讀掛載mount | grep 分區(qū)Operation not permitted屬性位或SELinuxlsattr/getenforceToo many levels of symbolic links軟鏈接成環(huán)ls -l逐層查5.5 幾個(gè)我踩過(guò)的坑坑一改錯(cuò)目錄層級(jí)。有次同事說(shuō)建不了文件夾我一看他改的是子目錄權(quán)限但報(bào)錯(cuò)的是父目錄。權(quán)限是逐層檢查的父目錄沒(méi)x子目錄權(quán)限再高也進(jìn)不去。排查要從報(bào)錯(cuò)路徑的每一層往上查??佣hown -R 改錯(cuò)對(duì)象。chown -R會(huì)遞歸改所有子內(nèi)容有次手抖把系統(tǒng)目錄整個(gè)改了屬主差點(diǎn)出事。執(zhí)行遞歸操作前先用ls確認(rèn)路徑必要時(shí)先--dry-run或小范圍測(cè)試??尤詾閟udo能解決一切。sudo mkdir建出來(lái)的目錄屬主是root普通用戶(hù)后續(xù)操作還是受限。sudo建完記得chown否則等于給自己挖坑??铀暮雎評(píng)mask。新建目錄的默認(rèn)權(quán)限受umask影響。umask是022時(shí)新建目錄權(quán)限是755是002時(shí)是775。如果團(tuán)隊(duì)目錄需要組內(nèi)可寫(xiě)把umask設(shè)成002更省事可以在~/.bashrc里加umask 002。6. 從根上避免權(quán)限問(wèn)題一些習(xí)慣和思路與其每次撞墻再解決不如養(yǎng)成幾個(gè)習(xí)慣從源頭減少權(quán)限問(wèn)題。第一搞清楚自己的工作目錄。普通用戶(hù)就該在家目錄干活~/projects、~/work隨便建。需要放系統(tǒng)目錄的走部署流程別手動(dòng)亂塞。第二團(tuán)隊(duì)協(xié)作優(yōu)先用組權(quán)限而不是改屬主。屬主只能有一個(gè)組可以有很多人。用組SGID是共享目錄的標(biāo)準(zhǔn)做法擴(kuò)展性好也不會(huì)因?yàn)槟橙穗x職就出問(wèn)題。第三改權(quán)限前先想清楚影響范圍。chmod -R和chown -R是雙刃劍遞歸改之前一定確認(rèn)路徑。我現(xiàn)在的習(xí)慣是遞歸命令先不加-R跑一遍看輸出確認(rèn)無(wú)誤再加。第四善用sudo但別依賴(lài)sudo。需要提權(quán)的操作走sudo但日常操作盡量用普通用戶(hù)完成。長(zhǎng)期用root干活遲早出大事。第五遇到權(quán)限問(wèn)題先查再改。whoami、id、ls -ld三連基本能定位九成問(wèn)題。別一上來(lái)就777那是治標(biāo)不治本還留隱患。最后分享一個(gè)我常用的排查小腳本遇到權(quán)限問(wèn)題直接跑#!/bin/bash # 權(quán)限排查小工具 TARGET${1:-.} echo 當(dāng)前用戶(hù) whoami id echo 目標(biāo)路徑逐層權(quán)限 path IFS/ read -ra PARTS $(realpath $TARGET) for part in ${PARTS[]}; do [ -z $part ] continue path$path/$part ls -ld $path 2/dev/null done echo 磁盤(pán)空間 df -h $TARGET echo 掛載狀態(tài) mount | grep $(df --outputtarget $TARGET | tail -1)這個(gè)腳本會(huì)把從根目錄到目標(biāo)路徑的每一層權(quán)限都列出來(lái)一眼就能看出是哪一層缺了w或x。我用了好幾年排查權(quán)限問(wèn)題效率高很多。你可以保存成checkperm.shchmod x后直接用。權(quán)限這東西理解了模型就一通百通。核心就一句話(huà)創(chuàng)建文件夾看父目錄的w權(quán)限訪(fǎng)問(wèn)內(nèi)容看路徑上每一層的x權(quán)限。把這句話(huà)記牢再配合ls -ld逐層排查L(zhǎng)inux權(quán)限問(wèn)題基本都能自己搞定。