なんか慣れてきた
Dockerでホスト側のディレクトリをVolumeマウントして、そこに対してコンテナの中から書き込むと、コンテナ内の実行ユーザーのuidとgidで書き込まれてしまって、ホスト側から触れない。さて、困った。ってなった。
あれー?Macのときはこんなことあったっけ?って思ってたら、Linuxの場合だけみたい。最近Dockerのそういうのばっかりひっかかってるから、なんか慣れてきた!
対応策
んで、ここにいくつか対応策が紹介されてて。そっかー。ってなった。
この中の最後の「実行ユーザーのuidとgidを実行時にentrypoint.shで書き換えてホスト側のものと同じにする」ってのが今の僕のやりたいことに合ってるかもなぁと思いながら・・・。
他にも面白い記事ないかなー
って探してみたら、こういう記事を見つけた。
へー。コンテナの中にこのfixuidプログラムを置いて実行すれば、さっきのQiitaの記事でやってることをやってくれるっぽい。便利そう。と思いながら読んでて。
あれ?でもUSER sample:sample
みたいに実行ユーザーを指定してるのに、どうやってuidとgidを書き換えてるんだろう?と思ったので
コードを読んでみた
https://github.com/boxboat/fixuid/blob/05869a9ead4f95f7175564984a6ec52fb8ed009d/fixuid.go#L349-L379
if err := ioutil.WriteFile("/etc/passwd", []byte(newLines), 0644); err != nil { return err }
Golang分からんけど、/etc/passwd
を書き換えてるっぽい。権限なさそうなのになんで書き換えられるんだろう?と思って見てみたら、この辺。
https://github.com/boxboat/fixuid/blob/05869a9ead4f95f7175564984a6ec52fb8ed009d/fixuid.go#L48-L55
// check that script is running as root if os.Geteuid() != 0 { logger.Fatalln(`fixuid is not running as root, ensure that the following criteria are met: - fixuid binary is owned by root: 'chown root:root /path/to/fixuid' - fixuid binary has the setuid bit: 'chmod u+s /path/to/fixuid' - NoNewPrivileges is disabled in container security profile - volume containing fixuid binary does not have the 'nosuid' mount option`) }
あれ?rootで実行されてるって書いてる。
このGeteuid()
ってなんだろうなー?
と思って調べたら、この記事見つけて、へーってなった。
Linuxの実効ユーザIDについて実験してみた – ブーログ
実行ファイルのオーナーがroot:rootで、パーミッションが4755だったら、一般ユーザーで実行してもroot権限で書き込めるってことなのかな。
試してみよう!
ということで、実行ファイルを作るのをGoでやってみることにした。
Go書くのはじめてだー!って思ってダウンロードしたら、既にインストールされてて、はて・・・?いつの間に?記憶にないぞ?ってなりつつバージョンアップ。
みようみまねでこんな感じのhello.go
を書いた。心を込めていっこずつググりながら書いたから結構時間かかったー。
package main import "fmt" import "os" func main() { fmt.Printf("uid: %d\n", os.Getuid()) fmt.Printf("euid: %d\n", os.Geteuid()) file, err := os.Create("sample.txt") if err != nil { panic(err) } defer file.Close() _, err = file.WriteString("Hello") if err != nil { panic(err) } }
で、ビルドして実行ファイルの権限を確認。Goってお手軽だなー。
❯ go build hello.go ❯ stat --format='%a %U:%G' hello 775 bufferings:bufferings
775で、僕がオーナーになってる。
じゃ、まずは
普通のファイルには書き込めることを確認しとこう。
❯ touch sample.txt ❯ ./hello uid: 1000 euid: 1000 ❯ cat sample.txt Hello
OKだね。
次は
権限がなかったら書き込めないことを確認。
❯ rm sample.txt ❯ sudo touch sample.txt ❯ ls -al sample.txt -rw-r--r-- 1 root root 0 8月 26 01:33 sample.txt ❯ ./hello uid: 1000 euid: 1000 panic: open sample.txt: permission denied goroutine 1 [running]: main.main() /path/to/project/hello.go:12 +0x1d7
OKだね。
最後に
実行ファイルのオーナーと権限を変えて実行してみよう
❯ sudo chown root:root ./hello ❯ sudo chmod 4755 ./hello ❯ stat --format='%a %U:%G' hello 4755 root:root ❯ ./hello uid: 1000 euid: 0 ❯ cat sample.txt Hello
おー。書きこめた。こんな仕組み全然知らなかったなー。面白かった。
ところで
元々のVolumeマウントの問題は、色々考えたんだけど僕のこのマシンでしか使わないからuidとgidを1000固定でDockerfileに書いちゃうことにしようと思う。