user
目的: ローカルの Linux ユーザー(/etc/passwd)を宣言する。存在
(present)または不在(absent)、そして指定した項目 — uid、プライマリ
グループ、シェル、ホームディレクトリの記録、補助グループ — だけを対象と
します。指定しない項目は変更も監査もされません。
- id: app_group type: group with: name: app gid: 990 system: true
- id: app_user type: user depends_on: [app_group] with: name: app uid: 990 group: app groups: [systemd-journal] shell: /usr/sbin/nologin home: /var/lib/app system: true
- id: app_state type: directory depends_on: [app_user] with: path: /var/lib/app owner: app group: app mode: "0750"| パラメータ | 必須 | 型 | デフォルト | 説明 |
|---|---|---|---|---|
name |
はい | string | — | ユーザー名。静的。[a-z_][a-z0-9_-]*、最大 32 文字。 |
state |
いいえ | string | present |
present または absent。 |
uid |
いいえ | integer | 管理しない | 必須の uid(1〜4294967294)。0 は不可。 |
group |
いいえ | string | 管理しない | プライマリグループ(名前で指定)。事前に存在している必要があります(依存関係を参照)。 |
groups |
いいえ | string のリスト | 管理しない | 補助グループ(名前)。追加のみ: ユーザーをこれらに追加し、どのグループからも削除しません。プライマリグループを重複して指定できません。 |
shell |
いいえ | string | 管理しない | ログインシェルの絶対パス(/usr/sbin/nologin)。/etc/shells との照合は行いません。パスの規則は home と同じです。 |
home |
いいえ | string | 管理しない | ホームディレクトリとして記録する絶対パス。記録のみを設定し、作成も移動も行いません。パスの規則を参照。 |
create_home |
いいえ | boolean | false |
ホームディレクトリを作成(useradd -m)。作成時のみ有効。false のときは -M を明示的に渡します。 |
system |
いいえ | boolean | false |
システムユーザーとして作成(useradd --system)。作成時のみ有効で、監査も後からの変更もしません。 |
password_hash |
いいえ | { secret: <path> } |
管理しない | パスワードのハッシュ(パスワード自体ではない)。暗号化シークレットとして保持します。パスワードハッシュを参照。 |
未知のフィールドはスキーマエラーです。平文のパスワード、ロック、有効期限、SSH 鍵、
move_home、remove_home、force、non_unique のフィールドはありません。
これらはこのリソースの対象外です。
home と shell のパスの規則
Section titled “home と shell のパスの規則”どちらもコロン区切りの /etc/passwd レコードに保存されるため、同じ規則が適用されます。
/ そのものではない絶対パスで、空・.・.. の要素、連続または末尾の /、NUL、
: や ,、制御文字を含みません。規則に反するリテラルはスキーマエラーです(validate が
失敗します)。{{ }} 補間を使う値は評価後に検査され、結果が不正ならコマンドを実行する前に
エラーになります。どちらの場合も、アカウントが黙って変更されることはありません。
項目を宣言しない場合、作成時にはディストリビューション既定の useradd が
適用されます(たとえば group を省略すると同名のプライベートグループ。同名のグループがすでにある場合、または group の依存先が作る場合は、拒否して group: の宣言を求めます)。
ホームディレクトリ自体は directory
リソースで管理してください。
期待される動作
Section titled “期待される動作”- ローカルのみ。 ユーザーは
getent -s files passwdで観測します。別の ID ソースだけが提供するユーザーはエラーです。それを覆い隠すローカル ユーザーを作ることはありません。group/groupsに指定したグループも同様 です。 presentでユーザーがいない →useraddを 1 回 ([--system] [-u uid] [-g group] [-G g1,g2] [-s shell] [-d home] (-m|-M) name)。 別のローカルユーザーが使用中のuidでの作成は拒否されます。presentでユーザーがいる → 最大 1 回のusermod(-g、-s、-d、足りないグループだけの-a -G)。-mは渡さないため、 ホームディレクトリは移動しません。- 既存ユーザーの uid 不一致は拒否され、修復されません(
usermod -uは ホーム外のファイルの所有者を直しません)。auditはuidのDRIFTを 報告します。 - 補助グループのメンバーシップは追加のみです。すでに所属しているグループ や宣言していないグループには触れません。完全一致(exact)には対応して いません。
absentでユーザーがいる →-rも-fもなしのuserdel name。ホーム ディレクトリとメールスプールは残り、その uid が所有するファイルも残ります (結果に明記されます。ファイルシステムは検索しません)。ディストリ ビューションのuserdelが同名のプライベートグループも削除した場合は、 その旨が結果に記載されます。root、uid 0、この実行が使うアカウント、 セッションを実行・接続しているアカウントは拒否されます。実行中のプロセスが あるユーザーではuserdel/usermodが失敗し、失敗として報告されます。
パスワードハッシュ
Section titled “パスワードハッシュ”password_hash には暗号化シークレットが必要です。
- id: app_user type: user with: name: app password_hash: { secret: secrets/app-password-hash.age }Sinter は平文のパスワードを見ず、password フィールドもありません。手元のツール
(mkpasswd -m sha-512、openssl passwd -6 など)でハッシュを作り、その 1 行を
sinter secrets encrypt で保存して参照します。ハッシュは秘密情報
(オフラインで解読され得る)なので、レシピには書かず、表示もしません。
- 受け付ける値:
$y$(yescrypt)または$6$(sha512crypt)のハッシュ 1 つだけ ($6$[rounds=N$]salt$hash、N は 1000〜999999999)、256 バイト以下。文字は[./0-9A-Za-z]のみ、末尾の改行は 1 つまで。それ以外(DES、$1$、$5$、bcrypt、平文のパスワード、余分な 空白、先頭の!や*)は値を表示せずに拒否します。 - salt:
$6$の salt は[./0-9A-Za-z]の 1〜16 文字で、crypt(5) より厳格です。openssl passwd -6 -salt 'my_salt'で作ったハッシュは拒否されるため、salt はツールに 生成させてください。 - EL9: RHEL / Rocky / AlmaLinux 9 では
$y$を拒否します(shadow-utils と libxcrypt が yescrypt なしでビルドされているため)。$6$を使ってください。他のプラットフォームは 確認しません。yescrypt を検証できないディストリビューション(サポート対象より古いもの) では$y$ハッシュは保存されてもログインできません。 --sudoが必須です。/etc/shadowは root だけが読めます。--sudoがないとplan/apply/auditは失敗し(auditはERROR)、「変更なし」とは決して 報告しません。この確認の前にシークレットは開きません。- 常に sensitive(
sensitive:の指定に関わらず)で、これはリソース全体に及び、 パスワードだけではありません。plan の差分は伏せられ、ノートとエラーは固定文(アカウント名は[redacted]と表示され、拒否の理由は一般的な文言)で、ツールの stderr は出しません。auditはドリフトした項目(uid、shell、groups、password_hashなど)の名前は示しますが、 すべての項目で両側が[redacted]になり、値は出ません。したがってpassword_hashを 宣言したユーザーでは、観測値・宣言値の id、パス、グループ名はどの出力にも現れません。 validateは復号しません。 参照と age ファイルの存在だけを確認します。plan/apply/auditはsinter secretsと同じ identity 探索で 復号します。鍵が使えなければそのリソースは失敗し(auditはERROR)、「変更なし」には なりません。state: absentとは併用できません(スキーマエラー)。
適用と観測の方法:
- 保存されているフィールドは、
sudo配下のgetent -s files shadow <name>で読み、 宣言したハッシュとメモリ上で比較します。先頭の!(ロック)は比較で無視するため、 宣言したハッシュをすでに持つロック済みのアカウントは準拠とみなされ、ロックされたままです。 shadow レコードが読めない・ない、またはローカルファイルにないアカウントはエラーです。 - 不一致のときだけ、
sudo -n配下で/usr/sbin/chpasswd -eを実行し、name:hashを 標準入力で渡します(コマンドラインには載せず、usermod -pもシェルも使いません)。 ハッシュがすでに一致していれば何も書きません。書き込みのたびに最終変更日(パスワード エージング)が更新されます。 - 新しいユーザーは先に作成(
useradd)してからパスワードを設定します。アカウントを 作成・変更した後でパスワードの設定が失敗した場合は、その旨を結果に示します (change はchanged、失敗)。再実行で完了します。 - 宣言したハッシュは強制されます: ユーザーが変更したパスワードは次の
applyで 置き換えられます。 - ロックされたアカウント: 異なるハッシュでロックされたアカウント(
!<hash>)は 拒否します。chpasswd -eはフィールドを置き換え、黙ってロックを解除してしまうため です(ロック用のフィールドはまだありません)。パスワードが全くない状態(空のフィールド、!、!!、*、!*などのマーカー)には、そのままハッシュを設定します。つまり!!のアカウントは パスワードが有効になります。 - コントローラは比較のため、アカウントの現在のハッシュを一時的にメモリに保持します。
これは宣言したハッシュと同じく秘密情報であり、隠さず文書化しています。この
password_hashの動作は 2026-10-04 に実機受入検証されました(Ubuntu 26.04 のsudo-rsを含む)。対応プラットフォームを参照。
依存関係は明示的です。推測は行いません。参照の解決が保留されるのは、アカウントを作る
リソースが、依存する側のリソース自身の depends_on に直接挙げられていて、その
state が present(既定)と評価される場合だけです。ほかの依存関係の連鎖を介してしか
たどれないリソースや、absent のリソースが作るアカウントは考慮されず、未知のアカウントの
plan エラーはそのままです。保留は plan だけにあり、apply は依存関係の順に実行して
アカウントを実際に検索します。
group/groupsがgroupリソースで作られるグループを指す場合、その リソースを自身のdepends_onに挙げる必要があります。planでは、そのような ユーザーは失敗せず保留(apply まで unknown)され、それに依存する すべても同様です。依存関係のないグループ欠落は、その旨を示す plan エラー です。owner/groupがuser/groupリソースで作られるアカウントを指すfile・directory・templateは、そのリソースを自身のdepends_onに 挙げていればplanで保留されます。depends_onがなければ、まだ存在しない 所有者の plan は従来どおり未知のアカウントのエラーで失敗します。
宣言したすべての項目に一致するユーザーは何も変更しません。収束後の 2 回目の
apply は useradd/usermod/userdel を実行しません。
audit は宣言した項目 — state、uid、group、groups、shell、home、
password_hash — を個別にドリフトとして報告します。通常のユーザーでは値を表示しますが、
password_hash を持つユーザー(常に sensitive)では、すべての項目で両側が [redacted] になり、
password_hash には値がありません。別の ID ソースだけが提供するアカウントは
ERROR です。create_home と system は作成時のオプションで、監査されません。
失敗時の動作
Section titled “失敗時の動作”- アカウントコマンドの失敗は、変更の可能性あり・検証不明の失敗です。失敗した コマンドの後は再観測しません。終了コード 0 の場合は再観測し、宣言した状態に ならなければ検証失敗です。
- 拒否(番号振り直し、保護対象アカウント、使用中の ID、グループ欠落、外部
提供のアカウント)はコマンド実行前に行われ、
planでは plan エラーです。 - 失敗したユーザーに依存するリソースは実行されません。
プラットフォームに関する補足
Section titled “プラットフォームに関する補足”/usr/sbin/useradd、usermod、userdel、chpasswd と getent を argv のみ・シェルなしで
使います。上記の password_hash の動作は 2026-10-04 に Ubuntu 24.04 / 26.04、
Rocky Linux・RHEL・AlmaLinux 9 / 10 の実機で受入検証されました。このリソースの
useradd / usermod / userdel の各次元は実機では検証しておらず、スクリプト
化された fake ターゲットでのみ立証されています。