はじめに
rootlessコンテナを実行する際にsubuidとsubgidがある前提で進めている記事があります.しかし,subuidとsubgidの追加方法について載っている記事はなかなか見つけにくいです.
STNS(Simple Toml Name Service)1はTOML(Tom's Obvious, Minimal Language.)2ベースの構成でLinuxユーザーを簡単に管理できるOSS(Open Source Software)です.STNSがあれば,複数のサーバー1つ1つにauthorized_keysを設定しなくてもSSH公開鍵認証でアクセスすることができるようになります.
環境
問題点
STNSを用いてユーザー管理をしている場合,初めてログインしたユーザーにホームディレクトリを作成する方法があります.
以下を/etc/pam.d/sshd
の末尾に追加することでホームディレクトリを自動で作成することができます5.
session required pam_mkhomedir.so skel=/etc/skel/ umask=0022
この方法では,uid,gidはSTNSで作成できてもsubuid,subgidが生成されません.
実際に以下のコマンドで何も出力されない場合はsubuid,subgidがありません.
$ grep $USER /etc/subuid /etc/subgid
解決策
ログインした際にsubuidとsubgidを生成するshell scriptを/etc/bash.bashrcに追記します.subuidとsubgidの生成にはusermod
6コマンドを使用します.
追記する内容は以下に載せます.
# 1. 登録されたsubuidから1番うしろのsubuidを取得
ID_FILE='/etc/subuid'
LASTID=`cat ${ID_FILE} | tail -n 1 | cut -f 2 -d ":"`
# 2. 登録するsubuidとsubgidの始まりの値の決定
if [ -z "$LASTID" ]; then
HEADID=100000
else
HEADID=$(($LASTID + 65536))
fi
# 3. 登録するsubuidとsubgidの終わりの値の決定
TAILID=$(($HEADID + 65535))
# 4. subuidとsubgidの登録
USERID=`grep $USER /etc/subuid | cut -f 1 -d ":"`
if [ ! "$USER" = "$USERID" ]; then
sudo usermod -v "$HEADID""-""$TAILID" -w "$HEADID""-""$TAILID" $USER
echo "Create subuid & subgid: ""$HEADID""-""$TAILID"
fi
subuidとsubgidの確認
$ grep $USER /etc/subuid /etc/subgid
/etc/subuid:g212200344:1410720:65536
/etc/subgid:g212200344:1410720:65536
このようにsubuidとsubgidが出力されれば成功です!
ここから下は解説
解説
やっていることの解説をします.
- 登録されたsubuidから一番うしろのsubuidを取得
- 登録するsubuidとsubgidの始まりの値の決定
- 登録するsubuidとsubgidの終わりの値の決定
- subuidとsubgidの登録
変数と言葉の対応関係
HEADID:登録するIDの始まりの値
TAILID:登録するIDの終わりの値
1. 登録されたsubuidから1番うしろのsubuidを取得
subuidが記録しているファイルから1番うしろの行のsubuidを取得します.コマンドで説明すると,cat
7 8でファイルの内容を取得し,tail
で最後の1行を取り出し,cut
で":"で分けた2つ目の要素を取り出します.
2. 登録するsubuidとsubgidの始まりの値の決定
1.で出力したIDに何も入っていない際9は,登録するIDの始まりの値を100000にします.Ubuntuはuseradd
やadduser
コマンドでユーザーを追加した際にsubuidとsubgidの始まりの値を100000と設定するため,それに合わせています.
もし,1.で出力したIDがあった際はIDとして必要な範囲,65535の次の値である65536を足した値を登録するIDの始まりの値にします.Ubuntuはuseradd
やadduser
コマンドでユーザーを追加した際の値に合わせています.rootlessコンテナではapt-get
を実行した際は65534番を使用しているので,同じように割り当てられているものが65535個あるのでしょう.
subuidとsubgidの範囲が足りない際にapt-get
すると以下のようなエラーが出ると思います.
[error]
setgroups 65534 error
setegid 65534 error
3. 登録するsubuidとsubgidの終わりの値の決定
65535個のsubuidとsubgidのIDを割り当てるので,登録するIDの始まりの値から65535足した[^7]値を登録するIDの終わりの値とする.
4. subuidとsubgidの登録
subuidが記録しているファイルからsubuidが割り振られているか確認する10.subuidが割り振られている際は登録せずに処理を追える.subuidが割り振られていない際はusermod
コマンドでsubuidとsubgidを登録する.最後にsubuidとsubgidが新しく割り振られた際はSSH公開鍵認証でアクセスしたターミナルに新しくsubuidとsubgidが割り振られたことを表示する.
おまけ ~Ansibleでsubgidとsubuidを登録できるようにするには?~
1つ1つサーバーにログインして先程の/etc/bash.bashrcに追記するのは骨が折れると思います.なので,Ansible(IT自動化ツールの1つ)でぱぱっと入れちゃいたい人用のyaml(YAML Ain't Markup Language)ファイルを載せておきます.
- hosts: all
tasks:
- name: Copy sshrc file
become: true
ansible.builtin.blockinfile:
path: /etc/bash.bashrc
block: |
ID_FILE='/etc/subuid'
LASTID=`cat ${ID_FILE} | tail -n 1 | cut -f 2 -d ":"`
if [ -z "$LASTID" ]; then
LASTID=100000
else
LASTID=$(($LASTID + 65536))
fi
USERID=`grep $USER /etc/subuid | cut -f 1 -d ":"`
TAILID=$(($LASTID + 65535))
if [ ! "$USER" = "$USERID" ]; then
sudo usermod -v "$LASTID""-""$TAILID" -w "$LASTID""-""$TAILID" $USER
echo "Create subuid & subgid: ""$LASTID""-""$TAILID"
fi
state: present
- name: Remove subuid
become: true
ansible.builtin.file:
path: /etc/subuid
state: absent
- name: Remove subgid
become: true
ansible.builtin.file:
path: /etc/subgid
state: absent
- name: Make subuid file
become: true
ansible.builtin.file:
path: /etc/subuid
state: touch
- name: Make subgid file
become: true
ansible.builtin.file:
path: /etc/subgid
state: touch
hostファイルに宛先を書いておきます.sre001.localからsre003.localへ実行したい場合のhostsファイルを載せます.
sre001.local
sre002.local
sre003.local
実行コマンドです.
$ ansible-playbook -i hosts add_sub_uid_gid.yaml --ask-become-pass
[^7]今どきのシェルスクリプトは数値計算にexprを使わない(POSIX準拠) - Qiita