はじめに
冪等性を担保しつつ、ansibleでec2のSSH port番号を22から50001する手順をまとめました。
環境
- ローカル環境
- M1 Mac
- MacOS Monterey 12.6
- サーバ
- Amazon Linux2
ansibleインストール
ローカルにansibleをインストールします。
Homebrewでもインストールできますが、pipだと細かいバージョン指定ができるため、pipでのインストールを採用しました。
最新バージョンをインストール場合
$ pip install ansible
バージョン指定
$ pip install ansible==6.5.0
インストールできたか確認するため、バージョンを確認します。
$ pip list
Package Version
------------ -------
ansible 6.5.0
ansible-core 2.13.6
EC2を起動
EC2を起動しますが、起動方法は、省略します。
セキュリティーグループは、SSHポート番号の22とカスタムポート番号50001のインバウンドルールを許可します。
また、パブリック IP の自動割り当ては、有効化します。
ansibleのプロジェクトを作成
playbookというディレクトリを作成し、その中に、hostsファイル、playbook.ymlファイル、sshdのrolesディレクトリを作成します。
$ mkdir playbook
$ cd playbook
$ touch hosts playbook.yml
$ ansible-galaxy init --init-path="roles" sshd
$ tree
.
├── hosts
├── playbook.yml
└── roles
└── sshd
├── README.md
├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── tasks
│ └── main.yml
├── templates
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml
使わないディレクトリを削除し、以下のようにします。
$ tree
.
├── hosts
├── playbook.yml
└── roles
└── sshd
├── handlers
│ └── main.yml
└── tasks
└── main.yml
4 directories, 4 files
hostsファイル作成
以下のように記載します。
本来なら、rolesのvarsのmain.ymlにcustom_ssh_port=50001
などを書くのがよいですが、面倒なので、hostsファイルにまとめました。
IPは、サーバーのパブリックIPを記載してください。
[web] # 記載されたIPに対して接続
11.11.11.11
[web:vars] #[web]で使う変数を定義
ansible_ssh_port=22
ansible_user=ec2-user
__working_user=ec2-user
ansible_python_interpreter=/usr/bin/python2
# custom ssh port (49152~65535)
custom_ssh_port=50001
# pem key path
ansible_ssh_private_key_file=~/.ssh/test.pem
playbook.yml作成
- name: Change port
hosts: web
become: yes
gather_facts: false
roles:
- sshd
次の節でlocal_action
モジュールを使用するため、gather_facts
は、false
にする必要があります。
- gather_facts
- 対象ホストの情報をansible_facts変数というものに格納し、tasks内の変数で使用することができます。
rolesのsshdディレクトリ配下を作成
tasksとhandlersのmain.ymlのみ記載します。ほかは使いません。
# port22 でSSH接続する。タイムアウトは5秒で、接続失敗しても次に進む
- name: Connect default ssh port
local_action: wait_for port={{ansible_ssh_port}} timeout=5 host={{inventory_hostname}}
register: default_port
ignore_errors: true
become: False
# port22 で失敗した場合、port 50001でSSH接続する。タイムアウトは5秒
- name: Connect custom ssh port
local_action: wait_for port={{custom_ssh_port}} timeout=5 host={{inventory_hostname}}
register: custom_port
when: default_port.elapsed >= 5
become: False
# port22 でタイムアウトし、port50001でSSH接続成功した場合、ansible_ssh_portを50001に変える
- name: set ansible_ssh_port custom_ssh_port
set_fact: ansible_ssh_port={{custom_ssh_port}}
when: default_port.elapsed >= 5 and custom_port.elapsed < 5
become: False
# 現在port22でSSH接続している場合、/etc/ssh/sshd_configのPortを50001に書き換える
- name: Rewrite custom_ssh_port
lineinfile:
dest: /etc/ssh/sshd_config
regexp: '^#Port'
line: 'Port {{custom_ssh_port}}'
notify: Restart sshd
when: ansible_ssh_port == 22
# ssh接続時のパスワード認証を無効
- name: Disabling password authentication
lineinfile:
dest: /etc/ssh/sshd_config
regexp: '^PasswordAuthentication'
insertafter: '^#PasswordAuthentication'
line: PasswordAuthentication no
notify: Restart sshd
# ssh接続時のチャレンジ/レスポンス認証を無効
- name: Disabling Challenge-Response Authentication
lineinfile:
dest: /etc/ssh/sshd_config
regexp: '^ChallengeResponseAuthentication'
insertafter: '^#ChallengeResponseAuthentication'
line: ChallengeResponseAuthentication no
notify: Restart sshd
# rootユーザーのログイン無効
- name: Disabling root user login
lineinfile:
dest: /etc/ssh/sshd_config
regexp: '^PermitRootLogin'
insertafter: '^#PermitRootLogin'
line: PermitRootLogin no
notify: Restart sshd
# sshdの設定が変更された場合、再起動する
- name: Restart sshd
service:
name: sshd
state: restarted
モジュールの説明
- local_action
- リモートホストではなくローカルで実行したい場合に使用します。今回であれば、ローカルからSSH接続できます。
- wait_for
- SSH接続のアクション時、ポートが応答あるまで待つために使用します
- timeoutやhost先を指定できます。
- SSH接続のアクション時、ポートが応答あるまで待つために使用します
- register
- 処理結果を変数の中に一時的に保管できます
- elapsed
- 経過時間を示します
- become
- そのモジュールを root 権限で実行できます
- set_fact
- 新たな変数を定義できます。
- 今回は、ansible_ssh_portの値が元々22だったのをcustom_ssh_port(50001)に上書きしました
- 新たな変数を定義できます。
- lineinfile
- ファイルを行単位で編集できます
- dest
- 編集するファイルのパスを指定
- line
- 置換または挿入する文字列を指定
- regexp
- 指定した正規表現にマッチした行を、lineで指定した文字列に置き換えます
- lineで指定した文字列と、同じ場合は何もしません
- insertafter
- regexp にマッチする行が無かった場合、ここに指定した正規表現にマッチした次の行に、lineで指定した文字列を挿入する。
- それにもマッチしない場合はファイル末尾に、lineで指定した文字列が挿入されます。
- regexp にマッチする行が無かった場合、ここに指定した正規表現にマッチした次の行に、lineで指定した文字列を挿入する。
- notify
- notifyを付与したタスクがchangedになった場合、handlers内に定義されたタスクが実行されます。
- 同じhandlersの呼び出しは1回にまとめらます。notifyを付与している複数のタスクがchangedになっても1度しか実行されません。
- notifyを付与したタスクがchangedになった場合、handlers内に定義されたタスクが実行されます。
ansible実行
ルートディレクトリ配下で、下記コマンドにより、ansibleを実行できます。
$ ansible-playbook -i hosts playbook.yml
詳細なログを出力したい場合、-vv
をつけます
$ ansible-playbook -i hosts playbook.yml -vv
1回目を実行します。
$ ansible-playbook -i hosts playbook.yml -vv
PLAY [Change port] ************************************************************************************************************
TASK [sshd : Connect default ssh port] ****************************************************************************************
ok: [13.231.201.67 -> localhost]
TASK [sshd : Connect custom ssh port] *****************************************************************************************
skipping: [13.231.201.67]
TASK [sshd : set ansible_ssh_port custom_ssh_port] ****************************************************************************
skipping: [13.231.201.67]
TASK [sshd : Rewrite custom_ssh_port] *****************************************************************************************
The authenticity of host '13.231.201.67 (13.231.201.67)' can't be established.
ED25519 key fingerprint is SHA256:SgTQf176TUJ/wSqlWH4inIAZ7NWU+eAQrewxa+aqEns.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
changed: [13.231.201.67]
TASK [sshd : Disabling password authentication] *******************************************************************************
ok: [13.231.201.67]
TASK [sshd : Disabling Challenge-Response Authentication] *********************************************************************
ok: [13.231.201.67]
TASK [sshd : Disabling root user login] ***************************************************************************************
changed: [13.231.201.67]
RUNNING HANDLER [sshd : Restart sshd] *****************************************************************************************
changed: [13.231.201.67]
PLAY RECAP ********************************************************************************************************************
13.231.201.67 : ok=6 changed=3 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
1回目は、port22が使用されていることが分かります。
2回目を実行します。
$ ansible-playbook -i hosts playbook.yml
PLAY [Change port] ************************************************************************************************************
TASK [sshd : Connect default ssh port] ****************************************************************************************
fatal: [13.231.201.67 -> localhost]: FAILED! => {"changed": false, "elapsed": 5, "msg": "Timeout when waiting for 13.231.201.67:22"}
...ignoring
TASK [sshd : Connect custom ssh port] *****************************************************************************************
ok: [13.231.201.67 -> localhost]
TASK [sshd : set ansible_ssh_port custom_ssh_port] ****************************************************************************
ok: [13.231.201.67]
TASK [sshd : Rewrite custom_ssh_port] *****************************************************************************************
skipping: [13.231.201.67]
TASK [sshd : Disabling password authentication] *******************************************************************************
ok: [13.231.201.67]
TASK [sshd : Disabling Challenge-Response Authentication] *********************************************************************
ok: [13.231.201.67]
TASK [sshd : Disabling root user login] ***************************************************************************************
ok: [13.231.201.67]
PLAY RECAP ********************************************************************************************************************
13.231.201.67 : ok=6 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=1
2回目は、custom ssh portである50001ポートが使用されている事がわかります。
3回目を実行しましょう。
ansible-playbook -i hosts playbook.yml
PLAY [Change port] ************************************************************************************************************
TASK [sshd : Connect default ssh port] ****************************************************************************************
fatal: [13.231.201.67 -> localhost]: FAILED! => {"changed": false, "elapsed": 5, "msg": "Timeout when waiting for 13.231.201.67:22"}
...ignoring
TASK [sshd : Connect custom ssh port] *****************************************************************************************
ok: [13.231.201.67 -> localhost]
TASK [sshd : set ansible_ssh_port custom_ssh_port] ****************************************************************************
ok: [13.231.201.67]
TASK [sshd : Rewrite custom_ssh_port] *****************************************************************************************
skipping: [13.231.201.67]
TASK [sshd : Disabling password authentication] *******************************************************************************
ok: [13.231.201.67]
TASK [sshd : Disabling Challenge-Response Authentication] *********************************************************************
ok: [13.231.201.67]
TASK [sshd : Disabling root user login] ***************************************************************************************
ok: [13.231.201.67]
PLAY RECAP ********************************************************************************************************************
13.231.201.67 : ok=6 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=1
3回目もport 50001が使用されていますね。
また、changed=0
であり、冪等性があることが分かります。
次回、ansibleのansible-lintを使用してコードをリファクタリング致します。
参考