ssh는 처음 접속하는 대상에게 키를 받아올 때 신뢰할 수 있는 대상인지 확인하기 위해 사용자에게 물어보는 과정을 거치고 신뢰할 수 있다고 확인된 대상에게만 세션을 수립하고 known hosts에 등록한다.
하지만 ansible을 이용할 때 이는 굉장히 불편한데 동적 인벤토리를 이용할 때 새로운 노드가 추가될 때마다 아래와 같이 플레이북에서 신뢰할 수 있는 질의를 물어보기 때문이다.
이를 해결할 수 있는 방법은 여러가지가 있다.
먼저 환경 변수에 질의자체를 하지 않도록 정의하는 것이다.
host_key_checking = False
위와 같이 적게되면 위 상황에서 질의 자체를 하지 않는다. 하지만 굉장히 보안적으로 좋지 않다. 따라서 플레이 북에 플레이를 지정하여 주는 것이 좋은 방법이다.
ssh 파일에 직접 설정하여 해당 질의문에 대하여 yes를 자동 입력하도록 할 수 있다.
~/.ssh/config
StrictHostKeyChecking=accept-new
known hosts를 모두 삭제하고 사용해봤을 때 정상 작동하는 것을 확인할 수 있다. 하지만 이런 방식은 ssh를 이용하는 모든 대상에게 자동으로 신뢰한다고 선언하는 방식이기 때문에 보안적으로 좋지 않은 방법인 것 같다.
playbook에 정의
---
- hosts:
connection: local
serial: 1
gather_facts: no
# ssh 연결 전 처리이니 facts를 비활성화 해야한다.
tasks:
- command: /usr/bin/ssh-keyscan -t ecdsa {{ ansible_host }}
register: keyscan
- lineinfile:
name=~/.ssh/known_hosts
create=yes
line={{ item }}
with_items:
- "{{ keyscan.stdout_lines }}"
connection: local
키를 입력받아 known_hosts 파일에 기입하는 처리는 ssh 연결이 아닌 local에서 일어나기에 적어줘야 한다.
아래는 connection 변수의 또 다른 값들이다.
값 설명
ssh | 기본값으로 ssh 연결에 사용 |
paramiko: | ssh 연결에 paramiko 라이브러리를 사용함 |
local | 대상 호스트에 연결 없이 local 시스템에서 task를 수행함 |
docker | 대상 호스트가 docker인 경우 docker api를 이용하여 컨테이너 내에서 명령을 실행함 |
winrm | windows 호스트에 연결할 때 winrm을 사용하여 연결 |
serial: 1
동시에 실행되는 호스트 수를 지정하는데 사용하는 변수이다. 지정된 호스트 갯수만큼 task를 실행하고 대기했다가 실행하는 식으로 이용할 수 있다.
task에서는 command 모듈과 lineinfile 모듈을 좀 더 이해해봐야겠다. 기본적인 흐름은 ssh-keyscan 명령어로 해당 노드의 키를 읽고 이를 lineinfile 모듈을 이용하여 ~/.ssh/known_hosts 파일에 적어주는 것이다.
아무튼 정상작동한다 아래의 오류는 등록 후에 ping 모듈을 이용하게 했는데 remote_user를 명시하지 않아 잘못된 유저로 접속해 오류가 난 것이다. 결과적으로 ssh config 파일에 작성해주는 것보단 ansible playbook에 지정해주는 것이 더 보안성에 용이한 것 같다.
또는 아래의 코드로도 가능하다. 개인적으로 아래의 코드가 더 복잡하지만 가독성은 더 좋은 것 같다.
- name: Example play
gather_facts: no
hosts: all
tasks:
- name: Check SSH known_hosts for {{ inventory_hostname }}
local_action: shell ssh-keygen -l -F {{ inventory_hostname }}
register: checkForKnownHostsEntry
failed_when: false
changed_when: false
ignore_errors: yes
- name: Add {{ inventory_hostname }} to SSH known hosts automatically
when: checkForKnownHostsEntry.rc == 1
changed_when: checkForKnownHostsEntry.rc == 1
local_action:
module: shell
args: ssh-keyscan -H "{{ inventory_hostname }}" >> $HOME/.ssh/known_hosts
위 코드를 이용하여서도 새롭게 추가되는 노드만 추가되도록 구성할 수 있다. 흐름은 대충 이해되는데 when 을 더 공부해보야겠다. skipped로 뜨는 이유는 known_hosts 파일에 존재하지 않는 호스트가 없기 때문에 task가 생략됐기 때문이다.
'네트워크 > 네트워크 가상화, 자동화' 카테고리의 다른 글
Anycast Gateway (0) | 2024.04.29 |
---|---|
Ansible Tags (1) | 2023.10.10 |
Ansible facts (0) | 2023.09.13 |
Ansible Overview(config, inventory, dynamic inventory, playbook) (0) | 2023.09.11 |