Ansible:ansible-galaxyコマンドでroleのひな型を作成
ansible-galaxyコマンドを使うことでroleのひな型を作成できます。
roleに関連するディレクトリやmain.ymlを作成する手間がすこし省けるかも。
以下がコマンドとその実行結果です。
tasksやhandllersなどのディレクトリ、そして、ディレクトリの下にmain.ymlが作成されています。ここから必要なディレクトリ以外は削除していけばよさそうです。
$ ansible-galaxy init test_role - Role test_role was created successfully $ $ tree test_role/ test_role/ |-- README.md |-- defaults | `-- main.yml |-- files |-- handlers | `-- main.yml |-- meta | `-- main.yml |-- tasks | `-- main.yml |-- templates |-- tests | |-- inventory | `-- test.yml `-- vars `-- main.yml 8 directories, 8 files
ちなみに、main.ymlの中身は基本的にコメント行のみです。
--- # tasks file for test_role
--- # vars file for test_role
role-skeltonオプション
ansible-galaxy initに--role-skeletonオプションというのがありました。
このオプションを使えば、自身で作成したロールをひな型として新たにロールを作成することができるようです。
ためしに、test_roleというroleをひな型としてtest_role2というroleを作ることにします。
test_roleは以下のような構造になっています。
$ tree test_role test_role |-- README.md |-- files | `-- hello.txt |-- tasks | `-- main.yml `-- vars 3 directories, 3 files $ $ cat test_role/tasks/main.yml --- - name: copied hello.txt copy: src: hello.txt dest: /tmp/hello.txt mode: 0644
ansible-galaxy initの実行結果が以下になります。
test_roleのディレクトリ構造と同じようにtest_role2が作られているのが確認できました。また、tasks/main.ymlの中身もまるっきり同じ内容になっています。(普通のディレクトリコピーと何か違うのだろうか…)
$ ansible-galaxy init --role-skeleton ./test_role test_role2 - Role test_role2 was created successfully $ $ tree test_role2/ test_role2/ |-- README.md |-- files | `-- hello.txt |-- tasks | `-- main.yml `-- vars 3 directories, 3 files $ $ cat test_role2/tasks/main.yml --- - name: copied hello.txt copy: src: hello.txt dest: /tmp/hello.txt mode: 0644
Ansible:fileモジュールによるディレクトリの作成
*ansible 2.9.6での設定を想定しています
ansibleでディレクトリを作成する場合、fileモジュールを使います。
fileモジュールのstateオプションにdirectoryを指定することでディレクトリが作成できます。
オプション | 説明 |
---|---|
path | 作成するディレクトリのパス |
owner | 所有者 |
group | 所有グループ |
mode | ディレクトリのパーミッション |
以下は、/tmpディレクトリの下にtest1というディレクトリを作るプレイブックです。
--- - hosts: all become: yes tasks: - name: test directory created file: path: "/tmp/test1" state: directory owner: "root" group: "root" mode: "775"
複数のディレクトリを作成
loopを使えば複数のディレクトリを1つのtaskで作ることができます。
--- - hosts: all become: yes tasks: - name: test directory created file: path: "{{ item.path }}" state: directory owner: "{{ item.owner }}" group: "{{ item.group }}" mode: "{{ item.mode }}" loop: - path: "/tmp/test1" owner: "root" group: "root" mode: "775" - path: "/tmp/test2" owner: "root" group: "root" mode: "775"
リモートホスト(CentOS7)に対して実行した結果が以下になります。
test1、test2が作成されています。
$ ansible-playbook -i hosts make_dir/make_multi_dir.yml PLAY [all] ********************************************************************* TASK [Gathering Facts] ********************************************************* ok: [CentOS7.6] TASK [test directory created] ************************************************** changed: [CentOS7.6] => (item={u'owner': u'root', u'path': u'/tmp/test1', u'group': u'root', u'mode': u'775'}) changed: [CentOS7.6] => (item={u'owner': u'root', u'path': u'/tmp/test2', u'group': u'root', u'mode': u'775'}) PLAY RECAP ********************************************************************* CentOS7.6 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@centos7 tmp]# ll /tmp 合計 0 drwxrwxr-x. 2 root root 6 1月 1 04:58 test1 drwxrwxr-x. 2 root root 6 1月 1 04:58 test2
再帰的なディレクトリ作成
recurseオプションにyesを指定することで再帰的にディレクトリを作成することができます。
--- - hosts: all become: yes tasks: - name: test directory created file: path: "/tmp/test1/test1_1/test1_1_1" state: directory owner: "root" group: "root" mode: "775" recurse: yes
リモートホストに対して実行した結果が以下になります。
test1、test1_1、test1_1_1が作成されていることが確認できました。
$ ansible-playbook -i hosts make_dir/make_dir_recurse.yml PLAY [all] ********************************************************************* TASK [Gathering Facts] ********************************************************* ok: [CentOS7.6] TASK [test directory created] ************************************************** changed: [CentOS7.6] PLAY RECAP ********************************************************************* CentOS7.6 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@centos7 tmp]# ll /tmp/ 合計 0 drwxrwxr-x. 3 root root 21 1月 1 04:50 test1 [root@centos7 tmp]# [root@centos7 tmp]# ll /tmp/test1/ 合計 0 drwxrwxr-x. 3 root root 23 1月 1 04:50 test1_1 [root@centos7 tmp]# [root@centos7 tmp]# ll /tmp/test1/test1_1/ 合計 0 drwxrwxr-x. 2 root root 6 1月 1 04:50 test1_1_1 [root@centos7 tmp]#
以下のようなプレイブックをつくりました。
プレイブックでは/tmp/test1/test1_1、/tmp/test1/test1_2を再帰的に作成します。
この時、ディレクトリはどのような順番で作成されるのでしょうか?
また、test1の所有者・権限はどうなるのでしょうか?
--- - hosts: all become: yes tasks: - name: test directory created file: path: "{{ item.path }}" state: directory owner: "{{ item.owner }}" group: "{{ item.group }}" mode: "{{ item.mode }}" loop: - path: "/tmp/test1/test1_1" owner: "root" group: "root" mode: "775" - path: "/tmp/test1/test1_2" owner: "muknow" group: "muknow" mode: "644"
$ ansible-playbook -i hosts make_dir/make_dir_recurse2.yml -v Using /home/muknow/.ansible.cfg as config file PLAY [all] ********************************************************************* TASK [Gathering Facts] ********************************************************* ok: [CentOS7.6] TASK [test directory created] ************************************************** changed: [CentOS7.6] => (item={u'owner': u'root', u'path': u'/tmp/test1/test1_1', u'group': u'root', u'mode': u'775'}) => {"ansible_loop_var": "item", "changed": true, "gid": 0, "group": "root", "item": {"group": "root", "mode": "775", "owner": "root", "path": "/tmp/test1/test1_1"}, "mode": "0775", "owner": "root", "path": "/tmp/test1/test1_1", "secontext": "unconfined_u:object_r:user_tmp_t:s0", "size": 6, "state": "directory", "uid": 0} changed: [CentOS7.6] => (item={u'owner': u'muknow', u'path': u'/tmp/test1/test1_2', u'group': u'muknow', u'mode': u'644'}) => {"ansible_loop_var": "item", "changed": true, "gid": 1001, "group": "muknow", "item": {"group": "muknow", "mode": "644", "owner": "muknow", "path": "/tmp/test1/test1_2"}, "mode": "0644", "owner": "muknow", "path": "/tmp/test1/test1_2", "secontext": "unconfined_u:object_r:user_tmp_t:s0", "size": 6, "state": "directory", "uid": 1001} PLAY RECAP ********************************************************************* CentOS7.6 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@centos7 tmp]# ll /tmp 合計 0 drwxrwxr-x. 4 root root 36 1月 1 05:16 test1 [root@centos7 tmp]# ll /tmp/test1/ 合計 0 drwxrwxr-x. 2 root root 6 1月 1 05:16 test1_1 drw-r--r--. 2 muknow muknow 6 1月 1 05:16 test1_2
/tmp/test1の所有者・所有グループはrootとなりました。
実行ログを見ると、1回目の実行(1回目のchanged)で/tmp/test1、/tmp/test1_1が作成され、2回目の実行(2回目のchanged)で/tmp/test1/test1_2が作成されます。所有者やパーミッションはディレクトリの作成時に設定されるようです。2回目の実行時は/tmp/test1は既に存在するため作成されず、その結果、/tmp/test1の所有者・所有グループはrootとなったようです。
Ansible:copyモジュールについてメモ
*ansible 2.9.6での設定を想定しています
copyモジュールはコントロールノードのファイルをリモートホストへコピーするモジュールです。
srcでコピー元のファイル、destでコピー先を指定します。
--- - hosts: all tasks: - name: copied hello.txt copy: src: hello.txt dest: /tmp/hello.txt
mode:ファイルの権限設定
modeオプションをつけることでコピー先のファイルの権限を設定できます。
modeオプションをつけない場合、コピー元のファイルと同じ権限でコピー先のファイルは作られます。
linuxのchmodコマンドのように8進数で権限を指定できます。ansibleに8進数として認識させるため「0644」のように先頭に0をつけるのがポイントです。先頭に0をつけないとansibleに10進数として認識されてしまい予期しない動作をする可能性があります。
--- - hosts: all tasks: - name: copied hello.txt copy: src: hello.txt dest: /tmp/hello.txt mode: 0644
ちなみに、'644'のようにシングルクォートで囲んでもOKです。
--- - hosts: all tasks: - name: copied hello.txt copy: src: hello.txt dest: /tmp/hello.txt mode: '644'
force:コピーする条件を指定
forceオプションでyesを指定すれば、コピー先に既にファイルが存在する場合、ファイルの中身を比較して差分がある場合はコピーを実施します。noを指定した場合、コピー先にファイルが存在しない場合にのみ、コピーを実施します。なお、forceオプションはデフォルトでyesが指定されています。
--- - hosts: all tasks: - name: copied hello.txt copy: src: hello.txt dest: /tmp/hello.txt mode: 0644 force: no
backup:コピー時にバックアップを取得
backupオプションでyesを指定すると、コピー先に既にファイルが存在する場合、そのファイルのバックアップを取得します。
バックアップはコピー先のファイルが存在するディレクトリと同じディレクトリに作成されます。バックアップのファイル名は「(元のファイル名).(タイムスタンプ)」となります。
下の例であればバックアップとして「/tmp/hello.txt.2020-12-31@12:00:11~」のようなファイルが作成されます。
--- - hosts: all tasks: - name: copied hello.txt copy: src: hello.txt dest: /tmp/hello.txt mode: 0644 backup: yes
GitLabからgit cloneできない
VPSを借りてGitLabサーバを構築してみました。構築も終わり、テスト用プロジェクトを作ってgit cloneしようとしたところ以下のようなエラーがでてクローンできませんでした。
$ git clone https://gitlab.●●●●●●●●/muknow/test.git Cloning into 'test'... fatal: unable to access 'https://gitlab.●●●●●●●●/muknow/test.git/': server certificate verification failed. CAfile: /etc/ssl/certs/ca-certificates.crt CRLfile: none
原因
調べてみるとサーバ構築時に自己証明書(オレオレ証明書)を使っていたことが原因でした。サーバ側の証明書の妥当性が確認できず、アクセスできていなかったようです。(エラーメッセージにもserver certificate verification failedと書かれていますね)
解決策
サーバ側の自己証明書をクライアント側に登録します。
以下はUbuntuで実施した内容です。
手順1:自己証明書をダンプする
登録する必要のある証明書をダンプします。ダンプにはopensslコマンドを使います。
$ HOST=gitlab.●●●●●●●● $ PORT=443 $ openssl s_client -connect ${HOST}:${PORT} -showcerts </dev/null 2>/dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > my_gitlab.crt
my_gitlab.crtは以下のようになっています。
-----BEGIN CERTIFICATE----- (省略) -----END CERTIFICATE-----
コマンドについてざっくり説明
- opensslコマンドのs_clientはSSL/TLS通信をおこなうクライアントプログラムです。
- s_clientでは-quietをつけなければ接続時にサーバ証明書は出力されます。-showcertsをつけることで証明書チェインをすべて出力できます。
- そのままだとサーバに接続されっぱなしの状態となり、コンソールも入力待ちになります。そのため</dev/nullで通信を終了します。2>/dev/nullで標準エラー出力を破棄しています。
- opensslコマンドで得られた結果からsedコマンドにより証明書を抜き出します。
- 証明書はmy_gitlab.crtというファイルに保存します。
手順2:証明書の登録
ダンプした証明書を/usr/share/ca-certificates/に移動します。ファイルの所有者もrootに変更します。
$ mv my_gitlab.crt /usr/share/ca-certificates/
$ chown root:root /usr/share/ca-certificates/my_gitlab.crt
/etc/ca-certificates.confの末尾に「my_gitlab.crt」を追記します。(正確には追加したい証明書の/usr/share/ca-certificatesからの相対パスです)
$ sudo echo "my_gitlab.crt" >> /etc/ca-certificates.conf
最後にupdate-ca-certificatesを実行します。
$ sudo update-ca-certificates
/etc/ssl/certsに/usr/share/ca-certificates/my_gitlab.crtのシンボリックリンクが存在すればOKです。
$ ls /etc/ssl/certs/| grep my_gitlab my_gitlab.pem $ ls -l /etc/ssl/certs/my_gitlab.pem lrwxrwxrwx 1 root root 40 Dec 30 15:03 /etc/ssl/certs/my_gitlab.pem -> /usr/share/ca-certificates/my_gitlab.crt
無事、クローンできました。
$ git clone https://gitlab.●●●●●●●●/muknow/test.git Cloning into 'test'... remote: Enumerating objects: 6, done. remote: Counting objects: 100% (6/6), done. remote: Compressing objects: 100% (2/2), done. remote: Total 6 (delta 0), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (6/6), done.
おわりに
git cloneすることはできましたが、クライアントごとにこの設定をしなければいけないのが面倒ですね…
Powershell:ファイル内の文字列を検索する
linuxだとgrepコマンドを使えば文字列検索できますが、PowerShellだどうするのか知らなかったのでメモです。どうやらSelect-Stringという命令(PowerShellではコマンドレットと呼ぶ)でできそうです。
試しにtest1.txtというファイルを用意して、「あああ」という文字を検索してみました。が検索ヒットせず…
PS C:\test> Get-Content .\test1.txt あああ かかか さささ たたた ななな PS C:\test> PS C:\test> Select-String "あああ" .\test1.txt PS C:\test>
どうやら日本語の場合は以下のようにEncodingでdefaultを指定しなければならないようです。指定したところ想定通り結果が得られました。
PS C:\test> Select-String "あああ" .\test1.txt -Encoding default test1.txt:1:あああ PS C:\test>
以下のようにすればカレントフォルダ以下のすべてのtxtファイルを検索できます。
PS C:\test> ls *.txt -Recurse -Force | Select-String "あああ" -Encoding default
Ubuntu:管理者権限でのコマンド実行
*本記事はUbuntu 18.04LTSでの設定を想定しています
suコマンドが使えない
OSインストール直後のUbuntuでsuコマンドを実行すると以下のような結果になり、rootユーザーになれない。Ubuntuではデフォルトでrootユーザーのパスワードが設定されていないため、それが原因らしいです。
muknow@Ubuntu18:~$ su Password: su: Authentication failure
新規ユーザーでsudoを使えるようにする
adduserコマンドやuseraddコマンドを使うことで新規にユーザーを作成できます。
muknow@Ubuntu18:~$ sudo adduser test1
しかし、新規ユーザーにおいてsudo権限でコマンドを実行しようとしてもできません。
test1@Ubuntu18:~$ sudo adduser test2 [sudo] password for test1: test1 is not in the sudoers file. This incident will be reported.
上の出力では「test1はsudoresファイルに記載がない」と怒られています。sudoコマンドを実行するためには/etc/sudoresファイルを編集して、ユーザーに権限を付与しなければならないのです。なお、編集は直接sudoresを書き換えるのではなく、visudoというsudoresを編集する専用のコマンドを使います。
ただ、sudoresを編集せずとも、ユーザーをsudoグループに追加すればsudoコマンドを実行できるようになります。sudoグループはデフォルトで作成されており、sudoresファイル内にもsudoグループに関する設定が記載されています。ちなみに設定の意味は「sudoグループに属するユーザーは、他のすべてのユーザー権限・グループ権限で、すべてのコマンドを実行できる」といった感じです。
muknow@Ubuntu18:~$ sudo cat /etc/sudoers (省略) # Allow members of group sudo to execute any command %sudo ALL=(ALL:ALL) ALL (省略)
ユーザーをグループに追加するにはgpasswdコマンドを使用します。-aオプションがグループに追加するためのオプションです。
muknow@Ubuntu18:~$ sudo gpasswd -a test1 sudo
Adding user test1 to group sudo
idコマンドを実行するとtest1がsudoグループに属していることが確認できます。
muknow@Ubuntu18:~$ id test1 uid=1003(test1) gid=1004(test1) groups=1004(test1),27(sudo)
tshark:出力フォーマットをfieldsに変更
通常、tsharkコマンドを実行すると以下のような形式で出力が得られます。
$ tshark -r test.pcap -Y "http.response" 12 0.270305 104.20.31.112 → 192.168.164.128 HTTP 1442 HTTP/1.1 200 OK (text/html) 55 0.329930 104.20.31.112 → 192.168.164.128 HTTP 789 HTTP/1.1 200 OK (GIF89a) 65 0.333970 104.20.31.112 → 192.168.164.128 HTTP 1134 HTTP/1.1 200 OK (GIF89a) 73 0.351571 104.20.31.112 → 192.168.164.128 HTTP 1074 HTTP/1.1 200 OK (text/css) 109 0.573289 104.31.66.122 → 192.168.164.128 HTTP 640 HTTP/1.1 200 OK (text/html) 137 0.622275 202.32.15.217 → 192.168.164.128 HTTP 1026 HTTP/1.1 200 OK (GIF87a) 149 0.675307 52.196.10.155 → 192.168.164.128 HTTP 1328 HTTP/1.1 200 OK (text/javascript) (省略)
tsharkの-Tオプションでfieldsを指定すれば自分が必要な情報だけを出力するようにフォーマットを変更できます。この時、-eオプションにフィールド名を指定することで出力する情報を設定します。具体的なコマンドは以下のようになります。
$ tshark -r pcapファイル -T fields -e フィールド名1 -e フィールド名2
フィールド名はフィルタに設定できる「ip.addr」や「tcp.dstport」などです。ちなみに、パケット中に指定したフィールドが存在しない場合、その部分には何も出力されません。
具体例として、HTTPレスポンスの送信元IPアドレス、Content-Type、Content-Lengthだけを出力させるようにしてみます。この場合はtsharkの出力結果をtsvファイルとして保存しています。
$ tshark -r test.pcap -Y "http.response" -T fields -e ip.src -e http.content_type -e http.content_length > test.tsv
test.tsvの中身は以下のようになります。
104.20.31.112 text/html 104.20.31.112 image/gif 1787 104.20.31.112 image/gif 19990 104.20.31.112 text/css 104.31.66.122 text/html 202.32.15.217 image/gif 15782 52.196.10.155 text/javascript 966 (省略)
-Eオプションでheaderを指定すればフィールド名をヘッダとして出力させることもできます。また、区切り文字をタブ以外の文字にしたい場合は-Eオプションでseparatorを指定します。下記コマンドではヘッダの出力と区切り文字に「,」を使うことを指定し、出力結果をtest.csvファイルに保存しています。
$ tshark -r test.pcap -Y "http.response" -T fields -E header=y -E separator=, -e ip.src -e http.content_type -e http.content_length > test.csv
test.csvの中身は以下のようになります。
ip.src,http.content_type,http.content_length 104.20.31.112,text/html, 104.20.31.112,image/gif,1787 104.20.31.112,image/gif,19990 104.20.31.112,text/css, 104.31.66.122,text/html, 202.32.15.217,image/gif,15782 52.196.10.155,text/javascript,966 (省略)