[AIX] Ansible  ibm.power_aix モジュールを使用したユーザー作成

### はじめに

Ansible モジュールの ibm.power_aix.user を使用してユーザー作成のplaybook を検証を含めて作成したログです。


---

### 環境

Ansible サーバー
　RHEL9.4 (ppc64le)

Ansible 実行対象サーバー
　AIX 7.3 TL1 SP1


---

### ansible 基本設定


* インベントリー

```inventory/test.yml
[aix]
AIX73  ansible_user=root ansible_ssh_private_key_file=/root/.ssh/id_rsa_ansible
```

ホスト名 AIX73 は/etc/hosts で名前解決しています。
AIX73 は Ansible 実行サーバーと /root/.ssh/id_rsa_ansible で鍵交換しています。


+ ansible.cfg は以下の内容です。

```ansible.cfg
[defaults]
inventory = ./inventory/test.yml
deprecation_warnings=False
host_key_checking = False
#vault_password_file = /root/.vault/automation.vault
verbosity = 1
#stdout_callback = debug
callback_whitelist = profile_tasks
interpreter_python='/bin/env LANG=C python3'
# skip のログを非表示にする
display_skipped_hosts = no
# ok のログを非表示にする
display_ok_hosts = no


[privilege_escalation]
become = True
become_method = sudo
become_user = root
become_ask_pass = False

[ssh_connection]
ssh_args ='-o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null'
```


検証環境のため`host_key_checking = False` で設定していますが、セキュリティ面で本番環境では True が望ましいです。

---

### オフラインで ibm.power_aix モジュールの導入

ibm.power_aix のサイトで download tarball を選択してダウンロードします。

https://galaxy.ansible.com/ui/repo/published/ibm/power_aix/

この時の最新版、ibm-power_aix-2.1.1.tar.gz を入手しました。


サーバーに ibm-power_aix-2.1.1.tar.gz を配置します。


ansible-galaxy コマンドを実行してモジュールを導入します。


```
# ansible-galaxy collection install ibm-power_aix-2.1.1.tar.gz
Process install dependency map
Starting collection install process
Installing 'ibm.power_aix:2.1.1' to '/root/.ansible/collections/ansible_collections/ibm/power_aix'
```

* ssh-copy-id コマンドを使用して 対象サーバーと鍵交換を実施

```
#  ssh-copy-id -i id_rsa_ansible.pub root@172.16.xxx.xx
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "id_rsa_ansible.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@172.16.xxx.xx's password:
sh: test: argument expected

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'root@172.16.xxx.xx'"
and check to make sure that only the key(s) you wanted were added.

#

```


"sh: test: argument expected" というエラーが表示が出ていますが、鍵はコピーされています。


* 疎通確認


ping モジュールで Ansible サーバーと対象サーバーの疎通を確認します。

```
# ansible aix -i inventory/test.yml -m ping
Using /work/ansible-test/ansible.cfg as config file
AIX73 | SUCCESS => {
    "changed": false,
    "ping": "pong"
```

---

### AIX ユーザー作成 playbook

role を使用して、loop ができるような構造です。


```
<ansible home>
│
├── create_aix_user.yml
|
├── ansible.cfg
│
├── group_vars
│   └── aix_user_vars.yml
│
├── inventory
│   └── test.yml
│
└── roles
    └── aix_users
        └── tasks
            └── main.yml

```


https://ibm.github.io/ansible-power-aix/modules/user.html


* <ansible home>/create_aix_user.yml

```create_aix_user.yml
---
- name:  create aix users
  hosts: "{{ target_hosts | default(dummy) }}"
  gather_facts: no

  roles:
   - role: aix_users

```


* <ansible_home_dir>roles/create_aix_user/tasks/main.yml

```
# https://ibm.github.io/ansible-power-aix/modules/user.html
---
- name: "AIXユーザー [{{ aix_user.aix_user_name }}] を作成または更新します"
  ibm.power_aix.user:
   name: "{{ aix_user.aix_user_name }}"
   state: present
   password: "{{ aix_user.aix_user_password if aix_user.aix_user_password != '' else omit }}"
   change_passwd_on_login: "{{ true if aix_user.user_change_passwd_on_login | default(false) else omit }}"
   load_module: "{{ aix_user.user_load_module if aix_user.user_load_module is defined and aix_user.user_load_module else omit }}"
   attributes: "{{ aix_user.aix_user_attributes | dict2items | selectattr('value', '!=', '') | list | items2dict }}"
  loop: "{{ aix_users }}"
  loop_control:
      loop_var: aix_user
```





### ユーザー変数ファイル

* <ansible home>/group_vars/aix_user_vars.yml


```group_vars/aix_user_vars.yml
---
---
# attribute https://www.ibm.com/docs/en/aix/7.3.0?topic=c-chuser-command
# --- 基本ユーザー情報 ---
# 作成・更新するユーザー名を指定します (必須)
#aix_user_name: "sampleuser"
# パスワードを設定する場合に指定します。空文字列 ('') の場合はパスワード設定をスキップします。
# 初回作成時やパスワード変更時に設定してください。
#aix_user_password: "YourSecurePassword!1"
# 初回ログイン時にパスワードを設定
#change_passwd_on_login = true or false
# ロード可能 I&A モジュールを指定
#load_module = files or LDAP
# --- chuser 属性リスト ---
# 設定したい属性の値を入力してください。
# 値が空文字列 ('') の属性は、設定対象から自動的に除外されます。
#aix_user_attributes:
# --- 一般的な属性の例 ---
#home: "/home/sampleuser"
#gecos: "Ansible test user create" # Supplies general information about the user specified by the Name parameter.
#shell: "/usr/bin/ksh"
#groups: "staff"
#id: "" # 例: IDをシステムに自動割り当てさせたい場合は空のままにします
#pgrp: "staff" # 例: プライマリグループ
#umask: "022" # 例: デフォルトのumask値
# --- 設定可能な　attributeリスト (アルファベット順) ---
#account_locked: "" # "true" または "false"
#admin: "" # "true" または "false"
#admgroups: "" # コンマ区切りのグループリスト (例: "system,security")
#auditclasses: "" # コンマ区切りの監査クラス (例: "general,objects,events")
#auth1: "" # 第一認証メソッド名 (例: "SYSTEM")
#auth2: "" # 第二認証メソッド名
#capabilities: "" # login コマンドまたは su コマンドによってユーザーに認可する特権 (機能) を定義
# (CAP_AACCT,CAP_ARM_APPLICATION,CAP_BYPASS_RAC_VMM,CAP_EWLM_AGENT,CAP_NUMA_ATTACH,CAP_PROPAGATE)
#core: "" # ソフトコアファイルサイズ (512バイトブロック単位) (例: "2048")
#core_compress: "" # コア・ファイル圧縮を使用可能または使用不可にする
#core_hard: "" # ユーザーのプロセスが作成できる最大のコア・ファイルを指定(512バイトブロック単位)
#core_path: "" # コア・ファイル・パス指定を使用可能または使用不可にする
#core_pathname: "" # core_path 属性がオンに設定されている場合に、コア・ファイルを置くために使用される場所を指定
#cpu: "" # ソフトCPU時間制限 (秒単位) (例: "-1" は無制限)
#cpu_hard: "" # ユーザーのプロセスが使用できるシステム装置時間の最大値 (秒数) を識別
#daemon: "" #
#data: "" # ソフトデータセグメントサイズ (512バイトブロック単位) (例: "262144")
#data_hard: "" # ユーザーのプロセスのための最大データ・セグメントを指定
#dce_export # DCE エクスポート操作時に、DCE ユーザー情報をもつローカル・ユーザー情報を DCE レジストリーが上書きできるようにする
#default_roles: "" # コンマ区切りのデフォルトロール (例: "UserAdmin")
#dictionlist: "" # パスワード辞書ファイルのパス (例: "/usr/share/dict/words")
#domains: "" # ユーザーがアクセス可能なドメイン (コンマ区切り)
#expires: "" # アカウント有効期限 (MMDDhhmmYYYY形式) (例: "031523592025")
#fsize: "" # ソフトファイルサイズ制限 (512バイトブロック単位) (例: "2097151")
#fsize_hard: "" #
#histexpire: "" # パスワード履歴の有効期限 (週単位) (例: "26")
#histsize: "" # 保持する過去のパスワード数 (例: "8")
#login: "" # ログインを許可するかどうか ("true" または "false")
#logintimes: "" # ログイン可能時間 (例: "MON-FRI,0800-1700")
#loginretries: "" # ログイン失敗許容回数 (例: "3")
#maxage: "" # パスワード最大有効期間 (週単位) (例: "13")
#maxexpired: "" # パスワード有効期限切れ後の猶予期間 (週単位) (例: "2")
#maxrepeats: "" # パスワード内で同じ文字を繰り返せる最大回数 (例: "2")
#maxulogs: "" # ユーザーごとの並行ログインの最大数を指定
#minage: "" # パスワード最小有効期間 (週単位) (例: "1")
#minalpha: "" # パスワードに必要な英字の最小文字数 (例: "1")
#mindiff: "" # 新パスワードと旧パスワードで異なる必要がある最小文字数 (例: "3")
#minlen: "" # パスワードの最小長 (例: "8")
#minother: "" # パスワードに必要な英字/数字以外の文字の最小数 (例: "1")
#nofiles: "" # maxfiles と同義 (例: "2000")
#nofiles_hard: "" # ユーザー・プロセスが一度にオープンさせることができるファイル・ディスクリプターの数のハード制限を定義
#nproc: "" # ユーザーが一度に実行させることができるプロセス数のソフト制限を定義
#nproc_hard: "" # ユーザーが一度に実行させることができるプロセス数のハード制限を定義
#pgrp: "" # ユーザーの 1 次グループを識別
#projects: "" # ユーザーのプロセスを割り当てることができるプロジェクトのリストを 定義
#pwdchecks: "" # パスワード制約をチェックする外部メソッドのパス (コンマ区切り)
#pwdwarntime: "" # パスワード有効期限切れの警告を開始する日数 (例: "7")
#rcmds: "" # rコマンド (rsh、 rexec、および rcp) のリモート実行を制御
#rlogin: "" # telnet コマンドまたは rlogin コマンドを使用して、 リモート・ロケーションからアカウントにアクセスできるようにする
#roles: "" # ユーザーに割り当てるロール (コンマ区切り) (例: "UserAdmin,SecurityAdmin")
#rss: "" # ソフト実メモリサイズ制限 (512バイトブロック単位) (例: "65536")
#rss_hard: "" #　　ユーザーのプロセスが割り当て可能な物理メモリーの最大量
#shell: "" #　　セッション開始時にユーザー用に実行されるプログラムを定義
#stack: "" # ソフトスタックサイズ (512バイトブロック単位) (例: "65536")
#stack_hard: "" # ハードスタックサイズ (512バイトブロック単位) (例: "65536")
#su: "" # ユーザーへのsuを許可するかどうか ("true" または "false")
#sugroups: "" # このユーザーにsuできるグループ (例: "system,staff", "ALL")
#sysenv: "" # ログイン時に設定される環境変数 (例: "LANG=ja_JP,MAIL=/var/spool/mail/$(logname)")
#threads: ""　　　　　　　　　　　　　　　　　　　　　　　　# ユーザー・プロセスが作成できるスレッドの最大数のソフト制限を指定
#threads_hard: "" # ユーザー・プロセスが作成できるスレッドの最大可能数を指定
#tpath: "" # トラステッドパスか ("on", "nosak", "notsh")
#ttys: "" # ログインを許可するtty (コンマ区切り) (例: "/dev/pts/1,/dev/tty0")
#usrenv: "" # ユーザー環境に設定する変数 (例: "HOME=/home/sampleuser,LOGIN=/usr/bin/ksh")
#efs_keystore_access: "" # ユーザー鍵ストアのデータベース・タイプを指定
#efs_adminks_access: "" # efs_admin 鍵ストアのデータベース・タイプ
#efs_initialks_mode: "" # ユーザー鍵ストアの初期モードを指定
#efs_allowksmodechangebyuser: "" # モードを変更できるようにするかどうかを指定
#efs_keystore_algo: "" # 鍵ストアの作成中にユーザーの秘密鍵を生成するために使用されるアルゴリズムを指定
#efs_file_algo: "" # ユーザー・ファイル用の暗号化アルゴリズムを指定
#minloweralpha: "" # 新しいパスワードに含める必要のある英小文字の最小数を定義
#minupperalpha: "" # 新しいパスワードに含める必要のある英大文字の最小数を定義
#mindigit: "" # 新しいパスワードに含める必要のある数字の最小数を定義
#minspecialchar: "" # 新しいパスワードに含める必要のある特殊文字の最小数を定義
aix_users:
- aix_user_name: "sampleuser"
  aix_user_password: "YourSecurePassword!1"
  change_passwd_on_login: "true"
  load_module: "LDAP"
  aix_user_attributes:
    home: "/home/sampleuser"
    gecos: "First Sample User"
    shell: "/usr/bin/ksh"
    groups: "staff"
    id: "121"
    pgrp: "staff"
    umask: "022"
    account_locked: ""
    admin: ""
    admgroups: ""
    auditclasses: ""
    auth_name: ""
    core: ""
    cpu: ""
    data: ""
    default_roles: ""
    dictionlist: ""
    domains: ""
    expires: ""
    fsize: "-1"
    histexpire: ""
    histsize: ""
    login: ""
    logintimes: ""
    loginretries: ""
    maxage: "22"
    maxexpired: ""
    maxrepeats: "10"
    minlen: "1"
    capabilities: "CAP_NUMA_ATTACH,CAP_BYPASS_RAC_VMM,CAP_PROPAGATE"
- aix_user_name: "sampleuser2"
  aix_user_password: "AnotherSecurePassword!2"
  change_passwd_on_login: ""
  load_module: ""
  aix_user_attributes:
    home: "/home/sampleuser2"
    gecos: "Second Sample User"
    shell: "/usr/bin/ksh"
    groups: "staff"
    id: "211"
    pgrp: "staff"
    umask: "022"
    account_locked: "false"
    admin: "true"
    fsize: "-1"
    logintimes: ""
    loginretries: ""
    maxage: "4"
    maxexpired: "4"
    maxfiles: ""
    maxrepeats: ""
    minalpha: ""
    minage: "12"
    minchar: ""
    mindiff: "1"
    minlen: "1"
    minother: ""
    passwd_set: ""
    pwdchecks: ""
    pwdwarntime: "8"
    capabilities: "CAP_NUMA_ATTACH"
```


---

### ユーザー作成実行

`ansible-playbook create_aix_user.yml -e "@./group_vars/aix_user_vars.yml" -e "target_hosts=aix"` というコマンドで実行します。

```
# ansible-playbook create_aix_user.yml -e "@./group_vars/aix_user_vars.yml" -e "target_hosts=aix"
Using /work/ansible-test/ansible.cfg as config file

PLAY [create aix users] **************************************************************************************************************
Sunday 22 June 2025  19:30:13 -0400 (0:00:00.050)       0:00:00.050 ***********

TASK [aix_users : AIXユーザー [{{ aix_user.aix_user_name }}] を作成または更新します] ****************************************************************
changed: [AIX73] => (item={'aix_user_name': 'sampleuser', 'aix_user_password': 'YourSecurePassword!1', 'change_passwd_on_login': 'true', 'load_module': 'LDAP', 'aix_user_attributes': {'home': '/home/sampleuser', 'gecos': 'First Sample User', 'shell': '/usr/bin/ksh', 'groups': 'staff', 'id': '121', 'pgrp': 'staff', 'umask': '022', 'account_locked': '', 'admin': '', 'admgroups': '', 'auditclasses': '', 'auth_name': '', 'core': '', 'cpu': '', 'data': '', 'default_roles': '', 'dictionlist': '', 'domains': '', 'expires': '', 'fsize': '-1', 'histexpire': '', 'histsize': '', 'login': '', 'logintimes': '', 'loginretries': '', 'maxage': '22', 'maxexpired': '', 'maxrepeats': '10', 'minlen': '1', 'capabilities': 'CAP_NUMA_ATTACH,CAP_BYPASS_RAC_VMM,CAP_PROPAGATE'}}) => {"aix_user": {"aix_user_attributes": {"account_locked": "", "admgroups": "", "admin": "", "auditclasses": "", "auth_name": "", "capabilities": "CAP_NUMA_ATTACH,CAP_BYPASS_RAC_VMM,CAP_PROPAGATE", "core": "", "cpu": "", "data": "", "default_roles": "", "dictionlist": "", "domains": "", "expires": "", "fsize": "-1", "gecos": "First Sample User", "groups": "staff", "histexpire": "", "histsize": "", "home": "/home/sampleuser", "id": "121", "login": "", "loginretries": "", "logintimes": "", "maxage": "22", "maxexpired": "", "maxrepeats": "10", "minlen": "1", "pgrp": "staff", "shell": "/usr/bin/ksh", "umask": "022"}, "aix_user_name": "sampleuser", "aix_user_password": "YourSecurePassword!1", "change_passwd_on_login": "true", "load_module": "LDAP"}, "ansible_loop_var": "aix_user", "changed": true, "msg": "Username is created SUCCESSFULLY: sampleuser\nPassword is set successfully for the user: sampleuser"}
changed: [AIX73] => (item={'aix_user_name': 'sampleuser2', 'aix_user_password': 'AnotherSecurePassword!2', 'change_passwd_on_login': '', 'load_module': '', 'aix_user_attributes': {'home': '/home/sampleuser2', 'gecos': 'Second Sample User', 'shell': '/usr/bin/ksh', 'groups': 'staff', 'id': '211', 'pgrp': 'staff', 'umask': '022', 'account_locked': 'false', 'admin': 'true', 'fsize': '-1', 'logintimes': '', 'loginretries': '', 'maxage': '4', 'maxexpired': '4', 'maxfiles': '', 'maxrepeats': '', 'minalpha': '', 'minage': '12', 'minchar': '', 'mindiff': '1', 'minlen': '1', 'minother': '', 'passwd_set': '', 'pwdchecks': '', 'pwdwarntime': '8', 'capabilities': 'CAP_NUMA_ATTACH'}}) => {"aix_user": {"aix_user_attributes": {"account_locked": "false", "admin": "true", "capabilities": "CAP_NUMA_ATTACH", "fsize": "-1", "gecos": "Second Sample User", "groups": "staff", "home": "/home/sampleuser2", "id": "211", "loginretries": "", "logintimes": "", "maxage": "4", "maxexpired": "4", "maxfiles": "", "maxrepeats": "", "minage": "12", "minalpha": "", "minchar": "", "mindiff": "1", "minlen": "1", "minother": "", "passwd_set": "", "pgrp": "staff", "pwdchecks": "", "pwdwarntime": "8", "shell": "/usr/bin/ksh", "umask": "022"}, "aix_user_name": "sampleuser2", "aix_user_password": "AnotherSecurePassword!2", "change_passwd_on_login": "", "load_module": ""}, "ansible_loop_var": "aix_user", "changed": true, "msg": "Username is created SUCCESSFULLY: sampleuser2\nPassword is set successfully for the user: sampleuser2"}

PLAY RECAP ***************************************************************************************************************************
AIX73                      : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Sunday 22 June 2025  19:30:15 -0400 (0:00:02.608)       0:00:02.659 ***********
===============================================================================
aix_users : AIXユーザー [{{ aix_user.aix_user_name }}] を作成または更新します ---------------------------------------------------------------- 2.61s
```


なお、-e で変数を引数に指定していますが、 group_vars/aix.yml という名前で配置すると、インベントリ内の [aix] グループに属するホストに対して自動で変数が適用されるため、aix グループには引数指定が不要になる方法もあります。

---

### ユーザー作成確認

shell モジュールを使用して、Ansible サーバーから対象サーバーにコマンドを実行します。

```
# ansible aix -m shell -a "lsuser sampleuser"
Using /work/ansible-test/ansible.cfg as config file
AIX73 | CHANGED | rc=0 >>
sampleuser id=121 pgrp=staff groups=staff home=/home/sampleuser shell=/usr/bin/ksh gecos=First Sample User login=true su=true rlogin=true daemon=true admin=false sugroups=ALL admgroups= tpath=nosak ttys=ALL expires=0 auth1=SYSTEM auth2=NONE umask=22 registry=files SYSTEM=compat logintimes= loginretries=0 pwdwarntime=5 account_locked=false minage=4 maxage=22 maxexpired=4 minalpha=2 minloweralpha=1 minupperalpha=1 minother=1 mindigit=1 minspecialchar=1 mindiff=0 maxrepeats=10 minlen=1 histexpire=52 histsize=4 pwdchecks= dictionlist= capabilities=CAP_NUMA_ATTACH,CAP_BYPASS_RAC_VMM,CAP_PROPAGATE default_roles= datecreated=1565836317 fsize=-1 cpu=-1 data=-1 stack=65536 core=2097151 rss=65536 nofiles=2000 roles=
```

```
# ansible aix -m shell -a "lsuser sampleuser2"
Using /work/ansible-test/ansible.cfg as config file
AIX73 | CHANGED | rc=0 >>
sampleuser2 id=211 pgrp=staff groups=staff home=/home/sampleuser2 shell=/usr/bin/ksh gecos=Second Sample User login=true su=true rlogin=true daemon=true admin=true sugroups=ALL admgroups= tpath=nosak ttys=ALL expires=0 auth1=SYSTEM auth2=NONE umask=22 registry=files SYSTEM=compat logintimes= loginretries=0 pwdwarntime=8 account_locked=false minage=12 maxage=4 maxexpired=4 minalpha=2 minloweralpha=1 minupperalpha=1 minother=1 mindigit=1 minspecialchar=1 mindiff=1 maxrepeats=8 minlen=1 histexpire=52 histsize=4 pwdchecks= dictionlist= capabilities=CAP_NUMA_ATTACH default_roles= datecreated=1565836318 fsize=-1 cpu=-1 data=-1 stack=65536 core=2097151 rss=65536 nofiles=2000 roles=
```

変数通りに sampleuser, sampleuser2 が作成されています。



---

### 当 playbook のこだわり

・hosts 指定を変数化し、コマンドライン指定
・ibm.power_aix.user モジュールを使用
・role 構造
・loop により変数指定で複数ユーザー作成が可能
・変数の change_passwd_on_login, load_module, 各attributes は 空白の場合は無視するロジックを追加



---

### 作成したユーザーの削除

shell モジュールを使用してAnsible管理サーバーから対象サーバーのユーザーを削除します。


```
# ansible aix -m shell -a "rmuser sampleuser"
Using /work/ansible-test/ansible.cfg as config file
AIX73 | CHANGED | rc=0 >>


# ansible aix -m shell -a "rmuser sampleuser2"
Using /work/ansible-test/ansible.cfg as config file
AIX73 | CHANGED | rc=0 >>
```


---

### おわりに

コード生成AIを使用してドラフトを作成し、あとは自分の望み通りに詳細修正する形でコーディングしています。
コード構造を読み込ませたりが必要そうですが、詳細部分も生成AIができる方法を探せたらと思います。

パスワードのハッシュ化や、aix_group モジュールの組み合わせが次の課題です。


<br>
以上です。